combo/tests/test_import_export.py

271 lines
9.4 KiB
Python

import base64
import datetime
import json
import os
import shutil
import sys
import tempfile
import pytest
from django.contrib.auth.models import Group
from django.core.files import File
from django.core.management import call_command
from django.utils.encoding import force_bytes, force_text
from django.utils.six import BytesIO, StringIO
from combo.apps.assets.models import Asset
from combo.apps.gallery.models import Image, GalleryCell
from combo.apps.maps.models import MapLayer, Map
from combo.apps.pwa.models import PwaSettings, PwaNavigationEntry
from combo.data.models import Page, TextCell
from combo.data.utils import export_site, import_site, MissingGroups
pytestmark = pytest.mark.django_db
@pytest.fixture
def some_data():
page = Page(title='One', slug='one')
page.save()
page = Page(title='Two', slug='two')
page.save()
page = Page(title='Three', slug='three')
page.save()
cell = TextCell(page=page, order=0, text='hello world', placeholder='content')
cell.save()
@pytest.fixture
def some_map_layers():
MapLayer(label='Foo', slug='foo', geojson_url='http://example.net/foo/').save()
MapLayer(label='Bar', slug='bar', geojson_url='http://example.net/bar/').save()
@pytest.fixture
def some_assets():
Asset(key='banner', asset=File(BytesIO(b'test'), 'test.png')).save()
Asset(key='favicon', asset=File(BytesIO(b'test2'), 'test2.png')).save()
def get_output_of_command(command, *args, **kwargs):
old_stdout = sys.stdout
output = sys.stdout = StringIO()
call_command(command, *args, **kwargs)
sys.stdout = old_stdout
return output.getvalue()
def test_import_export(app, some_data):
output = get_output_of_command('export_site')
assert len(json.loads(output)['pages']) == 3
import_site(data={}, clean=True)
assert Page.objects.all().count() == 0
assert TextCell.objects.all().count() == 0
empty_output = get_output_of_command('export_site')
assert len(json.loads(empty_output)['pages']) == 0
Page(title='test', slug='test').save()
old_stdin = sys.stdin
sys.stdin = StringIO(json.dumps({}))
assert Page.objects.count() == 1
try:
call_command('import_site', '-', clean=True)
finally:
sys.stdin = old_stdin
assert Page.objects.count() == 0
with tempfile.NamedTemporaryFile() as f:
f.write(force_bytes(output))
f.flush()
call_command('import_site', f.name)
assert Page.objects.count() == 3
assert TextCell.objects.all().count() == 1
import_site(data={}, if_empty=True)
assert Page.objects.count() == 3
assert TextCell.objects.all().count() == 1
import_site(data=[], clean=True)
tempdir = tempfile.mkdtemp('chrono-test')
empty_output = get_output_of_command('export_site', output=os.path.join(tempdir, 't.json'))
assert os.path.exists(os.path.join(tempdir, 't.json'))
shutil.rmtree(tempdir)
def test_backward_compatibility_import(app, some_data):
old_export = Page.export_all_for_json()
Page.objects.all().delete()
import_site(data=old_export)
assert Page.objects.count() == 3
def test_import_export_map_layers(app, some_map_layers):
output = get_output_of_command('export_site')
assert len(json.loads(output)['map-layers']) == 2
import_site(data={}, clean=True)
assert MapLayer.objects.all().count() == 0
empty_output = get_output_of_command('export_site')
assert len(json.loads(empty_output)['map-layers']) == 0
MapLayer(label='Baz', slug='baz', geojson_url='http://example.net/baz/').save()
old_stdin = sys.stdin
sys.stdin = StringIO(json.dumps({}))
assert MapLayer.objects.count() == 1
try:
call_command('import_site', '-', clean=True)
finally:
sys.stdin = old_stdin
assert MapLayer.objects.count() == 0
with tempfile.NamedTemporaryFile() as f:
f.write(force_bytes(output))
f.flush()
call_command('import_site', f.name)
assert MapLayer.objects.count() == 2
import_site(data={}, if_empty=True)
assert MapLayer.objects.count() == 2
def test_import_export_map_cells(app, some_data, some_map_layers):
page = Page.objects.get(slug='one')
cell = Map(page=page, order=0, placeholder='content')
cell.save()
cell.layers.add(MapLayer.objects.get(slug='foo'))
cell.save()
site_export = get_output_of_command('export_site')
import_site(data={}, clean=True)
assert Map.objects.count() == 0
import_site(data=json.loads(site_export), clean=True)
assert Map.objects.count() == 1
assert Map.objects.all()[0].layers.all()[0].slug == 'foo'
def test_group_restrictions_import_export(app, some_data):
group = Group(name='A Group')
group.save()
page = Page.objects.get(slug='one')
page.groups = [group]
page.save()
cell = TextCell.objects.get(order=0)
cell.groups = [group]
cell.save()
output = get_output_of_command('export_site')
assert len(json.loads(output)['pages']) == 3
import_site(data={}, clean=True)
assert Page.objects.all().count() == 0
assert TextCell.objects.all().count() == 0
Group.objects.all().delete()
with pytest.raises(MissingGroups) as excinfo:
import_site(json.loads(output), clean=True)
assert excinfo.value.names == ['A Group']
group = Group(name='A Group')
group.save()
import_site(json.loads(output), clean=True)
assert Page.objects.all().count() == 3
assert TextCell.objects.all().count() == 1
page = Page.objects.get(slug='one')
assert [x.name for x in page.groups.all()] == ['A Group']
cell = TextCell.objects.get(order=0)
assert [x.name for x in cell.groups.all()] == ['A Group']
def test_import_export_assets(app, some_assets):
output = get_output_of_command('export_site')
assert len(json.loads(output)['assets']) == 2
import_site(data={}, clean=True)
assert Asset.objects.all().count() == 0
empty_output = get_output_of_command('export_site')
assert len(json.loads(empty_output)['assets']) == 0
Asset(key='footer', asset=File(StringIO('test3'), 'test3.png')).save()
old_stdin = sys.stdin
sys.stdin = StringIO(json.dumps({}))
assert Asset.objects.count() == 1
try:
call_command('import_site', '-', clean=True)
finally:
sys.stdin = old_stdin
assert Asset.objects.count() == 0
with tempfile.NamedTemporaryFile() as f:
f.write(force_bytes(output))
f.flush()
call_command('import_site', f.name)
assert Asset.objects.count() == 2
import_site(data={}, if_empty=True)
assert Asset.objects.count() == 2
def test_import_export_pwa_settings(app):
output = get_output_of_command('export_site')
pwa_settings = PwaSettings.singleton()
pwa_settings.offline_text = 'Hello world'
pwa_settings.offline_retry_button = False
pwa_settings.save()
output = get_output_of_command('export_site')
import_site(data={}, clean=True)
assert PwaSettings.objects.all().count() == 0
import_site(data=json.loads(output))
assert PwaSettings.singleton().offline_retry_button is False
assert PwaSettings.singleton().offline_text == 'Hello world'
def test_import_export_pwa_navigation(app, some_data):
page = Page.objects.get(slug='one')
entry1 = PwaNavigationEntry(label='a', url='/', order=0)
entry2 = PwaNavigationEntry(link_page=page, order=1, icon=File(BytesIO(b'te\30st'), 'test.png'))
entry1.save()
entry2.save()
output = get_output_of_command('export_site')
import_site(data={}, clean=True)
assert PwaNavigationEntry.objects.all().count() == 0
import_site(data=json.loads(output))
assert PwaNavigationEntry.objects.all().count() == 2
# check identical file was not touched
assert os.path.basename(PwaNavigationEntry.objects.get(order=1).icon.file.name) == 'test.png'
assert PwaNavigationEntry.objects.get(order=1).icon.read() == b'te\30st'
# check a second import doesn't create additional entries
import_site(data=json.loads(output))
assert PwaNavigationEntry.objects.all().count() == 2
# check with a change in icon file content
data = json.loads(output)
data['pwa']['navigation'][1]['icon:base64'] = force_text(base64.encodestring(b'TEST'))
import_site(data=data)
assert PwaNavigationEntry.objects.all().count() == 2
assert PwaNavigationEntry.objects.get(order=1).icon.read() == b'TEST'
# check with a change in icon file name
data = json.loads(output)
data['pwa']['navigation'][1]['fields']['icon'] = 'pwa/test2.png'
data['pwa']['navigation'][1]['icon:base64'] = force_text(base64.encodestring(b'TEST2'))
import_site(data=data)
assert PwaNavigationEntry.objects.all().count() == 2
assert os.path.basename(PwaNavigationEntry.objects.get(order=1).icon.file.name) == 'test2.png'
assert PwaNavigationEntry.objects.get(order=1).icon.read() == b'TEST2'
def test_import_export_gallery_images(app, some_data):
page = Page.objects.get(slug='one')
gallery = GalleryCell(page=page, order=2, placeholder='images')
gallery.save()
image1 = Image(gallery=gallery, image='path/foo.jpg', title='foo', order=1)
image2 = Image(gallery=gallery, image='path/bar.jpg', title='bar', order=2)
image1.save()
image2.save()
output = get_output_of_command('export_site')
import_site(data={}, clean=True)
assert Image.objects.all().count() == 0
import_site(data=json.loads(output))
assert Image.objects.all().count() == 2
assert image1.title == 'foo'
assert image1.image == 'path/foo.jpg'