import inspect
import json
import uuid
from collections import Counter
from datetime import datetime
from io import StringIO

import mock
from django.contrib.admin.utils import NestedObjects
from django.db import transaction, IntegrityError
from django.db.models.signals import post_delete, post_save
from django.test import SimpleTestCase, TestCase
from nose.tools import nottest

from casexml.apps.case.mock import CaseFactory, CaseIndex, CaseStructure

from corehq.apps.commtrack.helpers import make_product
from corehq.apps.commtrack.tests.util import get_single_balance_block
from corehq.apps.domain.models import Domain
from corehq.apps.dump_reload.sql import SqlDataDumper, SqlDataLoader
from corehq.apps.dump_reload.sql.dump import (
    get_model_iterator_builders_to_dump,
    get_objects_to_dump,
)
from corehq.apps.dump_reload.sql.load import (
    DefaultDictWithKey,
    constraint_checks_deferred,
)
from corehq.apps.hqcase.utils import submit_case_blocks
from corehq.apps.products.models import SQLProduct
from corehq.apps.zapier.consts import EventTypes
from corehq.apps.zapier.models import ZapierSubscription
from corehq.apps.zapier.signals.receivers import (
    zapier_subscription_post_delete,
)
from corehq.blobs.models import BlobMeta
from corehq.form_processor.backends.sql.dbaccessors import LedgerAccessorSQL
from corehq.form_processor.interfaces.dbaccessors import (
    CaseAccessors,
    FormAccessors,
)
from corehq.form_processor.models import (
    CaseTransaction,
    CommCareCaseIndexSQL,
    CommCareCaseSQL,
    LedgerTransaction,
    LedgerValue,
    XFormInstanceSQL,
)
from corehq.form_processor.tests.utils import (
    FormProcessorTestUtils,
    create_form_for_test,
    sharded,
)
from corehq.messaging.scheduling.scheduling_partitioned.models import (
    AlertScheduleInstance,
)


class BaseDumpLoadTest(TestCase):
    @classmethod
    def setUpClass(cls):
        post_delete.disconnect(zapier_subscription_post_delete, sender=ZapierSubscription)
        super(BaseDumpLoadTest, cls).setUpClass()
        cls.domain_name = uuid.uuid4().hex
        cls.domain = Domain(name=cls.domain_name)
        cls.domain.save()

        cls.default_objects_counts = Counter({})

    @classmethod
    def tearDownClass(cls):
        cls.domain.delete()
        super(BaseDumpLoadTest, cls).tearDownClass()
        post_delete.connect(zapier_subscription_post_delete, sender=ZapierSubscription)

    def delete_sql_data(self):
        delete_domain_sql_data_for_dump_load_test(self.domain_name)

    def tearDown(self):
        self.delete_sql_data()
        super(BaseDumpLoadTest, self).tearDown()

    def _dump_and_load(self, expected_dump_counts, load_filter=None, expected_load_counts=None, dumper_fn=None):
        expected_load_counts = expected_load_counts or expected_dump_counts
        expected_dump_counts.update(self.default_objects_counts)

        models = list(expected_dump_counts)
        self._check_signals_handle_raw(models)

        output_stream = StringIO()
        if dumper_fn:
            dumper_fn(output_stream)
        else:
            SqlDataDumper(self.domain_name, [], []).dump(output_stream)

        self.delete_sql_data()

        # make sure that there's no data left in the DB
        objects_remaining = list(get_objects_to_dump(self.domain_name, [], []))
        object_classes = [obj.__class__.__name__ for obj in objects_remaining]
        counts = Counter(object_classes)
        self.assertEqual([], objects_remaining, 'Not all data deleted: {}'.format(counts))

        # Dump
        actual_model_counts, dump_lines = self._parse_dump_output(output_stream)

        expected_model_counts = _normalize_object_counter(expected_dump_counts)
        self.assertDictEqual(dict(expected_model_counts), dict(actual_model_counts))

        # Load
        loader = SqlDataLoader(object_filter=load_filter)
        loaded_model_counts = loader.load_objects(dump_lines)

        normalized_expected_loaded_counts = _normalize_object_counter(expected_load_counts, for_loaded=True)
        self.assertDictEqual(dict(normalized_expected_loaded_counts), dict(loaded_model_counts))
        self.assertEqual(sum(expected_load_counts.values()), sum(loaded_model_counts.values()))

        return dump_lines

    def _parse_dump_output(self, output_stream):
        dump_output = output_stream.getvalue().split('\n')
        dump_lines = [line.strip() for line in dump_output if line.strip()]
        actual_model_counts = Counter([json.loads(line)['model'] for line in dump_lines])
        return actual_model_counts, dump_lines

    def _check_signals_handle_raw(self, models):
        """Ensure that any post_save signal handlers have been updated
        to handle 'raw' calls."""
        whitelist_receivers = [
            'django_digest.models._post_save_persist_partial_digests'
        ]
        for model in models:
            for receiver in post_save._live_receivers(model):
                receiver_path = receiver.__module__ + '.' + receiver.__name__
                if receiver_path in whitelist_receivers:
                    continue
                args = inspect.getargspec(receiver).args
                message = 'Signal handler "{}" for model "{}" missing raw arg'.format(
                    receiver, model
                )
                self.assertIn('raw', args, message)


@nottest
def delete_domain_sql_data_for_dump_load_test(domain_name):
    for model_class, builder in get_model_iterator_builders_to_dump(domain_name, [], []):
        for iterator in builder.querysets():
            with transaction.atomic(using=iterator.db), \
                 constraint_checks_deferred(iterator.db):
                collector = NestedObjects(using=iterator.db)
                collector.collect(iterator)
                collector.delete()

    assert [] == list(get_objects_to_dump(domain_name, [], [])), "Not all SQL objects deleted"


@sharded
class TestSQLDumpLoadShardedModels(BaseDumpLoadTest):
    maxDiff = None

    @classmethod
    def setUpClass(cls):
        super(TestSQLDumpLoadShardedModels, cls).setUpClass()
        cls.factory = CaseFactory(domain=cls.domain_name)
        cls.form_accessors = FormAccessors(cls.domain_name)
        cls.case_accessors = CaseAccessors(cls.domain_name)
        cls.product = make_product(cls.domain_name, 'A Product', 'prodcode_a')
        cls.default_objects_counts.update({SQLProduct: 1})

    @classmethod
    def tearDownClass(cls):
        FormProcessorTestUtils.delete_all_cases_forms_ledgers(cls.domain_name)
        super(TestSQLDumpLoadShardedModels, cls).tearDownClass()

    def test_dump_load_form(self):
        expected_object_counts = Counter({
            XFormInstanceSQL: 2,
            BlobMeta: 2
        })

        pre_forms = [
            create_form_for_test(self.domain_name),
            create_form_for_test(self.domain_name)
        ]
        self._dump_and_load(expected_object_counts)

        form_ids = self.form_accessors.get_all_form_ids_in_domain('XFormInstance')
        self.assertEqual(set(form_ids), set(form.form_id for form in pre_forms))

        for pre_form in pre_forms:
            post_form = self.form_accessors.get_form(pre_form.form_id)
            self.assertDictEqual(pre_form.to_json(), post_form.to_json())

    def test_sql_dump_load_case(self):
        expected_object_counts = Counter({
            XFormInstanceSQL: 2,
            BlobMeta: 2,
            CommCareCaseSQL: 2,
            CaseTransaction: 3,
            CommCareCaseIndexSQL: 1

        })

        pre_cases = self.factory.create_or_update_case(
            CaseStructure(
                attrs={'case_name': 'child', 'update': {'age': 3, 'diabetic': False}, 'create': True},
                indices=[
                    CaseIndex(CaseStructure(attrs={'case_name': 'parent', 'update': {'age': 42}, 'create': True})),
                ]
            )
        )
        pre_cases[0] = self.factory.create_or_update_case(CaseStructure(
            case_id=pre_cases[0].case_id,
            attrs={'external_id': 'billie jean', 'update': {'name': 'Billie Jean'}}
        ))[0]

        self._dump_and_load(expected_object_counts)

        case_ids = self.case_accessors.get_case_ids_in_domain()
        self.assertEqual(set(case_ids), set(case.case_id for case in pre_cases))
        for pre_case in pre_cases:
            post_case = self.case_accessors.get_case(pre_case.case_id)
            self.assertDictEqual(pre_case.to_json(), post_case.to_json())

    def test_ledgers(self):
        expected_object_counts = Counter({
            XFormInstanceSQL: 3,
            BlobMeta: 3,
            CommCareCaseSQL: 1,
            CaseTransaction: 3,
            LedgerValue: 1,
            LedgerTransaction: 2

        })

        case = self.factory.create_case()
        submit_case_blocks([
            get_single_balance_block(case.case_id, self.product._id, 10)
        ], self.domain_name)
        submit_case_blocks([
            get_single_balance_block(case.case_id, self.product._id, 5)
        ], self.domain_name)

        pre_ledger_values = LedgerAccessorSQL.get_ledger_values_for_case(case.case_id)
        pre_ledger_transactions = LedgerAccessorSQL.get_ledger_transactions_for_case(case.case_id)
        self.assertEqual(1, len(pre_ledger_values))
        self.assertEqual(2, len(pre_ledger_transactions))

        self._dump_and_load(expected_object_counts)

        post_ledger_values = LedgerAccessorSQL.get_ledger_values_for_case(case.case_id)
        post_ledger_transactions = LedgerAccessorSQL.get_ledger_transactions_for_case(case.case_id)
        self.assertEqual(1, len(post_ledger_values))
        self.assertEqual(2, len(post_ledger_transactions))
        self.assertEqual(pre_ledger_values[0].ledger_reference, post_ledger_values[0].ledger_reference)
        self.assertDictEqual(pre_ledger_values[0].to_json(), post_ledger_values[0].to_json())

        pre_ledger_transactions = sorted(pre_ledger_transactions, key=lambda t: t.pk)
        post_ledger_transactions = sorted(post_ledger_transactions, key=lambda t: t.pk)
        for pre, post in zip(pre_ledger_transactions, post_ledger_transactions):
            self.assertEqual(str(pre), str(post))


class TestSQLDumpLoad(BaseDumpLoadTest):
    def test_case_search_config(self):
        from corehq.apps.case_search.models import CaseSearchConfig, FuzzyProperties
        expected_object_counts = Counter({
            CaseSearchConfig: 1,
            FuzzyProperties: 2,
        })

        pre_config, created = CaseSearchConfig.objects.get_or_create(pk=self.domain_name)
        pre_config.enabled = True
        pre_fuzzies = [
            FuzzyProperties(domain=self.domain, case_type='dog', properties=['breed', 'color']),
            FuzzyProperties(domain=self.domain, case_type='owner', properties=['name']),
        ]
        for fuzzy in pre_fuzzies:
            fuzzy.save()
        pre_config.fuzzy_properties.set(pre_fuzzies)
        pre_config.save()

        self._dump_and_load(expected_object_counts)

        post_config = CaseSearchConfig.objects.get(domain=self.domain_name)
        self.assertTrue(post_config.enabled)
        self.assertEqual(pre_config.fuzzy_properties, post_config.fuzzy_properties)
        post_fuzzies = FuzzyProperties.objects.filter(domain=self.domain_name)
        self.assertEqual(set(f.case_type for f in post_fuzzies), {'dog', 'owner'})

    def test_users(self):
        from corehq.apps.users.models import CommCareUser
        from corehq.apps.users.models import WebUser
        from django.contrib.auth.models import User

        expected_object_counts = Counter({User: 3})

        ccuser_1 = CommCareUser.create(
            domain=self.domain_name,
            username='user_1',
            password='secret',
            created_by=None,
            created_via=None,
            email='email@example.com',
        )
        ccuser_2 = CommCareUser.create(
            domain=self.domain_name,
            username='user_2',
            password='secret',
            created_by=None,
            created_via=None,
            email='email1@example.com',
        )
        web_user = WebUser.create(
            domain=self.domain_name,
            username='webuser_t1',
            password='secret',
            created_by=None,
            created_via=None,
            email='webuser@example.com',
        )
        self.addCleanup(ccuser_1.delete, self.domain_name, deleted_by=None)
        self.addCleanup(ccuser_2.delete, self.domain_name, deleted_by=None)
        self.addCleanup(web_user.delete, self.domain_name, deleted_by=None)

        self._dump_and_load(expected_object_counts)

    def test_dump_roles(self):
        from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission

        expected_object_counts = Counter({
            UserRole: 2,
            RolePermission: 11,
            RoleAssignableBy: 1
        })

        role1 = UserRole.create(self.domain_name, 'role1')
        role2 = UserRole.create(
            self.domain_name, 'role1',
            permissions=Permissions(edit_web_users=True),
            assignable_by=[role1.id]
        )
        self.addCleanup(role1.delete)
        self.addCleanup(role2.delete)

        self._dump_and_load(expected_object_counts)

        role1_loaded = UserRole.objects.get(id=role1.id)
        role2_loaded = UserRole.objects.get(id=role2.id)

        self.assertEqual(role1_loaded.permissions.to_list(), Permissions().to_list())
        self.assertEqual(role1_loaded.assignable_by, [])
        self.assertEqual(role2_loaded.permissions.to_list(), Permissions(edit_web_users=True).to_list())
        self.assertEqual(role2_loaded.assignable_by, [role1_loaded.get_id])


    def test_device_logs(self):
        from corehq.apps.receiverwrapper.util import submit_form_locally
        from phonelog.models import DeviceReportEntry, ForceCloseEntry, UserEntry, UserErrorEntry
        from corehq.apps.users.models import CommCareUser
        from django.contrib.auth.models import User

        expected_object_counts = Counter({
            User: 1,
            DeviceReportEntry: 7,
            UserEntry: 1,
            UserErrorEntry: 2,
            ForceCloseEntry: 1
        })

        user = CommCareUser.create(
            domain=self.domain_name,
            username='user_1',
            password='secret',
            created_by=None,
            created_via=None,
            email='email@example.com',
            uuid='428d454aa9abc74e1964e16d3565d6b6'  # match ID in devicelog.xml
        )
        self.addCleanup(user.delete, self.domain_name, deleted_by=None)

        with open('corehq/ex-submodules/couchforms/tests/data/devicelogs/devicelog.xml', 'rb') as f:
            xml = f.read()
        submit_form_locally(xml, self.domain_name)

        self._dump_and_load(expected_object_counts)

    def test_demo_user_restore(self):
        from corehq.apps.users.models import CommCareUser
        from corehq.apps.ota.models import DemoUserRestore
        from django.contrib.auth.models import User

        expected_object_counts = Counter({
            User: 1,
            DemoUserRestore: 1
        })

        user_id = uuid.uuid4().hex
        user = CommCareUser.create(
            domain=self.domain_name,
            username='user_1',
            password='secret',
            created_by=None,
            created_via=None,
            email='email@example.com',
            uuid=user_id
        )
        self.addCleanup(user.delete, self.domain_name, deleted_by=None)

        DemoUserRestore(
            demo_user_id=user_id,
            restore_blob_id=uuid.uuid4().hex,
            content_length=1027,
            restore_comment="Test migrate demo user restore"
        ).save()

        self._dump_and_load(expected_object_counts)

    def test_products(self):
        from corehq.apps.products.models import SQLProduct
        expected_object_counts = Counter({SQLProduct: 3})

        p1 = SQLProduct.objects.create(domain=self.domain_name, product_id='test1', name='test1')
        p2 = SQLProduct.objects.create(domain=self.domain_name, product_id='test2', name='test2')
        parchived = SQLProduct.objects.create(domain=self.domain_name, product_id='test3', name='test3', is_archived=True)

        self._dump_and_load(expected_object_counts)

        self.assertEqual(2, SQLProduct.active_objects.filter(domain=self.domain_name).count())
        all_active = SQLProduct.active_objects.filter(domain=self.domain_name).all()
        self.assertTrue(p1 in all_active)
        self.assertTrue(p2 in all_active)
        self.assertTrue(parchived not in all_active)

    def test_location_type(self):
        from corehq.apps.locations.models import LocationType
        from corehq.apps.locations.tests.test_location_types import make_loc_type
        expected_object_counts = Counter({LocationType: 7})

        state = make_loc_type('state', domain=self.domain_name)

        district = make_loc_type('district', state, domain=self.domain_name)
        section = make_loc_type('section', district, domain=self.domain_name)
        block = make_loc_type('block', district, domain=self.domain_name)
        center = make_loc_type('center', block, domain=self.domain_name)

        county = make_loc_type('county', state, domain=self.domain_name)
        city = make_loc_type('city', county, domain=self.domain_name)

        self._dump_and_load(expected_object_counts)

        hierarchy = LocationType.objects.full_hierarchy(self.domain_name)
        desired_hierarchy = {
            state.id: (
                state,
                {
                    district.id: (
                        district,
                        {
                            section.id: (section, {}),
                            block.id: (block, {
                                center.id: (center, {}),
                            }),
                        },
                    ),
                    county.id: (
                        county,
                        {city.id: (city, {})},
                    ),
                },
            ),
        }
        self.assertEqual(hierarchy, desired_hierarchy)

    def test_location(self):
        from corehq.apps.locations.models import LocationType, SQLLocation
        from corehq.apps.locations.tests.util import setup_locations_and_types
        expected_object_counts = Counter({LocationType: 3, SQLLocation: 11})

        location_type_names = ['province', 'district', 'city']
        location_structure = [
            ('Western Cape', [
                ('Cape Winelands', [
                    ('Stellenbosch', []),
                    ('Paarl', []),
                ]),
                ('Cape Town', [
                    ('Cape Town City', []),
                ])
            ]),
            ('Gauteng', [
                ('Ekurhuleni ', [
                    ('Alberton', []),
                    ('Benoni', []),
                    ('Springs', []),
                ]),
            ]),
        ]

        location_types, locations = setup_locations_and_types(
            self.domain_name,
            location_type_names,
            [],
            location_structure,
        )

        self._dump_and_load(expected_object_counts)

        names = ['Cape Winelands', 'Paarl', 'Cape Town']
        location_ids = [locations[name].location_id for name in names]
        result = SQLLocation.objects.get_locations_and_children(location_ids)
        self.assertItemsEqual(
            [loc.name for loc in result],
            ['Cape Winelands', 'Stellenbosch', 'Paarl', 'Cape Town', 'Cape Town City']
        )

        result = SQLLocation.objects.get_locations_and_children([locations['Gauteng'].location_id])
        self.assertItemsEqual(
            [loc.name for loc in result],
            ['Gauteng', 'Ekurhuleni ', 'Alberton', 'Benoni', 'Springs']
        )

    def test_sms(self):
        from corehq.apps.sms.models import PhoneNumber, MessagingEvent, MessagingSubEvent
        expected_object_counts = Counter({PhoneNumber: 1, MessagingEvent: 1, MessagingSubEvent: 1})

        phone_number = PhoneNumber(
            domain=self.domain_name,
            owner_doc_type='CommCareCase',
            owner_id='fake-owner-id1',
            phone_number='99912341234',
            backend_id=None,
            ivr_backend_id=None,
            verified=True,
            is_two_way=True,
            pending_verification=False,
            contact_last_modified=datetime.utcnow()
        )
        phone_number.save()
        event = MessagingEvent.objects.create(
            domain=self.domain_name,
            date=datetime.utcnow(),
            source=MessagingEvent.SOURCE_REMINDER,
            content_type=MessagingEvent.CONTENT_SMS,
            status=MessagingEvent.STATUS_COMPLETED
        )
        MessagingSubEvent.objects.create(
            parent=event,
            date=datetime.utcnow(),
            recipient_type=MessagingEvent.RECIPIENT_CASE,
            content_type=MessagingEvent.CONTENT_SMS,
            status=MessagingEvent.STATUS_COMPLETED
        )

        self._dump_and_load(expected_object_counts)

    def test_message_scheduling(self):
        AlertScheduleInstance(
            schedule_instance_id=uuid.uuid4(),
            domain=self.domain_name,
            recipient_type='CommCareUser',
            recipient_id=uuid.uuid4().hex,
            current_event_num=0,
            schedule_iteration_num=1,
            next_event_due=datetime(2017, 3, 1),
            active=True,
            alert_schedule_id=uuid.uuid4(),
        ).save()
        self._dump_and_load({AlertScheduleInstance: 1})

    def test_mobile_backend(self):
        from corehq.apps.sms.models import (
            SQLMobileBackend,
            SQLMobileBackendMapping,
        )

        domain_backend = SQLMobileBackend.objects.create(
            domain=self.domain_name,
            name='test-domain-mobile-backend',
            display_name='Test Domain Mobile Backend',
            hq_api_id='TDMB',
            inbound_api_key='test-domain-mobile-backend-inbound-api-key',
            supported_countries=["*"],
            backend_type=SQLMobileBackend.SMS,
            is_global=False,
        )
        SQLMobileBackendMapping.objects.create(
            domain=self.domain_name,
            backend=domain_backend,
            backend_type=SQLMobileBackend.SMS,
            prefix='123',
        )

        global_backend = SQLMobileBackend.objects.create(
            domain=None,
            name='test-global-mobile-backend',
            display_name='Test Global Mobile Backend',
            hq_api_id='TGMB',
            inbound_api_key='test-global-mobile-backend-inbound-api-key',
            supported_countries=["*"],
            backend_type=SQLMobileBackend.SMS,
            is_global=True,
        )
        SQLMobileBackendMapping.objects.create(
            domain=self.domain_name,
            backend=global_backend,
            backend_type=SQLMobileBackend.SMS,
            prefix='*',
        )
        self._dump_and_load({
            SQLMobileBackendMapping: 1,
            SQLMobileBackend: 1,
        })
        self.assertEqual(SQLMobileBackend.objects.first().domain,
                         self.domain_name)
        self.assertEqual(SQLMobileBackendMapping.objects.first().domain,
                         self.domain_name)

    def test_case_importer(self):
        from corehq.apps.case_importer.tracking.models import (
            CaseUploadFileMeta,
            CaseUploadFormRecord,
            CaseUploadRecord,
        )

        upload_file_meta = CaseUploadFileMeta.objects.create(
            identifier=uuid.uuid4().hex,
            filename='picture.jpg',
            length=1024,
        )
        case_upload_record = CaseUploadRecord.objects.create(
            domain=self.domain_name,
            upload_id=uuid.uuid4(),
            task_id=uuid.uuid4(),
            couch_user_id=uuid.uuid4().hex,
            case_type='person',
            upload_file_meta=upload_file_meta,
        )
        CaseUploadFormRecord.objects.create(
            case_upload_record=case_upload_record,
            form_id=uuid.uuid4().hex,
        )
        self._dump_and_load(Counter({
            CaseUploadFileMeta: 1,
            CaseUploadRecord: 1,
            CaseUploadFormRecord: 1,
        }))

    def test_transifex(self):
        from corehq.apps.translations.models import TransifexProject, TransifexOrganization
        org = TransifexOrganization.objects.create(slug='test', name='demo', api_token='123')
        TransifexProject.objects.create(
            organization=org, slug='testp', name='demop', domain=self.domain_name
        )
        TransifexProject.objects.create(
            organization=org, slug='testp1', name='demop1', domain=self.domain_name
        )
        self._dump_and_load(Counter({TransifexOrganization: 1, TransifexProject: 2}))

    def test_filtered_dump_load(self):
        from corehq.apps.locations.tests.test_location_types import make_loc_type
        from corehq.apps.products.models import SQLProduct
        from corehq.apps.locations.models import LocationType

        make_loc_type('state', domain=self.domain_name)
        SQLProduct.objects.create(domain=self.domain_name, product_id='test1', name='test1')
        expected_object_counts = Counter({LocationType: 1, SQLProduct: 1})

        self._dump_and_load(expected_object_counts, load_filter='sqlproduct', expected_load_counts=Counter({SQLProduct: 1}))
        self.assertEqual(0, LocationType.objects.count())

    def test_sms_content(self):
        from corehq.messaging.scheduling.models import AlertSchedule, SMSContent, AlertEvent
        from corehq.messaging.scheduling.scheduling_partitioned.dbaccessors import \
            delete_alert_schedule_instances_for_schedule

        schedule = AlertSchedule.create_simple_alert(self.domain, SMSContent())

        schedule.set_custom_alert(
            [
                (AlertEvent(minutes_to_wait=5), SMSContent()),
                (AlertEvent(minutes_to_wait=15), SMSContent()),
            ]
        )

        self.addCleanup(lambda: delete_alert_schedule_instances_for_schedule(AlertScheduleInstance, schedule.schedule_id))
        self._dump_and_load(Counter({AlertSchedule: 1, AlertEvent: 2, SMSContent: 2}))

    def test_zapier_subscription(self):
        ZapierSubscription.objects.create(
            domain=self.domain_name,
            case_type='case_type',
            event_name=EventTypes.NEW_CASE,
            url='example.com',
            user_id='user_id',
        )
        self._dump_and_load(Counter({ZapierSubscription: 1}))


@mock.patch("corehq.apps.dump_reload.sql.load.ENQUEUE_TIMEOUT", 1)
class TestSqlLoadWithError(BaseDumpLoadTest):
    def setUp(self):
        self.products = [
            SQLProduct.objects.create(domain=self.domain_name, product_id='test1', name='test1'),
            SQLProduct.objects.create(domain=self.domain_name, product_id='test2', name='test2'),
            SQLProduct.objects.create(domain=self.domain_name, product_id='test3', name='test3'),
        ]

    def test_load_error_queue_full(self):
        """Blocks when sending 'test3'"""
        self._load_with_errors(chunk_size=1)

    def test_load_error_queue_full_on_terminate(self):
        """Blocks when sending ``None`` into the queue to 'terminate' it."""
        self._load_with_errors(chunk_size=2)

    def _load_with_errors(self, chunk_size):
        output_stream = StringIO()
        SqlDataDumper(self.domain_name, [], []).dump(output_stream)
        self.delete_sql_data()
        # resave the product to force an error
        self.products[0].save()
        actual_model_counts, dump_lines = self._parse_dump_output(output_stream)
        self.assertEqual(actual_model_counts['products.sqlproduct'], 3)

        loader = SqlDataLoader()
        with self.assertRaises(IntegrityError),\
             mock.patch("corehq.apps.dump_reload.sql.load.CHUNK_SIZE", chunk_size):
            # patch the chunk size so that the queue blocks
            loader.load_objects(dump_lines)


class DefaultDictWithKeyTests(SimpleTestCase):

    def test_intended_use_case(self):
        def enlist(item):
            return [item]
        greasy_spoon = DefaultDictWithKey(enlist)
        self.assertEqual(greasy_spoon['spam'], ['spam'])
        greasy_spoon['spam'].append('spam')
        self.assertEqual(greasy_spoon['spam'], ['spam', 'spam'])

    def test_not_enough_params(self):
        def empty_list():
            return []
        greasy_spoon = DefaultDictWithKey(empty_list)
        with self.assertRaisesRegex(
            TypeError,
            r'empty_list\(\) takes 0 positional arguments but 1 was given'
        ):
            greasy_spoon['spam']

    def test_too_many_params(self):
        def appender(item1, item2):
            return [item1, item2]
        greasy_spoon = DefaultDictWithKey(appender)
        with self.assertRaisesRegex(
            TypeError,
            r"appender\(\) missing 1 required positional argument: 'item2'"
        ):
            greasy_spoon['spam']

    def test_no_factory(self):
        greasy_spoon = DefaultDictWithKey()
        with self.assertRaisesRegex(
            TypeError,
            "'NoneType' object is not callable"
        ):
            greasy_spoon['spam']


def _normalize_object_counter(counter, for_loaded=False):
    """Converts a <Model Class> keyed counter to an model label keyed counter"""
    def _model_class_to_label(model_class):
        label = '{}.{}'.format(model_class._meta.app_label, model_class.__name__)
        return label if for_loaded else label.lower()
    return Counter({
        _model_class_to_label(model_class): count
        for model_class, count in counter.items()
    })

[((701, 1, 701, 66), 'mock.patch', 'mock.patch', ({(701, 12, 701, 62): '"""corehq.apps.dump_reload.sql.load.ENQUEUE_TIMEOUT"""', (701, 64, 701, 65): '(1)'}, {}), "('corehq.apps.dump_reload.sql.load.ENQUEUE_TIMEOUT', 1)", False, 'import mock\n'), ((147, 32, 147, 88), 'corehq.apps.dump_reload.sql.dump.get_model_iterator_builders_to_dump', 'get_model_iterator_builders_to_dump', ({(147, 68, 147, 79): 'domain_name', (147, 81, 147, 83): '[]', (147, 85, 147, 87): '[]'}, {}), '(domain_name, [], [])', False, 'from corehq.apps.dump_reload.sql.dump import get_model_iterator_builders_to_dump, get_objects_to_dump\n'), ((63, 8, 63, 90), 'django.db.models.signals.post_delete.disconnect', 'post_delete.disconnect', (), '', False, 'from django.db.models.signals import post_delete, post_save\n'), ((66, 21, 66, 49), 'corehq.apps.domain.models.Domain', 'Domain', (), '', False, 'from corehq.apps.domain.models import Domain\n'), ((69, 37, 69, 48), 'collections.Counter', 'Counter', ({(69, 45, 69, 47): '{}'}, {}), '({})', False, 'from collections import Counter\n'), ((75, 8, 75, 87), 'django.db.models.signals.post_delete.connect', 'post_delete.connect', (), '', False, 'from django.db.models.signals import post_delete, post_save\n'), ((91, 24, 91, 34), 'io.StringIO', 'StringIO', ({}, {}), '()', False, 'from io import StringIO\n'), ((102, 17, 102, 40), 'collections.Counter', 'Counter', ({(102, 25, 102, 39): 'object_classes'}, {}), '(object_classes)', False, 'from collections import Counter\n'), ((112, 17, 112, 57), 'corehq.apps.dump_reload.sql.SqlDataLoader', 'SqlDataLoader', (), '', False, 'from corehq.apps.dump_reload.sql import SqlDataDumper, SqlDataLoader\n'), ((165, 22, 165, 57), 'casexml.apps.case.mock.CaseFactory', 'CaseFactory', (), '', False, 'from casexml.apps.case.mock import CaseFactory, CaseIndex, CaseStructure\n'), ((166, 29, 166, 59), 'corehq.form_processor.interfaces.dbaccessors.FormAccessors', 'FormAccessors', ({(166, 43, 166, 58): 'cls.domain_name'}, {}), '(cls.domain_name)', False, 'from corehq.form_processor.interfaces.dbaccessors import CaseAccessors, FormAccessors\n'), ((167, 29, 167, 59), 'corehq.form_processor.interfaces.dbaccessors.CaseAccessors', 'CaseAccessors', ({(167, 43, 167, 58): 'cls.domain_name'}, {}), '(cls.domain_name)', False, 'from corehq.form_processor.interfaces.dbaccessors import CaseAccessors, FormAccessors\n'), ((168, 22, 168, 78), 'corehq.apps.commtrack.helpers.make_product', 'make_product', ({(168, 35, 168, 50): 'cls.domain_name', (168, 52, 168, 63): '"""A Product"""', (168, 65, 168, 77): '"""prodcode_a"""'}, {}), "(cls.domain_name, 'A Product', 'prodcode_a')", False, 'from corehq.apps.commtrack.helpers import make_product\n'), ((173, 8, 173, 78), 'corehq.form_processor.tests.utils.FormProcessorTestUtils.delete_all_cases_forms_ledgers', 'FormProcessorTestUtils.delete_all_cases_forms_ledgers', ({(173, 62, 173, 77): 'cls.domain_name'}, {}), '(cls.domain_name)', False, 'from corehq.form_processor.tests.utils import FormProcessorTestUtils, create_form_for_test, sharded\n'), ((177, 33, 180, 10), 'collections.Counter', 'Counter', ({(177, 41, 180, 9): '{XFormInstanceSQL: 2, BlobMeta: 2}'}, {}), '({XFormInstanceSQL: 2, BlobMeta: 2})', False, 'from collections import Counter\n'), ((196, 33, 203, 10), 'collections.Counter', 'Counter', ({(196, 41, 203, 9): '{XFormInstanceSQL: 2, BlobMeta: 2, CommCareCaseSQL: 2, CaseTransaction: 3,\n    CommCareCaseIndexSQL: 1}'}, {}), '({XFormInstanceSQL: 2, BlobMeta: 2, CommCareCaseSQL: 2,\n    CaseTransaction: 3, CommCareCaseIndexSQL: 1})', False, 'from collections import Counter\n'), ((227, 33, 235, 10), 'collections.Counter', 'Counter', ({(227, 41, 235, 9): '{XFormInstanceSQL: 3, BlobMeta: 3, CommCareCaseSQL: 1, CaseTransaction: 3,\n    LedgerValue: 1, LedgerTransaction: 2}'}, {}), '({XFormInstanceSQL: 3, BlobMeta: 3, CommCareCaseSQL: 1,\n    CaseTransaction: 3, LedgerValue: 1, LedgerTransaction: 2})', False, 'from collections import Counter\n'), ((245, 28, 245, 86), 'corehq.form_processor.backends.sql.dbaccessors.LedgerAccessorSQL.get_ledger_values_for_case', 'LedgerAccessorSQL.get_ledger_values_for_case', ({(245, 73, 245, 85): 'case.case_id'}, {}), '(case.case_id)', False, 'from corehq.form_processor.backends.sql.dbaccessors import LedgerAccessorSQL\n'), ((246, 34, 246, 98), 'corehq.form_processor.backends.sql.dbaccessors.LedgerAccessorSQL.get_ledger_transactions_for_case', 'LedgerAccessorSQL.get_ledger_transactions_for_case', ({(246, 85, 246, 97): 'case.case_id'}, {}), '(case.case_id)', False, 'from corehq.form_processor.backends.sql.dbaccessors import LedgerAccessorSQL\n'), ((252, 29, 252, 87), 'corehq.form_processor.backends.sql.dbaccessors.LedgerAccessorSQL.get_ledger_values_for_case', 'LedgerAccessorSQL.get_ledger_values_for_case', ({(252, 74, 252, 86): 'case.case_id'}, {}), '(case.case_id)', False, 'from corehq.form_processor.backends.sql.dbaccessors import LedgerAccessorSQL\n'), ((253, 35, 253, 99), 'corehq.form_processor.backends.sql.dbaccessors.LedgerAccessorSQL.get_ledger_transactions_for_case', 'LedgerAccessorSQL.get_ledger_transactions_for_case', ({(253, 86, 253, 98): 'case.case_id'}, {}), '(case.case_id)', False, 'from corehq.form_processor.backends.sql.dbaccessors import LedgerAccessorSQL\n'), ((268, 33, 271, 10), 'collections.Counter', 'Counter', ({(268, 41, 271, 9): '{CaseSearchConfig: 1, FuzzyProperties: 2}'}, {}), '({CaseSearchConfig: 1, FuzzyProperties: 2})', False, 'from collections import Counter\n'), ((273, 30, 273, 89), 'corehq.apps.case_search.models.CaseSearchConfig.objects.get_or_create', 'CaseSearchConfig.objects.get_or_create', (), '', False, 'from corehq.apps.case_search.models import CaseSearchConfig, FuzzyProperties\n'), ((286, 22, 286, 75), 'corehq.apps.case_search.models.CaseSearchConfig.objects.get', 'CaseSearchConfig.objects.get', (), '', False, 'from corehq.apps.case_search.models import CaseSearchConfig, FuzzyProperties\n'), ((289, 23, 289, 78), 'corehq.apps.case_search.models.FuzzyProperties.objects.filter', 'FuzzyProperties.objects.filter', (), '', False, 'from corehq.apps.case_search.models import CaseSearchConfig, FuzzyProperties\n'), ((297, 33, 297, 51), 'collections.Counter', 'Counter', ({(297, 41, 297, 50): '{User: 3}'}, {}), '({User: 3})', False, 'from collections import Counter\n'), ((299, 19, 306, 9), 'corehq.apps.users.models.CommCareUser.create', 'CommCareUser.create', (), '', False, 'from corehq.apps.users.models import CommCareUser\n'), ((307, 19, 314, 9), 'corehq.apps.users.models.CommCareUser.create', 'CommCareUser.create', (), '', False, 'from corehq.apps.users.models import CommCareUser\n'), ((315, 19, 322, 9), 'corehq.apps.users.models.WebUser.create', 'WebUser.create', (), '', False, 'from corehq.apps.users.models import WebUser\n'), ((332, 33, 336, 10), 'collections.Counter', 'Counter', ({(332, 41, 336, 9): '{UserRole: 2, RolePermission: 11, RoleAssignableBy: 1}'}, {}), '({UserRole: 2, RolePermission: 11, RoleAssignableBy: 1})', False, 'from collections import Counter\n'), ((338, 16, 338, 58), 'corehq.apps.users.models.UserRole.create', 'UserRole.create', ({(338, 32, 338, 48): 'self.domain_name', (338, 50, 338, 57): '"""role1"""'}, {}), "(self.domain_name, 'role1')", False, 'from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission\n'), ((349, 23, 349, 56), 'corehq.apps.users.models.UserRole.objects.get', 'UserRole.objects.get', (), '', False, 'from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission\n'), ((350, 23, 350, 56), 'corehq.apps.users.models.UserRole.objects.get', 'UserRole.objects.get', (), '', False, 'from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission\n'), ((364, 33, 370, 10), 'collections.Counter', 'Counter', ({(364, 41, 370, 9): '{User: 1, DeviceReportEntry: 7, UserEntry: 1, UserErrorEntry: 2,\n    ForceCloseEntry: 1}'}, {}), '({User: 1, DeviceReportEntry: 7, UserEntry: 1, UserErrorEntry: 2,\n    ForceCloseEntry: 1})', False, 'from collections import Counter\n'), ((372, 15, 380, 9), 'corehq.apps.users.models.CommCareUser.create', 'CommCareUser.create', (), '', False, 'from corehq.apps.users.models import CommCareUser\n'), ((385, 8, 385, 50), 'corehq.apps.receiverwrapper.util.submit_form_locally', 'submit_form_locally', ({(385, 28, 385, 31): 'xml', (385, 33, 385, 49): 'self.domain_name'}, {}), '(xml, self.domain_name)', False, 'from corehq.apps.receiverwrapper.util import submit_form_locally\n'), ((394, 33, 397, 10), 'collections.Counter', 'Counter', ({(394, 41, 397, 9): '{User: 1, DemoUserRestore: 1}'}, {}), '({User: 1, DemoUserRestore: 1})', False, 'from collections import Counter\n'), ((400, 15, 408, 9), 'corehq.apps.users.models.CommCareUser.create', 'CommCareUser.create', (), '', False, 'from corehq.apps.users.models import CommCareUser\n'), ((422, 33, 422, 57), 'collections.Counter', 'Counter', ({(422, 41, 422, 56): '{SQLProduct: 3}'}, {}), '({SQLProduct: 3})', False, 'from collections import Counter\n'), ((424, 13, 424, 97), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((425, 13, 425, 97), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((426, 20, 426, 122), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((439, 33, 439, 59), 'collections.Counter', 'Counter', ({(439, 41, 439, 58): '{LocationType: 7}'}, {}), '({LocationType: 7})', False, 'from collections import Counter\n'), ((441, 16, 441, 63), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((443, 19, 443, 76), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((444, 18, 444, 77), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((445, 16, 445, 73), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((446, 17, 446, 72), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((448, 17, 448, 72), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((449, 15, 449, 69), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((453, 20, 453, 73), 'corehq.apps.locations.models.LocationType.objects.full_hierarchy', 'LocationType.objects.full_hierarchy', ({(453, 56, 453, 72): 'self.domain_name'}, {}), '(self.domain_name)', False, 'from corehq.apps.locations.models import LocationType\n'), ((479, 33, 479, 76), 'collections.Counter', 'Counter', ({(479, 41, 479, 75): '{LocationType: 3, SQLLocation: 11}'}, {}), '({LocationType: 3, SQLLocation: 11})', False, 'from collections import Counter\n'), ((501, 36, 506, 9), 'corehq.apps.locations.tests.util.setup_locations_and_types', 'setup_locations_and_types', ({(502, 12, 502, 28): 'self.domain_name', (503, 12, 503, 31): 'location_type_names', (504, 12, 504, 14): '[]', (505, 12, 505, 30): 'location_structure'}, {}), '(self.domain_name, location_type_names, [],\n    location_structure)', False, 'from corehq.apps.locations.tests.util import setup_locations_and_types\n'), ((512, 17, 512, 77), 'corehq.apps.locations.models.SQLLocation.objects.get_locations_and_children', 'SQLLocation.objects.get_locations_and_children', ({(512, 64, 512, 76): 'location_ids'}, {}), '(location_ids)', False, 'from corehq.apps.locations.models import LocationType, SQLLocation\n'), ((518, 17, 518, 99), 'corehq.apps.locations.models.SQLLocation.objects.get_locations_and_children', 'SQLLocation.objects.get_locations_and_children', ({(518, 64, 518, 98): "[locations['Gauteng'].location_id]"}, {}), "([locations['Gauteng'].\n    location_id])", False, 'from corehq.apps.locations.models import LocationType, SQLLocation\n'), ((526, 33, 526, 99), 'collections.Counter', 'Counter', ({(526, 41, 526, 98): '{PhoneNumber: 1, MessagingEvent: 1, MessagingSubEvent: 1}'}, {}), '({PhoneNumber: 1, MessagingEvent: 1, MessagingSubEvent: 1})', False, 'from collections import Counter\n'), ((578, 25, 587, 9), 'corehq.apps.sms.models.SQLMobileBackend.objects.create', 'SQLMobileBackend.objects.create', (), '', False, 'from corehq.apps.sms.models import SQLMobileBackend, SQLMobileBackendMapping\n'), ((588, 8, 593, 9), 'corehq.apps.sms.models.SQLMobileBackendMapping.objects.create', 'SQLMobileBackendMapping.objects.create', (), '', False, 'from corehq.apps.sms.models import SQLMobileBackend, SQLMobileBackendMapping\n'), ((595, 25, 604, 9), 'corehq.apps.sms.models.SQLMobileBackend.objects.create', 'SQLMobileBackend.objects.create', (), '', False, 'from corehq.apps.sms.models import SQLMobileBackend, SQLMobileBackendMapping\n'), ((605, 8, 610, 9), 'corehq.apps.sms.models.SQLMobileBackendMapping.objects.create', 'SQLMobileBackendMapping.objects.create', (), '', False, 'from corehq.apps.sms.models import SQLMobileBackend, SQLMobileBackendMapping\n'), ((652, 14, 652, 93), 'corehq.apps.translations.models.TransifexOrganization.objects.create', 'TransifexOrganization.objects.create', (), '', False, 'from corehq.apps.translations.models import TransifexProject, TransifexOrganization\n'), ((653, 8, 655, 9), 'corehq.apps.translations.models.TransifexProject.objects.create', 'TransifexProject.objects.create', (), '', False, 'from corehq.apps.translations.models import TransifexProject, TransifexOrganization\n'), ((656, 8, 658, 9), 'corehq.apps.translations.models.TransifexProject.objects.create', 'TransifexProject.objects.create', (), '', False, 'from corehq.apps.translations.models import TransifexProject, TransifexOrganization\n'), ((666, 8, 666, 55), 'corehq.apps.locations.tests.test_location_types.make_loc_type', 'make_loc_type', (), '', False, 'from corehq.apps.locations.tests.test_location_types import make_loc_type\n'), ((667, 8, 667, 92), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((668, 33, 668, 74), 'collections.Counter', 'Counter', ({(668, 41, 668, 73): '{LocationType: 1, SQLProduct: 1}'}, {}), '({LocationType: 1, SQLProduct: 1})', False, 'from collections import Counter\n'), ((691, 8, 697, 9), 'corehq.apps.zapier.models.ZapierSubscription.objects.create', 'ZapierSubscription.objects.create', (), '', False, 'from corehq.apps.zapier.models import ZapierSubscription\n'), ((719, 24, 719, 34), 'io.StringIO', 'StringIO', ({}, {}), '()', False, 'from io import StringIO\n'), ((727, 17, 727, 32), 'corehq.apps.dump_reload.sql.SqlDataLoader', 'SqlDataLoader', ({}, {}), '()', False, 'from corehq.apps.dump_reload.sql import SqlDataDumper, SqlDataLoader\n'), ((739, 23, 739, 49), 'corehq.apps.dump_reload.sql.load.DefaultDictWithKey', 'DefaultDictWithKey', ({(739, 42, 739, 48): 'enlist'}, {}), '(enlist)', False, 'from corehq.apps.dump_reload.sql.load import DefaultDictWithKey, constraint_checks_deferred\n'), ((747, 23, 747, 53), 'corehq.apps.dump_reload.sql.load.DefaultDictWithKey', 'DefaultDictWithKey', ({(747, 42, 747, 52): 'empty_list'}, {}), '(empty_list)', False, 'from corehq.apps.dump_reload.sql.load import DefaultDictWithKey, constraint_checks_deferred\n'), ((757, 23, 757, 51), 'corehq.apps.dump_reload.sql.load.DefaultDictWithKey', 'DefaultDictWithKey', ({(757, 42, 757, 50): 'appender'}, {}), '(appender)', False, 'from corehq.apps.dump_reload.sql.load import DefaultDictWithKey, constraint_checks_deferred\n'), ((765, 23, 765, 43), 'corehq.apps.dump_reload.sql.load.DefaultDictWithKey', 'DefaultDictWithKey', ({}, {}), '()', False, 'from corehq.apps.dump_reload.sql.load import DefaultDictWithKey, constraint_checks_deferred\n'), ((65, 26, 65, 38), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((100, 33, 100, 78), 'corehq.apps.dump_reload.sql.dump.get_objects_to_dump', 'get_objects_to_dump', ({(100, 53, 100, 69): 'self.domain_name', (100, 71, 100, 73): '[]', (100, 75, 100, 77): '[]'}, {}), '(self.domain_name, [], [])', False, 'from corehq.apps.dump_reload.sql.dump import get_model_iterator_builders_to_dump, get_objects_to_dump\n'), ((134, 28, 134, 60), 'django.db.models.signals.post_save._live_receivers', 'post_save._live_receivers', ({(134, 54, 134, 59): 'model'}, {}), '(model)', False, 'from django.db.models.signals import post_delete, post_save\n'), ((155, 22, 155, 62), 'corehq.apps.dump_reload.sql.dump.get_objects_to_dump', 'get_objects_to_dump', ({(155, 42, 155, 53): 'domain_name', (155, 55, 155, 57): '[]', (155, 59, 155, 61): '[]'}, {}), '(domain_name, [], [])', False, 'from corehq.apps.dump_reload.sql.dump import get_model_iterator_builders_to_dump, get_objects_to_dump\n'), ((183, 12, 183, 50), 'corehq.form_processor.tests.utils.create_form_for_test', 'create_form_for_test', ({(183, 33, 183, 49): 'self.domain_name'}, {}), '(self.domain_name)', False, 'from corehq.form_processor.tests.utils import FormProcessorTestUtils, create_form_for_test, sharded\n'), ((184, 12, 184, 50), 'corehq.form_processor.tests.utils.create_form_for_test', 'create_form_for_test', ({(184, 33, 184, 49): 'self.domain_name'}, {}), '(self.domain_name)', False, 'from corehq.form_processor.tests.utils import FormProcessorTestUtils, create_form_for_test, sharded\n'), ((276, 12, 276, 95), 'corehq.apps.case_search.models.FuzzyProperties', 'FuzzyProperties', (), '', False, 'from corehq.apps.case_search.models import CaseSearchConfig, FuzzyProperties\n'), ((277, 12, 277, 87), 'corehq.apps.case_search.models.FuzzyProperties', 'FuzzyProperties', (), '', False, 'from corehq.apps.case_search.models import CaseSearchConfig, FuzzyProperties\n'), ((399, 18, 399, 30), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((644, 28, 648, 10), 'collections.Counter', 'Counter', ({(644, 36, 648, 9): '{CaseUploadFileMeta: 1, CaseUploadRecord: 1, CaseUploadFormRecord: 1}'}, {}), '({CaseUploadFileMeta: 1, CaseUploadRecord: 1, CaseUploadFormRecord: 1})', False, 'from collections import Counter\n'), ((659, 28, 659, 84), 'collections.Counter', 'Counter', ({(659, 36, 659, 83): '{TransifexOrganization: 1, TransifexProject: 2}'}, {}), '({TransifexOrganization: 1, TransifexProject: 2})', False, 'from collections import Counter\n'), ((671, 28, 671, 56), 'corehq.apps.locations.models.LocationType.objects.count', 'LocationType.objects.count', ({}, {}), '()', False, 'from corehq.apps.locations.models import LocationType\n'), ((678, 66, 678, 78), 'corehq.messaging.scheduling.models.SMSContent', 'SMSContent', ({}, {}), '()', False, 'from corehq.messaging.scheduling.models import AlertSchedule, SMSContent, AlertEvent\n'), ((688, 28, 688, 85), 'collections.Counter', 'Counter', ({(688, 36, 688, 84): '{AlertSchedule: 1, AlertEvent: 2, SMSContent: 2}'}, {}), '({AlertSchedule: 1, AlertEvent: 2, SMSContent: 2})', False, 'from collections import Counter\n'), ((698, 28, 698, 60), 'collections.Counter', 'Counter', ({(698, 36, 698, 59): '{ZapierSubscription: 1}'}, {}), '({ZapierSubscription: 1})', False, 'from collections import Counter\n'), ((705, 12, 705, 96), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((706, 12, 706, 96), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((707, 12, 707, 96), 'corehq.apps.products.models.SQLProduct.objects.create', 'SQLProduct.objects.create', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((729, 13, 729, 82), 'mock.patch', 'mock.patch', ({(729, 24, 729, 69): '"""corehq.apps.dump_reload.sql.load.CHUNK_SIZE"""', (729, 71, 729, 81): 'chunk_size'}, {}), "('corehq.apps.dump_reload.sql.load.CHUNK_SIZE', chunk_size)", False, 'import mock\n'), ((149, 17, 149, 54), 'django.db.transaction.atomic', 'transaction.atomic', (), '', False, 'from django.db import transaction, IntegrityError\n'), ((150, 17, 150, 56), 'corehq.apps.dump_reload.sql.load.constraint_checks_deferred', 'constraint_checks_deferred', ({(150, 44, 150, 55): 'iterator.db'}, {}), '(iterator.db)', False, 'from corehq.apps.dump_reload.sql.load import DefaultDictWithKey, constraint_checks_deferred\n'), ((151, 28, 151, 60), 'django.contrib.admin.utils.NestedObjects', 'NestedObjects', (), '', False, 'from django.contrib.admin.utils import NestedObjects\n'), ((213, 58, 216, 9), 'casexml.apps.case.mock.CaseStructure', 'CaseStructure', (), '', False, 'from casexml.apps.case.mock import CaseFactory, CaseIndex, CaseStructure\n'), ((239, 12, 239, 72), 'corehq.apps.commtrack.tests.util.get_single_balance_block', 'get_single_balance_block', ({(239, 37, 239, 49): 'case.case_id', (239, 51, 239, 67): 'self.product._id', (239, 69, 239, 71): '(10)'}, {}), '(case.case_id, self.product._id, 10)', False, 'from corehq.apps.commtrack.tests.util import get_single_balance_block\n'), ((242, 12, 242, 71), 'corehq.apps.commtrack.tests.util.get_single_balance_block', 'get_single_balance_block', ({(242, 37, 242, 49): 'case.case_id', (242, 51, 242, 67): 'self.product._id', (242, 69, 242, 70): '(5)'}, {}), '(case.case_id, self.product._id, 5)', False, 'from corehq.apps.commtrack.tests.util import get_single_balance_block\n'), ((341, 24, 341, 56), 'corehq.apps.users.models.Permissions', 'Permissions', (), '', False, 'from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission\n'), ((431, 21, 431, 78), 'corehq.apps.products.models.SQLProduct.active_objects.filter', 'SQLProduct.active_objects.filter', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((538, 34, 538, 51), 'datetime.datetime.utcnow', 'datetime.utcnow', ({}, {}), '()', False, 'from datetime import datetime\n'), ((543, 17, 543, 34), 'datetime.datetime.utcnow', 'datetime.utcnow', ({}, {}), '()', False, 'from datetime import datetime\n'), ((550, 17, 550, 34), 'datetime.datetime.utcnow', 'datetime.utcnow', ({}, {}), '()', False, 'from datetime import datetime\n'), ((615, 25, 615, 57), 'corehq.apps.sms.models.SQLMobileBackend.objects.first', 'SQLMobileBackend.objects.first', ({}, {}), '()', False, 'from corehq.apps.sms.models import SQLMobileBackend, SQLMobileBackendMapping\n'), ((617, 25, 617, 64), 'corehq.apps.sms.models.SQLMobileBackendMapping.objects.first', 'SQLMobileBackendMapping.objects.first', ({}, {}), '()', False, 'from corehq.apps.sms.models import SQLMobileBackend, SQLMobileBackendMapping\n'), ((634, 22, 634, 34), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((635, 20, 635, 32), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((670, 99, 670, 123), 'collections.Counter', 'Counter', ({(670, 107, 670, 122): '{SQLProduct: 1}'}, {}), '({SQLProduct: 1})', False, 'from collections import Counter\n'), ((687, 32, 687, 121), 'corehq.messaging.scheduling.scheduling_partitioned.dbaccessors.delete_alert_schedule_instances_for_schedule', 'delete_alert_schedule_instances_for_schedule', ({(687, 77, 687, 98): 'AlertScheduleInstance', (687, 100, 687, 120): 'schedule.schedule_id'}, {}), '(AlertScheduleInstance,\n    schedule.schedule_id)', False, 'from corehq.messaging.scheduling.scheduling_partitioned.dbaccessors import delete_alert_schedule_instances_for_schedule\n'), ((720, 8, 720, 47), 'corehq.apps.dump_reload.sql.SqlDataDumper', 'SqlDataDumper', ({(720, 22, 720, 38): 'self.domain_name', (720, 40, 720, 42): '[]', (720, 44, 720, 46): '[]'}, {}), '(self.domain_name, [], [])', False, 'from corehq.apps.dump_reload.sql import SqlDataDumper, SqlDataLoader\n'), ((95, 12, 95, 51), 'corehq.apps.dump_reload.sql.SqlDataDumper', 'SqlDataDumper', ({(95, 26, 95, 42): 'self.domain_name', (95, 44, 95, 46): '[]', (95, 48, 95, 50): '[]'}, {}), '(self.domain_name, [], [])', False, 'from corehq.apps.dump_reload.sql import SqlDataDumper, SqlDataLoader\n'), ((124, 39, 124, 55), 'json.loads', 'json.loads', ({(124, 50, 124, 54): 'line'}, {}), '(line)', False, 'import json\n'), ((138, 23, 138, 51), 'inspect.getargspec', 'inspect.getargspec', ({(138, 42, 138, 50): 'receiver'}, {}), '(receiver)', False, 'import inspect\n'), ((352, 61, 352, 74), 'corehq.apps.users.models.Permissions', 'Permissions', ({}, {}), '()', False, 'from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission\n'), ((354, 61, 354, 93), 'corehq.apps.users.models.Permissions', 'Permissions', (), '', False, 'from corehq.apps.users.models import UserRole, Permissions, RoleAssignableBy, RolePermission\n'), ((430, 28, 430, 85), 'corehq.apps.products.models.SQLProduct.active_objects.filter', 'SQLProduct.active_objects.filter', (), '', False, 'from corehq.apps.products.models import SQLProduct\n'), ((628, 23, 628, 35), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((636, 26, 636, 38), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((642, 20, 642, 32), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((682, 17, 682, 46), 'corehq.messaging.scheduling.models.AlertEvent', 'AlertEvent', (), '', False, 'from corehq.messaging.scheduling.models import AlertSchedule, SMSContent, AlertEvent\n'), ((682, 48, 682, 60), 'corehq.messaging.scheduling.models.SMSContent', 'SMSContent', ({}, {}), '()', False, 'from corehq.messaging.scheduling.models import AlertSchedule, SMSContent, AlertEvent\n'), ((683, 17, 683, 47), 'corehq.messaging.scheduling.models.AlertEvent', 'AlertEvent', (), '', False, 'from corehq.messaging.scheduling.models import AlertSchedule, SMSContent, AlertEvent\n'), ((683, 49, 683, 61), 'corehq.messaging.scheduling.models.SMSContent', 'SMSContent', ({}, {}), '()', False, 'from corehq.messaging.scheduling.models import AlertSchedule, SMSContent, AlertEvent\n'), ((560, 33, 560, 45), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((566, 27, 566, 47), 'datetime.datetime', 'datetime', ({(566, 36, 566, 40): '(2017)', (566, 42, 566, 43): '(3)', (566, 45, 566, 46): '(1)'}, {}), '(2017, 3, 1)', False, 'from datetime import datetime\n'), ((568, 30, 568, 42), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((209, 30, 209, 113), 'casexml.apps.case.mock.CaseStructure', 'CaseStructure', (), '', False, 'from casexml.apps.case.mock import CaseFactory, CaseIndex, CaseStructure\n'), ((413, 28, 413, 40), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((563, 25, 563, 37), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n')]