def setUpClass(cls): super(TestBuildingCaseSchemaFromMultipleApplications, cls).setUpClass() cls.current_app = Application.wrap(cls.get_json('basic_case_application')) cls.other_current_app = Application.wrap(cls.get_json('basic_case_application')) cls.other_current_app._id = 'other-app-id' cls.first_build = Application.wrap(cls.get_json('basic_case_application')) cls.first_build._id = '123' cls.first_build.copy_of = cls.current_app.get_id cls.first_build.version = 3 cls.other_build = Application.wrap(cls.get_json('basic_case_application')) cls.other_build._id = '456' cls.other_build.copy_of = cls.other_current_app._id cls.other_build.version = 4 cls.other_build.has_submissions = True cls.apps = [ cls.current_app, cls.other_current_app, cls.first_build, cls.other_build, ] with drop_connected_signals(app_post_save): for app in cls.apps: app.save()
def setUpClass(cls): cls.current_app = Application.wrap(cls.get_json('basic_case_application')) cls.first_build = Application.wrap(cls.get_json('basic_case_application')) cls.first_build._id = '123' cls.first_build.copy_of = cls.current_app.get_id cls.first_build.version = 3 cls.apps = [ cls.current_app, cls.first_build, ] for app in cls.apps: app.save()
def setUpClass(cls): cls.current_app = Application.wrap(cls.get_json('basic_case_application')) cls.first_build = Application.wrap(cls.get_json('basic_case_application')) cls.first_build._id = '123' cls.first_build.copy_of = cls.current_app.get_id cls.first_build.version = 3 cls.apps = [ cls.current_app, cls.first_build, ] with drop_connected_signals(app_post_save): for app in cls.apps: app.save()
def test_app_icon_permissions(self): LOGO_HOME = u'hq_logo_android_home' LOGO_LOGIN = u'hq_logo_android_login' advanced_sub = Subscription.new_domain_subscription( self.account, self.domain.name, self.advanced_plan, web_user=self.admin_user.username ) with open(os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-standard.json')) as f: standard_source = json.load(f) with open(os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-build.json')) as f: build_source = json.load(f) app_standard = Application.wrap(standard_source) app_standard.save() self.assertEqual(self.domain.name, app_standard.domain) app_build = Application.wrap(build_source) app_build.save() self.assertEqual(self.domain.name, app_build.domain) self.assertTrue(LOGO_HOME in app_standard.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs.keys()) self.assertTrue(LOGO_HOME in app_build.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_build.logo_refs.keys()) advanced_sub.cancel_subscription(web_user=self.admin_user.username) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertFalse(LOGO_HOME in app_standard.logo_refs.keys()) self.assertFalse(LOGO_LOGIN in app_standard.logo_refs.keys()) self.assertFalse(LOGO_HOME in app_build.logo_refs.keys()) self.assertFalse(LOGO_LOGIN in app_build.logo_refs.keys()) Subscription.new_domain_subscription( self.account, self.domain.name, self.advanced_plan, web_user=self.admin_user.username ) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertTrue(LOGO_HOME in app_standard.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs.keys()) self.assertTrue(LOGO_HOME in app_build.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_build.logo_refs.keys())
def test_form_workflow_root(self): app = Application.wrap(self.get_json('suite-workflow')) for module in app.get_modules(): for form in module.get_forms(): form.post_form_workflow = WORKFLOW_ROOT self.assertXmlPartialEqual(self.get_xml('suite-workflow-root'), app.create_suite(), "./entry")
def test_form_workflow_module_in_root(self): app = Application.wrap(self.get_json('suite-workflow')) for m in [1, 2]: module = app.get_module(m) module.put_in_root = True self.assertXmlPartialEqual(self.get_xml('suite-workflow-module-in-root'), app.create_suite(), "./entry")
def test_build_from_saved_schema(self): app = self.current_app schema = CaseExportDataSchema.generate_schema_from_builds( app.domain, app._id, self.case_type, ) self.assertEqual(schema.last_app_versions[app._id], app.version) # One for case, one for case history self.assertEqual(len(schema.group_schemas), 2) # After the first schema has been saved let's add a second app to process second_build = Application.wrap(self.get_json('basic_case_application')) second_build._id = '456' second_build.copy_of = app.get_id second_build.version = 6 with drop_connected_signals(app_post_save): second_build.save() self.addCleanup(second_build.delete) new_schema = CaseExportDataSchema.generate_schema_from_builds( app.domain, app._id, self.case_type, ) self.assertEqual(new_schema._id, schema._id) self.assertEqual(new_schema.last_app_versions[app._id], app.version) # One for case, one for case history self.assertEqual(len(new_schema.group_schemas), 2)
def testBuildApp(self): # do it from a NOT-SAVED app; # regression test against case where contents gets lazy-put w/o saving app = Application.wrap(self._yesno_source) self.assertEqual(app['_id'], None) # i.e. hasn't been saved copy = app.make_build() copy.save()
def test_advanced_suite_auto_select_user(self): app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases[0].auto_select = AutoSelectCase( mode=AUTO_SELECT_USER, value_key='case_id' ) self.assertXmlEqual(self.get_xml('suite-advanced-autoselect-user'), app.create_suite())
def test_advanced_suite_auto_select_with_filter(self): """ Form filtering should be done using the last 'non-autoload' case being loaded. """ app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases.append(LoadUpdateAction( case_tag='autoload', auto_select=AutoSelectCase( mode=AUTO_SELECT_USER, value_key='case_id' ) )) form = app.get_module(1).get_form(0) form.form_filter = "./edd = '123'" suite = app.create_suite() self.assertXmlPartialEqual(self.get_xml('suite-advanced-autoselect-with-filter'), suite, './entry[2]') menu = """ <partial> <menu id="m1"> <text> <locale id="modules.m1"/> </text> <command id="m1-f0" relevant="instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_case_clinic]/edd = '123'"/> <command id="m1-f1"/> <command id="m1-f2"/> <command id="m1-case-list"/> </menu> </partial> """ self.assertXmlPartialEqual(menu, suite, "./menu[@id='m1']")
def test_missing_itext(self): self.app = Application.wrap(self.get_json("app_no_itext")) self.assert_question_label('question1', 0, 0, "en", "/data/question1") try: self.do_upload("upload_no_change") except Exception as e: self.fail(e)
def test_missing_itext(self): self.app = Application.wrap(self.get_json("app_no_itext")) self.assert_question_label('question1', 0, 0, "en", "/data/question1") try: self.upload_raw_excel_translations(self.upload_no_change_headers, self.upload_no_change_data) except Exception as e: self.fail(e)
def test_advanced_suite_auto_select_raw(self): app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases[0].auto_select = AutoSelectCase( mode=AUTO_SELECT_RAW, value_key='some xpath expression' ) self.assertXmlEqual(self.get_xml('suite-advanced-autoselect-raw'), app.create_suite())
def test_advanced_suite_case_list_filter(self): app = Application.wrap(self.get_json('suite-advanced')) clinic_module = app.get_module(0) clinic_module.case_details.short.filter = "(filter = 'danny')" clinic_module_id = clinic_module.unique_id app.get_module(1).get_form(0).actions.load_update_cases[0].details_module = clinic_module_id self.assertXmlEqual(self.get_xml('suite-advanced-filter'), app.create_suite())
def test_form_workflow_module(self): app = Application.wrap(self.get_json('suite-workflow')) for module in app.get_modules(): for form in module.get_forms(): form.post_form_workflow = WORKFLOW_MODULE self.assertXmlEqual(self.get_xml('suite-workflow-module'), app.create_suite())
def test_advanced_suite_auto_select_usercase(self): app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases[0].auto_select = AutoSelectCase( mode=AUTO_SELECT_USERCASE ) self.assertXmlPartialEqual(self.get_xml('suite-advanced-autoselect-usercase'), app.create_suite(), './entry[2]')
def test_subcase_errors(self): with open(os.path.join(os.path.dirname(__file__), "data", "subcase-details.json")) as f: source = json.load(f) app = Application.wrap(source) errors = app.validate_app() update_path_error = { "type": "path error", "path": "/data/parent_age", "form_type": "module_form", "module": {"name": {"en": "Parent"}, "id": 0}, "form": {"id": 0, "name": {"en": "Register"}}, } subcase_path_error = { "type": "path error", "path": "/data/child_age", "form_type": "module_form", "module": {"name": {"en": "Parent"}, "id": 0}, "form": {"id": 0, "name": {"en": "Register"}}, } self.assertIn(update_path_error, errors) self.assertIn(subcase_path_error, errors) form = app.get_module(0).get_form(0) errors = form.validate_for_build() self.assertIn(update_path_error, errors) self.assertIn(subcase_path_error, errors)
def test_advanced_suite_details(self): app = Application.wrap(self.get_json('suite-advanced')) clinic_module_id = app.get_module(0).unique_id other_module_id = app.get_module(1).unique_id app.get_module(1).get_form(0).actions.load_update_cases[0].details_module = clinic_module_id app.get_module(1).get_form(1).actions.load_update_cases[0].details_module = other_module_id self.assertXmlEqual(self.get_xml('suite-advanced-details'), app.create_suite())
def test(self): app = Application.wrap(self.get_json('question_schema_test_app')) app._id = '123' app.version = 1 xmlns = 'http://openrosa.org/formdesigner/284D3F7C-9C10-48E6-97AC-C37927CBA89A' schema = FormQuestionSchema(xmlns=xmlns) schema.update_for_app(app) self.assertIn(app.get_id, schema.processed_apps) self.assertEqual(app.version, schema.last_processed_version) self.assertEqual(schema.question_schema['form.multi_root'].options, ['item1', 'item2', 'item3']) self.assertEqual(schema.question_schema['form.group1.multi_level1'].options, ['item1', 'item2']) self.assertEqual(schema.question_schema['form.group1.question6.multi_level_2'].options, ['item1', 'item2']) self.assertEqual(schema.question_schema['form.repeat_1.multi_level_1_repeat'].options, ['item1', 'item2']) self.assertEqual(schema.question_schema['form.repeat_1.multi_level_1_repeat'].repeat_context, 'form.repeat_1') updated_form_xml = self.get_xml('question_schema_update_form') app.get_form_by_xmlns(xmlns).source = updated_form_xml app.version = 2 schema.update_for_app(app) self.assertEqual(1, len(schema.processed_apps)) self.assertIn(app.get_id, schema.processed_apps) self.assertEqual(app.version, schema.last_processed_version) self.assertEqual(schema.question_schema['form.new_multi'].options, ['z_first', 'a_last']) self.assertEqual(schema.question_schema['form.group1.multi_level1'].options, ['item1', 'item2', '1_item'])
def update_schema(self): key = [self.domain, self.app_id] all_apps = Application.get_db().view( 'app_manager/saved_app', startkey=key + [self.last_processed_version], endkey=key + [{}], reduce=False, include_docs=False, skip=(1 if self.last_processed_version else 0)).all() all_seen_apps = self.apps_with_errors | self.processed_apps to_process = [ app['id'] for app in all_apps if app['id'] not in all_seen_apps ] if self.app_id not in all_seen_apps: to_process.append(self.app_id) for app_doc in iter_docs(Application.get_db(), to_process): if app_doc['doc_type'] == 'RemoteApp': continue app = Application.wrap(app_doc) try: self.update_for_app(app) except AppManagerException: self.apps_with_errors.add(app.get_id) self.last_processed_version = app.version if to_process: self.save()
def handle(self, *args, **options): path, build_slug = args app_slugs = [] perfpath = os.path.join(path, '{}-performance.txt'.format(build_slug)) if os.path.exists(perfpath): os.remove(perfpath) for name in os.listdir(os.path.join(path, 'src')): _JSON = '.json' if name.endswith(_JSON): app_slugs.append(name[:-len(_JSON)]) for slug in app_slugs: print 'Fetching %s...' % slug source_path = os.path.join(path, 'src', '%s.json' % slug) with open(source_path) as f: j = json.load(f) if j['doc_type'] == 'Application': app = Application.wrap(j) elif j['doc_type'] == 'RemoteApp': app = RemoteApp.wrap(j) app.version = 1 if not app.domain: app.domain = "test" build_path = os.path.join(path, build_slug, slug) print ' Creating files...' if options.get('track_perf'): with record_performance_stats(perfpath, slug): files = app.create_all_files() else: files = app.create_all_files() self.write_files(files, build_path)
def test_advanced_suite_auto_select_raw(self): app = Application.wrap(self.get_json("suite-advanced")) app.get_module(1).get_form(0).actions.load_update_cases[0].auto_select = AutoSelectCase( mode=AUTO_SELECT_RAW, value_key=("some xpath expression " "containing instance('casedb') " "and instance('commcaresession')"), ) self.assertXmlPartialEqual(self.get_xml("suite-advanced-autoselect-raw"), app.create_suite(), "./entry[2]")
def generate_schema_from_builds(domain, case_type): """Builds a schema from Application builds for a given identifier :param domain: The domain that the export belongs to :param unique_form_id: The unique identifier of the item being exported :returns: Returns a ExportDataSchema instance """ app_build_ids = get_all_app_ids(domain) all_case_schema = CaseExportDataSchema() for app_doc in iter_docs(Application.get_db(), app_build_ids): app = Application.wrap(app_doc) case_property_mapping = get_case_properties( app, [case_type], include_parent_properties=False ) case_schema = CaseExportDataSchema._generate_schema_from_case_property_mapping( case_property_mapping, app.version, ) case_history_schema = CaseExportDataSchema._generate_schema_for_case_history( case_property_mapping, app.version, ) all_case_schema = CaseExportDataSchema._merge_schemas( all_case_schema, case_schema, case_history_schema ) return all_case_schema
def setUpClass(cls): cls.project = Domain(name=cls.domain) cls.project.save() cls.first_saved_version = 2 cls.apps = [ # .wrap adds lots of stuff in, but is hard to call directly # this workaround seems to work Application.wrap(Application(domain=cls.domain, name="foo", version=1, modules=[Module()]).to_json()), RemoteApp.wrap(RemoteApp(domain=cls.domain, version=1, name="bar").to_json()), ] for app in cls.apps: app.save() cls.decoy_apps = [ # this one is a build Application( domain=cls.domain, copy_of=cls.apps[0].get_id, version=cls.first_saved_version, has_submissions=True ), # this one is another build Application(domain=cls.domain, copy_of=cls.apps[0].get_id, version=12), # this one is another app Application(domain=cls.domain, copy_of="1234", version=12), # this one is in the wrong domain Application(domain="decoy-domain", version=5), ] for app in cls.decoy_apps: app.save()
def test_subcase_errors(self): with open(os.path.join(os.path.dirname(__file__), 'data', 'subcase-details.json')) as f: source = json.load(f) app = Application.wrap(source) errors = app.validate_app() update_path_error = { 'type': 'path error', 'path': '/data/parent_age', 'form_type': 'module_form', 'module': {'name': {'en': "Parent"}, 'id': 0}, 'form': {'id': 0, 'name': {'en': "Register"}}, } subcase_path_error = { 'type': 'path error', 'path': '/data/child_age', 'form_type': 'module_form', 'module': {'name': {'en': "Parent"}, 'id': 0}, 'form': {'id': 0, 'name': {'en': "Register"}}, } self.assertIn(update_path_error, errors) self.assertIn(subcase_path_error, errors) form = app.get_module(0).get_form(0) errors = form.validate_for_build() self.assertIn(update_path_error, errors) self.assertIn(subcase_path_error, errors)
def test_build_from_saved_schema(self): app = self.current_app schema = FormExportDataSchema.generate_schema_from_builds( app.domain, app._id, 'my_sweet_xmlns' ) self.assertEqual(len(schema.group_schemas), 1) self.assertEqual(schema.last_app_versions[app._id], self.first_build.version) # After the first schema has been saved let's add a second app to process second_build = Application.wrap(self.get_json('basic_application')) second_build._id = '456' second_build.copy_of = app.get_id second_build.version = 6 second_build.has_submissions = True second_build.save() self.addCleanup(second_build.delete) new_schema = FormExportDataSchema.generate_schema_from_builds( app.domain, app._id, 'my_sweet_xmlns' ) self.assertEqual(new_schema._id, schema._id) self.assertEqual(new_schema.last_app_versions[app._id], second_build.version) self.assertEqual(len(new_schema.group_schemas), 1)
def test_advanced_suite_auto_select_fixture(self): app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases[0].auto_select = AutoSelectCase( mode=AUTO_SELECT_FIXTURE, value_source='table_tag', value_key='field_name' ) self.assertXmlEqual(self.get_xml('suite-advanced-autoselect-fixture'), app.create_suite())
def test_form_filter(self): """ Ensure form filter gets added correctly and appropriate instances get added to the entry. """ app = Application.wrap(self.get_json('suite-advanced')) form = app.get_module(1).get_form(1) form.form_filter = "./edd = '123'" self.assertXmlEqual(self.get_xml('form-filter'), app.create_suite())
def test_simple_form_management(self): app = Application.wrap(self.get_json('simple_app.json')) self.assertEqual('userreports_test', app.domain) data_sources = get_form_data_sources(app) self.assertEqual(1, len(data_sources)) data_source = data_sources['http://openrosa.org/formdesigner/AF6F83BA-09A9-4773-9177-AB51EA6CF802'] for indicator in data_source.configured_indicators: self.assertIsNotNone(indicator)
def test_app_icon_permissions(self): LOGO_HOME = 'hq_logo_android_home' LOGO_LOGIN = '******' advanced_sub = self._subscribe_to_advanced() with open(os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-standard.json')) as f: standard_source = json.load(f) with open(os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-build.json')) as f: build_source = json.load(f) app_standard = Application.wrap(standard_source) app_standard.save() self.assertEqual(self.project.name, app_standard.domain) app_build = Application.wrap(build_source) app_build.save() self.assertEqual(self.project.name, app_build.domain) self.assertTrue(LOGO_HOME in app_standard.logo_refs) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs) self.assertTrue(LOGO_HOME in app_build.logo_refs) self.assertTrue(LOGO_LOGIN in app_build.logo_refs) community_sub = advanced_sub.change_plan(DefaultProductPlan.get_default_plan_version()) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertFalse(LOGO_HOME in app_standard.logo_refs) self.assertFalse(LOGO_LOGIN in app_standard.logo_refs) self.assertFalse(LOGO_HOME in app_build.logo_refs) self.assertFalse(LOGO_LOGIN in app_build.logo_refs) community_sub.change_plan( DefaultProductPlan.get_default_plan_version(edition=SoftwarePlanEdition.ADVANCED) ) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertTrue(LOGO_HOME in app_standard.logo_refs) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs) self.assertTrue(LOGO_HOME in app_build.logo_refs) self.assertTrue(LOGO_LOGIN in app_build.logo_refs)
def test_sort_cache_suite(self): app = Application.wrap(self.get_json('suite-advanced')) detail = app.modules[0].case_details.short detail.sort_elements.append( SortElement( field=detail.columns[0].field, type='index', direction='descending', blanks='first', ) ) self.assertXmlPartialEqual( self.get_xml('sort-cache'), app.create_suite(), "./detail[@id='m0_case_short']" )
def test_advanced_suite_load_from_fixture(self): nodeset = "instance('item-list:table_tag')/calendar/year/month/day[@date > 735992 and @date < 736000]" app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases.append(LoadUpdateAction( case_type="clinic", load_case_from_fixture=LoadCaseFromFixture( fixture_nodeset=nodeset, fixture_tag="selected_date", fixture_variable="date", case_property="adherence_event_date", auto_select=True, ) )) suite = app.create_suite() self.assertXmlPartialEqual(self.get_xml('load_from_fixture_session'), suite, './entry[2]/session') self.assertXmlPartialEqual(self.get_xml('load_from_fixture_instance'), suite, './entry[2]/instance')
def test_advanced_suite_case_list_filter(self, *args): app = Application.wrap(self.get_json('suite-advanced')) clinic_module = app.get_module(0) clinic_module.case_details.short.filter = "(filter = 'danny')" clinic_module_id = clinic_module.unique_id app.get_module(1).get_form( 0).actions.load_update_cases[0].details_module = clinic_module_id req_module = app.get_module(2) req_module.case_details.short.filter = "filter = 'this'][other = 'that'" req_module_id = req_module.unique_id app.get_module(2).get_form( 0).actions.load_update_cases[0].details_module = req_module_id self.assertXmlEqual(self.get_xml('suite-advanced-filter'), app.create_suite())
def test_duplicate_remote_request(self, *args): """ Adding a second search config should not affect the initial one. """ copy_app = Application.wrap(self.app.to_json()) copy_app.modules.append(Module.wrap(copy_app.modules[0].to_json())) with patch( 'corehq.util.view_utils.get_url_base') as get_url_base_patch: get_url_base_patch.return_value = 'https://www.example.com' suite = copy_app.create_suite() self.assertXmlPartialEqual( self.get_xml('remote_request').decode('utf-8').format( module_id="m0"), suite, "./remote-request[1]") self.assertXmlPartialEqual( self.get_xml('remote_request').decode('utf-8').format( module_id="m1"), suite, "./remote-request[2]")
def setUp(self): self.is_usercase_in_use_patch = patch( 'corehq.apps.app_manager.models.is_usercase_in_use') self.is_usercase_in_use_mock = self.is_usercase_in_use_patch.start() self.is_usercase_in_use_mock.return_value = True self.app = Application.wrap(self.get_json('suite-advanced')) self.module = self.app.get_module(1) self.module.has_schedule = True self.form_1 = self.module.get_form(0) self.form_2 = self.module.get_form(1) self.form_3 = self.module.get_form(2) self._add_form_abbreviations() self._add_form_schedules() self._add_form_detail_variable()
def setUpClass(cls): cls.app = Application.wrap(cls.get_json("app")) # Todo, refactor this into BulkAppTranslationTestBase.upload_raw_excel_translations file = StringIO() export_raw(cls.excel_headers, cls.excel_data, file, format=Format.XLS_2007) with tempfile.TemporaryFile(suffix='.xlsx') as f: f.write(file.getvalue()) wb_reader = WorkbookJSONReader(f) cls.expected_workbook = [{ 'name': ws.title, 'rows': list(ws) } for ws in wb_reader.worksheets]
def premature_auto_gps(build): app = Application.wrap(build) if app.build_version and app.build_version >= LooseVersion('2.14'): return for module in app.get_modules(): for form in module.get_forms(): try: built_source = app.fetch_attachment( 'files/modules-{}/forms-{}.xml'.format(module.id, form.id)) except ResourceNotFound: continue if form.get_auto_gps_capture(): return 'auto gps error' elif XForm(built_source).model_node.find("{orx}pollsensor"): return 'auto gps error'
def test_unused_media_removed(self, mock): image_path = 'jr://file/commcare/image{}_{}.jpg' audio_path = 'jr://file/commcare/audio{}_{}.mp3' app = Application.wrap(self.get_json('app')) app.domain = self.domain app.save() for lang in ['en', 'hin']: for num in ['1', '2', '3', '4']: app.create_mapping(CommCareImage(_id=num), image_path.format(num, lang), save=False) app.create_mapping(CommCareAudio(_id=num), audio_path.format(num, lang), save=False) app.get_module(0).case_list.show = True app.get_module(0).case_list.set_icon('en', image_path.format('4', 'en')) app.get_module(0).case_list.set_audio('en', audio_path.format('4', 'en')) app.get_module(0).set_icon('en', image_path.format('1', 'en')) app.get_module(0).set_audio('en', audio_path.format('1', 'en')) app.get_module(0).case_list_form.form_id = app.get_module(0).get_form(0).unique_id app.get_module(0).case_list_form.set_icon('en', image_path.format('2', 'en')) app.get_module(0).case_list_form.set_audio('en', audio_path.format('2', 'en')) app.get_module(0).get_form(0).set_icon('en', image_path.format('3', 'en')) app.get_module(0).get_form(0).set_audio('en', audio_path.format('3', 'en')) app.save() should_contain_media = [image_path.format(num, 'en') for num in [1, 2, 3, 4]] + \ [audio_path.format(num, 'en') for num in [1, 2, 3, 4]] media_for_removal = [image_path.format(num, 'hin') for num in [1, 2, 3, 4]] + \ [audio_path.format(num, 'hin') for num in [1, 2, 3, 4]] self.assertTrue(app.get_module(0).uses_media()) self.assertEqual(app.all_media_paths(), set(should_contain_media)) self.assertEqual(set(app.multimedia_map.keys()), set(should_contain_media + media_for_removal)) app.remove_unused_mappings() self.assertEqual(set(app.multimedia_map.keys()), set(should_contain_media)) # test multimedia removed app.get_module(0).case_list.set_icon('en', '') app.get_module(0).case_list.set_audio('en', '') app.get_module(0).set_icon('en', '') app.get_module(0).set_audio('en', '') app.get_module(0).case_list_form.set_icon('en', '') app.get_module(0).case_list_form.set_audio('en', '') app.get_module(0).get_form(0).set_icon('en', '') app.get_module(0).get_form(0).set_audio('en', '') self.assertFalse(list(app.multimedia_map.keys()))
def setUpClass(cls): cls.project = Domain(name=cls.domain) cls.project.save() cls.apps = [ # .wrap adds lots of stuff in, but is hard to call directly # this workaround seems to work Application.wrap( Application(domain=cls.domain, name='foo', version=1, modules=[Module()]).to_json()), RemoteApp.wrap( RemoteApp(domain=cls.domain, version=1, name='bar').to_json()), ] for app in cls.apps: app.save()
def test_duplicate_remote_request(self, *args): """ Adding a second search config should not affect the initial one. """ copy_app = Application.wrap(self.app.to_json()) copy_app.modules.append(Module.wrap(copy_app.modules[0].to_json())) suite = copy_app.create_suite() self.assertXmlPartialEqual( self.get_xml('remote_request').decode('utf-8').format(module_id="m0"), suite, "./remote-request[1]" ) self.assertXmlPartialEqual( self.get_xml('remote_request').decode('utf-8').format(module_id="m1"), suite, "./remote-request[2]" )
def test_case_list_media(self): app = Application.wrap(self.get_json('app')) app.get_module(0).case_list_form.form_id = app.get_module(0).get_form( 0).unique_id image_path = 'jr://file/commcare/case_list_image.jpg' audo_path = 'jr://file/commcare/case_list_audo.mp3' app.get_module(0).case_list_form.set_icon('en', image_path) app.get_module(0).case_list_form.set_audio('en', audo_path) app.create_mapping(CommCareImage(_id='123'), image_path, save=False) app.create_mapping(CommCareAudio(_id='456'), audo_path, save=False) app.set_media_versions(previous_version=None) self.assertXmlEqual(self.get_xml('media_suite'), app.create_media_suite())
def test_build_from_saved_schema(self): app = self.current_app schema = CaseExportDataSchema.generate_schema_from_builds( app.domain, app._id, self.case_type, ) self.assertEqual(schema.last_app_versions[app._id], self.first_build.version) # One for case, one for case history self.assertEqual(len(schema.group_schemas), 2) self.assertEqual(len(schema.group_schemas[0].items), 2) self.assertEqual(len(schema.group_schemas[1].items), len(KNOWN_CASE_PROPERTIES) + 2) # After the first schema has been saved let's add a second app to process second_build = Application.wrap( self.get_json('basic_case_application')) second_build._id = '456' second_build.copy_of = app.get_id second_build.version = 6 second_build.has_submissions = True second_build.get_module(0).get_form( 0).actions.update_case.update['name'] = ConditionalCaseUpdate( question_path='/data/question2') with drop_connected_signals(app_post_save): second_build.save() self.addCleanup(second_build.delete) new_schema = CaseExportDataSchema.generate_schema_from_builds( app.domain, app._id, self.case_type, ) self.assertEqual(new_schema._id, schema._id) self.assertEqual(new_schema.last_app_versions[app._id], second_build.version) # One for case, one for case history self.assertEqual(len(new_schema.group_schemas), 2) self.assertEqual(len(schema.group_schemas[0].items), 2) self.assertEqual(len(schema.group_schemas[1].items), len(KNOWN_CASE_PROPERTIES) + 2)
def migrate_app(self, app_doc): modules = [ m for m in app_doc['modules'] if m.get('module_type', '') == 'advanced' ] should_save = False for module in modules: forms = module['forms'] for form in forms: load_actions = form.get('actions', {}).get('load_update_cases', []) for action in load_actions: preload = action['preload'] if preload and list(preload.values())[0].startswith('/'): action['preload'] = {v: k for k, v in preload.items()} should_save = True return Application.wrap(app_doc) if should_save else None
def testBuildApp(self, mock): # do it from a NOT-SAVED app; # regression test against case where contents gets lazy-put w/o saving app = Application.wrap(self._yesno_source) self.assertEqual(app['_id'], None) # i.e. hasn't been saved app._id = uuid.uuid4().hex copy = app.make_build() copy.save() self._check_has_build_files(copy, self.min_paths) app_strings_files = self._app_strings_files(copy) self._check_has_build_files(copy, app_strings_files) for path in app_strings_files: lang = path.split("/")[1] data_path = os.path.join(os.path.dirname(__file__), 'data', 'yesno_{}_app_strings.txt'.format(lang)) with open(data_path, encoding='utf-8') as f: self.assertEqual(f.read().strip(), copy.fetch_attachment(path).decode('utf-8').strip()) self._check_legacy_odk_files(copy)
def test_sort_calculation(self): app = Application.wrap(self.get_json('suite-advanced')) detail = app.modules[0].case_details.short detail.sort_elements.append( SortElement(field=detail.columns[0].field, type='string', direction='descending', sort_calculation='random()')) sort_node = """ <partial> <sort direction="descending" order="1" type="string"> <text> <xpath function="random()"/> </text> </sort> </partial> """ self.assertXmlPartialEqual(sort_node, app.create_suite(), "./detail[@id='m0_case_short']/field/sort")
def test_advanced_suite_load_case_from_fixture_with_report_fixture(self): app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).actions.load_update_cases.append( LoadUpdateAction( case_tag="", case_type="clinic", load_case_from_fixture=LoadCaseFromFixture( fixture_nodeset= "instance('commcare:reports')/reports/report[@id='some-report-guid']/rows/row", fixture_tag="selected_row", fixture_variable="index", ))) suite = app.create_suite() self.assertXmlPartialEqual( self.get_xml('load_case_from_report_fixture_session'), suite, './entry[2]/session') self.assertXmlPartialEqual( self.get_xml('load_case_from_report_fixture_instance'), suite, './entry[2]/instance')
def test_case_tile_configuration_errors(self): case_tile_error = { 'type': "invalid tile configuration", 'module': { 'id': 0, 'name': { u'en': u'View' } }, 'reason': 'A case property must be assigned to the "sex" tile field.' } with open( os.path.join(os.path.dirname(__file__), 'data', 'bad_case_tile_config.json')) as f: source = json.load(f) app = Application.wrap(source) errors = app.validate_app() self.assertIn(case_tile_error, errors)
def test_sort_cache_search(self): app = Application.wrap(self.get_json('suite-advanced')) app.modules[0].search_config = CaseSearch( properties=[CaseSearchProperty(name='name', label={'en': 'Name'})], ) detail = app.modules[0].case_details.short detail.sort_elements.append( SortElement( field=detail.columns[0].field, type='index', direction='descending', blanks='first', ) ) self.assertXmlPartialEqual( self.get_xml('sort-cache-search'), app.create_suite(), "./detail[@id='m0_search_short']" )
def migrate_app(self, app_doc): app = Application.wrap(app_doc) metadata = app.get_case_metadata() for case_type in metadata.case_types: if case_type.has_errors: logger.error('app {} has issue'.format(app._id)) for module in app.modules: for form in module.forms: if form.doc_type == 'AdvancedForm': # advanced forms don't have the same actions return None actions = form.actions if actions.case_preload: for action in actions.case_preload.preload.values(): log_excessive_parents(app, action) if actions.update_case: for action in actions.update_case.update: log_excessive_parents(app, action) return None
def test_form_media_with_app_profile(self, *args): # Test that media for languages not in the profile are removed from the media suite app = Application.wrap(self.get_json('app')) app.build_profiles = OrderedDict({ 'en': BuildProfile(langs=['en'], name='en-profile'), 'hin': BuildProfile(langs=['hin'], name='hin-profile'), 'all': BuildProfile(langs=['en', 'hin'], name='all-profile'), }) app.langs = ['en', 'hin'] image_path = 'jr://file/commcare/module0_en.png' audio_path = 'jr://file/commcare/module0_{}.mp3' app.get_module(0).set_icon('en', image_path) app.get_module(0).set_audio('en', audio_path.format('en')) app.get_module(0).set_audio('hin', audio_path.format('hin')) app.create_mapping(CommCareImage(_id='123'), image_path, save=False) app.create_mapping(CommCareAudio(_id='456'), audio_path.format('en'), save=False) app.create_mapping(CommCareAudio(_id='789'), audio_path.format('hin'), save=False) form_xml = self.get_xml('form_with_media_refs').decode('utf-8') form = app.get_module(0).new_form('form_with_media', 'en', attachment=form_xml) xform = form.wrapped_xform() for i, path in enumerate(reversed(sorted(xform.media_references(form="audio")))): app.create_mapping(CommCareAudio(_id='form_audio_{}'.format(i)), path, save=False) for i, path in enumerate(sorted(xform.media_references(form="image"))): app.create_mapping(CommCareImage(_id='form_image_{}'.format(i)), path, save=False) app.set_media_versions() app.remove_unused_mappings() # includes all media self._assertMediaSuiteResourcesEqual(self.get_xml('form_media_suite'), app.create_media_suite()) # generate all suites at once to mimic create_build_files_for_all_app_profiles suites = {id: app.create_media_suite(build_profile_id=id) for id in app.build_profiles.keys()} # include all app media and only language-specific form media self._assertMediaSuiteResourcesEqual(self.get_xml('form_media_suite_en'), suites['en']) self._assertMediaSuiteResourcesEqual(self.get_xml('form_media_suite_hin'), suites['hin']) self._assertMediaSuiteResourcesEqual(self.get_xml('form_media_suite_all'), suites['all'])
def testRevertToCopy(self, mock): old_name = 'old name' new_name = 'new name' app = Application.wrap(self._yesno_source) app.name = old_name app.save() copy = app.make_build() copy.save() self.assertEqual(copy.name, old_name) app.name = new_name app.save() app = Application.get(app.get_id) self.assertEqual(app.name, new_name) app = app.make_reversion_to_copy(copy) app.save() self.assertEqual(app.name, old_name)
def test_media_suite_generator(self): app = Application.wrap(self.get_json('app_video_inline')) image_path = 'jr://file/commcare/image1.jpg' audio_path = 'jr://file/commcare/audio1.mp3' video_path = 'jr://file/commcare/video-inline/data/inline_video.mp4' app.create_mapping(CommCareImage(_id='123'), image_path, save=False) app.create_mapping(CommCareAudio(_id='456'), audio_path, save=False) app.create_mapping(CommCareVideo(_id='789'), video_path, save=False) app.get_module(0).case_list_form.set_icon('en', image_path) app.get_module(0).case_list_form.set_audio('en', audio_path) app.get_module(0).case_list_form.form_id = app.get_module(0).get_form( 0).unique_id app.profile["properties"] = {'lazy-load-video-files': 'true'} self.assertXmlEqual(self.get_xml('media-suite-lazy-true'), MediaSuiteGenerator(app).generate_suite()) app.profile["properties"] = {'lazy-load-video-files': 'false'} self.assertXmlEqual(self.get_xml('media-suite-lazy-false'), MediaSuiteGenerator(app).generate_suite())
def test_only_default_properties(self, *args): self.module.search_config = CaseSearch( default_properties=[ DefaultCaseSearchProperty( property='ɨŧsȺŧɍȺᵽ', defaultValue=( "instance('casedb')/case" "[@case_id='instance('commcaresession')/session/data/case_id']" "/ɨŧsȺŧɍȺᵽ") ), DefaultCaseSearchProperty( property='name', defaultValue="instance('locations')/locations/location[@id=123]/@type", ), ], ) # wrap to have assign_references called self.app = Application.wrap(self.app.to_json()) suite = self.app.create_suite() self.assertXmlPartialEqual(self.get_xml('search_config_default_only'), suite, "./remote-request[1]")
def test_update_image_id(self): """ When an image is updated, change only version number, not resource id """ app = Application.wrap(self.get_json('app')) image_path = 'jr://file/commcare/case_list_image.jpg' app.get_module(0).case_list_form.set_icon('en', image_path) app.version = 1 app.create_mapping(CommCareImage(_id='123'), image_path, save=False) app.set_media_versions(previous_version=None) old_app = deepcopy(app) app.version = 2 app.create_mapping(CommCareImage(_id='456'), image_path, save=False) app.set_media_versions(previous_version=old_app) old_image = old_app.multimedia_map[image_path] new_image = app.multimedia_map[image_path] self.assertEqual(old_image.unique_id, new_image.unique_id) self.assertNotEqual(old_image.version, new_image.version)
def test_advanced_suite_arbitrary_datum(self, *args): app = Application.wrap(self.get_json('suite-advanced')) app.get_module(1).get_form(0).arbitrary_datums = [ ArbitraryDatum(datum_id='extra_id1', datum_function='extra_function1()'), ArbitraryDatum(datum_id='extra_id2', datum_function='extra_function2()') ] suite = app.create_suite() self.assertXmlPartialEqual( """ <partial> <session> <datum detail-confirm="m1_case_long" detail-select="m1_case_short" id="case_id_case_clinic" nodeset="instance('casedb')/casedb/case[@case_type='clinic'][@status='open']" value="./@case_id"/> <datum id="extra_id1" function="extra_function1()" /> <datum id="extra_id2" function="extra_function2()" /> </session> </partial> """, suite, './entry[2]/session')
def setUpClass(cls): cls.project = Domain(name=cls.domain) cls.project.save() app_doc = Application(domain=cls.domain, name='foo', langs=["en"], version=1, modules=[Module()]).to_json() app = Application.wrap(app_doc) # app is v1 app.save() # app is v2 cls.v2_build = app.make_build() cls.v2_build.is_released = True cls.v2_build.save() # There is a starred build at v2 app.save() # app is v3 app.make_build().save() # There is a build at v3 app.save() # app is v4 cls.app_id = app._id
def test(self): app = Application.wrap(self.get_json('question_schema_test_app')) app._id = '123' app.version = 1 xmlns = 'http://openrosa.org/formdesigner/284D3F7C-9C10-48E6-97AC-C37927CBA89A' schema = FormQuestionSchema(xmlns=xmlns) schema.update_for_app(app) self.assertIn(app.get_id, schema.processed_apps) self.assertEqual(app.version, schema.last_processed_version) self.assertEqual(schema.question_schema['form.multi_root'].options, ['item1', 'item2', 'item3']) self.assertEqual( schema.question_schema['form.group1.multi_level1'].options, ['item1', 'item2']) self.assertEqual( schema.question_schema['form.group1.question6.multi_level_2']. options, ['item1', 'item2']) self.assertEqual( schema.question_schema['form.repeat_1.multi_level_1_repeat']. options, ['item1', 'item2']) self.assertEqual( schema.question_schema['form.repeat_1.multi_level_1_repeat']. repeat_context, 'form.repeat_1') updated_form_xml = self.get_xml('question_schema_update_form').decode( 'utf-8') app.get_forms_by_xmlns(xmlns)[0].source = updated_form_xml app.version = 2 schema.update_for_app(app) self.assertEqual(1, len(schema.processed_apps)) self.assertIn(app.get_id, schema.processed_apps) self.assertEqual(app.version, schema.last_processed_version) self.assertEqual(schema.question_schema['form.new_multi'].options, ['z_first', 'a_last']) self.assertEqual( schema.question_schema['form.group1.multi_level1'].options, ['item1', 'item2', '1_item'])
def get(self, request, *args, **kwargs): app_id = get_app_id_from_hash(request.domain, kwargs.pop('app_hash')) if not app_id: raise Http404() app_doc = get_latest_released_app_doc(request.domain, app_id) if not app_doc: raise Http404() app = Application.wrap(app_doc) if not app.anonymous_cloudcare_enabled: raise Http404() return self.render_to_response({ 'app': app, 'formplayer_url': settings.FORMPLAYER_URL, "maps_api_key": settings.GMAPS_API_KEY, "environment": WEB_APPS_ENVIRONMENT, })
def setUpClass(cls): super(DBAccessorsTest, cls).setUpClass() cls.project = Domain(name=cls.domain) cls.project.save() cls.first_saved_version = 2 cls.apps = [ # .wrap adds lots of stuff in, but is hard to call directly # this workaround seems to work Application.wrap( Application(domain=cls.domain, name='foo', version=1, modules=[Module()]).to_json()), RemoteApp.wrap( RemoteApp(domain=cls.domain, version=1, name='bar').to_json()), ] for app in cls.apps: app.save() cls.decoy_apps = [ # this one is a build Application( domain=cls.domain, copy_of=cls.apps[0].get_id, version=cls.first_saved_version, has_submissions=True, ), # this one is another build Application(domain=cls.domain, copy_of=cls.apps[0].get_id, version=12), # this one is another app Application(domain=cls.domain, copy_of='1234', version=12), # this one is in the wrong domain Application(domain='decoy-domain', version=5) ] for app in cls.decoy_apps: app.save()
def _test_format(self, detail_format, template_form): app = Application.wrap(self.get_json('app_audio_format')) details = app.get_module(0).case_details details.short.get_column(0).format = detail_format details.long.get_column(0).format = detail_format expected = """ <partial> <template form="{0}"> <text> <xpath function="picproperty"/> </text> </template> <template form="{0}"> <text> <xpath function="picproperty"/> </text> </template> </partial> """.format(template_form) self.assertXmlPartialEqual(expected, app.create_suite(), "./detail/field/template")