"""QC domain, separation of duties, scope, evidence and query contracts."""
import uuid
from datetime import timedelta
from unittest.mock import patch

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission, Group
from django.core.exceptions import ValidationError
from django.db import IntegrityError, transaction
from django.db.models.deletion import Collector, ProtectedError
from django.test import TestCase
from django.utils import timezone

from apps.access import services as access
from apps.access.models import Role
from apps.organization import assignment_services as postings, services as organization
from apps.organization.models import Department
from apps.catalog import services as catalog
from apps.devices import services as devices
from apps.service_catalog.models import FaultDiagnosis, RepairAction
from . import quality_control_services as services, quality_control_queries as queries
from .quality_control_checklist import CHECKLIST
from . import test_diagnosis as diagnosis, test_repair as repair
from .test_engineer_assignment import setup_engineers, assign, reassign, unassign
from .services import add_service_case_complaint, cancel_service_case
from .models import (ServiceCase, ServiceEngineerAssignment, ServiceDiagnosticAssessment, ServiceRepairExecution,
    ServiceQualityControl, ServiceQualityControlCheck, ServiceQualityControlComplaintCheck, ServiceCaseComplaint)


def setup_qc(test):
    setup_engineers(test)
    test.complaint = add_service_case_complaint(service_case=test.case, complaint_symptom=test.symptom, customer_description="Synthetic reported fault")
    test.assignment = assign(test)
    test.fault = FaultDiagnosis.objects.create(code="QC-FAULT", name="Synthetic fault", applies_to_all_product_categories=True)
    test.assessment = diagnosis.begin(test)
    diagnosis.add(test, test.assessment)
    test.assessment = diagnosis.complete(test, test.assessment)
    test.action_type = RepairAction.objects.create(code="QC-REPAIR", name="Synthetic repair", applies_to_all_product_categories=True)
    test.execution, _ = repair.prepared(test)
    test.execution = repair.complete(test, test.execution)
    test.qc_permission = Permission.objects.get(content_type__app_label="service", codename="perform_quality_control")
    test.qc_role = Role.objects.create(code="QC-CAPABILITY", name="Synthetic QC capability")
    access.set_role_permissions(role=test.qc_role, permissions=[test.qc_permission])
    test.inspector = get_user_model().objects.create_user(username="qc-inspector")
    test.inspector2 = get_user_model().objects.create_user(username="qc-inspector-2")
    test.qc_path = postings.create_assignment(user=test.inspector, company=test.company, region=test.region, service_center=test.center)
    test.qc_role_assignment = access.create_role_assignment(user=test.inspector, role=test.qc_role, organization_assignment=test.qc_path)
    test.qc_path2 = postings.create_assignment(user=test.inspector2, company=test.company)
    access.create_role_assignment(user=test.inspector2, role=test.qc_role, organization_assignment=test.qc_path2)
    test.case.refresh_from_db()


def pending(test):
    test.case.refresh_from_db()
    test.case = services.submit_for_quality_control(service_case=test.case, inspector=test.inspector)
    return test.case


def begin(test, **kwargs):
    return services.begin_quality_control(**dict(dict(service_case=test.case, inspector=test.inspector), **kwargs))


def check(test, row, code="BOOT", result="PASS", **kwargs):
    row.refresh_from_db()
    return services.set_quality_control_check(**dict(dict(quality_control=row, inspector=test.inspector, check_code=code, result=result), **kwargs))


def complaint_check(test, row, result="RESOLVED", **kwargs):
    row.refresh_from_db()
    return services.set_quality_control_complaint_check(**dict(dict(quality_control=row, inspector=test.inspector, complaint=test.complaint, result=result), **kwargs))


def pass_qc(test, row, **kwargs):
    row.refresh_from_db()
    return services.complete_quality_control_pass(**dict(dict(quality_control=row, inspector=test.inspector), **kwargs))


def fail_qc(test, row, **kwargs):
    row.refresh_from_db()
    return services.complete_quality_control_fail(**dict(dict(quality_control=row, inspector=test.inspector, failure_note="Synthetic failure"), **kwargs))


def abandon(test, row, **kwargs):
    row.refresh_from_db()
    return services.abandon_quality_control(**dict(dict(quality_control=row, actor=test.user, reason="Synthetic interruption"), **kwargs))


def fill(test, row):
    for code, _, _ in CHECKLIST:
        check(test, row, code)
    complaint_check(test, row)
    row.refresh_from_db()
    return row


def prepared(test, *, filled=False):
    pending(test)
    row = begin(test)
    return fill(test, row) if filled else row


def invariants(test):
    for case in ServiceCase.objects.all():
        test.assertEqual(ServiceEngineerAssignment.objects.filter(service_case=case, ended_at=None).count(),
            int(case.status not in ("RECEIVED", "CANCELLED")))
        test.assertEqual(ServiceQualityControl.objects.filter(service_case=case, status="IN_PROGRESS").count(), int(case.status == "QC_IN_PROGRESS"))
        test.assertEqual(ServiceRepairExecution.objects.filter(service_case=case, status="OPEN").count(), int(case.status == "REPAIRING"))
        if case.status == "QC_PASSED":
            test.assertEqual(queries.latest_completed_quality_control(case).outcome, "PASSED")


class QualityControlTests(TestCase):
    def setUp(self):
        setup_qc(self)

    def tearDown(self):
        invariants(self)

    def test_explicit_pending_then_start_captures_repair_and_checklist(self):
        row = prepared(self)
        self.assertIsInstance(row.pk, uuid.UUID)
        self.assertEqual(row.repair_execution, self.execution)
        self.assertEqual(row.inspector, self.inspector)
        self.assertIsNone(row.outcome)
        self.assertTrue(timezone.is_aware(row.started_at))
        checks = queries.quality_control_checks(row)
        self.assertEqual(checks.count(), 21)
        self.assertFalse(checks.exclude(result=None).exists())
        self.assertEqual(queries.quality_control_complaint_checks(row).get().complaint, self.complaint)

    def test_start_requires_explicit_pending(self):
        with self.assertRaises(ValidationError):
            begin(self)
        self.assertFalse(ServiceQualityControl.objects.exists())

    def test_duplicate_begin_rejected(self):
        prepared(self)
        self.case.refresh_from_db()
        with self.assertRaises(ValidationError):
            begin(self)
        self.assertEqual(ServiceQualityControl.objects.count(), 1)

    def test_only_successful_latest_repair_qualifies(self):
        with self.assertRaises(ValidationError), transaction.atomic():
            ServiceRepairExecution.objects.filter(pk=self.execution.pk).update(outcome="NOT_REPAIRED")
            pending(self)

    def test_self_qc_rejected_even_superuser_with_real_qc_posting(self):
        access.create_role_assignment(user=self.engineer, role=self.qc_role, organization_assignment=self.path)
        self.engineer.is_superuser = self.engineer.is_staff = True
        self.engineer.save()
        pending(self)
        with self.assertRaises(ValidationError):
            begin(self, inspector=self.engineer)
        self.assertFalse(queries.qc_cases_for_inspector(self.engineer).exists())

    def test_superuser_without_posting_cannot_inspect(self):
        pending(self)
        self.user.is_superuser = self.user.is_staff = True
        self.user.save()
        with self.assertRaises(ValidationError):
            begin(self, inspector=self.user)

    def test_staff_groups_direct_permissions_do_not_grant_eligibility(self):
        pending(self)
        self.user.is_staff = True
        self.user.save()
        self.user.user_permissions.add(self.qc_permission)
        group = Group.objects.create(name="Synthetic QC group")
        group.permissions.add(self.qc_permission)
        self.user.groups.add(group)
        postings.create_assignment(user=self.user, company=self.company)
        with self.assertRaises(ValidationError):
            begin(self, inspector=self.user)

    def test_inactive_inspector_rejected(self):
        pending(self)
        self.inspector.is_active = False
        self.inspector.save()
        with self.assertRaises(ValidationError):
            begin(self)
        self.assertFalse(queries.qc_cases_for_inspector(self.inspector).exists())

    def test_inactive_posting_rejected(self):
        pending(self)
        postings.deactivate_assignment(assignment=self.qc_path)
        with self.assertRaises(ValidationError):
            begin(self)

    def test_inactive_role_rejected(self):
        pending(self)
        access.deactivate_role(role=self.qc_role)
        with self.assertRaises(ValidationError):
            begin(self)

    def test_unrelated_engineer_permission_not_qc(self):
        pending(self)
        with self.assertRaises(ValidationError):
            begin(self, inspector=self.engineer2)

    def candidate(self, **scope):
        user = get_user_model().objects.create_user(username="candidate-" + str(uuid.uuid4()))
        path = postings.create_assignment(user=user, **scope)
        access.create_role_assignment(user=user, role=self.qc_role, organization_assignment=path)
        return user

    def test_company_region_center_and_center_department_qualify(self):
        department = Department.objects.create(company=self.company, code="QC-DEPT", name="Arbitrary department")
        for scope in (dict(company=self.company), dict(company=self.company, region=self.region),
                      dict(company=self.company, region=self.region, service_center=self.center),
                      dict(company=self.company, region=self.region, service_center=self.center, department=department)):
            user = self.candidate(**scope)
            self.assertTrue(queries.eligible_quality_control_inspectors(self.case).filter(pk=user.pk).exists())

    def test_department_only_and_region_department_do_not_qualify(self):
        department = Department.objects.create(company=self.company, code="QC-DEPT", name="Arbitrary department")
        for scope in (dict(company=self.company, department=department), dict(company=self.company, region=self.region, department=department)):
            user = self.candidate(**scope)
            self.assertFalse(queries.eligible_quality_control_inspectors(self.case).filter(pk=user.pk).exists())

    def test_wrong_company_and_wrong_center_rejected(self):
        pending(self)
        for scope in (dict(company=self.other_company), dict(company=self.company, region=self.region, service_center=self.center2)):
            user = self.candidate(**scope)
            with self.subTest(scope=scope), self.assertRaises(ValidationError):
                begin(self, inspector=user)
            self.assertFalse(queries.qc_cases_for_inspector(user).exists())
            self.assertFalse(queries.quality_control_visible_cases(user).filter(pk=self.case.pk).exists())

    def test_permission_cannot_borrow_scope_from_another_path(self):
        user = self.candidate(company=self.other_company)
        postings.create_assignment(user=user, company=self.company)
        pending(self)
        with self.assertRaises(ValidationError):
            begin(self, inspector=user)

    def test_inactive_company_blocks_start(self):
        pending(self)
        organization.deactivate_company(company=self.company)
        with self.assertRaises(ValidationError):
            begin(self)

    def test_inactive_center_blocks_start(self):
        pending(self)
        organization.deactivate_service_center(service_center=self.center)
        with self.assertRaises(ValidationError):
            begin(self)

    def test_inactive_device_blocks_start(self):
        pending(self)
        devices.deactivate_device(device=self.device)
        with self.assertRaises(ValidationError):
            begin(self)

    def test_inactive_catalog_blocks_completion(self):
        row = prepared(self, filled=True)
        catalog.deactivate_category(category=self.category)
        with self.assertRaises(ValidationError):
            pass_qc(self, row)

    def test_only_responsible_inspector_can_modify(self):
        row = prepared(self)
        for method in (lambda: check(self, row, inspector=self.inspector2),
                       lambda: complaint_check(self, row, inspector=self.inspector2),
                       lambda: pass_qc(self, row, inspector=self.inspector2),
                       lambda: fail_qc(self, row, inspector=self.inspector2)):
            with self.assertRaises(ValidationError):
                method()

    def test_revocation_blocks_each_technical_operation(self):
        row = prepared(self)
        access.deactivate_role_assignment(assignment=self.qc_role_assignment)
        for method in (lambda: check(self, row), lambda: complaint_check(self, row), lambda: pass_qc(self, row), lambda: fail_qc(self, row)):
            with self.assertRaises(ValidationError):
                method()

    def test_unknown_check_and_invalid_result_reject(self):
        row = prepared(self)
        for kwargs in (dict(code="INVENTED"), dict(result="OTHER"), dict(result=None)):
            with self.subTest(kwargs=kwargs), self.assertRaises(ValidationError):
                check(self, row, **kwargs)

    def test_not_applicable_requires_allowed_check_and_reason(self):
        row = prepared(self)
        for kwargs in (dict(code="BOOT", note="not present"), dict(code="SIM", note="  ")):
            with self.subTest(kwargs=kwargs), self.assertRaises(ValidationError):
                check(self, row, result="NOT_APPLICABLE", **kwargs)
        result = check(self, row, code="SIM", result="NOT_APPLICABLE", note="Synthetic device has no SIM hardware")
        self.assertEqual(result.result, "NOT_APPLICABLE")

    def test_unanswered_checks_block_pass(self):
        row = prepared(self)
        with self.assertRaises(ValidationError):
            pass_qc(self, row)

    def test_failed_check_blocks_pass(self):
        row = prepared(self, filled=True)
        check(self, row, result="FAIL")
        with self.assertRaises(ValidationError):
            pass_qc(self, row)

    def test_missing_check_blocks_pass(self):
        row = prepared(self, filled=True)
        # Unsupported corruption is rolled back; public APIs never delete rows.
        with self.assertRaises(ValidationError), transaction.atomic():
            ServiceQualityControlCheck.objects.filter(quality_control=row, check_code="BOOT")._raw_delete("default")
            pass_qc(self, row)

    def test_missing_complaint_verification_blocks_pass(self):
        row = prepared(self)
        for code, _, _ in CHECKLIST:
            check(self, row, code)
        with self.assertRaises(ValidationError):
            pass_qc(self, row)

    def test_unresolved_and_untestable_complaints_block_pass(self):
        row = prepared(self, filled=True)
        for result in ("NOT_RESOLVED", "NOT_TESTABLE"):
            complaint_check(self, row, result)
            with self.subTest(result=result), self.assertRaises(ValidationError):
                pass_qc(self, row)

    def test_missing_complaint_row_blocks_pass(self):
        row = prepared(self, filled=True)
        with self.assertRaises(ValidationError), transaction.atomic():
            ServiceQualityControlComplaintCheck.objects.filter(quality_control=row)._raw_delete("default")
            pass_qc(self, row)

    def test_pass_with_explained_not_applicable_preserves_assignment(self):
        row = prepared(self, filled=True)
        check(self, row, "SIM", "NOT_APPLICABLE", note="No SIM hardware")
        row = pass_qc(self, row, summary=" Synthetic final verification ")
        self.case.refresh_from_db()
        self.assignment.refresh_from_db()
        self.assertEqual(self.case.status, "QC_PASSED")
        self.assertEqual(row.outcome, "PASSED")
        self.assertEqual(row.summary, "Synthetic final verification")
        self.assertIsNone(self.assignment.ended_at)

    def test_fail_requires_note_and_recorded_evidence(self):
        row = prepared(self)
        with self.assertRaises(ValidationError):
            fail_qc(self, row)
        check(self, row, result="FAIL")
        with self.assertRaises(ValidationError):
            fail_qc(self, row, failure_note=" ")

    def test_complaint_failure_sufficient_for_fail(self):
        row = prepared(self)
        complaint_check(self, row, "NOT_TESTABLE")
        completed = fail_qc(self, row)
        self.assertEqual(completed.outcome, "FAILED")

    def test_fail_preserves_repair_diagnosis_and_original_complaint(self):
        before = [model.objects.values().get(pk=obj.pk) for model, obj in
            ((ServiceRepairExecution, self.execution), (ServiceDiagnosticAssessment, self.assessment), (ServiceCaseComplaint, self.complaint))]
        row = prepared(self)
        check(self, row, result="FAIL")
        fail_qc(self, row)
        self.case.refresh_from_db()
        self.assertEqual(self.case.status, "DIAGNOSED")
        after = [model.objects.values().get(pk=obj.pk) for model, obj in
            ((ServiceRepairExecution, self.execution), (ServiceDiagnosticAssessment, self.assessment), (ServiceCaseComplaint, self.complaint))]
        self.assertEqual(before, after)

    def test_three_repair_qc_cycles_preserve_exact_links(self):
        repair_ids = []
        for outcome in ("FAILED", "FAILED", "PASSED"):
            row = prepared(self)
            repair_ids.append(row.repair_execution_id)
            if outcome == "PASSED":
                fill(self, row)
                pass_qc(self, row)
            else:
                check(self, row, result="FAIL")
                fail_qc(self, row)
                new, _ = repair.prepared(self)
                repair.complete(self, new)
        self.assertEqual(len(set(repair_ids)), 3)
        self.assertEqual(list(queries.quality_control_history(self.case).values_list("outcome", flat=True)), ["FAILED", "FAILED", "PASSED"])
        self.assertEqual(queries.failed_quality_controls_for_case(self.case).count(), 2)

    def test_abandon_returns_pending_new_attempt_same_repair(self):
        row = prepared(self)
        check(self, row)
        old = abandon(self, row)
        self.case.refresh_from_db()
        self.assertEqual(self.case.status, "QC_PENDING")
        new = begin(self, inspector=self.inspector2)
        self.assertNotEqual(old.pk, new.pk)
        self.assertEqual(old.repair_execution_id, new.repair_execution_id)
        self.assertEqual(queries.quality_control_checks(old).get(check_code="BOOT").result, "PASS")

    def test_abandon_after_revocation_with_active_recovery_actor(self):
        row = prepared(self)
        access.deactivate_role_assignment(assignment=self.qc_role_assignment)
        abandon(self, row)

    def test_abandon_requires_reason_and_active_actor(self):
        row = prepared(self)
        with self.assertRaises(ValidationError):
            abandon(self, row, reason=" ")
        self.user.is_active = False
        self.user.save()
        with self.assertRaises(ValidationError):
            abandon(self, row)

    def test_cancellation_denied_through_post_repair_and_qc(self):
        for state in ("REPAIRED", "QC_PENDING", "QC_IN_PROGRESS", "QC_PASSED"):
            if state == "QC_PENDING":
                pending(self)
            elif state == "QC_IN_PROGRESS":
                row = begin(self)
            elif state == "QC_PASSED":
                fill(self, row)
                pass_qc(self, row)
            with self.subTest(state=state), self.assertRaises(ValidationError):
                cancel_service_case(service_case=self.case, cancelled_by=self.user)

    def test_failed_qc_rework_can_cancel_and_stale_attempt_cannot_change(self):
        row = prepared(self)
        check(self, row, result="FAIL")
        fail_qc(self, row)
        cancel_service_case(service_case=self.case, cancelled_by=self.user)
        with self.assertRaises(ValidationError):
            check(self, row)
        self.assertEqual(ServiceQualityControl.objects.get().outcome, "FAILED")

    def test_reassignment_unassignment_and_repair_start_reject_during_qc(self):
        prepared(self)
        for method in (lambda: reassign(self), lambda: unassign(self), lambda: repair.begin(self)):
            with self.assertRaises(ValidationError):
                method()

    def test_stale_aggregate_edit_rejects(self):
        row = prepared(self)
        old = row.updated_at
        check(self, row)
        with self.assertRaises(ValidationError):
            services.set_quality_control_check(quality_control=row, inspector=self.inspector, check_code="DISPLAY", result="PASS", expected_updated_at=old)

    def test_stale_pass_after_fail_and_fail_after_pass(self):
        row = prepared(self, filled=True)
        old = row.updated_at
        passed = pass_qc(self, row)
        with self.assertRaises(ValidationError):
            services.complete_quality_control_fail(quality_control=passed, inspector=self.inspector, failure_note="stale", expected_updated_at=old)

    def test_finalized_attempts_and_children_immutable(self):
        row = prepared(self)
        abandon(self, row)
        for method in (lambda: check(self, row), lambda: complaint_check(self, row), lambda: pass_qc(self, row),
                       lambda: fail_qc(self, row), lambda: abandon(self, row)):
            with self.assertRaises(ValidationError):
                method()
        for obj in (row, queries.quality_control_checks(row).first(), queries.quality_control_complaint_checks(row).first()):
            for method in (obj.save, obj.delete, lambda obj=obj: type(obj).objects.filter(pk=obj.pk).delete()):
                with self.assertRaises(ValidationError):
                    method()

    def test_protected_references(self):
        row = prepared(self)
        for obj in (self.inspector, self.execution, self.complaint, row):
            with self.subTest(obj=obj), self.assertRaises(ProtectedError):
                Collector(using="default").collect([obj])

    def test_database_attempt_constraints(self):
        row = prepared(self)
        for changes in ({"status": "OTHER"}, {"outcome": "PASSED"}, {"status": "COMPLETED"}, {"status": "ABANDONED"},
                        {"status": "COMPLETED", "completed_at": timezone.now(), "outcome": "FAILED"},
                        {"status": "COMPLETED", "completed_at": row.started_at - timedelta(seconds=1), "outcome": "PASSED"}):
            with self.subTest(changes=changes), self.assertRaises(IntegrityError), transaction.atomic():
                ServiceQualityControl.objects.filter(pk=row.pk).update(**changes)

    def test_database_one_open_attempt(self):
        prepared(self)
        with self.assertRaises(IntegrityError), transaction.atomic():
            ServiceQualityControl.objects.bulk_create([ServiceQualityControl(service_case=self.case, repair_execution=self.execution, inspector=self.inspector2)])

    def test_database_check_and_complaint_uniqueness(self):
        row = prepared(self)
        for model, kwargs in ((ServiceQualityControlCheck, dict(check_code="BOOT", check_name="Duplicate", sequence=1)),
                              (ServiceQualityControlComplaintCheck, dict(complaint=self.complaint))):
            with self.assertRaises(IntegrityError), transaction.atomic():
                model.objects.bulk_create([model(quality_control=row, **kwargs)])

    def test_database_result_constraints(self):
        row = prepared(self)
        for model in (ServiceQualityControlCheck, ServiceQualityControlComplaintCheck):
            with self.assertRaises(IntegrityError), transaction.atomic():
                model.objects.filter(quality_control=row).update(result="OTHER")
        with self.assertRaises(IntegrityError), transaction.atomic():
            ServiceQualityControlCheck.objects.filter(quality_control=row, check_code="BOOT").update(result="NOT_APPLICABLE", note="invalid")

    def test_pass_rollback_after_attempt_finalized(self):
        row = prepared(self, filled=True)
        before = ServiceQualityControl.objects.values().get(pk=row.pk)
        with patch.object(ServiceCase, "_persist", side_effect=ValidationError("Synthetic late failure")):
            with self.assertRaises(ValidationError):
                pass_qc(self, row)
        self.assertEqual(ServiceQualityControl.objects.values().get(pk=row.pk), before)

    def test_fail_rollback_after_attempt_finalized(self):
        row = prepared(self)
        check(self, row, result="FAIL")
        before = ServiceQualityControl.objects.values().get(pk=row.pk)
        with patch.object(ServiceCase, "_persist", side_effect=ValidationError("Synthetic late failure")):
            with self.assertRaises(ValidationError):
                fail_qc(self, row)
        self.assertEqual(ServiceQualityControl.objects.values().get(pk=row.pk), before)

    def test_queries_lazy_ordered_single_query_related_display(self):
        row = prepared(self)
        with self.assertNumQueries(0):
            history = queries.quality_control_history(self.case)
            checks = queries.quality_control_checks(row)
            complaints = queries.quality_control_complaint_checks(row)
            queue = queries.qc_cases_for_inspector(self.inspector)
        with self.assertNumQueries(1):
            for item in history:
                str(item.service_case), str(item.inspector), str(item.repair_execution.engineer_assignment.engineer)
        with self.assertNumQueries(1):
            for item in checks:
                item.quality_control.status
        with self.assertNumQueries(1):
            for item in complaints:
                str(item.complaint.complaint_symptom), item.quality_control.status
        with self.assertNumQueries(1):
            for case in queue:
                str(case.company), str(case.service_center), str(case.customer), str(case.device)
        self.assertEqual(list(checks.values_list("check_code", flat=True)), [c[0] for c in CHECKLIST])

    def test_queue_no_duplicates_and_current_scope(self):
        pending(self)
        extra = postings.create_assignment(user=self.inspector, company=self.company)
        access.create_role_assignment(user=self.inspector, role=self.qc_role, organization_assignment=extra)
        self.assertEqual(list(queries.qc_pending_cases_for_center(self.center, inspector=self.inspector)), [self.case])
        self.assertFalse(queries.qc_pending_cases_for_center(self.other_center, inspector=self.inspector).exists())
        row = begin(self)
        self.assertFalse(queries.qc_pending_cases_for_center(self.center).exists())
        self.assertEqual(queries.current_quality_control(self.case).pk, row.pk)
        self.assertEqual(list(queries.qc_cases_for_inspector(self.inspector)), [self.case])

    def test_invalid_query_inputs_empty(self):
        self.assertIsNone(queries.current_quality_control(None))
        self.assertIsNone(queries.latest_completed_quality_control(None))
        for rows in (queries.quality_control_history(None), queries.quality_control_checks(None), queries.quality_control_complaint_checks(None),
                     queries.qc_cases_for_inspector(None), queries.qc_pending_cases_for_center(None), queries.eligible_quality_control_inspectors(None)):
            self.assertFalse(rows.exists())
