wcs/tests/test_snapshots.py

428 lines
14 KiB
Python

import os
import shutil
import xml.etree.ElementTree as ET
import pytest
from django.utils.six import BytesIO
from quixote.http_request import Upload
from wcs.blocks import BlockDef
from wcs.carddef import CardDef
from wcs.data_sources import NamedDataSource
from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.workflows import Workflow
from wcs.workflows import ExportToModel
from wcs.wscalls import NamedWsCall
from utilities import get_app, login, create_temporary_pub, clean_temporary_pub
from test_admin_pages import create_superuser, create_role
@pytest.fixture
def pub(request, emails):
pub = create_temporary_pub(sql_mode=True, templates_mode=True, lazy_mode=True,)
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
FormDef.wipe()
CardDef.wipe()
NamedDataSource.wipe()
pub.snapshot_class.wipe()
pub.user_class.wipe()
return pub
@pytest.fixture
def formdef_with_history(pub):
formdef = FormDef()
formdef.name = 'testform'
formdef.fields = []
formdef.store()
for i in range(5):
formdef.name = 'testform %s' % i
formdef.description = 'this is a description (%s)' % i
formdef.store()
return formdef
def teardown_module(module):
clean_temporary_pub()
def test_snapshot_basics(pub):
formdef = FormDef()
formdef.name = 'testform'
formdef.fields = []
formdef.store()
carddef = CardDef()
carddef.name = 'testcard'
carddef.fields = []
carddef.store()
formdef.name = 'testform2'
formdef.store()
carddef.name = 'testcard2'
carddef.store()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'formula',
'value': repr([('1', 'un'), ('2', 'deux')])}
data_source.store()
assert pub.snapshot_class.count() == 5
# check calling .store() without changes doesn't create snapshots
# (this cannot be done on formdefs/carddefs as they embed a modification
# time)
data_source.store()
assert pub.snapshot_class.count() == 5
# check we got correct data in the serializations
snapshot = pub.snapshot_class.get_latest('formdef', formdef.id)
assert '>testform2<' in snapshot.serialization
snapshot = pub.snapshot_class.get_latest('carddef', carddef.id)
assert '>testcard2<' in snapshot.serialization
def test_snapshot_instance(pub):
formdef = FormDef()
formdef.name = 'testform'
formdef.fields = []
formdef.store()
carddef = CardDef()
carddef.name = 'testcard'
carddef.fields = []
carddef.store()
# remove existing snapshots as they may be duplicated if table_name was
# generated in a different second.
pub.snapshot_class.wipe()
carddef.name = 'testcard2'
carddef.store()
for i in range(10):
formdef.name = 'testform %s' % i
formdef.store()
assert pub.snapshot_class.count() == 11
snapshots = pub.snapshot_class.select_object_history(formdef)
assert len(snapshots) == 10
for i in range(10):
assert snapshots[i].serialization is None
assert pub.snapshot_class.get(snapshots[i].id).instance.name == 'testform %s' % (9 - i)
snapshots = pub.snapshot_class.select_object_history(carddef)
assert len(snapshots) == 1
def test_snapshot_user(pub):
user = pub.user_class()
user.name = 'User Name'
user.email = 'foo@localhost'
user.store()
carddef = CardDef()
carddef.name = 'testcard'
carddef.fields = []
carddef.store()
snapshot = pub.snapshot_class.select_object_history(carddef)[0]
assert snapshot.user is None
snapshot.user_id = user.id
snapshot.store()
snapshot = pub.snapshot_class.select_object_history(carddef)[0]
assert str(snapshot.user) == 'User Name'
snapshot.user_id = 'nope'
snapshot.store()
snapshot = pub.snapshot_class.select_object_history(carddef)[0]
assert str(snapshot.user) == 'unknown user'
def test_form_snapshot_comments(pub):
create_superuser(pub)
create_role()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/')
resp = resp.click('New Form')
resp.form['name'] = 'form title'
resp = resp.form.submit().follow()
# .store() then .disabled = True, then .store() again -> 2.
assert pub.snapshot_class.count() == 2
resp = resp.click('Confirmation Page')
assert resp.form['confirmation'].checked
resp.form['confirmation'].checked = False
resp = resp.form.submit().follow()
assert pub.snapshot_class.count() == 3
assert pub.snapshot_class.select(order_by='-timestamp')[0].comment == 'Changed "Confirmation Page" parameters'
resp = resp.click(href='fields/')
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'string'
resp = resp.forms[0].submit().follow()
assert pub.snapshot_class.select(order_by='-timestamp')[0].comment == 'New field "foobar"'
def test_form_snapshot_history(pub, formdef_with_history):
create_superuser(pub)
create_role()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef_with_history.id)
resp = resp.click('History')
assert [x.attrib['class'] for x in resp.pyquery.find('ul.snapshots-list li')] == [
'new-day', 'collapsed', 'collapsed', 'collapsed', 'collapsed', 'collapsed']
def test_form_snapshot_export(pub, formdef_with_history):
create_superuser(pub)
create_role()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
snapshot = pub.snapshot_class.select_object_history(formdef_with_history)[2]
resp_export = resp.click(href='%s/export' % snapshot.id)
assert resp_export.content_type == 'application/x-wcs-snapshot'
assert '>testform 2<' in resp_export.text
def test_form_snapshot_restore(pub, formdef_with_history):
create_superuser(pub)
create_role()
app = login(get_app(pub))
# restore as new
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
snapshot = pub.snapshot_class.select_object_history(formdef_with_history)[2]
resp = resp.click(href='%s/restore' % snapshot.id)
assert resp.form['action'].value == 'as-new'
resp = resp.form.submit('submit')
assert FormDef.count() == 2
formdef = FormDef.get(resp.location.split('/')[-2])
assert formdef.url_name != formdef_with_history.url_name
# restore over
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
snapshot = pub.snapshot_class.select_object_history(formdef_with_history)[2]
resp = resp.click(href='%s/restore' % snapshot.id)
resp.form['action'].value = 'overwrite'
resp = resp.form.submit('submit')
assert FormDef.count() == 2
formdef = FormDef.get(resp.location.split('/')[-2])
assert formdef.id == formdef_with_history.id
assert formdef.url_name == formdef_with_history.url_name
def test_block_snapshot_browse(pub, blocks_feature):
create_superuser(pub)
create_role()
BlockDef.wipe()
blockdef = BlockDef()
blockdef.name = 'testblock'
blockdef.fields = []
blockdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/blocks/%s/history/' % blockdef.id)
snapshot = pub.snapshot_class.select_object_history(blockdef)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This block of fields is readonly.' in resp
def test_card_snapshot_browse(pub):
create_superuser(pub)
create_role()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'testcard'
carddef.fields = []
carddef.store()
pub.custom_view_class.wipe()
custom_view = pub.custom_view_class()
custom_view.title = 'shared form view'
custom_view.formdef = carddef
custom_view.columns = {'list': [{'id': 'id'}]}
custom_view.filters = {}
custom_view.visibility = 'any'
custom_view.store()
# new version has custom views
carddef.name = 'test 1'
carddef.store()
# delete custom views
pub.custom_view_class.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/cards/%s/history/' % carddef.id)
snapshot = pub.snapshot_class.select_object_history(carddef)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This card model is readonly' in resp
resp = resp.click('Geolocation')
assert [x[0].name for x in resp.form.fields.values() if x[0].tag == 'button'] == ['cancel']
assert pub.custom_view_class.count() == 0 # custom views are not restore on preview
def test_datasource_snapshot_browse(pub):
create_superuser(pub)
create_role()
NamedDataSource.wipe()
datasource = NamedDataSource(name='test')
datasource.data_source = {'type': 'formula',
'value': repr([('1', 'un'), ('2', 'deux')])}
datasource.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/data-sources/%s/history/' % datasource.id)
snapshot = pub.snapshot_class.select_object_history(datasource)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This data source is readonly' in resp
with pytest.raises(IndexError):
resp = resp.click('Edit')
def test_form_snapshot_browse(pub, formdef_with_history):
create_superuser(pub)
create_role()
app = login(get_app(pub))
pub.custom_view_class.wipe()
custom_view = pub.custom_view_class()
custom_view.title = 'shared form view'
custom_view.formdef = formdef_with_history
custom_view.columns = {'list': [{'id': 'id'}]}
custom_view.filters = {}
custom_view.visibility = 'any'
custom_view.store()
# version 5 has custom views
formdef_with_history.name = 'testform 5'
formdef_with_history.description = 'this is a description (5)'
formdef_with_history.store()
# delete custom views
pub.custom_view_class.wipe()
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
snapshot = pub.snapshot_class.select_object_history(formdef_with_history)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This form is readonly' in resp
resp = resp.click('Description')
assert resp.form['description'].value == 'this is a description (5)'
assert [x[0].name for x in resp.form.fields.values() if x[0].tag == 'button'] == ['cancel']
assert pub.custom_view_class.count() == 0 # custom views are not restore on preview
def test_workflow_snapshot_browse(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='test')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/history/' % workflow.id)
snapshot = pub.snapshot_class.select_object_history(workflow)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This workflow is readonly' in resp
def test_workflow_with_model_snapshot_browse(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
if os.path.exists(os.path.join(pub.app_dir, 'models')):
shutil.rmtree(os.path.join(pub.app_dir, 'models'))
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
export_to = ExportToModel()
export_to.label = 'test'
upload = Upload('/foo/bar', content_type='application/vnd.oasis.opendocument.text')
file_content = b'''PK\x03\x04\x14\x00\x00\x08\x00\x00\'l\x8eG^\xc62\x0c\'\x00'''
upload.fp = BytesIO()
upload.fp.write(file_content)
upload.fp.seek(0)
export_to.model_file = UploadedFile('models', 'tmp', upload)
st1.items.append(export_to)
export_to.parent = st1
# export/import to get models stored in the expected way
workflow.store()
workflow = Workflow.import_from_xml_tree(
ET.fromstring(ET.tostring(workflow.export_to_xml(include_id=True))), include_id=True)
assert len(os.listdir(os.path.join(pub.app_dir, 'models'))) == 2
workflow = Workflow.import_from_xml_tree(
ET.fromstring(ET.tostring(workflow.export_to_xml(include_id=True))), include_id=True)
assert len(os.listdir(os.path.join(pub.app_dir, 'models'))) == 2
app = login(get_app(pub))
for i in range(3):
# check document model is not overwritten
resp = app.get('/backoffice/workflows/%s/history/' % workflow.id)
snapshot = pub.snapshot_class.select_object_history(workflow)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This workflow is readonly' in resp
assert len(os.listdir(os.path.join(pub.app_dir, 'models'))) == 3 + i
def test_wscall_snapshot_browse(pub):
create_superuser(pub)
create_role()
NamedWsCall.wipe()
wscall = NamedWsCall(name='test')
wscall.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/wscalls/%s/history/' % wscall.id)
snapshot = pub.snapshot_class.select_object_history(wscall)[0]
resp = resp.click(href='%s/view/' % snapshot.id)
assert 'This webservice call is readonly' in resp
with pytest.raises(IndexError):
resp = resp.click('Edit')
def test_form_snapshot_save(pub, formdef_with_history):
create_superuser(pub)
create_role()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef_with_history.id)
resp = resp.click('Save snapshot')
resp.form['label'] = 'test snapshot'
resp = resp.form.submit('submit')
# add more snapshots
formdef = FormDef.get(id=formdef_with_history.id)
for i in range(10, 15):
formdef.description = 'this is a description (%s)' % i
formdef.store()
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
assert [x.attrib['class'] for x in resp.pyquery.find('ul.snapshots-list li')] == [
'new-day', 'collapsed', 'collapsed', 'collapsed', 'collapsed', 'has-label',
'collapsed', 'collapsed', 'collapsed', 'collapsed', 'collapsed', 'collapsed']