Пример #1
0
    def test_extension_index(self):
        factory = CaseFactory()
        standard_case_id = uuid.uuid4().hex
        [case] = factory.create_or_update_case(
            CaseStructure(case_id=standard_case_id, attrs={'case_type': "standard_type", 'create': True})
        )

        extension_case_id = uuid.uuid4().hex
        factory.create_or_update_case(
            CaseStructure(
                case_id=extension_case_id,
                attrs={'case_type': "extension_type", 'create': True},
                indices=[
                    CaseIndex(
                        CaseStructure(case_id=standard_case_id),
                        related_type='standard_type',
                        relationship=CASE_INDEX_EXTENSION
                    )
                ],
                walk_related=False
            )
        )

        hierarchy = get_case_hierarchy(case, {})
        self.assertEqual(2, len(hierarchy['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases']))
Пример #2
0
class TestIndexedCaseIds(TestCase):
    def setUp(self):
        super(TestIndexedCaseIds, self).setUp()
        self.domain = 'domain'
        self.factory = CaseFactory(self.domain)

    def tearDown(self):
        FormProcessorTestUtils.delete_all_cases()
        FormProcessorTestUtils.delete_all_xforms()
        super(TestIndexedCaseIds, self).tearDown()

    @run_with_all_backends
    def test_indexed_case_ids_returns_extensions(self):
        """ When getting indices, also return extensions """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id)

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[CaseIndex(host, relationship=CASE_INDEX_EXTENSION)]))
        returned_cases = CaseAccessors(self.domain).get_indexed_case_ids(
            [extension_id])
        self.assertItemsEqual(returned_cases, [host_id])
Пример #3
0
    def test_normal_index(self):
        factory = CaseFactory()
        parent_id = uuid.uuid4().hex
        [cp] = factory.create_or_update_case(
            CaseStructure(case_id=parent_id,
                          attrs={
                              'case_type': 'parent',
                              'create': True
                          }))

        child_id = uuid.uuid4().hex
        factory.create_or_update_case(
            CaseStructure(case_id=child_id,
                          attrs={
                              'case_type': 'child',
                              'create': True
                          },
                          indices=[
                              CaseIndex(CaseStructure(case_id=parent_id),
                                        related_type='parent')
                          ],
                          walk_related=False))

        hierarchy = get_case_hierarchy(cp, {})
        self.assertEqual(2, len(hierarchy['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases']))
Пример #4
0
class TestIndexedCaseIds(TestCase):

    def setUp(self):
        super(TestIndexedCaseIds, self).setUp()
        self.domain = 'domain'
        self.factory = CaseFactory(self.domain)

    def tearDown(self):
        FormProcessorTestUtils.delete_all_cases()
        FormProcessorTestUtils.delete_all_xforms()
        super(TestIndexedCaseIds, self).tearDown()

    def test_indexed_case_ids_returns_extensions(self):
        """ When getting indices, also return extensions """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id, attrs={'create': True})

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION)
                ],
                attrs={'create': True}
            )
        )
        returned_cases = CaseAccessors(self.domain).get_indexed_case_ids([extension_id])
        self.assertItemsEqual(returned_cases, [host_id])
Пример #5
0
class TestIndexedCaseIds(TestCase):
    @classmethod
    def setUpClass(cls):
        delete_all_cases()

    def setUp(self):
        self.domain = 'domain'
        self.factory = CaseFactory(self.domain)

    def test_indexed_case_ids_returns_extensions(self):
        """ When getting indices, also return extensions """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id)

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION)
                ]
            )
        )
        returned_cases = get_indexed_case_ids(self.domain, [extension_id])
        self.assertItemsEqual(returned_cases, [host_id])
Пример #6
0
    def test_extension_index(self):
        factory = CaseFactory()
        standard_case_id = uuid.uuid4().hex
        [case] = factory.create_or_update_case(
            CaseStructure(case_id=standard_case_id, attrs={'case_type': "standard_type", 'create': True})
        )

        extension_case_id = uuid.uuid4().hex
        factory.create_or_update_case(
            CaseStructure(
                case_id=extension_case_id,
                attrs={'case_type': "extension_type", 'create': True},
                indices=[
                    CaseIndex(
                        CaseStructure(case_id=standard_case_id),
                        related_type='standard_type',
                        relationship=CASE_INDEX_EXTENSION
                    )
                ],
                walk_related=False
            )
        )

        hierarchy = get_case_hierarchy(case, {})
        self.assertEqual(2, len(hierarchy['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases']))
Пример #7
0
class TestCaseHierarchyContext(TestCase):
    def setUp(self):
        self.factory = CaseFactory()
        parent_id = uuid.uuid4().hex
        [self.parent] = self.factory.create_or_update_case(
            CaseStructure(case_id=parent_id,
                          attrs={
                              'case_type': 'parent',
                              'create': True
                          }))

        child_id = uuid.uuid4().hex
        [self.child] = self.factory.create_or_update_case(
            CaseStructure(case_id=child_id,
                          attrs={
                              'case_type': 'child',
                              'create': True
                          },
                          indices=[
                              CaseIndex(CaseStructure(case_id=parent_id),
                                        related_type='parent')
                          ],
                          walk_related=False))

    def tearDown(self):
        self.parent.delete()
        self.child.delete()

    def test_case_hierarchy_context_parent(self):
        hierarchy = case_hierarchy_context(self.parent, _get_case_url_blank)
        self.assertEqual(2, len(hierarchy['case_list']))

    def test_case_hierarchy_context_parent_deleted_index(self):
        self._delete_child_index()
        hierarchy = case_hierarchy_context(self.parent, _get_case_url_blank)
        self.assertEqual(1, len(hierarchy['case_list']))

    def test_case_hierarchy_context_child(self):
        hierarchy = case_hierarchy_context(self.child, _get_case_url_blank)
        self.assertEqual(2, len(hierarchy['case_list']))

    def test_case_hierarchy_context_child_deleted_index(self):
        self._delete_child_index()
        hierarchy = case_hierarchy_context(self.child, _get_case_url_blank)
        self.assertEqual(1, len(hierarchy['case_list']))

    def _delete_child_index(self):
        ref = CaseStructure()
        ref.case_id = ""  # reset case_id to empty
        self.factory.create_or_update_case(
            CaseStructure(case_id=self.child.case_id,
                          indices=[CaseIndex(ref, related_type='parent')],
                          walk_related=False), )

        # re-fetch case to clear memoized properties
        self.parent = CommCareCase.objects.get_case(self.parent.case_id,
                                                    self.parent.domain)
        self.child = CommCareCase.objects.get_case(self.child.case_id,
                                                   self.parent.domain)
Пример #8
0
 def setUpClass(cls):
     super(TestFormsExpressionSpec, cls).setUpClass()
     cls.domain = uuid.uuid4().hex
     factory = CaseFactory(domain=cls.domain)
     [cls.case] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))
     cls.forms = [f.to_json() for f in FormAccessors(cls.domain).get_forms(cls.case.xform_ids)]
     #  redundant case to create extra forms that shouldn't be in the results for cls.case
     [cls.case_b] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))
Пример #9
0
    def handle(self, domain, log_path, **options):
        commit = options['commit']
        factory = CaseFactory(domain)

        logger.info("Starting {} migration on {} at {}".format(
            "real" if commit else "fake", domain, datetime.datetime.utcnow()))

        cases = (CaseSearchES().domain(domain).case_type("episode").scroll())

        with open(log_path, "w") as f:
            for case in cases:
                case_props = {
                    prop['key']: prop['value']
                    for prop in case['case_properties']
                }
                treatment_status = None
                treatment_initiated = case_props.get('treatment_initiated')
                diagnosing_facility_id = case_props.get(
                    'diagnosing_facility_id')
                treatment_initiating_facility_id = case_props.get(
                    'treatment_initiating_facility_id')

                if treatment_initiated == 'yes_phi' and \
                        diagnosing_facility_id and treatment_initiating_facility_id and \
                        diagnosing_facility_id != treatment_initiating_facility_id:
                    treatment_status = 'initiated_outside_facility'
                elif treatment_initiated == 'yes_phi' and \
                        diagnosing_facility_id and treatment_initiating_facility_id:
                    treatment_status = 'initiated_first_line_treatment'
                elif treatment_initiated == 'yes_private':
                    treatment_status = 'initiated_outside_rntcp'

                if treatment_status:
                    case_id = case['_id']
                    f.write(case_id + "\n")
                    logger.info(case_id)

                    case_structure = CaseStructure(
                        case_id=case_id,
                        walk_related=False,
                        attrs={
                            "create": False,
                            "update": {
                                "treatment_status":
                                treatment_status,
                                "updated_by_migration":
                                "enikshay_2b_treatment_status_fix",
                            },
                        },
                    )

                    if commit:
                        try:
                            factory.create_or_update_case(case_structure)
                        except NikshayLocationNotFound:
                            pass
        logger.info("Migration finished at {}".format(
            datetime.datetime.utcnow()))
Пример #10
0
    def test_complex_index(self):
        factory = CaseFactory()
        parent_id = uuid.uuid4().hex
        cp = factory.create_or_update_case(
            CaseStructure(case_id=parent_id,
                          attrs={
                              'case_type': 'parent',
                              'create': True
                          }))[0]

        # cases processed according to ID order so ensure that this case is
        # processed after the task case by making its ID sort after task ID
        goal_id = uuid.uuid4().hex
        factory.create_or_update_case(
            CaseStructure(case_id=goal_id,
                          attrs={
                              'case_type': 'goal',
                              'create': True
                          },
                          indices=[
                              CaseIndex(CaseStructure(case_id=parent_id),
                                        related_type='parent')
                          ],
                          walk_related=False))

        task_id = uuid.uuid4().hex
        factory.create_or_update_case(
            CaseStructure(
                case_id=task_id,
                attrs={
                    'case_type': 'task',
                    'create': True
                },
                indices=[
                    CaseIndex(CaseStructure(case_id=goal_id),
                              related_type='goal',
                              identifier='goal'),
                    CaseIndex(CaseStructure(case_id=parent_id),
                              related_type='parent')
                ],
                walk_related=False,
            ))

        # with 'ignore_relationship_types' if a case got processed along the ignored relationship first
        # then it got marked as 'seen' and would be not be processed again when it came to the correct relationship
        type_info = {
            'task': {
                'ignore_relationship_types': ['parent']
            },
        }

        hierarchy = get_case_hierarchy(cp, type_info)
        self.assertEqual(3, len(hierarchy['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases']))
        self.assertEqual(2, len(hierarchy['child_cases'][0]['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases'][0]['child_cases']))
Пример #11
0
class TestGetSubcasesExpression(TestCase):

    def setUp(self):
        super(TestGetSubcasesExpression, self).setUp()
        self.domain = uuid.uuid4().hex
        self.factory = CaseFactory(domain=self.domain)
        self.expression = ExpressionFactory.from_spec({
            "type": "get_subcases",
            "case_id_expression": {
                "type": "property_name",
                "property_name": "_id"
            },
        })
        self.context = EvaluationContext({"domain": self.domain})

    def tearDown(self):
        delete_all_xforms()
        delete_all_cases()
        super(TestGetSubcasesExpression, self).tearDown()

    @run_with_all_backends
    def test_no_subcases(self):
        case = self.factory.create_case()
        subcases = self.expression(case.to_json(), self.context)
        self.assertEqual(len(subcases), 0)

    @run_with_all_backends
    def test_single_child(self):
        parent_id = uuid.uuid4().hex
        child_id = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(CaseStructure(
            case_id=child_id,
            indices=[
                CaseIndex(CaseStructure(case_id=parent_id, attrs={'create': True}))
            ]
        ))
        subcases = self.expression(parent.to_json(), self.context)
        self.assertEqual(len(subcases), 1)
        self.assertEqual(child.case_id, subcases[0]['_id'])

    @run_with_all_backends
    def test_single_extension(self):
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        [extension, host] = self.factory.create_or_update_case(CaseStructure(
            case_id=extension_id,
            indices=[
                CaseIndex(
                    CaseStructure(case_id=host_id, attrs={'create': True}),
                    relationship=CASE_INDEX_EXTENSION
                )
            ]
        ))
        subcases = self.expression(host.to_json(), self.context)
        self.assertEqual(len(subcases), 1)
        self.assertEqual(extension.case_id, subcases[0]['_id'])
Пример #12
0
 def setUpClass(cls):
     super(TestFormsExpressionSpecWithFilter, cls).setUpClass()
     global es_form_cache
     cls.domain = uuid.uuid4().hex
     factory = CaseFactory(domain=cls.domain)
     [cls.case] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))
     cls.forms = [f.to_json() for f in FormAccessors(cls.domain).get_forms(cls.case.xform_ids)]
     for form in cls.forms:
         es_form_cache.append(deepcopy(form))
     # redundant case to create extra forms that shouldn't be in the results for cls.case
     [cls.case_b] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))
     cls.forms_b = [f.to_json() for f in FormAccessors(cls.domain).get_forms(cls.case_b.xform_ids)]
     for form in cls.forms_b:
         es_form_cache.append(deepcopy(form))
Пример #13
0
    def test_normal_index(self):
        factory = CaseFactory()
        [cp] = factory.create_or_update_case(
            CaseStructure(case_id='parent', attrs={'case_type': 'parent'})
        )

        factory.create_or_update_case(CaseStructure(
            case_id='child',
            attrs={'case_type': 'child'},
            indices=[CaseIndex(CaseStructure(case_id='parent'), related_type='parent')],
            walk_related=False
        ))

        hierarchy = get_case_hierarchy(cp, {})
        self.assertEqual(2, len(hierarchy['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases']))
Пример #14
0
    def test_deleted_indices_removed(self):
        factory = CaseFactory(
            self.domain,
            case_defaults={
                'user_id': self.commcare_user._id,
                'owner_id': self.commcare_user._id,
                'case_type': 'a-case',
                'create': True,
            },
        )
        # create a parent/child set of cases
        parent_id, child_id = [uuid.uuid4().hex for i in range(2)]
        child, parent = factory.create_or_update_case(CaseStructure(
            case_id=child_id,
            indices=[
                CaseIndex(CaseStructure(case_id=parent_id))
            ]
        ))
        # confirm the child has an index, and 1 form
        self.assertEqual(1, len(child.indices))
        self.assertEqual(parent_id, child.indices[0].referenced_id)
        self.assertEqual(1, len(child.xform_ids))

        # simulate parent deletion
        parent.soft_delete()

        # call the remove index task
        remove_indices_from_deleted_cases(self.domain, [parent_id])

        # check that the index is removed via a new form
        child = CaseAccessors(self.domain).get_case(child_id)
        self.assertEqual(0, len(child.indices))
        self.assertEqual(2, len(child.xform_ids))
Пример #15
0
    def setUp(self):
        super(TestFormsExpressionSpec, self).setUp()
        self.domain = uuid.uuid4().hex
        factory = CaseFactory(domain=self.domain)
        [self.case] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))
        self.forms = [f.to_json() for f in FormAccessors(self.domain).get_forms(self.case.xform_ids)]
        #  redundant case to create extra forms that shouldn't be in the results for self.case
        [self.case_b] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))

        self.expression = ExpressionFactory.from_spec({
            "type": "get_case_forms",
            "case_id_expression": {
                "type": "property_name",
                "property_name": "_id"
            },
        })
Пример #16
0
 def test_form_extras_override_defaults(self):
     domain = uuid.uuid4().hex
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain, form_extras={'last_sync_token': token_id})
     [case] = factory.create_or_update_case(CaseStructure(attrs={'create': True}), form_extras={'last_sync_token': 'differenttoken'})
     form = FormAccessors(domain).get_form(case.xform_ids[0])
     self.assertEqual('differenttoken', form.last_sync_token)
Пример #17
0
    def setUp(self):
        super(TestFormsExpressionSpec, self).setUp()
        self.domain = uuid.uuid4().hex
        factory = CaseFactory(domain=self.domain)
        [self.case] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))
        self.forms = [f.to_json() for f in FormAccessors(self.domain).get_forms(self.case.xform_ids)]
        #  redundant case to create extra forms that shouldn't be in the results for self.case
        [self.case_b] = factory.create_or_update_case(CaseStructure(attrs={'create': True}))

        self.expression = ExpressionFactory.from_spec({
            "type": "get_case_forms",
            "case_id_expression": {
                "type": "property_name",
                "property_name": "_id"
            },
        })
Пример #18
0
    def test_deleted_indices_removed(self):
        factory = CaseFactory(
            self.domain,
            case_defaults={
                'user_id': self.commcare_user._id,
                'owner_id': self.commcare_user._id,
                'case_type': 'a-case',
                'create': True,
            },
        )
        # create a parent/child set of cases
        parent_id, child_id = [uuid.uuid4().hex for i in range(2)]
        child, parent = factory.create_or_update_case(
            CaseStructure(case_id=child_id,
                          relationships=[
                              CaseRelationship(
                                  CaseStructure(case_id=parent_id))
                          ]))
        # confirm the child has an index, and 1 form
        self.assertEqual(1, len(child.indices))
        self.assertEqual(parent_id, child.indices[0].referenced_id)
        self.assertEqual(1, len(child.xform_ids))

        # simulate parent deletion
        parent.doc_type = 'CommCareCase-Deleted'
        parent.save()

        # call the remove index task
        remove_indices_from_deleted_cases(self.domain, [parent_id])

        # check that the index is removed via a new form
        child = CommCareCase.get(child_id)
        self.assertEqual(0, len(child.indices))
        self.assertEqual(2, len(child.xform_ids))
Пример #19
0
    def test_simple_delete(self):
        factory = CaseFactory()
        case = factory.create_case()
        [case] = factory.create_or_update_case(
            CaseStructure(case_id=case.case_id, attrs={'update': {'foo': 'bar'}})
        )
        self.assertIsNotNone(self.casedb.get_case(case.case_id))
        self.assertEqual(2, len(case.xform_ids))
        for form_id in case.xform_ids:
            self.assertIsNotNone(self.formdb.get_form(form_id))

        with capture_kafka_changes_context(topics.FORM_SQL, topics.CASE_SQL) as change_context:
            safe_hard_delete(case)

        if should_use_sql_backend(case.domain):
            self.assertEqual(3, len(change_context.changes))
            expected_ids = {case.case_id} | set(case.xform_ids)
            self.assertEqual(expected_ids, {change.id for change in change_context.changes})
            for change in change_context.changes:
                self.assertTrue(change.deleted)

        with self.assertRaises(CaseNotFound):
            self.casedb.get_case(case.case_id)

        for form_id in case.xform_ids:
            with self.assertRaises(XFormNotFound):
                self.formdb.get_form(form_id)
Пример #20
0
 def test_form_extras(self):
     domain = uuid.uuid4().hex
     LOOSE_SYNC_TOKEN_VALIDATION.set(domain, True, namespace='domain')
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain)
     [case] = factory.create_or_update_case(CaseStructure(), form_extras={'last_sync_token': token_id})
     form = FormProcessorInterface(domain).xform_model.get(case.xform_ids[0])
     self.assertEqual(token_id, form.last_sync_token)
Пример #21
0
    def test_deleted_index(self):
        hierarchy = self.test_normal_index()
        parent, child = hierarchy['case_list']

        factory = CaseFactory()
        ref = CaseStructure()
        ref.case_id = ""  # reset case_id to empty
        factory.create_or_update_case(
            CaseStructure(case_id=child.case_id,
                          indices=[CaseIndex(ref, related_type='parent')],
                          walk_related=False), )

        # re-fetch case to clear memoized properties
        parent = CommCareCase.objects.get_case(parent.case_id, parent.domain)
        hierarchy = get_case_hierarchy(parent, {})
        self.assertEqual(1, len(hierarchy['case_list']))
        self.assertEqual(0, len(hierarchy['child_cases']))
Пример #22
0
    def handle(self, domain, log_path, **options):
        commit = options['commit']
        factory = CaseFactory(domain)

        logger.info("Starting {} migration on {} at {}".format(
            "real" if commit else "fake", domain, datetime.datetime.utcnow()))

        cases = (CaseSearchES().domain(domain).case_type(
            "episode").case_property_query("case_version", "20",
                                           "must").scroll())

        with open(log_path, "w") as f:
            for case in cases:
                case_props = {
                    prop['key']: prop['value']
                    for prop in case['case_properties']
                }
                referred_by_id = case_props.get('referred_by_id')
                updated_by_migration = case_props.get('updated_by_migration')
                if ((updated_by_migration == 'enikshay_2b_case_properties'
                     or updated_by_migration
                     == 'enikshay_2b_treatment_status_fix')
                        and referred_by_id):

                    case_id = case['_id']
                    f.write(case_id + "\n")
                    logger.info(case_id)

                    case_structure = CaseStructure(
                        case_id=case_id,
                        walk_related=False,
                        attrs={
                            "create": False,
                            "update": {
                                "referred_outside_enikshay_by_id":
                                referred_by_id,
                                "updated_by_migration":
                                "enikshay_2b_referred_by_id_fix",
                            },
                        },
                    )

                    if commit:
                        factory.create_or_update_case(case_structure)
        logger.info("Migration finished at {}".format(
            datetime.datetime.utcnow()))
Пример #23
0
 def test_form_extras_override_defaults(self):
     domain = uuid.uuid4().hex
     LOOSE_SYNC_TOKEN_VALIDATION.set(domain, True, namespace="domain")
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain, form_extras={"last_sync_token": token_id})
     [case] = factory.create_or_update_case(CaseStructure(), form_extras={"last_sync_token": "differenttoken"})
     form = FormAccessors(domain).get_form(case.xform_ids[0])
     self.assertEqual("differenttoken", form.last_sync_token)
Пример #24
0
 def test_form_extras_override_defaults(self):
     domain = uuid.uuid4().hex
     LOOSE_SYNC_TOKEN_VALIDATION.set(domain, True, namespace='domain')
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain, form_extras={'last_sync_token': token_id})
     [case] = factory.create_or_update_case(CaseStructure(), form_extras={'last_sync_token': 'differenttoken'})
     form = XFormInstance.get(case.xform_ids[0])
     self.assertEqual('differenttoken', form.last_sync_token)
Пример #25
0
 def test_form_extras(self):
     domain = uuid.uuid4().hex
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain)
     [case] = factory.create_or_update_case(
         CaseStructure(attrs={'create': True}),
         form_extras={'last_sync_token': token_id})
     form = XFormInstance.objects.get_form(case.xform_ids[0], domain)
     self.assertEqual(token_id, form.last_sync_token)
Пример #26
0
 def test_form_extras(self):
     domain = uuid.uuid4().hex
     LOOSE_SYNC_TOKEN_VALIDATION.set(domain, True, namespace='domain')
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain)
     [case] = factory.create_or_update_case(
         CaseStructure(), form_extras={'last_sync_token': token_id})
     form = FormAccessors(domain).get_form(case.xform_ids[0])
     self.assertEqual(token_id, form.last_sync_token)
Пример #27
0
 def test_no_walk_related(self):
     factory = CaseFactory()
     parent = factory.create_case()
     child_updates = factory.create_or_update_case(
         CaseStructure(attrs={'create': True}, walk_related=False, indices=[
             CaseIndex(CaseStructure(case_id=parent.case_id))
         ]),
     )
     self.assertEqual(1, len(child_updates))
     self.assertEqual(parent.case_id, child_updates[0].indices[0].referenced_id)
Пример #28
0
 def test_no_walk_related(self):
     factory = CaseFactory()
     parent = factory.create_case()
     child_updates = factory.create_or_update_case(
         CaseStructure(attrs={'create': True}, walk_related=False, relationships=[
             CaseRelationship(CaseStructure(case_id=parent._id))
         ]),
     )
     self.assertEqual(1, len(child_updates))
     self.assertEqual(parent._id, child_updates[0].indices[0].referenced_id)
Пример #29
0
 def test_form_extras_override_defaults(self):
     domain = uuid.uuid4().hex
     LOOSE_SYNC_TOKEN_VALIDATION.set(domain, True, namespace='domain')
     token_id = uuid.uuid4().hex
     factory = CaseFactory(domain=domain,
                           form_extras={'last_sync_token': token_id})
     [case] = factory.create_or_update_case(
         CaseStructure(), form_extras={'last_sync_token': 'differenttoken'})
     form = XFormInstance.get(case.xform_ids[0])
     self.assertEqual('differenttoken', form.last_sync_token)
    def handle(self, domain, log_path, **options):
        commit = options['commit']
        factory = CaseFactory(domain)

        logger.info("Starting {} migration on {} at {}".format(
            "real" if commit else "fake", domain, datetime.datetime.utcnow()))

        cases = (CaseSearchES().domain(domain).case_type(
            "test").case_property_query("updated_by_migration",
                                        "enikshay_2b_case_properties",
                                        "must").run().hits)

        with open(log_path, "w") as f:
            for case in cases:
                case_props = {
                    prop['key']: prop['value']
                    for prop in case['case_properties']
                }
                if (case_props.get('purpose_of_testing') == "follow_up_dstb"
                        and case_props.get("rft_general", "") in ("", None)):
                    case_id = case['_id']
                    f.write(case_id + "\n")
                    logger.info(case_id)

                    case_structure = CaseStructure(
                        case_id=case_id,
                        walk_related=False,
                        attrs={
                            "create": False,
                            "update": {
                                "rft_general":
                                "follow_up_dstb",
                                "updated_by_migration":
                                "enikshay_2b_reason_for_test_fix",
                            },
                        },
                    )

                    if commit:
                        factory.create_or_update_case(case_structure)

        logger.info("Migration finished at {}".format(
            datetime.datetime.utcnow()))
Пример #31
0
 def setUp(self):
     super(TestGetCaseFormsExpressionTest, self).setUp()
     self.domain = uuid.uuid4().hex
     factory = CaseFactory(domain=self.domain)
     self.test_case_id = uuid.uuid4().hex
     factory.create_or_update_case(CaseStructure(
         case_id=self.test_case_id,
         attrs={
             'case_type': 'test',
             'create': True,
             'date_opened': datetime(2015, 1, 10),
             'date_modified': datetime(2015, 3, 10),
         },
     ))
     self._submit_form(form_date=datetime(2015, 1, 10), case_id=self.test_case_id, xmlns="xmlns_a", foo="a")
     self._submit_form(form_date=datetime(2015, 1, 11), case_id=self.test_case_id, xmlns="xmlns_a", foo="a")
     self._submit_form(form_date=datetime(2015, 2, 3), case_id=self.test_case_id, xmlns="xmlns_b", foo="b")
     self._submit_form(form_date=datetime(2015, 3, 3), case_id=self.test_case_id, xmlns="xmlns_b", foo="b")
     self._submit_form(form_date=datetime(2015, 3, 4), case_id=self.test_case_id, xmlns="xmlns_b", foo="b")
     self._submit_form(form_date=datetime(2015, 3, 5), case_id=self.test_case_id, xmlns="xmlns_c", foo="b")
Пример #32
0
    def test_complex_index(self):
        factory = CaseFactory()
        parent_id = uuid.uuid4().hex
        cp = factory.create_or_update_case(CaseStructure(case_id=parent_id, attrs={
            'case_type': 'parent', 'create': True
        }))[0]

        # cases processed according to ID order so ensure that this case is
        # processed after the task case by making its ID sort after task ID
        goal_id = uuid.uuid4().hex
        factory.create_or_update_case(CaseStructure(
            case_id=goal_id,
            attrs={'case_type': 'goal', 'create': True},
            indices=[CaseIndex(CaseStructure(case_id=parent_id), related_type='parent')],
            walk_related=False
        ))

        task_id = uuid.uuid4().hex
        factory.create_or_update_case(CaseStructure(
            case_id=task_id,
            attrs={'case_type': 'task', 'create': True},
            indices=[
                CaseIndex(CaseStructure(case_id=goal_id), related_type='goal', identifier='goal'),
                CaseIndex(CaseStructure(case_id=parent_id), related_type='parent')
            ],
            walk_related=False,
        ))

        # with 'ignore_relationship_types' if a case got processed along the ignored relationship first
        # then it got marked as 'seen' and would be not be processed again when it came to the correct relationship
        type_info = {
            'task': {
                'ignore_relationship_types': ['parent']
            },
        }

        hierarchy = get_case_hierarchy(cp, type_info)
        self.assertEqual(3, len(hierarchy['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases']))
        self.assertEqual(2, len(hierarchy['child_cases'][0]['case_list']))
        self.assertEqual(1, len(hierarchy['child_cases'][0]['child_cases']))
Пример #33
0
    def test_recursive_indexes(self):
        factory = CaseFactory()
        [case] = factory.create_or_update_case(CaseStructure(
            case_id='infinite-recursion',
            attrs={'case_type': 'bug'},
            indices=[CaseIndex(CaseStructure(case_id='infinite-recursion'), related_type='bug')],
            walk_related=False
        ))

        # this call used to fail with infinite recursion
        hierarchy = get_case_hierarchy(case, {})
        self.assertEqual(1, len(hierarchy['case_list']))
Пример #34
0
    def test_recursive_indexes(self):
        factory = CaseFactory()
        [case] = factory.create_or_update_case(CaseStructure(
            case_id='infinite-recursion',
            attrs={'case_type': 'bug', 'create': True},
            indices=[CaseIndex(CaseStructure(case_id='infinite-recursion', attrs={'create': True}), related_type='bug')],
            walk_related=False
        ))

        # this call used to fail with infinite recursion
        hierarchy = get_case_hierarchy(case, {})
        self.assertEqual(1, len(hierarchy['case_list']))
Пример #35
0
 def test_simple_delete(self):
     factory = CaseFactory()
     case = factory.create_case()
     [case] = factory.create_or_update_case(CaseStructure(case_id=case._id, attrs={'update': {'foo': 'bar'}}))
     self.assertTrue(CommCareCase.get_db().doc_exist(case._id))
     self.assertEqual(2, len(case.xform_ids))
     for form_id in case.xform_ids:
         self.assertTrue(XFormInstance.get_db().doc_exist(form_id))
     safe_hard_delete(case)
     self.assertFalse(CommCareCase.get_db().doc_exist(case._id))
     for form_id in case.xform_ids:
         self.assertFalse(XFormInstance.get_db().doc_exist(form_id))
Пример #36
0
class TestCaseHistory(TestCase):
    def setUp(self):
        self.domain = "isildur"
        self.factory = CaseFactory(self.domain)
        self.case = self.factory.create_case(owner_id='owner', case_name="Aragorn", update={"prop_1": "val1"})
        self.other_case = self.factory.create_case()

    def tearDown(self):
        delete_all_xforms()
        delete_all_cases()

    @run_with_all_backends
    def test_case_history(self):
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'prop_1': "val1",
                        'prop_2': "val1",
                        'prop_3': "val1",
                    },
                }),
        )
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'prop_1': "val2",
                        'prop_2': "val2",
                        'prop_4': "val",
                    },
                }),
        )
        case = CaseAccessors(self.domain).get_case(self.case.case_id)
        history = get_case_history(case)
        self.assertEqual(history[0]['prop_1'], "val1")
        self.assertEqual(history[1]['prop_2'], "val1")
        self.assertEqual(history[2]['prop_2'], "val2")
Пример #37
0
    def test_delete_with_related(self):
        factory = CaseFactory()
        parent = factory.create_case()
        [child] = factory.create_or_update_case(
            CaseStructure(attrs={'create': True}, walk_related=False, relationships=[
                CaseRelationship(CaseStructure(case_id=parent._id))
            ]),
        )
        # deleting the parent should not be allowed because the child still references it
        with self.assertRaises(CommCareCaseError):
            safe_hard_delete(parent)

        # deleting the child is ok
        safe_hard_delete(child)
        self.assertTrue(CommCareCase.get_db().doc_exist(parent._id))
        self.assertFalse(CommCareCase.get_db().doc_exist(child._id))
Пример #38
0
    def test_simple_delete(self):
        factory = CaseFactory()
        case = factory.create_case()
        [case] = factory.create_or_update_case(CaseStructure(case_id=case._id, attrs={'update': {'foo': 'bar'}}))
        self.assertIsNotNone(FormProcessorInterface.get_case(case.id))
        self.assertEqual(2, len(case.xform_ids))
        for form_id in case.xform_ids:
            self.assertIsNotNone(FormProcessorInterface.get_xform(form_id))
        FormProcessorInterface.hard_delete_case(case)

        with self.assertRaises(CaseNotFound):
            FormProcessorInterface.get_case(case.id)

        for form_id in case.xform_ids:
            with self.assertRaises(XFormNotFound):
                FormProcessorInterface.get_xform(form_id)
Пример #39
0
    def test_delete_with_related(self):
        factory = CaseFactory()
        parent = factory.create_case()
        [child] = factory.create_or_update_case(
            CaseStructure(
                attrs={'create': True},
                walk_related=False,
                indices=[CaseIndex(CaseStructure(case_id=parent.case_id))]), )
        # deleting the parent should not be allowed because the child still references it
        with self.assertRaises(CommCareCaseError):
            safe_hard_delete(parent)

        # deleting the child is ok
        safe_hard_delete(child)
        self.assertIsNotNone(self.casedb.get_case(parent.case_id))
        with self.assertRaises(CaseNotFound):
            self.casedb.get_case(child.case_id)
Пример #40
0
    def test_delete_with_related(self):
        factory = CaseFactory()
        parent = factory.create_case()
        [child] = factory.create_or_update_case(
            CaseStructure(attrs={'create': True}, walk_related=False, indices=[
                CaseIndex(CaseStructure(case_id=parent._id))
            ]),
        )
        # deleting the parent should not be allowed because the child still references it
        with self.assertRaises(CommCareCaseError):
            FormProcessorInterface.hard_delete_case(parent)

        # deleting the child is ok
        FormProcessorInterface.hard_delete_case(child)
        self.assertIsNotNone(FormProcessorInterface.get_case(parent.id))
        with self.assertRaises(CaseNotFound):
            FormProcessorInterface.get_case(child.id)
Пример #41
0
    def test_delete_with_related(self):
        factory = CaseFactory()
        parent = factory.create_case()
        [child] = factory.create_or_update_case(
            CaseStructure(attrs={'create': True},
                          walk_related=False,
                          relationships=[
                              CaseRelationship(
                                  CaseStructure(case_id=parent._id))
                          ]), )
        # deleting the parent should not be allowed because the child still references it
        with self.assertRaises(CommCareCaseError):
            safe_hard_delete(parent)

        # deleting the child is ok
        safe_hard_delete(child)
        self.assertTrue(CommCareCase.get_db().doc_exist(parent._id))
        self.assertFalse(CommCareCase.get_db().doc_exist(child._id))
    def test_update_cases(self):
        builder1 = (IntentCaseBuilder(self.registry_slug).target_case(
            self.target_domain,
            self.target_case_id_1).case_properties(new_prop="new_val_case1"))
        builder2 = (IntentCaseBuilder(self.registry_slug).target_case(
            self.target_domain,
            self.target_case_id_2).case_properties(new_prop="new_val_case2"))
        factory = CaseFactory(self.domain)
        host = CaseStructure(attrs={
            "create": True,
            "case_type": "registry_case_update",
            "update": builder1.props
        }, )
        extension = CaseStructure(
            attrs={
                "create": True,
                "case_type": "registry_case_update",
                "update": builder2.props
            },
            indices=[CaseIndex(
                host,
                relationship=CASE_INDEX_EXTENSION,
            )])
        cases = factory.create_or_update_case(extension,
                                              user_id=self.mobile_user.get_id)
        repeat_records = self.repeat_records(self.domain).all()
        self.assertEqual(len(repeat_records), 1)
        payload = repeat_records[0].get_payload()
        host_case = cases[1]
        form = DataRegistryUpdateForm(payload, host_case)
        form.assert_case_updates({
            self.target_case_id_1: {
                "new_prop": "new_val_case1"
            },
            self.target_case_id_2: {
                "new_prop": "new_val_case2"
            }
        })

        url = self.repeater.get_url(repeat_records[0])
        self.assertEqual(url, f"case-repeater-url/{self.target_domain}/")

        # check that the synchronous attempt of the repeat record happened
        self.assertEqual(1, len(repeat_records[0].attempts))
Пример #43
0
 def test_full_ancestry(self):
     """get_case_hierarchy should return the full parentage tree for any case
     """
     factory = CaseFactory('baggins-of-hobbiton')
     bagginses = ['balbo', 'mungo', 'bungo', 'bilbo']
     cases = {}
     for level, baggins in enumerate(bagginses):
         cases[baggins] = factory.create_or_update_case(
             CaseStructure(
                 case_id=baggins,
                 attrs={
                     'case_type': 'baggins',
                     'update': {'name': baggins},
                     'create': True},
                 indices=[CaseIndex(CaseStructure(case_id=bagginses[level - 1]))] if level != 0 else None,
                 walk_related=False,
             )
         )[0]
     hierarchy = get_case_hierarchy(cases['bungo'], {})
     self.assertEqual(4, len(hierarchy['case_list']))
class AutoCloseExtensionsTest(SyncBaseTest):
    def setUp(self):
        FormProcessorTestUtils.delete_all_cases()
        FormProcessorTestUtils.delete_all_xforms()
        self.domain = "domain"
        self.project = Domain(name=self.domain)
        self.user = User(user_id='user', username='******', password="******",
                         date_joined=datetime(2011, 6, 9))
        self.factory = CaseFactory()
        self.extension_ids = ['1', '2', '3']
        self.host = CaseStructure(case_id='host')
        self.extension = CaseStructure(
            case_id=self.extension_ids[0],
            indices=[CaseIndex(
                related_structure=self.host,
                relationship="extension",
            )],
        )
        self.extension_2 = CaseStructure(
            case_id=self.extension_ids[1],
            indices=[CaseIndex(
                related_structure=self.extension,
                relationship="extension",
            )],
        )
        self.extension_3 = CaseStructure(
            case_id=self.extension_ids[2],
            indices=[CaseIndex(
                related_structure=self.extension_2,
                relationship="extension",
            )],
        )

    def test_get_extension_chain_simple(self):
        self.factory.create_or_update_cases([self.extension])
        self.assertEqual(set(self.extension_ids[0]), get_extension_chain([self.host], self.domain))

    def test_get_extension_chain_multiple(self):
        self.factory.create_or_update_cases([self.extension_3])
        self.assertEqual(set(self.extension_ids),
                         get_extension_chain([self.host], self.domain))

    @flag_enabled('EXTENSION_CASES_SYNC_ENABLED')
    def test_get_extension_to_close(self):
        """should return empty if case is not a host, otherwise should return full chain"""
        created_cases = self.factory.create_or_update_cases([self.extension_3])
        # host open, should be empty
        no_cases = get_extensions_to_close(created_cases[-1], self.domain)
        self.assertEqual(set(), no_cases)

        created_cases[-1] = self.factory.create_or_update_case(CaseStructure(
            case_id=self.host.case_id,
            attrs={'close': True}
        ))[0]

        # host closed, should get full chain
        full_chain = get_extensions_to_close(created_cases[-1], self.domain)
        self.assertEqual(set(self.extension_ids), full_chain)

        # extension (not a host), should be empty
        no_cases = get_extensions_to_close(created_cases[2], self.domain)
        self.assertEqual(set(), no_cases)

    @flag_enabled('EXTENSION_CASES_SYNC_ENABLED')
    def test_close_cases(self):
        """Closing a host should close all the extensions"""
        self.factory.create_or_update_cases([self.extension_3])
        self.assertFalse(CommCareCase.get(self.extension.case_id).closed)
        self.assertFalse(CommCareCase.get(self.extension_2.case_id).closed)
        self.assertFalse(CommCareCase.get(self.extension_3.case_id).closed)

        self.factory.create_or_update_case(CaseStructure(
            case_id=self.extension.case_id,
            attrs={'close': True}
        ))
        self.assertFalse(CommCareCase.get(self.host.case_id).closed)
        self.assertTrue(CommCareCase.get(self.extension.case_id).closed)
        self.assertFalse(CommCareCase.get(self.extension_2.case_id).closed)
        self.assertFalse(CommCareCase.get(self.extension_3.case_id).closed)

        self.factory.create_or_update_case(CaseStructure(
            case_id=self.host.case_id,
            attrs={'close': True}
        ))
        self.assertTrue(CommCareCase.get(self.host.case_id).closed)
        self.assertTrue(CommCareCase.get(self.extension.case_id).closed)
        self.assertTrue(CommCareCase.get(self.extension_2.case_id).closed)
        self.assertTrue(CommCareCase.get(self.extension_3.case_id).closed)
Пример #45
0
class TestExtensionCaseIds(TestCase):

    def setUp(self):
        super(TestExtensionCaseIds, self).setUp()
        self.domain = 'domain'
        FormProcessorTestUtils.delete_all_cases()
        self.factory = CaseFactory(self.domain)

    def tearDown(self):
        FormProcessorTestUtils.delete_all_cases()
        FormProcessorTestUtils.delete_all_xforms()
        super(TestExtensionCaseIds, self).tearDown()

    def test_no_extensions(self):
        """ Returns empty when there are other index types """
        parent_id = uuid.uuid4().hex
        child_id = uuid.uuid4().hex
        parent = CaseStructure(case_id=parent_id, attrs={'create': True})

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=child_id,
                indices=[
                    CaseIndex(parent, relationship=CASE_INDEX_CHILD)
                ],
                attrs={'create': True}
            )
        )
        returned_cases = CaseAccessors(self.domain).get_extension_case_ids([parent_id])
        self.assertEqual(returned_cases, [])

    def test_simple_extension_returned(self):
        """ Should return extension if it exists """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id, attrs={'create': True})

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION)
                ],
                attrs={'create': True}
            )
        )
        returned_cases = CaseAccessors(self.domain).get_extension_case_ids([host_id])
        self.assertItemsEqual(returned_cases, [extension_id])

    def test_extension_of_multiple_hosts_returned(self):
        """ Should return an extension from any host if there are multiple indices """
        host_id = uuid.uuid4().hex
        host_2_id = uuid.uuid4().hex
        parent_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id, attrs={'create': True})
        host_2 = CaseStructure(case_id=host_2_id, attrs={'create': True})
        parent = CaseStructure(case_id=parent_id, attrs={'create': True})

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                    CaseIndex(host_2, relationship=CASE_INDEX_EXTENSION, identifier="host_2"),
                    CaseIndex(parent, relationship=CASE_INDEX_CHILD),
                ],
                attrs={'create': True}
            )
        )

        returned_cases = CaseAccessors(self.domain).get_extension_case_ids([host_2_id])
        self.assertItemsEqual(returned_cases, [extension_id])
        returned_cases = CaseAccessors(self.domain).get_extension_case_ids([host_id])
        self.assertItemsEqual(returned_cases, [extension_id])

    def test_host_with_multiple_extensions(self):
        """ Return all extensions from a single host """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        extension_2_id = uuid.uuid4().hex

        host = CaseStructure(case_id=host_id, attrs={'create': True})

        self.factory.create_or_update_cases([
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ],
                attrs={'create': True}
            ),
            CaseStructure(
                case_id=extension_2_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ],
                attrs={'create': True}
            ),
        ]
        )

        returned_cases = CaseAccessors(self.domain).get_extension_case_ids([host_id])
        self.assertItemsEqual(returned_cases, [extension_id, extension_2_id])

    def test_extensions_from_list(self):
        """ Given a list of hosts, should return all extensions """
        host_id = uuid.uuid4().hex
        host_2_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        extension_2_id = uuid.uuid4().hex

        host = CaseStructure(case_id=host_id, attrs={'create': True})
        host_2 = CaseStructure(case_id=host_2_id, attrs={'create': True})
        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ],
                attrs={'create': True}
            )
        )
        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_2_id,
                indices=[
                    CaseIndex(host_2, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ],
                attrs={'create': True}
            )
        )
        returned_cases = CaseAccessors(self.domain).get_extension_case_ids([host_id, host_2_id])
        self.assertItemsEqual(returned_cases, [extension_id, extension_2_id])
class TestCasePropertyChanged(TestCase):
    def setUp(self):
        self.domain = "isildur"
        self.factory = CaseFactory(self.domain)
        self.case = self.factory.create_case(owner_id='owner', case_name="Aragorn", update={"sword": "Narsil"})
        self.other_case = self.factory.create_case()

    def tearDown(self):
        delete_all_xforms()
        delete_all_cases()

    @run_with_all_backends
    def test_date_case_property_changed(self):
        updated_on = datetime(2015, 5, 3, 12, 11)
        # submit 2 updates
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'abc': "updated"
                    },
                    "date_modified": updated_on
                }),
        )
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'bcd': "updated"
                    },
                }),
        )
        case = CaseAccessors(self.domain).get_case(self.case.case_id)

        self.assertEqual(
            updated_on.replace(tzinfo=pytz.UTC),
            get_datetime_case_property_changed(case, "abc", "updated")
        )

    @run_with_all_backends
    def test_multiple_cases_in_update(self):
        day_1 = datetime(2015, 5, 1, 12, 11)
        day_2 = datetime(2015, 5, 2, 12, 11)

        # Submit two updates TOGETHER, one for this case, but irrelevant,
        # and one for another case, but touching the same property
        self.factory.create_or_update_cases([
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'not_relevant': "updated"
                    },
                    "date_modified": day_1,
                }),
            CaseStructure(
                self.other_case.case_id,
                attrs={
                    "update": {
                        'relevant_property': "updated"
                    },
                    "date_modified": day_1,
                }),
        ])

        # Submit an update that DOES modify the relevant property
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'relevant_property': "updated"
                    },
                    "date_modified": day_2,
                }),
        )
        case = CaseAccessors(self.domain).get_case(self.case.case_id)

        self.assertEqual(
            day_2.replace(tzinfo=pytz.UTC),
            get_datetime_case_property_changed(case, "relevant_property", "updated")
        )

    @run_with_all_backends
    def test_owner_id_changed(self):
        changes, _ = get_paged_changes_to_case_property(self.case, 'owner_id')
        self.assertEqual(len(changes), 1)
        self.assertEqual(changes[0].new_value, 'owner')

        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'owner_id': 'new_owner'
                    },
                }),
        )
        case = CaseAccessors(self.domain).get_case(self.case.case_id)

        changes, _ = get_paged_changes_to_case_property(case, 'owner_id')
        self.assertEqual(len(changes), 2)
        self.assertEqual(changes[0].new_value, 'new_owner')
        self.assertEqual(changes[1].new_value, 'owner')

    @run_with_all_backends
    def test_name_changed(self):
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'name': 'Strider'
                    },
                }),
        )
        case = CaseAccessors(self.domain).get_case(self.case.case_id)
        changes, _ = get_paged_changes_to_case_property(case, 'name')
        self.assertEqual(len(changes), 2)
        self.assertEqual(changes[0].new_value, 'Strider')
        self.assertEqual(changes[1].new_value, 'Aragorn')

    @run_with_all_backends
    def test_blank_change(self):
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'sword': ''
                    },
                }),
        )
        case = CaseAccessors(self.domain).get_case(self.case.case_id)
        changes, _ = get_paged_changes_to_case_property(case, 'sword')
        self.assertEqual(len(changes), 2)
        self.assertEqual(changes[0].new_value, '')
        self.assertEqual(changes[1].new_value, 'Narsil')

    @run_with_all_backends
    def test_case_rebuild(self):
        # Cases with rebuild actions were failing because rebuild actions have no form
        # https://manage.dimagi.com/default.asp?276216#1494409
        self.factory.create_or_update_case(
            CaseStructure(
                self.case.case_id,
                attrs={
                    "update": {
                        'sword': ''
                    },
                }),
        )
        rebuild_case_from_forms(self.domain, self.case.case_id, RebuildWithReason())
        case = CaseAccessors(self.domain).get_case(self.case.case_id)
        changes, _ = get_paged_changes_to_case_property(case, 'sword')
        self.assertEqual(len(changes), 2)
        self.assertEqual(changes[0].new_value, '')
        self.assertEqual(changes[1].new_value, 'Narsil')
Пример #47
0
class OwnerCleanlinessTest(SyncBaseTest):

    def setUp(self):
        super(OwnerCleanlinessTest, self).setUp()
        self.owner_id = uuid.uuid4().hex
        self.synclog_id = uuid.uuid4().hex
        self.domain = uuid.uuid4().hex
        self.factory = CaseFactory(
            domain=self.domain,
            case_defaults={
                'create': True,
                'owner_id': self.owner_id,
                'user_id': self.owner_id,
            }
        )
        self.assert_owner_clean()  # this first call creates the OwnershipCleanliness doc
        self.sample_case = self.factory.create_case()
        self.child, self.parent = self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(),
                ]
            )
        )
        self.extension, self.host = self.factory.create_or_update_case(
            CaseStructure(
                attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
                indices=[
                    CaseIndex(
                        relationship=CASE_INDEX_EXTENSION
                    ),
                ]
            )
        )
        self.assert_owner_clean()  # this is an actual assertion

    def _verify_set_cleanliness_flags(self, owner_id=None):
        """
        Can be run at the end of any relevant test to check the current state of the
        OwnershipCleanliness object and verify that rebuilding it from scratch produces
        the same result
        """
        if owner_id is None:
            owner_id = self.owner_id
        owner_cleanliness = self._owner_cleanliness_for_id(owner_id)
        is_clean = owner_cleanliness.is_clean
        hint = owner_cleanliness.hint
        owner_cleanliness.delete()
        set_cleanliness_flags(self.domain, owner_id, force_full=True)
        new_cleanliness = OwnershipCleanlinessFlag.objects.get(owner_id=owner_id)
        self.assertEqual(is_clean, new_cleanliness.is_clean)
        self.assertEqual(hint, new_cleanliness.hint)
        if hint:
            self.assertTrue(hint_still_valid(self.domain, hint))

    @property
    def owner_cleanliness(self):
        return self._owner_cleanliness_for_id(self.owner_id)

    def _owner_cleanliness_for_id(self, owner_id):
        return OwnershipCleanlinessFlag.objects.get_or_create(
            owner_id=owner_id,
            domain=self.domain,
            defaults={'is_clean': True}
        )[0]

    def assert_owner_clean(self):
        self.assertTrue(self.owner_cleanliness.is_clean)

    def assert_owner_dirty(self):
        self.assertFalse(self.owner_cleanliness.is_clean)

    def assert_owner_temporarily_dirty(self):
        """
        Changing any case's owner makes the previous owner ID temporarily dirty, to allow
        syncs to happen, but the should become clean on a rebuild.

        This checks that workflow and rebuilds the cleanliness flag.
        """
        self.assertFalse(self.owner_cleanliness.is_clean)
        set_cleanliness_flags(self.domain, self.owner_id, force_full=True)
        self.assertTrue(self.owner_cleanliness.is_clean)

    def _set_owner(self, case_id, owner_id):
        case = self.factory.create_or_update_case(
            CaseStructure(case_id=case_id, attrs={'create': False, 'owner_id': owner_id})
        )[0]
        self.assertEqual(owner_id, case.owner_id)

    @run_with_all_backends
    def test_add_normal_case_stays_clean(self):
        """Owned case with no indices remains clean"""
        self.factory.create_case()
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_change_owner_stays_clean(self):
        """change the owner ID of a normal case, should remain clean"""
        new_owner = uuid.uuid4().hex
        self._set_owner(self.sample_case.case_id, new_owner)
        self.assert_owner_temporarily_dirty()
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_change_owner_child_case_stays_clean(self):
        """change the owner ID of a child case, should remain clean"""
        new_owner = uuid.uuid4().hex
        self._set_owner(self.child.case_id, new_owner)
        self.assert_owner_temporarily_dirty()
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_add_clean_parent_stays_clean(self):
        """add a parent with the same owner, should remain clean"""
        self.factory.create_or_update_case(CaseStructure(indices=[CaseIndex()]))
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_create_dirty_makes_dirty(self):
        """create a case and a parent case with a different owner at the same time
        make sure the owner becomes dirty.
        """
        new_owner = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(CaseStructure(attrs={'owner_id': new_owner}))
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertEqual(child.case_id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_add_dirty_parent_makes_dirty(self):
        """add parent with a different owner and make sure the owner becomes dirty"""
        new_owner = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(
            CaseStructure(
                case_id=self.sample_case.case_id,
                indices=[
                    CaseIndex(CaseStructure(attrs={'owner_id': new_owner}))
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertEqual(child.case_id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_change_parent_owner_makes_dirty(self):
        """change the owner id of a parent case and make sure the owner becomes dirty"""
        new_owner = uuid.uuid4().hex
        self._set_owner(self.parent.case_id, new_owner)
        self.assert_owner_dirty()
        self.assertEqual(self.child.case_id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_change_host_owner_remains_clean(self):
        """change owner for unowned extension, owner remains clean"""
        new_owner = uuid.uuid4().hex
        self._owner_cleanliness_for_id(new_owner)
        self._set_owner(self.host.case_id, new_owner)

        self.assert_owner_temporarily_dirty()
        self.assertTrue(self._owner_cleanliness_for_id(new_owner).is_clean)
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_change_host_owner_makes_both_owners_dirty(self):
        """change owner for extension, both owners dirty"""
        new_owner = uuid.uuid4().hex
        self._owner_cleanliness_for_id(new_owner)
        self._set_owner(self.extension.case_id, new_owner)
        self.assert_owner_dirty()
        self.assertFalse(self._owner_cleanliness_for_id(new_owner).is_clean)

    @run_with_all_backends
    def test_set_flag_clean_no_data(self):
        unused_owner_id = uuid.uuid4().hex
        set_cleanliness_flags(self.domain, unused_owner_id)
        self.assertTrue(OwnershipCleanlinessFlag.objects.get(owner_id=unused_owner_id).is_clean)

    @run_with_all_backends
    def test_hint_invalidation(self):
        new_owner = uuid.uuid4().hex
        self._set_owner(self.parent.case_id, new_owner)
        self._set_owner(self.parent.case_id, self.owner_id)
        # after the submission the dirtiness flag should still be set
        # since it isn't invalidated right away
        self.assert_owner_dirty()
        # explicitly make sure the hint is no longer valid
        self.assertFalse(hint_still_valid(self.domain, self.owner_cleanliness.hint))
        # reset the cleanliness flag and ensure it worked
        set_cleanliness_flags(self.domain, self.owner_id)
        self.assert_owner_clean()
        self.assertEqual(None, self.owner_cleanliness.hint)

    @run_with_all_backends
    def test_hint_invalidation_extensions(self):
        other_owner_id = uuid.uuid4().hex
        [extension, host] = self.factory.create_or_update_case(
            CaseStructure(
                case_id='extension',
                attrs={'owner_id': other_owner_id},
                indices=[
                    CaseIndex(
                        CaseStructure(case_id="host"),
                        relationship=CASE_INDEX_EXTENSION
                    )
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertTrue(hint_still_valid(self.domain, self.owner_cleanliness.hint))

        self._set_owner(extension.case_id, UNOWNED_EXTENSION_OWNER_ID)
        self.assertFalse(hint_still_valid(self.domain, self.owner_cleanliness.hint))

    @run_with_all_backends
    def test_hint_invalidation_extension_chain(self):
        other_owner_id = uuid.uuid4().hex
        self._owner_cleanliness_for_id(other_owner_id)
        host = CaseStructure(case_id=self.sample_case.case_id, attrs={'create': False})
        extension_1 = CaseStructure(
            case_id="extension1",
            attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
            indices=[
                CaseIndex(
                    host,
                    relationship=CASE_INDEX_EXTENSION,
                )
            ]
        )
        extension_2 = CaseStructure(
            case_id="extension2",
            attrs={'owner_id': other_owner_id},
            indices=[
                CaseIndex(
                    extension_1,
                    relationship=CASE_INDEX_EXTENSION,
                )
            ]
        )
        self.factory.create_or_update_case(extension_2)
        self.assert_owner_dirty()

        self._set_owner(extension_2.case_id, UNOWNED_EXTENSION_OWNER_ID)
        self.assertFalse(hint_still_valid(self.domain, self.owner_cleanliness.hint))

    @run_with_all_backends
    def test_cross_domain_on_submission(self):
        """create a form that makes a dirty owner with the same ID but in a different domain
        make sure the original owner stays clean"""
        new_domain = uuid.uuid4().hex
        # initialize the new cleanliness flag
        OwnershipCleanlinessFlag.objects.create(domain=new_domain, owner_id=self.owner_id, is_clean=True)
        self.factory.domain = new_domain
        self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(CaseStructure(attrs={'owner_id': uuid.uuid4().hex}))
                ]
            )
        )
        self.assert_owner_clean()
        self.assertEqual(
            False,
            OwnershipCleanlinessFlag.objects.get(owner_id=self.owner_id, domain=new_domain).is_clean,
        )

    @run_with_all_backends
    def test_cross_domain_both_clean(self):
        new_domain = uuid.uuid4().hex
        self.factory.domain = new_domain
        self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(),
                ]
            )
        )
        # two clean ownership models in different domains should report clean
        self.assertTrue(get_cleanliness_flag_from_scratch(self.domain, self.owner_id).is_clean)
        self.assertTrue(get_cleanliness_flag_from_scratch(new_domain, self.owner_id).is_clean)

    @run_with_all_backends
    def test_cross_domain_dirty(self):
        new_domain = uuid.uuid4().hex
        new_owner = uuid.uuid4().hex
        self.factory.domain = new_domain
        self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(CaseStructure(attrs={'owner_id': new_owner})),
                ]
            )
        )
        # original domain should stay clean but the new one should be dirty
        self.assertTrue(get_cleanliness_flag_from_scratch(self.domain, self.owner_id).is_clean)
        self.assertFalse(get_cleanliness_flag_from_scratch(new_domain, self.owner_id).is_clean)

    @run_with_all_backends
    def test_non_existent_parent(self):
        self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(CaseStructure()),
                ],
                walk_related=False,
            )
        )
        self.assertTrue(get_cleanliness_flag_from_scratch(self.domain, self.owner_id).is_clean)

    @override_settings(TESTS_SHOULD_TRACK_CLEANLINESS=False)
    @run_with_all_backends
    def test_autocreate_flag_off(self):
        new_owner = uuid.uuid4().hex
        self.factory.create_or_update_case(
            CaseStructure(case_id=uuid.uuid4().hex, attrs={'create': True, 'owner_id': new_owner})
        )[0]
        self.assertFalse(OwnershipCleanlinessFlag.objects.filter(domain=self.domain, owner_id=new_owner).exists())

    @override_settings(TESTS_SHOULD_TRACK_CLEANLINESS=True)
    @run_with_all_backends
    def test_autocreate_flag_on(self):
        new_owner = uuid.uuid4().hex
        self.factory.create_or_update_case(
            CaseStructure(case_id=uuid.uuid4().hex, attrs={'create': True, 'owner_id': new_owner})
        )[0]
        flag = OwnershipCleanlinessFlag.objects.get(domain=self.domain, owner_id=new_owner)
        self.assertEqual(True, flag.is_clean)

    @run_with_all_backends
    def test_simple_unowned_extension(self):
        """Simple unowned extensions should be clean"""
        self.factory.create_or_update_case(
            CaseStructure(
                case_id=uuid.uuid4().hex,
                attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
                indices=[
                    CaseIndex(
                        CaseStructure(),
                        relationship=CASE_INDEX_EXTENSION
                    )
                ]
            )
        )
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    @run_with_all_backends
    def test_owned_extension(self):
        """Extension owned by another owner should be dirty"""
        other_owner_id = uuid.uuid4().hex
        self._owner_cleanliness_for_id(other_owner_id)
        [extension, host] = self.factory.create_or_update_case(
            CaseStructure(
                case_id='extension',
                attrs={'owner_id': other_owner_id},
                indices=[
                    CaseIndex(
                        CaseStructure(case_id="host"),
                        relationship=CASE_INDEX_EXTENSION
                    )
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertFalse(self._owner_cleanliness_for_id(other_owner_id).is_clean)
        self.assertEqual(host.case_id, self.owner_cleanliness.hint)
        self.assertEqual(extension.case_id, self._owner_cleanliness_for_id(other_owner_id).hint)
        self._verify_set_cleanliness_flags(self.owner_id)
        self._verify_set_cleanliness_flags(other_owner_id)

    @run_with_all_backends
    def test_extension_chain_with_other_owner_makes_dirty(self):
        """An extension chain of unowned extensions that ends at a case owned by a different owner is dirty"""
        other_owner_id = uuid.uuid4().hex
        self._owner_cleanliness_for_id(other_owner_id)
        host = CaseStructure(case_id=self.sample_case.case_id, attrs={'create': False})
        extension_1 = CaseStructure(
            case_id="extension1",
            attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
            indices=[
                CaseIndex(
                    host,
                    relationship=CASE_INDEX_EXTENSION,
                )
            ]
        )
        extension_2 = CaseStructure(
            case_id="extension2",
            attrs={'owner_id': other_owner_id},
            indices=[
                CaseIndex(
                    extension_1,
                    relationship=CASE_INDEX_EXTENSION,
                )
            ]
        )
        self.factory.create_or_update_case(extension_2)

        self.assert_owner_dirty()
        self.assertFalse(self._owner_cleanliness_for_id(other_owner_id).is_clean)
        self.assertEqual(host.case_id, self.owner_cleanliness.hint)
        self.assertEqual(extension_2.case_id, self._owner_cleanliness_for_id(other_owner_id).hint)
        self._verify_set_cleanliness_flags(self.owner_id)
        self._verify_set_cleanliness_flags(other_owner_id)

    @run_with_all_backends
    def test_multiple_indices_multiple_owners(self):
        """Extension that indexes a case with another owner should make all owners dirty"""
        other_owner_id = uuid.uuid4().hex
        self._owner_cleanliness_for_id(other_owner_id)
        host_1 = CaseStructure()
        host_2 = CaseStructure(attrs={'owner_id': other_owner_id})

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=self.sample_case.case_id,
                attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
                indices=[
                    CaseIndex(
                        host_1,
                        relationship=CASE_INDEX_EXTENSION,
                        identifier="host_1",
                    ),
                    CaseIndex(
                        host_2,
                        relationship=CASE_INDEX_EXTENSION,
                        identifier="host_2",
                    )
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertFalse(self._owner_cleanliness_for_id(other_owner_id).is_clean)
        self.assertEqual(host_1.case_id, self.owner_cleanliness.hint)
        self.assertEqual(host_2.case_id, self._owner_cleanliness_for_id(other_owner_id).hint)
        self._verify_set_cleanliness_flags(self.owner_id)
        self._verify_set_cleanliness_flags(other_owner_id)

    @run_with_all_backends
    def test_long_extension_chain_with_branches(self):
        """An extension chain of unowned extensions that ends at an owned case is dirty"""
        owner_1 = uuid.uuid4().hex
        self._owner_cleanliness_for_id(owner_1)
        owner_2 = uuid.uuid4().hex
        self._owner_cleanliness_for_id(owner_2)
        host = CaseStructure(case_id=self.sample_case.case_id, attrs={'create': False})
        host_2 = CaseStructure(
            case_id="host_with_other_owner",
            attrs={'owner_id': owner_1}
        )
        extension_1 = CaseStructure(
            case_id="extension1",
            attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
            indices=[
                CaseIndex(
                    host,
                    relationship=CASE_INDEX_EXTENSION,
                    identifier="host_1",
                ),
                CaseIndex(
                    host_2,
                    relationship=CASE_INDEX_EXTENSION,
                    identifier="host_2",
                )
            ]
        )
        extension_2 = CaseStructure(
            case_id="extension2",
            attrs={'owner_id': owner_2},
            indices=[
                CaseIndex(
                    extension_1,
                    relationship=CASE_INDEX_EXTENSION,
                )
            ]
        )
        self.factory.create_or_update_case(extension_2)
        self.assert_owner_dirty()
        self.assertFalse(self._owner_cleanliness_for_id(owner_1).is_clean)
        self.assertFalse(self._owner_cleanliness_for_id(owner_2).is_clean)
        self.assertEqual(host.case_id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()
Пример #48
0
class GetDependentCasesTest(TestCase):

    @classmethod
    def setUpClass(cls):
        super(GetDependentCasesTest, cls).setUpClass()
        delete_all_cases()

    def setUp(self):
        super(GetDependentCasesTest, self).setUp()
        self.domain = 'domain'
        self.owner_id = uuid.uuid4().hex
        self.other_owner_id = uuid.uuid4().hex
        self.factory = CaseFactory(self.domain)

    @run_with_all_backends
    def test_returns_nothing_with_no_dependencies(self):
        case = CaseStructure()
        self.factory.create_or_update_case(case)
        self.assertEqual(set(), get_dependent_case_info(self.domain, [case.case_id]).all_ids)

    @run_with_all_backends
    def test_returns_simple_extension(self):
        host = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.owner_id}
        )
        extension = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.other_owner_id},
            indices=[CaseIndex(host, relationship=CASE_INDEX_EXTENSION)]
        )
        all_ids = set([host.case_id, extension.case_id])

        self.factory.create_or_update_cases([host, extension])
        self.assertEqual(all_ids, get_dependent_case_info(self.domain, [host.case_id]).all_ids)
        self.assertEqual(all_ids, get_dependent_case_info(self.domain, [extension.case_id]).all_ids)
        self.assertEqual(set([extension.case_id]),
                         get_dependent_case_info(self.domain, [host.case_id]).extension_ids)

    @run_with_all_backends
    def test_returns_extension_of_extension(self):
        host = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.owner_id}
        )
        extension = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.other_owner_id},
            indices=[CaseIndex(host, relationship=CASE_INDEX_EXTENSION)]
        )
        extension_2 = CaseStructure(
            case_id=uuid.uuid4().hex,
            indices=[CaseIndex(extension, relationship=CASE_INDEX_EXTENSION)]
        )
        all_ids = set([host.case_id, extension.case_id, extension_2.case_id])

        self.factory.create_or_update_cases([extension_2])
        self.assertEqual(all_ids, get_dependent_case_info(self.domain, [host.case_id]).all_ids)
        self.assertEqual(all_ids, get_dependent_case_info(self.domain, [extension.case_id]).all_ids)
        self.assertEqual(all_ids, get_dependent_case_info(self.domain, [extension_2.case_id]).all_ids)
        self.assertEqual(set([extension.case_id, extension_2.case_id]),
                         get_dependent_case_info(self.domain, [host.case_id]).extension_ids)

    @run_with_all_backends
    def test_children_and_extensions(self):
        parent = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.other_owner_id, 'close': True}
        )
        child = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.owner_id},
            indices=[CaseIndex(parent)]
        )
        extension = CaseStructure(
            case_id=uuid.uuid4().hex,
            attrs={'owner_id': self.other_owner_id},
            indices=[CaseIndex(child, relationship=CASE_INDEX_EXTENSION)]
        )
        self.factory.create_or_update_cases([parent, child, extension])
        all_ids = set([parent.case_id, child.case_id, extension.case_id])
        self.assertEqual(all_ids, get_dependent_case_info(self.domain, [child.case_id]).all_ids)
        self.assertEqual(set([]), get_dependent_case_info(self.domain, [parent.case_id]).all_ids)
        self.assertEqual(set([extension.case_id]),
                         get_dependent_case_info(self.domain, [child.case_id]).extension_ids)
        self.assertEqual(set([]),
                         get_dependent_case_info(self.domain, [parent.case_id]).extension_ids)
class AutoCloseExtensionsTest(TestCase):

    def setUp(self):
        FormProcessorTestUtils.delete_all_cases()
        FormProcessorTestUtils.delete_all_xforms()
        delete_all_users()
        self.domain = "domain"
        self.project = Domain(name=self.domain)
        self.user = create_restore_user(self.domain, username='******', password="******")
        self.factory = CaseFactory(domain=self.domain)
        self.extension_ids = ['1', '2', '3']
        self.host_id = 'host'

    def tearDown(self):
        FormProcessorTestUtils.delete_all_cases()
        FormProcessorTestUtils.delete_all_xforms()
        delete_all_users()

    def _create_extension_chain(self):
        host = CaseStructure(case_id=self.host_id)
        extension = CaseStructure(
            case_id=self.extension_ids[0],
            indices=[CaseIndex(
                related_structure=host,
                relationship="extension",
            )],
        )
        extension_2 = CaseStructure(
            case_id=self.extension_ids[1],
            indices=[CaseIndex(
                related_structure=extension,
                relationship="extension",
            )],
        )
        extension_3 = CaseStructure(
            case_id=self.extension_ids[2],
            indices=[CaseIndex(
                related_structure=extension_2,
                relationship="extension",
            )],
        )
        return self.factory.create_or_update_cases([extension_3])

    def _create_extension_loop(self):
        extension_3 = CaseStructure(case_id=self.extension_ids[2])
        host = CaseStructure(
            case_id=self.host_id,
            indices=[CaseIndex(
                related_structure=extension_3,
                relationship="extension",
            )],
        )
        return self.factory.create_or_update_cases([host])

    def _create_host_is_subcase_chain(self):
        parent = CaseStructure(case_id='parent')
        host = CaseStructure(
            case_id=self.host_id,
            indices=[CaseIndex(
                related_structure=parent,
                relationship="child",
            )],
        )
        extension = CaseStructure(
            case_id=self.extension_ids[0],
            indices=[CaseIndex(
                related_structure=host,
                relationship="extension",
            )],
        )
        extension_2 = CaseStructure(
            case_id=self.extension_ids[1],
            indices=[CaseIndex(
                related_structure=extension,
                relationship="extension",
            )],
        )
        return self.factory.create_or_update_cases([extension_2])

    @run_with_all_backends
    def test_get_extension_chain_simple(self):
        host = CaseStructure(case_id=self.host_id)
        extension = CaseStructure(
            case_id=self.extension_ids[0],
            indices=[CaseIndex(
                related_structure=host,
                relationship="extension",
            )],
        )
        self.factory.create_or_update_cases([extension])
        self.assertEqual(
            set(self.extension_ids[0]),
            CaseAccessors(self.domain).get_extension_chain([self.host_id])
        )

    @run_with_all_backends
    def test_get_extension_chain_multiple(self):
        created_cases = self._create_extension_chain()
        self.assertEqual(
            set(self.extension_ids),
            CaseAccessors(self.domain).get_extension_chain([created_cases[-1].case_id])
        )

    @run_with_all_backends
    def test_get_extension_chain_circular_ref(self):
        """If there is a circular reference, this should not hang forever
        """
        self._create_extension_chain()
        self._create_extension_loop()

        self.assertEqual(
            set([self.host_id] + self.extension_ids),
            CaseAccessors(self.domain).get_extension_chain([self.extension_ids[2]])
        )

    @flag_enabled('EXTENSION_CASES_SYNC_ENABLED')
    @run_with_all_backends
    def test_get_extension_to_close(self):
        """should return empty if case is not a host, otherwise should return full chain"""
        created_cases = self._create_extension_chain()
        # host open, should be empty
        no_cases = get_extensions_to_close(created_cases[-1], self.domain)
        self.assertEqual(set(), no_cases)

        created_cases[-1] = self.factory.create_or_update_case(CaseStructure(
            case_id=self.host_id,
            attrs={'close': True}
        ))[0]

        # host closed, should get full chain
        full_chain = get_extensions_to_close(created_cases[-1], self.domain)
        self.assertEqual(set(self.extension_ids), full_chain)

        # extension (not a host), should be empty
        no_cases = get_extensions_to_close(created_cases[2], self.domain)
        self.assertEqual(set(), no_cases)

    @flag_enabled('EXTENSION_CASES_SYNC_ENABLED')
    @run_with_all_backends
    def test_get_extension_to_close_child_host(self):
        """should still return extension chain if outgoing index is a child index"""
        created_cases = self._create_host_is_subcase_chain()
        # host open, should be empty
        no_cases = get_extensions_to_close(created_cases[-1], self.domain)
        self.assertEqual(set(), no_cases)

        # close parent, shouldn't get extensions
        created_cases[-1] = self.factory.create_or_update_case(CaseStructure(
            case_id='parent',
            attrs={'close': True}
        ))[0]
        no_cases = get_extensions_to_close(created_cases[-1], self.domain)
        self.assertEqual(set(), no_cases)

        # close host that is also a child
        created_cases[-2] = self.factory.create_or_update_case(CaseStructure(
            case_id=self.host_id,
            attrs={'close': True}
        ))[0]
        full_chain = get_extensions_to_close(created_cases[-2], self.domain)
        self.assertEqual(set(self.extension_ids[0:2]), full_chain)

    @flag_enabled('EXTENSION_CASES_SYNC_ENABLED')
    @run_with_all_backends
    def test_close_cases_host(self):
        """Closing a host should close all the extensions"""
        self._create_extension_chain()
        cases = CaseAccessors(self.domain).get_cases(self.extension_ids)
        self.assertFalse(cases[0].closed)
        self.assertFalse(cases[1].closed)
        self.assertFalse(cases[2].closed)

        self.factory.create_or_update_case(CaseStructure(
            case_id=self.extension_ids[0],
            attrs={'close': True}
        ))
        cases = {
            case.case_id: case.closed
            for case in CaseAccessors(self.domain).get_cases([self.host_id] + self.extension_ids)
        }
        self.assertFalse(cases[self.host_id])
        self.assertTrue(cases[self.extension_ids[0]])
        self.assertFalse(cases[self.extension_ids[1]])
        self.assertFalse(cases[self.extension_ids[2]])

        self.factory.create_or_update_case(CaseStructure(
            case_id=self.host_id,
            attrs={'close': True}
        ))
        cases = {
            case.case_id: case.closed
            for case in CaseAccessors(self.domain).get_cases([self.host_id] + self.extension_ids)
        }
        self.assertTrue(cases[self.host_id])
        self.assertTrue(cases[self.extension_ids[0]])
        self.assertTrue(cases[self.extension_ids[1]])
        self.assertTrue(cases[self.extension_ids[2]])

    @flag_enabled('EXTENSION_CASES_SYNC_ENABLED')
    @run_with_all_backends
    def test_close_cases_child(self):
        """Closing a host that is also a child should close all the extensions"""
        self._create_host_is_subcase_chain()
        cases = {
            case.case_id: case.closed
            for case in CaseAccessors(self.domain).get_cases([self.host_id] + self.extension_ids)
        }
        self.assertFalse(cases[self.host_id])
        self.assertFalse(cases[self.extension_ids[0]])
        self.assertFalse(cases[self.extension_ids[1]])

        self.factory.create_or_update_case(CaseStructure(
            case_id=self.host_id,
            attrs={'close': True}
        ))
        cases = {
            case.case_id: case.closed
            for case in CaseAccessors(self.domain).get_cases(['parent', self.host_id] + self.extension_ids)
        }
        self.assertFalse(cases['parent'])
        self.assertTrue(cases[self.host_id])
        self.assertTrue(cases[self.extension_ids[0]])
        self.assertTrue(cases[self.extension_ids[1]])
Пример #50
0
class ImporterTest(TestCase):

    def setUp(self):
        super(ImporterTest, self).setUp()
        self.domain_obj = create_domain("importer-test")
        self.domain = self.domain_obj.name
        self.default_case_type = 'importer-test-casetype'

        self.couch_user = WebUser.create(None, "test", "foobar")
        self.couch_user.add_domain_membership(self.domain, is_admin=True)
        self.couch_user.save()

        self.accessor = CaseAccessors(self.domain)

        self.factory = CaseFactory(domain=self.domain, case_defaults={
            'case_type': self.default_case_type,
        })
        delete_all_cases()

    def tearDown(self):
        self.couch_user.delete()
        self.domain_obj.delete()
        super(ImporterTest, self).tearDown()

    def _config(self, col_names, search_column=None, case_type=None,
                search_field='case_id', create_new_cases=True):
        return ImporterConfig(
            couch_user_id=self.couch_user._id,
            case_type=case_type or self.default_case_type,
            excel_fields=col_names,
            case_fields=[''] * len(col_names),
            custom_fields=col_names,
            search_column=search_column or col_names[0],
            search_field=search_field,
            create_new_cases=create_new_cases,
        )

    @run_with_all_backends
    @patch('corehq.apps.case_importer.tasks.bulk_import_async.update_state')
    def testImportNone(self, update_state):
        res = bulk_import_async.delay(self._config(['anything']), self.domain, None)
        self.assertIsInstance(res.result, Ignore)
        update_state.assert_called_with(
            state=states.FAILURE,
            meta={'errors': 'Sorry, your session has expired. Please start over and try again.'})
        self.assertEqual(0, len(get_case_ids_in_domain(self.domain)))

    @run_with_all_backends
    def testImportBasic(self):
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
            ['case_id-4', 'age-4', 'sex-4', 'location-4'],
        )
        res = do_import(file, config, self.domain)
        self.assertEqual(5, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertFalse(res['errors'])
        self.assertEqual(1, res['num_chunks'])
        case_ids = self.accessor.get_case_ids_in_domain()
        cases = list(self.accessor.get_cases(case_ids))
        self.assertEqual(5, len(cases))
        properties_seen = set()
        for case in cases:
            self.assertEqual(self.couch_user._id, case.user_id)
            self.assertEqual(self.couch_user._id, case.owner_id)
            self.assertEqual(self.default_case_type, case.type)
            for prop in ['age', 'sex', 'location']:
                self.assertTrue(prop in case.get_case_property(prop))
                self.assertFalse(case.get_case_property(prop) in properties_seen)
                properties_seen.add(case.get_case_property(prop))

    @run_with_all_backends
    def testImportNamedColumns(self):
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
        )
        res = do_import(file, config, self.domain)

        self.assertEqual(4, res['created_count'])
        self.assertEqual(4, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def testImportTrailingWhitespace(self):
        cols = ['case_id', 'age', 'sex\xa0', 'location']
        config = self._config(cols)
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex\xa0', 'location'],
            ['case_id-0', 'age-0', 'sex\xa0-0', 'location-0'],
        )
        res = do_import(file, config, self.domain)

        self.assertEqual(1, res['created_count'])
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        case = self.accessor.get_case(case_ids[0])
        self.assertTrue(bool(case.get_case_property('sex')))  # make sure the value also got properly set

    @run_with_all_backends
    def testCaseIdMatching(self):
        # bootstrap a stub case
        [case] = self.factory.create_or_update_case(CaseStructure(attrs={
            'create': True,
            'update': {'importer_test_prop': 'foo'},
        }))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [case.case_id, 'age-0', 'sex-0', 'location-0'],
            [case.case_id, 'age-1', 'sex-1', 'location-1'],
            [case.case_id, 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)
        self.assertEqual(0, res['created_count'])
        self.assertEqual(3, res['match_count'])
        self.assertFalse(res['errors'])

        # shouldn't create any more cases, just the one
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        [case] = self.accessor.get_cases(case_ids)
        for prop in ['age', 'sex', 'location']:
            self.assertTrue(prop in case.get_case_property(prop))

        # shouldn't touch existing properties
        self.assertEqual('foo', case.get_case_property('importer_test_prop'))

    @run_with_all_backends
    def testCaseLookupTypeCheck(self):
        [case] = self.factory.create_or_update_case(CaseStructure(attrs={
            'create': True,
            'case_type': 'nonmatch-type',
        }))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [case.case_id, 'age-0', 'sex-0', 'location-0'],
            [case.case_id, 'age-1', 'sex-1', 'location-1'],
            [case.case_id, 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)
        # because the type is wrong these shouldn't match
        self.assertEqual(3, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(4, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def testCaseLookupDomainCheck(self):
        self.factory.domain = 'wrong-domain'
        [case] = self.factory.create_or_update_case(CaseStructure(attrs={
            'create': True,
        }))
        self.assertEqual(0, len(self.accessor.get_case_ids_in_domain()))
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [case.case_id, 'age-0', 'sex-0', 'location-0'],
            [case.case_id, 'age-1', 'sex-1', 'location-1'],
            [case.case_id, 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)

        # because the domain is wrong these shouldn't match
        self.assertEqual(3, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(3, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def testExternalIdMatching(self):
        # bootstrap a stub case
        external_id = 'importer-test-external-id'
        [case] = self.factory.create_or_update_case(CaseStructure(
            attrs={
                'create': True,
                'external_id': external_id,
            }
        ))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

        headers = ['external_id', 'age', 'sex', 'location']
        config = self._config(headers, search_field='external_id')
        file = make_worksheet_wrapper(
            ['external_id', 'age', 'sex', 'location'],
            ['importer-test-external-id', 'age-0', 'sex-0', 'location-0'],
            ['importer-test-external-id', 'age-1', 'sex-1', 'location-1'],
            ['importer-test-external-id', 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)
        self.assertEqual(0, res['created_count'])
        self.assertEqual(3, res['match_count'])
        self.assertFalse(res['errors'])

        # shouldn't create any more cases, just the one
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def test_external_id_matching_on_create_with_custom_column_name(self):
        headers = ['id_column', 'age', 'sex', 'location']
        external_id = 'external-id-test'
        config = self._config(headers[1:], search_column='id_column', search_field='external_id')
        file = make_worksheet_wrapper(
            ['id_column', 'age', 'sex', 'location'],
            ['external-id-test', 'age-0', 'sex-0', 'location-0'],
            ['external-id-test', 'age-1', 'sex-1', 'location-1'],
        )

        res = do_import(file, config, self.domain)
        self.assertFalse(res['errors'])
        self.assertEqual(1, res['created_count'])
        self.assertEqual(1, res['match_count'])
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        case = self.accessor.get_case(case_ids[0])
        self.assertEqual(external_id, case.external_id)

    def testNoCreateNew(self):
        config = self._config(['case_id', 'age', 'sex', 'location'], create_new_cases=False)
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
            ['case_id-4', 'age-4', 'sex-4', 'location-4'],
        )
        res = do_import(file, config, self.domain)

        # no matching and no create new set - should do nothing
        self.assertEqual(0, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(0, len(get_case_ids_in_domain(self.domain)))

    def testBlankRows(self):
        # don't create new cases for rows left blank
        config = self._config(['case_id', 'age', 'sex', 'location'], create_new_cases=True)
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [None, None, None, None],
            ['', '', '', ''],
        )
        res = do_import(file, config, self.domain)

        # no matching and no create new set - should do nothing
        self.assertEqual(0, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(0, len(get_case_ids_in_domain(self.domain)))

    def testBasicChunking(self):
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
            ['case_id-4', 'age-4', 'sex-4', 'location-4'],
        )
        res = do_import(file, config, self.domain, chunksize=2)
        # 5 cases in chunks of 2 = 3 chunks
        self.assertEqual(3, res['num_chunks'])
        self.assertEqual(5, res['created_count'])
        self.assertEqual(5, len(get_case_ids_in_domain(self.domain)))

    @run_with_all_backends
    def testExternalIdChunking(self):
        # bootstrap a stub case
        external_id = 'importer-test-external-id'

        headers = ['external_id', 'age', 'sex', 'location']
        config = self._config(headers, search_field='external_id')
        file = make_worksheet_wrapper(
            ['external_id', 'age', 'sex', 'location'],
            ['importer-test-external-id', 'age-0', 'sex-0', 'location-0'],
            ['importer-test-external-id', 'age-1', 'sex-1', 'location-1'],
            ['importer-test-external-id', 'age-2', 'sex-2', 'location-2'],
        )

        # the first one should create the case, and the remaining two should update it
        res = do_import(file, config, self.domain)
        self.assertEqual(1, res['created_count'])
        self.assertEqual(2, res['match_count'])
        self.assertFalse(res['errors'])
        self.assertEqual(2, res['num_chunks']) # the lookup causes an extra chunk

        # should just create the one case
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        [case] = self.accessor.get_cases(case_ids)
        self.assertEqual(external_id, case.external_id)
        for prop in ['age', 'sex', 'location']:
            self.assertTrue(prop in case.get_case_property(prop))

    @run_with_all_backends
    def testParentCase(self):
        headers = ['parent_id', 'name', 'case_id']
        config = self._config(headers, create_new_cases=True, search_column='case_id')
        rows = 3
        [parent_case] = self.factory.create_or_update_case(CaseStructure(attrs={'create': True}))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

        file = make_worksheet_wrapper(
            ['parent_id', 'name', 'case_id'],
            [parent_case.case_id, 'name-0', 'case_id-0'],
            [parent_case.case_id, 'name-1', 'case_id-1'],
            [parent_case.case_id, 'name-2', 'case_id-2'],
        )
        file_missing = make_worksheet_wrapper(
            ['parent_id', 'name', 'case_id'],
            ['parent_id-0', 'name-0', 'case_id-0'],
            ['parent_id-1', 'name-1', 'case_id-1'],
            ['parent_id-2', 'name-2', 'case_id-2'],
        )

        # Should successfully match on `rows` cases
        res = do_import(file, config, self.domain)
        self.assertEqual(rows, res['created_count'])

        # Should be unable to find parent case on `rows` cases
        res = do_import(file_missing, config, self.domain)
        error_column_name = 'parent_id'
        self.assertEqual(rows,
                         len(res['errors'][ImportErrors.InvalidParentId][error_column_name]['rows']),
                         "All cases should have missing parent")

    def import_mock_file(self, rows):
        config = self._config(rows[0])
        xls_file = make_worksheet_wrapper(*rows)
        return do_import(xls_file, config, self.domain)

    @run_with_all_backends
    def testLocationOwner(self):
        # This is actually testing several different things, but I figure it's
        # worth it, as each of these tests takes a non-trivial amount of time.
        non_case_sharing = LocationType.objects.create(
            domain=self.domain, name='lt1', shares_cases=False
        )
        case_sharing = LocationType.objects.create(
            domain=self.domain, name='lt2', shares_cases=True
        )
        location = make_loc('loc-1', 'Loc 1', self.domain, case_sharing.code)
        make_loc('loc-2', 'Loc 2', self.domain, case_sharing.code)
        duplicate_loc = make_loc('loc-3', 'Loc 2', self.domain, case_sharing.code)
        improper_loc = make_loc('loc-4', 'Loc 4', self.domain, non_case_sharing.code)

        res = self.import_mock_file([
            ['case_id', 'name', 'owner_id', 'owner_name'],
            ['', 'location-owner-id', location.group_id, ''],
            ['', 'location-owner-code', '', location.site_code],
            ['', 'location-owner-name', '', location.name],
            ['', 'duplicate-location-name', '', duplicate_loc.name],
            ['', 'non-case-owning-name', '', improper_loc.name],
        ])
        case_ids = self.accessor.get_case_ids_in_domain()
        cases = {c.name: c for c in list(self.accessor.get_cases(case_ids))}

        self.assertEqual(cases['location-owner-id'].owner_id, location.group_id)
        self.assertEqual(cases['location-owner-code'].owner_id, location.group_id)
        self.assertEqual(cases['location-owner-name'].owner_id, location.group_id)

        error_message = ImportErrors.DuplicateLocationName
        error_column_name = None
        self.assertIn(error_message, res['errors'])
        self.assertEqual(res['errors'][error_message][error_column_name]['rows'], [5])

        error_message = ImportErrors.InvalidOwnerId
        self.assertIn(error_message, res['errors'])
        error_column_name = 'owner_id'
        self.assertEqual(res['errors'][error_message][error_column_name]['rows'], [6])

    @run_with_all_backends
    def test_opened_on(self):
        case = self.factory.create_case()
        new_date = '2015-04-30T14:41:53.000000Z'
        with flag_enabled('BULK_UPLOAD_DATE_OPENED'):
            self.import_mock_file([
                ['case_id', 'date_opened'],
                [case.case_id, new_date]
            ])
        case = CaseAccessors(self.domain).get_case(case.case_id)
        self.assertEqual(case.opened_on, PhoneTime(parse_datetime(new_date)).done())

    @run_with_all_backends
    def test_columns_and_rows_align(self):
        case_owner = CommCareUser.create(self.domain, 'username', 'pw')
        res = self.import_mock_file([
            ['case_id', 'name', '', 'favorite_color', 'owner_id'],
            ['', 'Jeff', '', 'blue', case_owner._id],
            ['', 'Caroline', '', 'yellow', case_owner._id],
        ])
        self.assertEqual(res['errors'], {})

        case_ids = self.accessor.get_case_ids_in_domain()
        cases = {c.name: c for c in list(self.accessor.get_cases(case_ids))}
        self.assertEqual(cases['Jeff'].owner_id, case_owner._id)
        self.assertEqual(cases['Jeff'].get_case_property('favorite_color'), 'blue')
        self.assertEqual(cases['Caroline'].owner_id, case_owner._id)
        self.assertEqual(cases['Caroline'].get_case_property('favorite_color'), 'yellow')
Пример #51
0
class ENikshayCaseStructureMixin(object):
    def setUp(self):
        super(ENikshayCaseStructureMixin, self).setUp()
        delete_all_users()
        self.domain = getattr(self, 'domain', 'fake-domain-from-mixin')
        self.factory = CaseFactory(domain=self.domain)
        self.username = "******"
        self.password = "******"
        self.user = CommCareUser.create(
            self.domain,
            username=self.username,
            password=self.password,
            first_name="Jon",
            last_name="Snow",
        )
        self.person_id = u"person"
        self.occurrence_id = u"occurrence"
        self.episode_id = u"episode"
        self.test_id = u"test"
        self.lab_referral_id = u"lab_referral"
        self.prescription_id = "prescription_id"
        self._prescription_created = False
        self.primary_phone_number = "0123456789"
        self.secondary_phone_number = "0999999999"
        self.treatment_supporter_phone = "066000666"
        self.other_number = "0123456666"
        self._episode = None
        self._person = None

    def tearDown(self):
        delete_all_users()
        super(ENikshayCaseStructureMixin, self).tearDown()

    @property
    def person(self):
        if not self._person:
            self._person = get_person_case_structure(
                self.person_id,
                self.user.user_id,
                extra_update={
                    PRIMARY_PHONE_NUMBER: self.primary_phone_number,
                    BACKUP_PHONE_NUMBER: self.secondary_phone_number,
                    ENROLLED_IN_PRIVATE: 'false',
                })
        return self._person

    @property
    def occurrence(self):
        return get_occurrence_case_structure(self.occurrence_id, self.person)

    @property
    def episode(self):
        if not self._episode:
            self._episode = get_episode_case_structure(
                self.episode_id,
                self.occurrence,
                extra_update={
                    OTHER_NUMBER: self.other_number,
                    TREATMENT_SUPPORTER_PHONE: self.treatment_supporter_phone,
                    WEIGHT_BAND: "adult_55-69"
                })
        return self._episode

    def create_case(self, case):
        return self.factory.create_or_update_cases([case])

    def create_case_structure(self):
        return {
            case.case_id: case
            for case in self.factory.create_or_update_cases([self.episode])
        }

    @property
    def test(self):
        return CaseStructure(
            case_id=self.test_id,
            attrs={
                'create':
                True,
                'case_type':
                'test',
                "update":
                dict(
                    date_reported=datetime(2016, 8, 6).date(),
                    lab_serial_number=19,
                    test_type_value="microscopy-zn",
                    purpose_of_testing="diagnostic",
                    result_grade="1plus",
                    testing_facility_id=self.dmc.get_id,
                )
            },
            indices=[
                CaseIndex(
                    self.occurrence,
                    identifier='host',
                    relationship=CASE_INDEX_EXTENSION,
                    related_type=self.occurrence.attrs['case_type'],
                )
            ],
        )

    @property
    def lab_referral(self):
        return CaseStructure(
            case_id=self.lab_referral_id,
            attrs={
                'create': True,
                'case_type': 'lab_referral',
                'owner_id': self.dmc.get_id,
                "update": {}
            },
            indices=[
                CaseIndex(
                    self.test,
                    identifier='host',
                    relationship=CASE_INDEX_EXTENSION,
                    related_type=self.test.attrs['case_type'],
                )
            ],
        )

    def create_adherence_cases(self,
                               adherence_dates,
                               adherence_source='99DOTS'):
        return self.factory.create_or_update_cases([
            get_adherence_case_structure(
                adherence_date.strftime('%Y-%m-%d-%H-%M'),
                self.episode_id,
                adherence_date,
                extra_update={
                    "name": adherence_date,
                    "adherence_source": adherence_source,
                    "adherence_value": "unobserved_dose",
                }) for adherence_date in adherence_dates
        ])

    def create_adherence_case(self,
                              adherence_date,
                              adherence_source="99DOTS",
                              adherence_value="unobserved_dose",
                              case_id=None):
        return self.factory.create_or_update_cases([
            get_adherence_case_structure(case_id,
                                         self.episode_id,
                                         adherence_date,
                                         extra_update={
                                             "adherence_source":
                                             adherence_source,
                                             "adherence_value":
                                             adherence_value,
                                         })
        ])

    def create_prescription_case(self, extra_update=None):
        return self.factory.create_or_update_case(
            get_prescription_case_structure(uuid.uuid4().hex, self.episode_id,
                                            extra_update))[0]

    def create_voucher_case(self, prescription_id, extra_update=None):
        return self.factory.create_or_update_case(
            get_voucher_case_structure(uuid.uuid4().hex, prescription_id,
                                       extra_update))[0]

    def create_referral_case(self, case_id):
        return self.factory.create_or_update_cases(
            [get_referral_case_structure(case_id, self.person_id)])

    @nottest
    def create_test_case(self, occurrence_id, extra_update=None):
        return self.factory.create_or_update_case(
            get_test_case_structure(uuid.uuid4().hex, occurrence_id,
                                    extra_update))[0]
Пример #52
0
class ImporterTest(TestCase):
    def setUp(self):
        super(ImporterTest, self).setUp()
        self.domain_obj = create_domain("importer-test")
        self.domain = self.domain_obj.name
        self.default_case_type = 'importer-test-casetype'

        self.couch_user = WebUser.create(None, "test", "foobar", None, None)
        self.couch_user.add_domain_membership(self.domain, is_admin=True)
        self.couch_user.save()

        self.accessor = CaseAccessors(self.domain)

        self.factory = CaseFactory(domain=self.domain,
                                   case_defaults={
                                       'case_type': self.default_case_type,
                                   })
        delete_all_cases()

    def tearDown(self):
        self.couch_user.delete()
        self.domain_obj.delete()
        super(ImporterTest, self).tearDown()

    def _config(self,
                col_names,
                search_column=None,
                case_type=None,
                search_field='case_id',
                create_new_cases=True):
        return ImporterConfig(
            couch_user_id=self.couch_user._id,
            case_type=case_type or self.default_case_type,
            excel_fields=col_names,
            case_fields=[''] * len(col_names),
            custom_fields=col_names,
            search_column=search_column or col_names[0],
            search_field=search_field,
            create_new_cases=create_new_cases,
        )

    @run_with_all_backends
    @patch('corehq.apps.case_importer.tasks.bulk_import_async.update_state')
    def testImportFileMissing(self, update_state):
        # by using a made up upload_id, we ensure it's not referencing any real file
        case_upload = CaseUploadRecord(upload_id=str(uuid.uuid4()),
                                       task_id=str(uuid.uuid4()))
        case_upload.save()
        res = bulk_import_async.delay(self._config(['anything']), self.domain,
                                      case_upload.upload_id)
        self.assertIsInstance(res.result, Ignore)
        update_state.assert_called_with(
            state=states.FAILURE,
            meta=get_interned_exception(
                'Sorry, your session has expired. Please start over and try again.'
            ))
        self.assertEqual(0, len(get_case_ids_in_domain(self.domain)))

    @run_with_all_backends
    def testImportBasic(self):
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
            ['case_id-4', 'age-4', 'sex-4', 'location-4'],
        )
        res = do_import(file, config, self.domain)
        self.assertEqual(5, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertFalse(res['errors'])
        self.assertEqual(1, res['num_chunks'])
        case_ids = self.accessor.get_case_ids_in_domain()
        cases = list(self.accessor.get_cases(case_ids))
        self.assertEqual(5, len(cases))
        properties_seen = set()
        for case in cases:
            self.assertEqual(self.couch_user._id, case.user_id)
            self.assertEqual(self.couch_user._id, case.owner_id)
            self.assertEqual(self.default_case_type, case.type)
            for prop in ['age', 'sex', 'location']:
                self.assertTrue(prop in case.get_case_property(prop))
                self.assertFalse(
                    case.get_case_property(prop) in properties_seen)
                properties_seen.add(case.get_case_property(prop))

    @run_with_all_backends
    def testImportNamedColumns(self):
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
        )
        res = do_import(file, config, self.domain)

        self.assertEqual(4, res['created_count'])
        self.assertEqual(4, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def testImportTrailingWhitespace(self):
        cols = ['case_id', 'age', 'sex\xa0', 'location']
        config = self._config(cols)
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex\xa0', 'location'],
            ['case_id-0', 'age-0', 'sex\xa0-0', 'location-0'],
        )
        res = do_import(file, config, self.domain)

        self.assertEqual(1, res['created_count'])
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        case = self.accessor.get_case(case_ids[0])
        self.assertTrue(bool(case.get_case_property(
            'sex')))  # make sure the value also got properly set

    @run_with_all_backends
    def testCaseIdMatching(self):
        # bootstrap a stub case
        [case] = self.factory.create_or_update_case(
            CaseStructure(attrs={
                'create': True,
                'update': {
                    'importer_test_prop': 'foo'
                },
            }))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [case.case_id, 'age-0', 'sex-0', 'location-0'],
            [case.case_id, 'age-1', 'sex-1', 'location-1'],
            [case.case_id, 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)
        self.assertEqual(0, res['created_count'])
        self.assertEqual(3, res['match_count'])
        self.assertFalse(res['errors'])

        # shouldn't create any more cases, just the one
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        [case] = self.accessor.get_cases(case_ids)
        for prop in ['age', 'sex', 'location']:
            self.assertTrue(prop in case.get_case_property(prop))

        # shouldn't touch existing properties
        self.assertEqual('foo', case.get_case_property('importer_test_prop'))

    @run_with_all_backends
    def testCaseLookupTypeCheck(self):
        [case] = self.factory.create_or_update_case(
            CaseStructure(attrs={
                'create': True,
                'case_type': 'nonmatch-type',
            }))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [case.case_id, 'age-0', 'sex-0', 'location-0'],
            [case.case_id, 'age-1', 'sex-1', 'location-1'],
            [case.case_id, 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)
        # because the type is wrong these shouldn't match
        self.assertEqual(3, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(4, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def testCaseLookupDomainCheck(self):
        self.factory.domain = 'wrong-domain'
        [case] = self.factory.create_or_update_case(
            CaseStructure(attrs={
                'create': True,
            }))
        self.assertEqual(0, len(self.accessor.get_case_ids_in_domain()))
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [case.case_id, 'age-0', 'sex-0', 'location-0'],
            [case.case_id, 'age-1', 'sex-1', 'location-1'],
            [case.case_id, 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)

        # because the domain is wrong these shouldn't match
        self.assertEqual(3, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(3, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def testExternalIdMatching(self):
        # bootstrap a stub case
        external_id = 'importer-test-external-id'
        [case] = self.factory.create_or_update_case(
            CaseStructure(attrs={
                'create': True,
                'external_id': external_id,
            }))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

        headers = ['external_id', 'age', 'sex', 'location']
        config = self._config(headers, search_field='external_id')
        file = make_worksheet_wrapper(
            ['external_id', 'age', 'sex', 'location'],
            ['importer-test-external-id', 'age-0', 'sex-0', 'location-0'],
            ['importer-test-external-id', 'age-1', 'sex-1', 'location-1'],
            ['importer-test-external-id', 'age-2', 'sex-2', 'location-2'],
        )
        res = do_import(file, config, self.domain)
        self.assertEqual(0, res['created_count'])
        self.assertEqual(3, res['match_count'])
        self.assertFalse(res['errors'])

        # shouldn't create any more cases, just the one
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

    @run_with_all_backends
    def test_external_id_matching_on_create_with_custom_column_name(self):
        headers = ['id_column', 'age', 'sex', 'location']
        external_id = 'external-id-test'
        config = self._config(headers[1:],
                              search_column='id_column',
                              search_field='external_id')
        file = make_worksheet_wrapper(
            ['id_column', 'age', 'sex', 'location'],
            ['external-id-test', 'age-0', 'sex-0', 'location-0'],
            ['external-id-test', 'age-1', 'sex-1', 'location-1'],
        )

        res = do_import(file, config, self.domain)
        self.assertFalse(res['errors'])
        self.assertEqual(1, res['created_count'])
        self.assertEqual(1, res['match_count'])
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        case = self.accessor.get_case(case_ids[0])
        self.assertEqual(external_id, case.external_id)

    def testNoCreateNew(self):
        config = self._config(['case_id', 'age', 'sex', 'location'],
                              create_new_cases=False)
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
            ['case_id-4', 'age-4', 'sex-4', 'location-4'],
        )
        res = do_import(file, config, self.domain)

        # no matching and no create new set - should do nothing
        self.assertEqual(0, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(0, len(get_case_ids_in_domain(self.domain)))

    def testBlankRows(self):
        # don't create new cases for rows left blank
        config = self._config(['case_id', 'age', 'sex', 'location'],
                              create_new_cases=True)
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            [None, None, None, None],
            ['', '', '', ''],
        )
        res = do_import(file, config, self.domain)

        # no matching and no create new set - should do nothing
        self.assertEqual(0, res['created_count'])
        self.assertEqual(0, res['match_count'])
        self.assertEqual(0, len(get_case_ids_in_domain(self.domain)))

    @patch('corehq.apps.case_importer.do_import.CASEBLOCK_CHUNKSIZE', 2)
    def testBasicChunking(self):
        config = self._config(['case_id', 'age', 'sex', 'location'])
        file = make_worksheet_wrapper(
            ['case_id', 'age', 'sex', 'location'],
            ['case_id-0', 'age-0', 'sex-0', 'location-0'],
            ['case_id-1', 'age-1', 'sex-1', 'location-1'],
            ['case_id-2', 'age-2', 'sex-2', 'location-2'],
            ['case_id-3', 'age-3', 'sex-3', 'location-3'],
            ['case_id-4', 'age-4', 'sex-4', 'location-4'],
        )
        res = do_import(file, config, self.domain)
        # 5 cases in chunks of 2 = 3 chunks
        self.assertEqual(3, res['num_chunks'])
        self.assertEqual(5, res['created_count'])
        self.assertEqual(5, len(get_case_ids_in_domain(self.domain)))

    @run_with_all_backends
    def testExternalIdChunking(self):
        # bootstrap a stub case
        external_id = 'importer-test-external-id'

        headers = ['external_id', 'age', 'sex', 'location']
        config = self._config(headers, search_field='external_id')
        file = make_worksheet_wrapper(
            ['external_id', 'age', 'sex', 'location'],
            ['importer-test-external-id', 'age-0', 'sex-0', 'location-0'],
            ['importer-test-external-id', 'age-1', 'sex-1', 'location-1'],
            ['importer-test-external-id', 'age-2', 'sex-2', 'location-2'],
        )

        # the first one should create the case, and the remaining two should update it
        res = do_import(file, config, self.domain)
        self.assertEqual(1, res['created_count'])
        self.assertEqual(2, res['match_count'])
        self.assertFalse(res['errors'])
        self.assertEqual(2,
                         res['num_chunks'])  # the lookup causes an extra chunk

        # should just create the one case
        case_ids = self.accessor.get_case_ids_in_domain()
        self.assertEqual(1, len(case_ids))
        [case] = self.accessor.get_cases(case_ids)
        self.assertEqual(external_id, case.external_id)
        for prop in ['age', 'sex', 'location']:
            self.assertTrue(prop in case.get_case_property(prop))

    @run_with_all_backends
    def testParentCase(self):
        headers = ['parent_id', 'name', 'case_id']
        config = self._config(headers,
                              create_new_cases=True,
                              search_column='case_id')
        rows = 3
        [parent_case] = self.factory.create_or_update_case(
            CaseStructure(attrs={'create': True}))
        self.assertEqual(1, len(self.accessor.get_case_ids_in_domain()))

        file = make_worksheet_wrapper(
            ['parent_id', 'name', 'case_id'],
            [parent_case.case_id, 'name-0', 'case_id-0'],
            [parent_case.case_id, 'name-1', 'case_id-1'],
            [parent_case.case_id, 'name-2', 'case_id-2'],
        )
        file_missing = make_worksheet_wrapper(
            ['parent_id', 'name', 'case_id'],
            ['parent_id-0', 'name-0', 'case_id-0'],
            ['parent_id-1', 'name-1', 'case_id-1'],
            ['parent_id-2', 'name-2', 'case_id-2'],
        )

        # Should successfully match on `rows` cases
        res = do_import(file, config, self.domain)
        self.assertEqual(rows, res['created_count'])

        # Should be unable to find parent case on `rows` cases
        res = do_import(file_missing, config, self.domain)
        error_column_name = 'parent_id'
        self.assertEqual(
            rows,
            len(res['errors'][exceptions.InvalidParentId.title]
                [error_column_name]['rows']),
            "All cases should have missing parent")

    def import_mock_file(self, rows):
        config = self._config(rows[0])
        xls_file = make_worksheet_wrapper(*rows)
        return do_import(xls_file, config, self.domain)

    @run_with_all_backends
    def testLocationOwner(self):
        # This is actually testing several different things, but I figure it's
        # worth it, as each of these tests takes a non-trivial amount of time.
        non_case_sharing = LocationType.objects.create(domain=self.domain,
                                                       name='lt1',
                                                       shares_cases=False)
        case_sharing = LocationType.objects.create(domain=self.domain,
                                                   name='lt2',
                                                   shares_cases=True)
        location = make_loc('loc-1', 'Loc 1', self.domain, case_sharing.code)
        make_loc('loc-2', 'Loc 2', self.domain, case_sharing.code)
        duplicate_loc = make_loc('loc-3', 'Loc 2', self.domain,
                                 case_sharing.code)
        improper_loc = make_loc('loc-4', 'Loc 4', self.domain,
                                non_case_sharing.code)

        res = self.import_mock_file([
            ['case_id', 'name', 'owner_id', 'owner_name'],
            ['', 'location-owner-id', location.group_id, ''],
            ['', 'location-owner-code', '', location.site_code],
            ['', 'location-owner-name', '', location.name],
            ['', 'duplicate-location-name', '', duplicate_loc.name],
            ['', 'non-case-owning-name', '', improper_loc.name],
        ])
        case_ids = self.accessor.get_case_ids_in_domain()
        cases = {c.name: c for c in list(self.accessor.get_cases(case_ids))}

        self.assertEqual(cases['location-owner-id'].owner_id,
                         location.group_id)
        self.assertEqual(cases['location-owner-code'].owner_id,
                         location.group_id)
        self.assertEqual(cases['location-owner-name'].owner_id,
                         location.group_id)

        error_message = exceptions.DuplicateLocationName.title
        error_column_name = None
        self.assertIn(error_message, res['errors'])
        self.assertEqual(
            res['errors'][error_message][error_column_name]['rows'], [5])

        error_message = exceptions.InvalidOwner.title
        self.assertIn(error_message, res['errors'])
        error_column_name = 'owner_name'
        self.assertEqual(
            res['errors'][error_message][error_column_name]['rows'], [6])

    @run_with_all_backends
    def test_opened_on(self):
        case = self.factory.create_case()
        new_date = '2015-04-30T14:41:53.000000Z'
        with flag_enabled('BULK_UPLOAD_DATE_OPENED'):
            self.import_mock_file([['case_id', 'date_opened'],
                                   [case.case_id, new_date]])
        case = CaseAccessors(self.domain).get_case(case.case_id)
        self.assertEqual(case.opened_on,
                         PhoneTime(parse_datetime(new_date)).done())
Пример #53
0
class OwnerCleanlinessTest(SyncBaseTest):

    def setUp(self):
        super(OwnerCleanlinessTest, self).setUp()
        # ensure that randomization is on
        OWNERSHIP_CLEANLINESS.randomness = 1
        self.owner_id = uuid.uuid4().hex
        self.synclog_id = uuid.uuid4().hex
        self.domain = uuid.uuid4().hex
        self.factory = CaseFactory(
            domain=self.domain,
            case_defaults={
                'create': True,
                'owner_id': self.owner_id,
                'user_id': self.owner_id,
            }
        )
        self.assert_owner_clean()  # this first call creates the OwnershipCleanliness doc
        self.sample_case = self.factory.create_case()
        self.child, self.parent = self.factory.create_or_update_case(
            CaseStructure(
                relationships=[
                    CaseRelationship(),
                ]
            )
        )
        self.assert_owner_clean()  # this is an actual assertion

    def _verify_set_cleanliness_flags(self):
        """
        Can be run at the end of any relevant test to check the current state of the
        OwnershipCleanliness object and verify that rebuilding it from scratch produces
        the same result
        """
        is_clean = self.owner_cleanliness.is_clean
        hint = self.owner_cleanliness.hint
        self.owner_cleanliness.delete()
        set_cleanliness_flags(self.domain, self.owner_id, force_full=True)
        new_cleanliness = OwnershipCleanlinessFlag.objects.get(owner_id=self.owner_id)
        self.assertEqual(is_clean, new_cleanliness.is_clean)
        self.assertEqual(hint, new_cleanliness.hint)
        if hint:
            self.assertTrue(hint_still_valid(self.domain, self.owner_id, hint))

    @property
    def owner_cleanliness(self):
        return OwnershipCleanlinessFlag.objects.get_or_create(
            owner_id=self.owner_id,
            domain=self.domain,
            defaults={'is_clean': True}
        )[0]

    def assert_owner_clean(self):
        return self.assertTrue(self.owner_cleanliness.is_clean)

    def assert_owner_dirty(self):
        return self.assertFalse(self.owner_cleanliness.is_clean)

    def _set_owner(self, case_id, owner_id):
        case = self.factory.create_or_update_case(
            CaseStructure(case_id=case_id, attrs={'create': False, 'owner_id': owner_id})
        )[0]
        self.assertEqual(owner_id, case.owner_id)

    def test_add_normal_case_stays_clean(self):
        # change the owner ID of a normal case, should remain clean
        self.factory.create_case()
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    def test_change_owner_stays_clean(self):
        # change the owner ID of a normal case, should remain clean
        new_owner = uuid.uuid4().hex
        self._set_owner(self.sample_case._id, new_owner)
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    def test_change_owner_child_case_stays_clean(self):
        # change the owner ID of a child case, should remain clean
        new_owner = uuid.uuid4().hex
        self._set_owner(self.child._id, new_owner)
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    def test_add_clean_parent_stays_clean(self):
        # add a parent with the same owner, should remain clean
        self.factory.create_or_update_case(CaseStructure(relationships=[CaseRelationship()]))
        self.assert_owner_clean()
        self._verify_set_cleanliness_flags()

    def test_create_dirty_makes_dirty(self):
        # create a case and a parent case with a different owner at the same time
        # make sure the owner becomes dirty.
        new_owner = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(
            CaseStructure(
                relationships=[
                    CaseRelationship(CaseStructure(attrs={'owner_id': new_owner}))
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertEqual(child._id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()

    def test_add_dirty_parent_makes_dirty(self):
        # add parent with a different owner and make sure the owner becomes dirty
        new_owner = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(
            CaseStructure(
                case_id=self.sample_case._id,
                relationships=[
                    CaseRelationship(CaseStructure(attrs={'owner_id': new_owner}))
                ]
            )
        )
        self.assert_owner_dirty()
        self.assertEqual(child._id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()

    def test_change_parent_owner_makes_dirty(self):
        # change the owner id of a parent case and make sure the owner becomes dirty
        new_owner = uuid.uuid4().hex
        self._set_owner(self.parent._id, new_owner)
        self.assert_owner_dirty()
        self.assertEqual(self.child._id, self.owner_cleanliness.hint)
        self._verify_set_cleanliness_flags()

    def test_toggle(self):
        # make sure the flag gets removed
        OWNERSHIP_CLEANLINESS.randomness = 0
        # and any test that normally expects a flag to be set to fail
        with self.assertRaises(AssertionError):
            self.test_create_dirty_makes_dirty()

    def test_set_flag_clean_no_data(self):
        unused_owner_id = uuid.uuid4().hex
        set_cleanliness_flags(self.domain, unused_owner_id)
        self.assertTrue(OwnershipCleanlinessFlag.objects.get(owner_id=unused_owner_id).is_clean)

    def test_hint_invalidation(self):
        self.test_change_parent_owner_makes_dirty()
        self._set_owner(self.parent._id, self.owner_id)
        # after the submission the dirtiness flag should still be set
        # since it isn't invalidated right away
        self.assert_owner_dirty()
        # explicitly make sure the hint is no longer valid
        self.assertFalse(hint_still_valid(self.domain, self.owner_id, self.owner_cleanliness.hint))
        # reset the cleanliness flag and ensure it worked
        set_cleanliness_flags(self.domain, self.owner_id)
        self.assert_owner_clean()
        self.assertEqual(None, self.owner_cleanliness.hint)

    def test_cross_domain_on_submission(self):
        # create a form that makes a dirty owner with the same ID but in a different domain
        # make sure the original owner stays clean
        new_domain = uuid.uuid4().hex
        # initialize the new cleanliness flag
        OwnershipCleanlinessFlag.objects.create(domain=new_domain, owner_id=self.owner_id, is_clean=True)
        self.factory.domain = new_domain
        self.factory.create_or_update_case(
            CaseStructure(
                relationships=[
                    CaseRelationship(CaseStructure(attrs={'owner_id': uuid.uuid4().hex}))
                ]
            )
        )
        self.assert_owner_clean()
        self.assertEqual(
            False,
            OwnershipCleanlinessFlag.objects.get(owner_id=self.owner_id, domain=new_domain).is_clean,
        )

    def test_cross_domain_both_clean(self):
        new_domain = uuid.uuid4().hex
        self.factory.domain = new_domain
        self.factory.create_or_update_case(
            CaseStructure(
                relationships=[
                    CaseRelationship(),
                ]
            )
        )
        # two clean ownership models in different domains should report clean
        self.assertTrue(get_cleanliness_flag_from_scratch(self.domain, self.owner_id).is_clean)
        self.assertTrue(get_cleanliness_flag_from_scratch(new_domain, self.owner_id).is_clean)

    def test_cross_domain_dirty(self):
        new_domain = uuid.uuid4().hex
        new_owner = uuid.uuid4().hex
        self.factory.domain = new_domain
        self.factory.create_or_update_case(
            CaseStructure(
                relationships=[
                    CaseRelationship(CaseStructure(attrs={'owner_id': new_owner})),
                ]
            )
        )
        # original domain should stay clean but the new one should be dirty
        self.assertTrue(get_cleanliness_flag_from_scratch(self.domain, self.owner_id).is_clean)
        self.assertFalse(get_cleanliness_flag_from_scratch(new_domain, self.owner_id).is_clean)

    @override_settings(TESTS_SHOULD_TRACK_CLEANLINESS=False)
    def test_autocreate_flag_off(self):
        new_owner = uuid.uuid4().hex
        self.factory.create_or_update_case(
            CaseStructure(case_id=uuid.uuid4().hex, attrs={'create': True, 'owner_id': new_owner})
        )[0]
        self.assertFalse(OwnershipCleanlinessFlag.objects.filter(domain=self.domain, owner_id=new_owner).exists())

    @override_settings(TESTS_SHOULD_TRACK_CLEANLINESS=True)
    def test_autocreate_flag_on(self):
        new_owner = uuid.uuid4().hex
        self.factory.create_or_update_case(
            CaseStructure(case_id=uuid.uuid4().hex, attrs={'create': True, 'owner_id': new_owner})
        )[0]
        flag = OwnershipCleanlinessFlag.objects.get(domain=self.domain, owner_id=new_owner)
        self.assertEqual(True, flag.is_clean)
Пример #54
0
class TestExtensionCaseIds(TestCase):

    @classmethod
    def setUpClass(cls):
        delete_all_cases()

    def setUp(self):
        self.domain = 'domain'
        self.factory = CaseFactory(self.domain)

    def test_no_extensions(self):
        """ Returns empty when there are other index types """
        parent_id = uuid.uuid4().hex
        child_id = uuid.uuid4().hex
        parent = CaseStructure(case_id=parent_id)

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=child_id,
                indices=[
                    CaseIndex(parent, relationship=CASE_INDEX_CHILD)
                ]
            )
        )
        returned_cases = get_extension_case_ids(self.domain, [parent_id])
        self.assertEqual(returned_cases, [])

    def test_simple_extension_returned(self):
        """ Should return extension if it exists """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id)

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION)
                ]
            )
        )
        returned_cases = get_extension_case_ids(self.domain, [host_id])
        self.assertItemsEqual(returned_cases, [extension_id])

    def test_extension_of_multiple_hosts_returned(self):
        """ Should return an extension from any host if there are multiple indices """
        host_id = uuid.uuid4().hex
        host_2_id = uuid.uuid4().hex
        parent_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        host = CaseStructure(case_id=host_id)
        host_2 = CaseStructure(case_id=host_2_id)
        parent = CaseStructure(case_id=parent_id)

        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                    CaseIndex(host_2, relationship=CASE_INDEX_EXTENSION, identifier="host_2"),
                    CaseIndex(parent, relationship=CASE_INDEX_CHILD),
                ]
            )
        )

        returned_cases = get_extension_case_ids(self.domain, [host_2_id])
        self.assertItemsEqual(returned_cases, [extension_id])
        returned_cases = get_extension_case_ids(self.domain, [host_id])
        self.assertItemsEqual(returned_cases, [extension_id])

    def test_host_with_multiple_extensions(self):
        """ Return all extensions from a single host """
        host_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        extension_2_id = uuid.uuid4().hex

        host = CaseStructure(case_id=host_id)

        self.factory.create_or_update_cases([
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ]
            ),
            CaseStructure(
                case_id=extension_2_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ]
            ),
        ]
        )

        returned_cases = get_extension_case_ids(self.domain, [host_id])
        self.assertItemsEqual(returned_cases, [extension_id, extension_2_id])

    def test_extensions_from_list(self):
        """ Given a list of hosts, should return all extensions """
        host_id = uuid.uuid4().hex
        host_2_id = uuid.uuid4().hex
        extension_id = uuid.uuid4().hex
        extension_2_id = uuid.uuid4().hex

        host = CaseStructure(case_id=host_id)
        host_2 = CaseStructure(case_id=host_2_id)
        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_id,
                indices=[
                    CaseIndex(host, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ]
            )
        )
        self.factory.create_or_update_case(
            CaseStructure(
                case_id=extension_2_id,
                indices=[
                    CaseIndex(host_2, relationship=CASE_INDEX_EXTENSION, identifier="host"),
                ]
            )
        )
        returned_cases = get_extension_case_ids(self.domain, [host_id, host_2_id])
        self.assertItemsEqual(returned_cases, [extension_id, extension_2_id])
Пример #55
0
class OwnerCleanlinessTest(DeprecatedBaseSyncTest):

    def setUp(self):
        super(OwnerCleanlinessTest, self).setUp()
        self.owner_id = uuid.uuid4().hex
        self.synclog_id = uuid.uuid4().hex
        self.domain = uuid.uuid4().hex
        self.factory = CaseFactory(
            domain=self.domain,
            case_defaults={
                'create': True,
                'owner_id': self.owner_id,
                'user_id': self.owner_id,
            }
        )
        self.assert_owner_clean()  # this first call creates the OwnershipCleanliness doc
        self.sample_case = self.factory.create_case()
        self.child, self.parent = self.factory.create_or_update_case(
            CaseStructure(
                indices=[
                    CaseIndex(),
                ]
            )
        )
        self.extension, self.host = self.factory.create_or_update_case(
            CaseStructure(
                attrs={'owner_id': UNOWNED_EXTENSION_OWNER_ID},
                indices=[
                    CaseIndex(
                        relationship=CASE_INDEX_EXTENSION
                    ),
                ]
            )
        )
        self.assert_owner_clean()  # this is an actual assertion

    def _verify_set_cleanliness_flags(self, owner_id=None):
        """
        Can be run at the end of any relevant test to check the current state of the
        OwnershipCleanliness object and verify that rebuilding it from scratch produces
        the same result
        """
        if owner_id is None:
            owner_id = self.owner_id
        owner_cleanliness = self._owner_cleanliness_for_id(owner_id)
        is_clean = owner_cleanliness.is_clean
        hint = owner_cleanliness.hint
        owner_cleanliness.delete()
        set_cleanliness_flags(self.domain, owner_id, force_full=True)
        new_cleanliness = OwnershipCleanlinessFlag.objects.get(owner_id=owner_id)
        self.assertEqual(is_clean, new_cleanliness.is_clean)
        self.assertEqual(hint, new_cleanliness.hint)
        if hint:
            self.assertTrue(hint_still_valid(self.domain, hint))

    @property
    def owner_cleanliness(self):
        return self._owner_cleanliness_for_id(self.owner_id)

    def _owner_cleanliness_for_id(self, owner_id):
        return OwnershipCleanlinessFlag.objects.get_or_create(
            owner_id=owner_id,
            domain=self.domain,
            defaults={'is_clean': True}
        )[0]

    def assert_owner_clean(self):
        self.assertTrue(self.owner_cleanliness.is_clean)

    def assert_owner_dirty(self):
        self.assertFalse(self.owner_cleanliness.is_clean)

    def assert_owner_temporarily_dirty(self):
        """
        Changing any case's owner makes the previous owner ID temporarily dirty, to allow
        syncs to happen, but the should become clean on a rebuild.

        This checks that workflow and rebuilds the cleanliness flag.
        """
        self.assertFalse(self.owner_cleanliness.is_clean)
        set_cleanliness_flags(self.domain, self.owner_id, force_full=True)
        self.assertTrue(self.owner_cleanliness.is_clean)

    def _set_owner(self, case_id, owner_id):
        case = self.factory.create_or_update_case(
            CaseStructure(case_id=case_id, attrs={'create': False, 'owner_id': owner_id})
        )[0]
        self.assertEqual(owner_id, case.owner_id)
    def handle(self, commit, domain, log_path, **options):
        commit = commit
        factory = CaseFactory(domain)
        headers = [
            'case_id',
            'testing_facility_id',
            'datamigration_testing_facility_id',
        ]

        print("Starting {} migration on {} at {}".format(
            "real" if commit else "fake", domain, datetime.datetime.utcnow()))

        case_ids = [
            hit['_id'] for hit in (CaseSearchES().domain(
                domain).case_type("test").case_property_query(
                    "result_recorded", "yes", "must").run().hits)
        ]

        failed_tests = []

        with open(log_path, "w") as log_file:
            writer = csv.writer(log_file)
            writer.writerow(headers)

            for test in CaseAccessors(domain=domain).iter_cases(case_ids):
                try:
                    if test.get_case_property('datamigration_testing_facility_id') != 'yes' \
                            and not test.get_case_property('testing_facility_id'):

                        form_data = self._get_result_recorded_form(test)
                        microscopy_id = self._get_path([
                            'update_test_result', 'microscopy',
                            'ql_testing_facility_details', 'default_dmc_id'
                        ], form_data)
                        cbnaat_id = self._get_path([
                            'update_test_result', 'cbnaat',
                            'ql_testing_facility_details', 'default_cdst_id'
                        ], form_data)
                        testing_facility_id = microscopy_id or cbnaat_id

                        if testing_facility_id:
                            writer.writerow(
                                [test.case_id, testing_facility_id, "yes"])
                            print('Updating {}...'.format(test.case_id))
                            case_structure = CaseStructure(
                                case_id=test.case_id,
                                walk_related=False,
                                attrs={
                                    "create": False,
                                    "update": {
                                        "datamigration_testing_facility_id":
                                        "yes",
                                        "testing_facility_id":
                                        testing_facility_id,
                                    },
                                },
                            )
                            if commit:
                                factory.create_or_update_case(case_structure)
                        else:
                            writer.writerow(
                                [test.case_id, testing_facility_id, "no"])
                except:
                    failed_tests.append(test.case_id)
        print("Migration finished at {}".format(datetime.datetime.utcnow()))
        print("Failed tests: {}".format(failed_tests))
Пример #57
0
class IndexedCaseExpressionTest(TestCase):
    def setUp(self):
        super(IndexedCaseExpressionTest, self).setUp()
        self.domain = uuid.uuid4().hex
        self.factory = CaseFactory(domain=self.domain)
        self.context = EvaluationContext({"domain": self.domain})

    def tearDown(self):
        delete_all_xforms()
        delete_all_cases()
        super(IndexedCaseExpressionTest, self).tearDown()

    def test_parent_case_no_index(self):
        parent_id = uuid.uuid4().hex
        child_id = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(CaseStructure(
            case_id=child_id,
            indices=[
                CaseIndex(CaseStructure(case_id=parent_id, attrs={'create': True}))
            ],
            attrs={'create': True}
        ))
        spec = {
            'type': 'nested',
            'argument_expression': {
                'type': 'indexed_case',
                'case_expression': {
                    'type': 'identity'
                }
            },
            'value_expression': {
                'type': 'property_name',
                'property_name': '_id'
            }
        }
        self.assertEqual(
            ExpressionFactory.from_spec(spec)(child.to_json(), self.context),
            parent_id
        )

    def test_named_index(self):
        parent_id = uuid.uuid4().hex
        child_id = uuid.uuid4().hex
        [child, parent] = self.factory.create_or_update_case(CaseStructure(
            case_id=child_id,
            indices=[
                CaseIndex(CaseStructure(case_id=parent_id, attrs={'create': True}),
                          identifier='mother')
            ],
            attrs={'create': True}
        ))
        spec = {
            'type': 'nested',
            'argument_expression': {
                'type': 'indexed_case',
                'case_expression': {
                    'type': 'identity'
                },
                'index': 'mother'
            },
            'value_expression': {
                'type': 'property_name',
                'property_name': '_id'
            }
        }
        self.assertEqual(
            ExpressionFactory.from_spec(spec)(child.to_json(), self.context),
            parent_id
        )

    def test_multiple_indexes(self):
        parent_id1 = uuid.uuid4().hex
        parent_id2 = uuid.uuid4().hex
        child_id = uuid.uuid4().hex
        [child, parent1, parent2] = self.factory.create_or_update_case(CaseStructure(
            case_id=child_id,
            indices=[
                CaseIndex(CaseStructure(case_id=parent_id1, attrs={'create': True}),
                          identifier='parent1'),
                CaseIndex(CaseStructure(case_id=parent_id2, attrs={'create': True}),
                          identifier='parent2')
            ],
            attrs={'create': True}
        ))
        spec = {
            'type': 'nested',
            'argument_expression': {
                'type': 'indexed_case',
                'case_expression': {
                    'type': 'identity'
                },
                'index': 'parent1'
            },
            'value_expression': {
                'type': 'property_name',
                'property_name': '_id'
            }
        }
        self.assertEqual(
            ExpressionFactory.from_spec(spec)(child.to_json(), self.context),
            parent_id1
        )

        spec['argument_expression']['index'] = 'parent2'
        self.assertEqual(
            ExpressionFactory.from_spec(spec)(child.to_json(), self.context),
            parent_id2
        )

    def test_grandparent_index(self):
        household_id = uuid.uuid4().hex
        parent_id = uuid.uuid4().hex
        child_id = uuid.uuid4().hex

        parent_case_structure = CaseStructure(
            case_id=parent_id,
            indices=[
                CaseIndex(CaseStructure(case_id=household_id, attrs={'create': True}),
                          identifier='household')
            ],
            attrs={'create': True}
        )
        [child, parent, household] = self.factory.create_or_update_case(CaseStructure(
            case_id=child_id,
            indices=[CaseIndex(parent_case_structure)],
            attrs={'create': True}
        ))

        spec = {
            'type': 'nested',
            'argument_expression': {
                'type': 'indexed_case',
                'case_expression': {
                    'type': 'indexed_case',
                    'case_expression': {
                        'type': 'identity'
                    },
                    'index': 'parent'
                },
                'index': 'household',
            },
            'value_expression': {
                'type': 'property_name',
                'property_name': '_id'
            }
        }
        self.assertEqual(
            ExpressionFactory.from_spec(spec)(child.to_json(), self.context),
            household_id
        )
Пример #58
0
    def handle(self, commit, domain, log_path, **options):
        commit = commit
        factory = CaseFactory(domain)
        headers = [
            'case_id',
            'current_treatment_initiated',
            'current_treatment_status',
            'current_diagnosing_facility_id',
            'current_treatment_initiating_facility_id',
            'updated_treatment_initiated',
            'updated_treatment_status',
            'datamigration_treatment_status_fix',
        ]

        print("Starting {} migration on {} at {}".format(
            "real" if commit else "fake", domain, datetime.datetime.utcnow()
        ))

        case_ids = [
            hit['_id'] for hit in (CaseSearchES()
                                   .domain(domain)
                                   .case_type("episode")
                                   .case_property_query("episode_type", "confirmed_tb", "must")
                                   .run().hits)
        ]

        with open(log_path, "w") as log_file:
            writer = csv.writer(log_file)
            writer.writerow(headers)

            for episode in CaseAccessors(domain=domain).iter_cases(case_ids):
                if episode.get_case_property('datamigration_treatment_status_fix') != 'yes' \
                        and not episode.get_case_property('diagnosing_facility_id') \
                        and not episode.get_case_property('treatment_initiating_facility_id'):

                    current_treatment_initiated = episode.get_case_property('treatment_initiated')
                    current_treatment_status = episode.get_case_property('treatment_status')
                    current_diagnosing_facility_id = episode.get_case_property('diagnosing_facility_id')
                    current_treatment_initiating_facility_id = \
                        episode.get_case_property('treatment_initiating_facility_id')

                    if current_treatment_status == "initiated_outside_rntcp" \
                            or current_treatment_initiated == "yes_private":
                        # this should ideally not need a migration but checking anyway
                        treatment_initiated = "yes_private"
                        treatment_status = "initiated_outside_rntcp"
                    elif current_diagnosing_facility_id == current_treatment_initiating_facility_id:
                        treatment_initiated = "yes_phi"
                        treatment_status = "initiated_first_line_treatment"
                    else:
                        treatment_initiated = "yes_phi"
                        treatment_status = "initiated_outside_facility"

                    if treatment_initiated == current_treatment_initiated \
                            and treatment_status == current_treatment_status:
                        # skip
                        writer.writerow([episode.case_id,
                                         current_treatment_initiated,
                                         current_treatment_status,
                                         current_diagnosing_facility_id,
                                         current_treatment_initiating_facility_id,
                                         None,
                                         None,
                                         "no"])
                    else:
                        writer.writerow([episode.case_id,
                                         current_treatment_initiated,
                                         current_treatment_status,
                                         current_diagnosing_facility_id,
                                         current_treatment_initiating_facility_id,
                                         treatment_initiated,
                                         treatment_status,
                                         "yes"])

                        print('Updating {}...'.format(episode.case_id))
                        case_structure = CaseStructure(
                            case_id=episode.case_id,
                            walk_related=False,
                            attrs={
                                "create": False,
                                "update": {
                                    "datamigration_treatment_status_fix": "yes",
                                    "treatment_initiated": treatment_initiated,
                                    "treatment_status": treatment_status,
                                },
                            },
                        )
                        if commit:
                            factory.create_or_update_case(case_structure)
        print("Migration finished at {}".format(datetime.datetime.utcnow()))