From 12ce6d2f87be01eab75c4da52e1c167ac66f3ea5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 28 Jul 2020 14:17:21 +0200
Subject: [PATCH 1/2] misc: split test module

---
 tests/test_admin_pages.py             | 414 +----------------------
 tests/test_datasources_admin_pages.py | 456 ++++++++++++++++++++++++++
 2 files changed, 457 insertions(+), 413 deletions(-)
 create mode 100644 tests/test_datasources_admin_pages.py

diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py
index c197abcd..fac4cc8b 100644
--- a/tests/test_admin_pages.py
+++ b/tests/test_admin_pages.py
@@ -1,12 +1,9 @@
 # -*- coding: utf-8 -*-
 
 import datetime
-from email.mime.text import MIMEText
-import json
 import logging
 import os
 import re
-import shutil
 import tarfile
 import time
 import xml.etree.ElementTree as ET
@@ -21,14 +18,11 @@ import pytest
 from webtest import Upload
 import mock
 
-from django.utils import six
 from django.utils.six import StringIO, BytesIO
 from django.utils.six.moves.urllib import parse as urlparse
 
-from quixote import cleanup, get_publisher
 from quixote.http_request import Upload as QuixoteUpload
 
-from wcs.qommon import errors, sessions
 from wcs.qommon.form import UploadedFile
 from wcs.qommon.ident.password_accounts import PasswordAccount
 from wcs.qommon.http_request import HTTPRequest
@@ -53,7 +47,7 @@ from wcs.carddef import CardDef
 from wcs.blocks import BlockDef
 from wcs import fields
 
-from utilities import get_app, login, create_temporary_pub, clean_temporary_pub, HttpRequestsMocking
+from utilities import get_app, login, create_temporary_pub, clean_temporary_pub
 
 
 def pytest_generate_tests(metafunc):
@@ -5238,412 +5232,6 @@ def test_settings_geolocation(pub):
     assert pub.cfg['misc']['default-position'] == '1.234;-1.234'
 
 
-def test_data_sources(pub):
-    create_superuser(pub)
-    app = login(get_app(pub))
-    app.get('/backoffice/settings/data-sources/')
-    # also check it's accessible from forms and workflows sections
-    app.get('/backoffice/forms/data-sources/')
-    app.get('/backoffice/workflows/data-sources/')
-
-    # unknown datasource
-    app.get('/backoffice/settings/data-sources/42/', status=404)
-    app.get('/backoffice/forms/data-sources/42/', status=404)
-    app.get('/backoffice/workflows/data-sources/42/', status=404)
-
-
-def test_data_sources_new(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    app = login(get_app(pub))
-
-    # go to the page and cancel
-    resp = app.get('/backoffice/settings/data-sources/')
-    resp = resp.click('New Data Source')
-    resp = resp.forms[0].submit('cancel')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
-
-    # go to the page and add a data source
-    resp = app.get('/backoffice/settings/data-sources/')
-    resp = resp.click('New Data Source')
-    resp.forms[0]['name'] = 'a new data source'
-    resp.forms[0]['description'] = 'description of the data source'
-    resp.forms[0]['data_source$type'] = 'python'
-    resp = resp.forms[0].submit('data_source$apply')
-    resp.forms[0]['data_source$value'] = repr(
-            [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])
-    resp = resp.forms[0].submit('submit')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
-    resp = resp.follow()
-    assert 'a new data source' in resp.text
-    resp = resp.click('a new data source')
-    assert 'Data Source - a new data source' in resp.text
-    resp = resp.click('Edit')
-    assert 'Edit Data Source' in resp.text
-
-    assert NamedDataSource.get(1).name == 'a new data source'
-    assert NamedDataSource.get(1).description == 'description of the data source'
-
-    # add a second one
-    resp = app.get('/backoffice/settings/data-sources/')
-    resp = resp.click('New Data Source')
-    resp.forms[0]['name'] = 'an other data source'
-    resp.forms[0]['description'] = 'description of the data source'
-    resp.forms[0]['data_source$type'] = 'python'
-    resp = resp.forms[0].submit('data_source$apply')
-    resp.forms[0]['data_source$value'] = repr(
-            [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])
-    resp = resp.forms[0].submit('submit')
-
-    assert NamedDataSource.count() == 2
-
-
-def test_data_sources_view(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-
-    data_source = NamedDataSource(name='foobar')
-    app = login(get_app(pub))
-
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Type of source: Python Expression' in resp.text
-    assert 'Python Expression' in resp.text
-    assert not 'Preview' in resp.text
-
-    data_source.data_source = {'type': 'formula', 'value': '["AAA", "BBB"]'}
-    data_source.store()
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Preview' in resp.text
-    assert resp.text.count('AAA') == 3 # expression + id + text
-
-    # check unicode
-    data_source.data_source = {'type': 'formula',
-            'value': repr([('Y', 'Domicilié'), ('N', u'Pas domicilié')])}
-    data_source.store()
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Preview' in resp.text
-    assert 'Domicilié' in resp.text
-
-    # check json
-    json_file_path = os.path.join(pub.app_dir, 'test.json')
-    json_file = open(json_file_path, 'w')
-    json.dump({'data': [{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]}, json_file)
-    json_file.close()
-
-    data_source.data_source = {'type': 'json', 'value': 'file://%s' % json_file_path}
-    data_source.store()
-    with HttpRequestsMocking() as http_requests:
-        resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Preview' in resp.text
-    assert 'foo' in resp.text
-
-    # variadic url
-    data_source.data_source = {'type': 'json', 'value': '{{ site_url }}/foo/bar'}
-    data_source.store()
-    with HttpRequestsMocking() as http_requests:
-        resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert '<a href="http://example.net/foo/bar"' in resp.text
-
-    data_source.data_source = {'type': 'formula', 'value': '[str(x) for x in range(100)]'}
-    data_source.store()
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Preview' in resp.text
-    assert resp.text.count('<li>') < 100
-    assert '<li>...</li>' in resp.text
-
-    data_source.data_source = {'type': 'formula', 'value': repr([
-        {'id': 'a', 'text': 'BBB', 'foo': 'bar1'},
-        {'id': 'b', 'text': 'BBB', 'foo': 'bar2'},
-        ])}
-    data_source.store()
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Preview' in resp.text
-    assert 'Additional keys are available: foo' in resp.text
-
-    # check formdef listing
-    FormDef.wipe()
-    formdef = FormDef()
-    formdef.name = 'test data source'
-    formdef.fields = [
-        fields.ItemField(id='1', label='item', data_source={'type': data_source.slug})
-    ]
-    formdef.store()
-
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Usage in forms' in resp.text
-    assert '/backoffice/forms/%s/' % formdef.id in resp.text
-
-    # additional formdef types
-    user_formdef = UserFieldsFormDef(pub)
-    user_formdef.fields.append(
-            fields.ItemField(id='1', type='item', label='item', data_source={'type': data_source.slug}))
-    user_formdef.store()
-
-    from wcs.workflows import WorkflowVariablesFieldsFormDef
-    Workflow.wipe()
-    workflow = Workflow(name='Workflow One')
-    workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
-    workflow.variables_formdef.fields.append(
-            fields.ItemField(id='1', type='idem', label='item', data_source={'type': data_source.slug}))
-    workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
-    workflow.backoffice_fields_formdef.fields.append(
-            fields.ItemField(id='1', type='item', label='item', data_source={'type': data_source.slug}))
-
-    from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
-    baz_status = workflow.add_status(name='baz')
-    display_form = FormWorkflowStatusItem()
-    display_form.id = '_x'
-    display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
-    display_form.formdef.fields.append(
-            fields.ItemField(id='1', type='item', label='item', data_source={'type': data_source.slug}))
-    baz_status.items.append(display_form)
-    display_form.parent = baz_status
-
-    workflow.store()
-
-    carddef = CardDef()
-    carddef.name = 'Baz'
-    carddef.fields = [
-        fields.ItemField(id='1', label='item', data_source={'type': data_source.slug})
-    ]
-    carddef.store()
-
-    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
-    assert 'Usage in forms' in resp.text
-    assert '/backoffice/forms/%s/' % formdef.id in resp.text
-    assert '/backoffice/workflows/%s/backoffice-fields/fields/' % workflow.id in resp.text
-    assert '/backoffice/workflows/%s/variables/fields/' % workflow.id in resp.text
-    assert '/backoffice/workflows/%s/status/1/items/_x/fields/' % workflow.id in resp.text
-    assert '/backoffice/settings/users/fields/' in resp.text
-    assert '/backoffice/cards/%s/' % carddef.id in resp.text
-
-    # cleanup
-    user_formdef = UserFieldsFormDef(pub)
-    user_formdef.fields = []
-    user_formdef.store()
-    Workflow.wipe()
-    CardDef.wipe()
-
-
-def test_data_sources_edit(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    data_source = NamedDataSource(name='foobar')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-
-    FormDef.wipe()
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/1/')
-
-    resp = resp.click(href='edit')
-    assert resp.forms[0]['name'].value == 'foobar'
-    resp.forms[0]['description'] = 'data source description'
-    resp = resp.forms[0].submit('submit')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
-    resp = resp.follow()
-
-    assert NamedDataSource.get(1).description == 'data source description'
-
-
-def test_data_sources_edit_duplicate_name(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    data_source = NamedDataSource(name='foobar')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-    data_source = NamedDataSource(name='foobar2')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='edit')
-    assert resp.forms[0]['name'].value == 'foobar'
-    resp.forms[0]['name'] = 'foobar2'
-    resp = resp.forms[0].submit('submit')
-    assert 'This name is already used' in resp.text
-
-    resp = resp.forms[0].submit('cancel')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
-
-
-def test_data_sources_delete(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    category = NamedDataSource(name='foobar')
-    category.store()
-
-    FormDef.wipe()
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/1/')
-
-    resp = resp.click(href='delete')
-    resp = resp.forms[0].submit('cancel')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
-    assert NamedDataSource.count() == 1
-
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='delete')
-    resp = resp.forms[0].submit()
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
-    resp = resp.follow()
-    assert NamedDataSource.count() == 0
-
-
-def test_data_sources_in_use_delete(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    category = NamedDataSource(name='foobar')
-    category.store()
-
-    FormDef.wipe()
-    formdef = FormDef()
-    formdef.name = 'form title'
-    formdef.fields = [
-        fields.ItemField(id='0', label='string', type='item',
-                data_source={'type': 'foobar'}),
-    ]
-    formdef.store()
-
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='delete')
-    assert 'This datasource is still used, it cannot be deleted.' in resp.text
-    assert 'delete-button' not in resp.text
-
-    formdef.fields = []
-    formdef.store()
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='delete')
-    assert 'delete-button' in resp.text
-
-
-def test_data_sources_export(pub):
-    create_superuser(pub)
-    create_role()
-
-    NamedDataSource.wipe()
-    data_source = NamedDataSource(name='foobar')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/1/')
-
-    resp = resp.click(href='export')
-    xml_export = resp.text
-
-    ds = StringIO(xml_export)
-    data_source2 = NamedDataSource.import_from_xml(ds)
-    assert data_source2.name == 'foobar'
-
-
-def test_data_sources_import(pub):
-    create_superuser(pub)
-    create_role()
-
-    NamedDataSource.wipe()
-    data_source = NamedDataSource(name='foobar')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-    data_source_xml = ET.tostring(data_source.export_to_xml(include_id=True))
-
-    NamedDataSource.wipe()
-    assert NamedDataSource.count() == 0
-
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/')
-    resp = resp.click(href='import')
-    resp.forms[0]['file'] = Upload('datasource.wcs', data_source_xml)
-    resp = resp.forms[0].submit()
-    assert NamedDataSource.count() == 1
-
-    # import the same datasource a second time, make sure slug is not reused
-    resp = app.get('/backoffice/settings/data-sources/')
-    resp = resp.click(href='import')
-    resp.forms[0]['file'] = Upload('datasource.wcs', data_source_xml)
-    resp = resp.forms[0].submit()
-    assert NamedDataSource.count() == 2
-    assert NamedDataSource.get(1).slug == 'foobar'
-    assert NamedDataSource.get(2).slug == 'foobar-1'
-
-    # import an invalid file
-    resp = app.get('/backoffice/settings/data-sources/')
-    resp = resp.click(href='import')
-    resp.form['file'] = Upload('datasource.wcs', b'garbage')
-    resp = resp.form.submit()
-    assert 'Invalid File' in resp.text
-
-
-def test_data_sources_edit_slug(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    data_source = NamedDataSource(name='foobar')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-    assert NamedDataSource.get(1).slug == 'foobar'
-
-    FormDef.wipe()
-    app = login(get_app(pub))
-
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='edit')
-    assert resp.forms[0]['name'].value == 'foobar'
-    resp.forms[0]['slug'] = 'foo_bar'
-    resp = resp.forms[0].submit('submit')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
-    assert NamedDataSource.get(1).slug == 'foo_bar'
-
-    data_source = NamedDataSource(name='barfoo')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='edit')
-    assert resp.forms[0]['name'].value == 'foobar'
-    resp.forms[0]['slug'] = 'barfoo'
-    resp = resp.forms[0].submit('submit')
-    assert 'This value is already used' in resp.text
-
-    resp.forms[0]['slug'] = 'foobar'
-    resp = resp.forms[0].submit('submit')
-    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
-
-
-def test_data_sources_in_use_edit_slug(pub):
-    create_superuser(pub)
-    NamedDataSource.wipe()
-    data_source = NamedDataSource(name='foobar')
-    data_source.data_source = {'type': 'formula', 'value': '[]'}
-    data_source.store()
-    assert NamedDataSource.get(1).slug == 'foobar'
-
-    FormDef.wipe()
-    formdef = FormDef()
-    formdef.name = 'form title'
-    formdef.fields = [
-        fields.ItemField(id='0', label='string', type='item',
-                data_source={'type': 'foobar'}),
-    ]
-    formdef.store()
-
-    app = login(get_app(pub))
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='edit')
-    assert 'form_slug' not in resp.form.fields
-    resp = resp.form.submit('submit')
-
-    formdef.fields = []
-    formdef.store()
-    resp = app.get('/backoffice/settings/data-sources/1/')
-    resp = resp.click(href='edit')
-    assert 'form_slug' in resp.text
-    resp = resp.form.submit('submit')
-
-
 def test_wscalls_new(pub):
     create_superuser(pub)
     NamedWsCall.wipe()
diff --git a/tests/test_datasources_admin_pages.py b/tests/test_datasources_admin_pages.py
new file mode 100644
index 00000000..2b7b7993
--- /dev/null
+++ b/tests/test_datasources_admin_pages.py
@@ -0,0 +1,456 @@
+# -*- coding: utf-8 -*-
+
+import json
+import os
+import xml.etree.ElementTree as ET
+
+try:
+    import lasso
+except ImportError:
+    lasso = None
+
+from django.utils.six import StringIO
+
+import pytest
+from webtest import Upload
+
+from wcs.qommon.http_request import HTTPRequest
+from wcs.admin.settings import UserFieldsFormDef
+from wcs.data_sources import NamedDataSource
+from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef
+from wcs.formdef import FormDef
+from wcs.carddef import CardDef
+from wcs import fields
+
+from utilities import get_app, login, create_temporary_pub, clean_temporary_pub, HttpRequestsMocking
+from test_admin_pages import create_superuser, create_role
+
+
+def pytest_generate_tests(metafunc):
+    if 'pub' in metafunc.fixturenames:
+        metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
+
+
+@pytest.fixture
+def pub(request):
+    pub = create_temporary_pub(
+            sql_mode=bool('sql' in request.param),
+            templates_mode=bool('templates' in request.param)
+            )
+
+    req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
+    pub.set_app_dir(req)
+    pub.cfg['identification'] = {'methods': ['password']}
+    pub.cfg['language'] = {'language': 'en'}
+    pub.write_cfg()
+
+    return pub
+
+
+def teardown_module(module):
+    clean_temporary_pub()
+
+
+def test_data_sources(pub):
+    create_superuser(pub)
+    app = login(get_app(pub))
+    app.get('/backoffice/settings/data-sources/')
+    # also check it's accessible from forms and workflows sections
+    app.get('/backoffice/forms/data-sources/')
+    app.get('/backoffice/workflows/data-sources/')
+
+    # unknown datasource
+    app.get('/backoffice/settings/data-sources/42/', status=404)
+    app.get('/backoffice/forms/data-sources/42/', status=404)
+    app.get('/backoffice/workflows/data-sources/42/', status=404)
+
+
+def test_data_sources_new(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    app = login(get_app(pub))
+
+    # go to the page and cancel
+    resp = app.get('/backoffice/settings/data-sources/')
+    resp = resp.click('New Data Source')
+    resp = resp.forms[0].submit('cancel')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
+
+    # go to the page and add a data source
+    resp = app.get('/backoffice/settings/data-sources/')
+    resp = resp.click('New Data Source')
+    resp.forms[0]['name'] = 'a new data source'
+    resp.forms[0]['description'] = 'description of the data source'
+    resp.forms[0]['data_source$type'] = 'python'
+    resp = resp.forms[0].submit('data_source$apply')
+    resp.forms[0]['data_source$value'] = repr(
+            [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])
+    resp = resp.forms[0].submit('submit')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
+    resp = resp.follow()
+    assert 'a new data source' in resp.text
+    resp = resp.click('a new data source')
+    assert 'Data Source - a new data source' in resp.text
+    resp = resp.click('Edit')
+    assert 'Edit Data Source' in resp.text
+
+    assert NamedDataSource.get(1).name == 'a new data source'
+    assert NamedDataSource.get(1).description == 'description of the data source'
+
+    # add a second one
+    resp = app.get('/backoffice/settings/data-sources/')
+    resp = resp.click('New Data Source')
+    resp.forms[0]['name'] = 'an other data source'
+    resp.forms[0]['description'] = 'description of the data source'
+    resp.forms[0]['data_source$type'] = 'python'
+    resp = resp.forms[0].submit('data_source$apply')
+    resp.forms[0]['data_source$value'] = repr(
+            [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])
+    resp = resp.forms[0].submit('submit')
+
+    assert NamedDataSource.count() == 2
+
+
+def test_data_sources_view(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+
+    data_source = NamedDataSource(name='foobar')
+    app = login(get_app(pub))
+
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Type of source: Python Expression' in resp.text
+    assert 'Python Expression' in resp.text
+    assert 'Preview' not in resp.text
+
+    data_source.data_source = {'type': 'formula', 'value': '["AAA", "BBB"]'}
+    data_source.store()
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Preview' in resp.text
+    assert resp.text.count('AAA') == 3  # expression + id + text
+
+    # check unicode
+    data_source.data_source = {
+        'type': 'formula',
+        'value': repr([('Y', 'Domicilié'), ('N', u'Pas domicilié')])}
+    data_source.store()
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Preview' in resp.text
+    assert 'Domicilié' in resp.text
+
+    # check json
+    json_file_path = os.path.join(pub.app_dir, 'test.json')
+    json_file = open(json_file_path, 'w')
+    json.dump({'data': [{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]}, json_file)
+    json_file.close()
+
+    data_source.data_source = {'type': 'json', 'value': 'file://%s' % json_file_path}
+    data_source.store()
+    with HttpRequestsMocking():
+        resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Preview' in resp.text
+    assert 'foo' in resp.text
+
+    # variadic url
+    data_source.data_source = {'type': 'json', 'value': '{{ site_url }}/foo/bar'}
+    data_source.store()
+    with HttpRequestsMocking():
+        resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert '<a href="http://example.net/foo/bar"' in resp.text
+
+    data_source.data_source = {'type': 'formula', 'value': '[str(x) for x in range(100)]'}
+    data_source.store()
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Preview' in resp.text
+    assert resp.text.count('<li>') < 100
+    assert '<li>...</li>' in resp.text
+
+    data_source.data_source = {'type': 'formula', 'value': repr([
+        {'id': 'a', 'text': 'BBB', 'foo': 'bar1'},
+        {'id': 'b', 'text': 'BBB', 'foo': 'bar2'},
+        ])}
+    data_source.store()
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Preview' in resp.text
+    assert 'Additional keys are available: foo' in resp.text
+
+    # check formdef listing
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test data source'
+    formdef.fields = [
+        fields.ItemField(id='1', label='item', data_source={'type': data_source.slug})
+    ]
+    formdef.store()
+
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Usage in forms' in resp.text
+    assert '/backoffice/forms/%s/' % formdef.id in resp.text
+
+    # additional formdef types
+    user_formdef = UserFieldsFormDef(pub)
+    user_formdef.fields.append(
+            fields.ItemField(id='1', type='item', label='item', data_source={'type': data_source.slug}))
+    user_formdef.store()
+
+    from wcs.workflows import WorkflowVariablesFieldsFormDef
+    Workflow.wipe()
+    workflow = Workflow(name='Workflow One')
+    workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
+    workflow.variables_formdef.fields.append(
+            fields.ItemField(id='1', type='idem', label='item', data_source={'type': data_source.slug}))
+    workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
+    workflow.backoffice_fields_formdef.fields.append(
+            fields.ItemField(id='1', type='item', label='item', data_source={'type': data_source.slug}))
+
+    from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
+    baz_status = workflow.add_status(name='baz')
+    display_form = FormWorkflowStatusItem()
+    display_form.id = '_x'
+    display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
+    display_form.formdef.fields.append(
+            fields.ItemField(id='1', type='item', label='item', data_source={'type': data_source.slug}))
+    baz_status.items.append(display_form)
+    display_form.parent = baz_status
+
+    workflow.store()
+
+    carddef = CardDef()
+    carddef.name = 'Baz'
+    carddef.fields = [
+        fields.ItemField(id='1', label='item', data_source={'type': data_source.slug})
+    ]
+    carddef.store()
+
+    resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
+    assert 'Usage in forms' in resp.text
+    assert '/backoffice/forms/%s/' % formdef.id in resp.text
+    assert '/backoffice/workflows/%s/backoffice-fields/fields/' % workflow.id in resp.text
+    assert '/backoffice/workflows/%s/variables/fields/' % workflow.id in resp.text
+    assert '/backoffice/workflows/%s/status/1/items/_x/fields/' % workflow.id in resp.text
+    assert '/backoffice/settings/users/fields/' in resp.text
+    assert '/backoffice/cards/%s/' % carddef.id in resp.text
+
+    # cleanup
+    user_formdef = UserFieldsFormDef(pub)
+    user_formdef.fields = []
+    user_formdef.store()
+    Workflow.wipe()
+    CardDef.wipe()
+
+
+def test_data_sources_edit(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+
+    FormDef.wipe()
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/1/')
+
+    resp = resp.click(href='edit')
+    assert resp.forms[0]['name'].value == 'foobar'
+    resp.forms[0]['description'] = 'data source description'
+    resp = resp.forms[0].submit('submit')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
+    resp = resp.follow()
+
+    assert NamedDataSource.get(1).description == 'data source description'
+
+
+def test_data_sources_edit_duplicate_name(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+    data_source = NamedDataSource(name='foobar2')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='edit')
+    assert resp.forms[0]['name'].value == 'foobar'
+    resp.forms[0]['name'] = 'foobar2'
+    resp = resp.forms[0].submit('submit')
+    assert 'This name is already used' in resp.text
+
+    resp = resp.forms[0].submit('cancel')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
+
+
+def test_data_sources_delete(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    category = NamedDataSource(name='foobar')
+    category.store()
+
+    FormDef.wipe()
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/1/')
+
+    resp = resp.click(href='delete')
+    resp = resp.forms[0].submit('cancel')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
+    assert NamedDataSource.count() == 1
+
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='delete')
+    resp = resp.forms[0].submit()
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
+    resp = resp.follow()
+    assert NamedDataSource.count() == 0
+
+
+def test_data_sources_in_use_delete(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    category = NamedDataSource(name='foobar')
+    category.store()
+
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'form title'
+    formdef.fields = [
+        fields.ItemField(id='0', label='string', type='item', data_source={'type': 'foobar'}),
+    ]
+    formdef.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='delete')
+    assert 'This datasource is still used, it cannot be deleted.' in resp.text
+    assert 'delete-button' not in resp.text
+
+    formdef.fields = []
+    formdef.store()
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='delete')
+    assert 'delete-button' in resp.text
+
+
+def test_data_sources_export(pub):
+    create_superuser(pub)
+    create_role()
+
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/1/')
+
+    resp = resp.click(href='export')
+    xml_export = resp.text
+
+    ds = StringIO(xml_export)
+    data_source2 = NamedDataSource.import_from_xml(ds)
+    assert data_source2.name == 'foobar'
+
+
+def test_data_sources_import(pub):
+    create_superuser(pub)
+    create_role()
+
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+    data_source_xml = ET.tostring(data_source.export_to_xml(include_id=True))
+
+    NamedDataSource.wipe()
+    assert NamedDataSource.count() == 0
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/')
+    resp = resp.click(href='import')
+    resp.forms[0]['file'] = Upload('datasource.wcs', data_source_xml)
+    resp = resp.forms[0].submit()
+    assert NamedDataSource.count() == 1
+
+    # import the same datasource a second time, make sure slug is not reused
+    resp = app.get('/backoffice/settings/data-sources/')
+    resp = resp.click(href='import')
+    resp.forms[0]['file'] = Upload('datasource.wcs', data_source_xml)
+    resp = resp.forms[0].submit()
+    assert NamedDataSource.count() == 2
+    assert NamedDataSource.get(1).slug == 'foobar'
+    assert NamedDataSource.get(2).slug == 'foobar-1'
+
+    # import an invalid file
+    resp = app.get('/backoffice/settings/data-sources/')
+    resp = resp.click(href='import')
+    resp.form['file'] = Upload('datasource.wcs', b'garbage')
+    resp = resp.form.submit()
+    assert 'Invalid File' in resp.text
+
+
+def test_data_sources_edit_slug(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+    assert NamedDataSource.get(1).slug == 'foobar'
+
+    FormDef.wipe()
+    app = login(get_app(pub))
+
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='edit')
+    assert resp.forms[0]['name'].value == 'foobar'
+    resp.forms[0]['slug'] = 'foo_bar'
+    resp = resp.forms[0].submit('submit')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
+    assert NamedDataSource.get(1).slug == 'foo_bar'
+
+    data_source = NamedDataSource(name='barfoo')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='edit')
+    assert resp.forms[0]['name'].value == 'foobar'
+    resp.forms[0]['slug'] = 'barfoo'
+    resp = resp.forms[0].submit('submit')
+    assert 'This value is already used' in resp.text
+
+    resp.forms[0]['slug'] = 'foobar'
+    resp = resp.forms[0].submit('submit')
+    assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
+
+
+def test_data_sources_in_use_edit_slug(pub):
+    create_superuser(pub)
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula', 'value': '[]'}
+    data_source.store()
+    assert NamedDataSource.get(1).slug == 'foobar'
+
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'form title'
+    formdef.fields = [
+        fields.ItemField(id='0', label='string', type='item', data_source={'type': 'foobar'}),
+    ]
+    formdef.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='edit')
+    assert 'form_slug' not in resp.form.fields
+    resp = resp.form.submit('submit')
+
+    formdef.fields = []
+    formdef.store()
+    resp = app.get('/backoffice/settings/data-sources/1/')
+    resp = resp.click(href='edit')
+    assert 'form_slug' in resp.text
+    resp = resp.form.submit('submit')
-- 
2.27.0

