From a33387cdfd0dd47ee958ca59cb57b9c1f40575d2 Mon Sep 17 00:00:00 2001 From: sauravsapkota Date: Thu, 1 Aug 2024 11:08:26 +0545 Subject: [PATCH 1/4] Add test case for update AssessmentRegistry --- apps/assessment_registry/mutation.py | 2 +- .../tests/snapshots/__init__.py | 0 .../tests/snapshots/snap_test_mutation.py | 196 ++++++++++ .../tests/test_mutation.py | 352 +++++++++++++++++- schema.graphql | 2 +- 5 files changed, 548 insertions(+), 4 deletions(-) create mode 100644 apps/assessment_registry/tests/snapshots/__init__.py create mode 100644 apps/assessment_registry/tests/snapshots/snap_test_mutation.py diff --git a/apps/assessment_registry/mutation.py b/apps/assessment_registry/mutation.py index 27077ad5e9..7884293ddd 100644 --- a/apps/assessment_registry/mutation.py +++ b/apps/assessment_registry/mutation.py @@ -57,7 +57,7 @@ class Arguments: class UpdateAssessmentRegistry(AssessmentRegsitryMutationMixin, PsGrapheneMutation): class Arguments: data = AssessmentRegistryCreateInputType(required=True) - id = graphene.ID(required=False) + id = graphene.ID(required=True) result = graphene.Field(AssessmentRegistryType) serializer_class = AssessmentRegistrySerializer diff --git a/apps/assessment_registry/tests/snapshots/__init__.py b/apps/assessment_registry/tests/snapshots/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/assessment_registry/tests/snapshots/snap_test_mutation.py b/apps/assessment_registry/tests/snapshots/snap_test_mutation.py new file mode 100644 index 0000000000..9a35b862f0 --- /dev/null +++ b/apps/assessment_registry/tests/snapshots/snap_test_mutation.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +# snapshottest: v1 - https://goo.gl/zC4yUc +from __future__ import unicode_literals + +from snapshottest import Snapshot + + +snapshots = Snapshot() + +snapshots['TestAnalysisMutationSnapShotTestCase::test_assessment_registry_update error'] = { + 'data': { + 'project': { + 'updateAssessmentRegistry': { + 'errors': None, + 'ok': True, + 'result': { + 'additionalDocumentComplete': True, + 'additionalDocuments': [ + ], + 'affectedGroups': [ + 'ALL_AFFECTED' + ], + 'bgCountries': [ + { + 'id': '1' + } + ], + 'bgCrisisStartDate': '2019-07-03', + 'bgCrisisType': 'LANDSLIDE', + 'bgPreparedness': 'WITHOUT_PREPAREDNESS', + 'cna': [ + ], + 'cnaComplete': True, + 'confidentiality': 'CONFIDENTIAL', + 'confidentialityDisplay': 'Confidential', + 'coordinatedJoint': 'HARMONIZED', + 'coordinatedJointDisplay': 'Coordinated - Harmonized', + 'costEstimatesUsd': 0, + 'createdAt': '2021-01-01T00:00:00.123456+00:00', + 'dataCollectionEndDate': '2020-09-06', + 'dataCollectionStartDate': '2021-06-21', + 'dataCollectionTechniques': '''Current hear claim well two truth out major. Upon these story film. Drive note bad rule. +She campaign little near enter their institution. Up sense ready require human.''', + 'detailsType': 'MONITORING', + 'detailsTypeDisplay': 'Monitoring', + 'externalSupport': 'NO_EXTERNAL_SUPPORT_RECEIVED', + 'externalSupportDisplay': 'No external support received', + 'family': 'HUMANITARIAN_NEEDS_OVERVIEW', + 'familyDisplay': 'Humanitarian Needs Overview (HNO)', + 'focusComplete': True, + 'focuses': [ + 'CONTEXT', + 'HUMANITERIAN_ACCESS', + 'DISPLACEMENT' + ], + 'frequency': 'REGULAR', + 'frequencyDisplay': 'Regular', + 'id': '1', + 'language': [ + 'ENGLISH', + 'FRENCH' + ], + 'lead': { + 'id': '2' + }, + 'limitations': '''Choice father why often my security arm. Live try most arm meet surface attention attack. Identify walk now often always. +Price north first end prove fire. How public feel first sell.''', + 'metadataComplete': True, + 'methodologyAttributes': [ + ], + 'methodologyComplete': True, + 'modifiedAt': '2021-01-01T00:00:00.123456+00:00', + 'noOfPages': 0, + 'objectives': '''Then fire pretty how trip learn enter. Seat much section investment on. +Young catch management sense technology. Physical society instead as. Other life edge network wall quite.''', + 'protectionInfoMgmts': [ + 'PROTECTION_MONITORING' + ], + 'protectionRisks': [ + ], + 'publicationDate': '2020-02-16', + 'sampling': '''Best issue interest level. Pull worker better. +Song body court movie cell contain. Economic type kitchen technology nearly anything yourself. Why unit support.''', + 'sectors': [ + 'HEALTH', + 'SHELTER', + 'WASH' + ], + 'status': 'ONGOING', + 'summaryComplete': True, + 'summaryDimensionMeta': [ + ], + 'summaryPillarMeta': None, + 'summarySubDimensionIssue': [ + ], + 'summarySubPillarIssue': [ + ] + } + } + } + } +} + +snapshots['TestAnalysisMutationSnapShotTestCase::test_assessment_registry_update success'] = { + 'data': { + 'project': { + 'updateAssessmentRegistry': { + 'errors': None, + 'ok': True, + 'result': { + 'additionalDocumentComplete': True, + 'additionalDocuments': [ + ], + 'affectedGroups': [ + 'ALL_AFFECTED' + ], + 'bgCountries': [ + { + 'id': '1' + } + ], + 'bgCrisisStartDate': '2019-07-03', + 'bgCrisisType': 'LANDSLIDE', + 'bgPreparedness': 'WITHOUT_PREPAREDNESS', + 'cna': [ + ], + 'cnaComplete': True, + 'confidentiality': 'CONFIDENTIAL', + 'confidentialityDisplay': 'Confidential', + 'coordinatedJoint': 'HARMONIZED', + 'coordinatedJointDisplay': 'Coordinated - Harmonized', + 'costEstimatesUsd': 0, + 'createdAt': '2021-01-01T00:00:00.123456+00:00', + 'dataCollectionEndDate': '2020-09-06', + 'dataCollectionStartDate': '2021-06-21', + 'dataCollectionTechniques': '''Current hear claim well two truth out major. Upon these story film. Drive note bad rule. +She campaign little near enter their institution. Up sense ready require human.''', + 'detailsType': 'MONITORING', + 'detailsTypeDisplay': 'Monitoring', + 'externalSupport': 'NO_EXTERNAL_SUPPORT_RECEIVED', + 'externalSupportDisplay': 'No external support received', + 'family': 'HUMANITARIAN_NEEDS_OVERVIEW', + 'familyDisplay': 'Humanitarian Needs Overview (HNO)', + 'focusComplete': True, + 'focuses': [ + 'CONTEXT', + 'HUMANITERIAN_ACCESS', + 'DISPLACEMENT' + ], + 'frequency': 'REGULAR', + 'frequencyDisplay': 'Regular', + 'id': '1', + 'language': [ + 'ENGLISH', + 'FRENCH' + ], + 'lead': { + 'id': '2' + }, + 'limitations': '''Choice father why often my security arm. Live try most arm meet surface attention attack. Identify walk now often always. +Price north first end prove fire. How public feel first sell.''', + 'metadataComplete': True, + 'methodologyAttributes': [ + ], + 'methodologyComplete': True, + 'modifiedAt': '2021-01-01T00:00:00.123456+00:00', + 'noOfPages': 0, + 'objectives': '''Then fire pretty how trip learn enter. Seat much section investment on. +Young catch management sense technology. Physical society instead as. Other life edge network wall quite.''', + 'protectionInfoMgmts': [ + 'PROTECTION_MONITORING' + ], + 'protectionRisks': [ + ], + 'publicationDate': '2020-02-16', + 'sampling': '''Best issue interest level. Pull worker better. +Song body court movie cell contain. Economic type kitchen technology nearly anything yourself. Why unit support.''', + 'sectors': [ + 'HEALTH', + 'SHELTER', + 'WASH' + ], + 'status': 'ONGOING', + 'summaryComplete': True, + 'summaryDimensionMeta': [ + ], + 'summaryPillarMeta': None, + 'summarySubDimensionIssue': [ + ], + 'summarySubPillarIssue': [ + ] + } + } + } + } +} diff --git a/apps/assessment_registry/tests/test_mutation.py b/apps/assessment_registry/tests/test_mutation.py index 64eff90bde..c0069a7ddd 100644 --- a/apps/assessment_registry/tests/test_mutation.py +++ b/apps/assessment_registry/tests/test_mutation.py @@ -1,4 +1,4 @@ -from utils.graphene.tests import GraphQLTestCase +from utils.graphene.tests import GraphQLTestCase, GraphQLSnapShotTestCase from organization.factories import OrganizationFactory from geo.factories import GeoAreaFactory, AdminLevelFactory, RegionFactory @@ -7,6 +7,7 @@ from user.factories import UserFactory from lead.factories import LeadFactory from assessment_registry.factories import ( + AssessmentRegistryFactory, QuestionFactory, SummaryIssueFactory, ) @@ -123,12 +124,44 @@ class TestAssessmentRegistryMutation(GraphQLTestCase): } } ''' + UPDATE_ASSESSMENT_REGISTRY_QUERY = ''' + mutation MyMutation ($projectId: ID!, $input: AssessmentRegistryCreateInputType!, $assessmentRegistryId: ID!) { + project(id: $projectId) { + updateAssessmentRegistry(data: $input, id: $assessmentRegistryId) { + ok + errors + result { + id + bgPreparedness + bgCountries { + id + } + bgCrisisType + confidentiality + coordinatedJoint + detailsType + externalSupport + family + frequency + language + status + lead { + id + } + } + } + } + } +''' def setUp(self): super().setUp() + # Users with different roles + self.non_member_user = UserFactory.create() + self.readonly_member_user = UserFactory.create() self.member_user = UserFactory.create() self.project1 = ProjectFactory.create() - self.lead1 = LeadFactory.create(project=self.project1) + self.lead1, self.lead2, self.lead3 = LeadFactory.create_batch(3, project=self.project1) self.organization1 = OrganizationFactory.create() self.organization2 = OrganizationFactory.create() self.region = RegionFactory.create() @@ -141,8 +174,27 @@ def setUp(self): question="test question" ) self.file = FileFactory.create() + self.project1.add_member(self.readonly_member_user, role=self.project_role_reader) self.project1.add_member(self.member_user, role=self.project_role_member) self.summary_issue1, self.summary_issue2, self.summary_issue3 = SummaryIssueFactory.create_batch(3) + self.assessment_registry = AssessmentRegistryFactory.create( + project=self.project1, + lead=self.lead3, + bg_crisis_type=AssessmentRegistry.CrisisType.EARTH_QUAKE, + bg_preparedness=AssessmentRegistry.PreparednessType.WITH_PREPAREDNESS, + confidentiality=AssessmentRegistry.ConfidentialityType.UNPROTECTED, + coordinated_joint=AssessmentRegistry.CoordinationType.COORDINATED, + status=AssessmentRegistry.StatusType.PLANNED, + details_type=AssessmentRegistry.Type.INITIAL, + external_support=AssessmentRegistry.ExternalSupportType.EXTERNAL_SUPPORT_RECIEVED, + family=AssessmentRegistry.FamilyType.DISPLACEMENT_TRAKING_MATRIX, + frequency=AssessmentRegistry.FrequencyType.ONE_OFF, + language=[ + AssessmentRegistry.Language.ENGLISH, + AssessmentRegistry.Language.SPANISH, + ], + bg_countries=[self.region.id], + ) def test_create_assessment_registry(self): def _query_check(minput, **kwargs): @@ -296,3 +348,299 @@ def _query_check(minput, **kwargs): self.assertIsNotNone(data['summarySubDimensionIssue']) self.assertEqual(data['metadataComplete'], True) self.assertIsNotNone(data['protectionRisks']) + + def test_update_assessment_registry(self): + def _query_check(mutation, minput, variables, assert_for_error=False, **kwargs): + return self.query_check( + mutation, + minput=minput, + variables=variables, + assert_for_error=assert_for_error, + **kwargs + ) + + update_minput = dict( + bgCrisisType=self.genum(AssessmentRegistry.CrisisType.LANDSLIDE), + bgPreparedness=self.genum(AssessmentRegistry.PreparednessType.WITHOUT_PREPAREDNESS), + confidentiality=self.genum(AssessmentRegistry.ConfidentialityType.CONFIDENTIAL), + coordinatedJoint=self.genum(AssessmentRegistry.CoordinationType.HARMONIZED), + status=self.genum(AssessmentRegistry.StatusType.ONGOING), + detailsType=self.genum(AssessmentRegistry.Type.MONITORING), + externalSupport=self.genum(AssessmentRegistry.ExternalSupportType.NO_EXTERNAL_SUPPORT_RECEIVED), + family=self.genum(AssessmentRegistry.FamilyType.HUMANITARIAN_NEEDS_OVERVIEW), + frequency=self.genum(AssessmentRegistry.FrequencyType.REGULAR), + lead=self.lead2.id, + language=[ + self.genum(AssessmentRegistry.Language.ENGLISH), + self.genum(AssessmentRegistry.Language.FRENCH) + ], + bgCountries=[self.region.id], + ) + # -- Without login + _query_check( + self.UPDATE_ASSESSMENT_REGISTRY_QUERY, + update_minput, + variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, + assert_for_error=True, + okay=False + ) + + user_roles = [self.non_member_user, self.readonly_member_user] + for user in user_roles: + self.force_login(user) + _query_check( + self.UPDATE_ASSESSMENT_REGISTRY_QUERY, + update_minput, + variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, + assert_for_error=True, + okay=False + ) + + # --- member user + self.force_login(self.member_user) + content = _query_check( + self.UPDATE_ASSESSMENT_REGISTRY_QUERY, + update_minput, + variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, + okay=False + ) + data = content['data']['project']['updateAssessmentRegistry']['result'] + self.assertEqual(data['id'], str(self.assessment_registry.id)) + self.assertEqual(data['bgCrisisType'], update_minput['bgCrisisType']) + self.assertEqual(data['bgPreparedness'], update_minput['bgPreparedness']) + self.assertEqual(data['confidentiality'], update_minput['confidentiality']) + self.assertEqual(data['coordinatedJoint'], update_minput['coordinatedJoint']) + self.assertEqual(data['status'], update_minput['status']) + self.assertEqual(data['detailsType'], update_minput['detailsType']) + self.assertEqual(data['externalSupport'], update_minput['externalSupport']) + self.assertEqual(data['family'], update_minput['family']) + self.assertEqual(data['frequency'], update_minput['frequency']) + self.assertEqual(data['lead']['id'], str(update_minput['lead'])) + self.assertEqual(data['language'], update_minput['language']) + self.assertEqual(data['bgCountries'][0]['id'], str(update_minput['bgCountries'][0])) + + +class TestAnalysisMutationSnapShotTestCase(GraphQLSnapShotTestCase): + UPDATE_ASSESSMENT_REGISTRY_QUERY = ''' + mutation MyMutation( + $projectId: ID!, + $input: AssessmentRegistryCreateInputType!, + $assessmentRegistryId: ID! + ) { + project(id: $projectId) { + updateAssessmentRegistry(data: $input, id: $assessmentRegistryId) { + ok + errors + result { + id + affectedGroups + bgPreparedness + bgCountries { + id + } + bgCrisisStartDate + bgCrisisType + confidentiality + confidentialityDisplay + coordinatedJoint + coordinatedJointDisplay + costEstimatesUsd + createdAt + dataCollectionEndDate + dataCollectionStartDate + dataCollectionTechniques + detailsType + detailsTypeDisplay + externalSupport + externalSupportDisplay + family + familyDisplay + metadataComplete + focuses + frequency + frequencyDisplay + language + limitations + modifiedAt + noOfPages + objectives + protectionInfoMgmts + protectionRisks + publicationDate + sampling + sectors + status + focusComplete + lead { + id + } + methodologyAttributes { + unitOfReportingDisplay + unitOfReporting + unitOfAnalysis + unitOfAnalysisDisplay + samplingApproach + samplingAppraochDisplay + proximity + proximityDisplay + id + dataCollectionTechniqueDisplay + dataCollectionTechnique + } + methodologyComplete + additionalDocuments { + documentType + documentTypeDisplay + externalLink + id + file { + id + mimeType + metadata + } + } + additionalDocumentComplete + cna { + answer + id + question { + id + question + sector + subSector + sectorDisplay + subSectorDisplay + } + } + cnaComplete + summaryDimensionMeta { + id + percentageInNeed + } + summarySubDimensionIssue { + id + } + summaryPillarMeta { + id + totalPeopleAssessed + } + summarySubPillarIssue { + id + } + summaryComplete + } + } + } + } + ''' + + def setUp(self): + super().setUp() + # Users with different roles + self.non_member_user, self.readonly_member_user, self.member_user = UserFactory.create_batch(3) + self.project1 = ProjectFactory.create() + # leads + self.lead1, self.lead2 = LeadFactory.create_batch(2, project=self.project1) + # organizations + self.organization1, self.organization2 = OrganizationFactory.create_batch(2) + # region + self.region = RegionFactory.create() + self.admin_level1 = AdminLevelFactory.create(region=self.region) + # geo_areas + self.geo_area1, self.geo_area2 = GeoAreaFactory.create_batch(2, admin_level=self.admin_level1) + self.question1 = QuestionFactory.create( + sector=Question.QuestionSector.RELEVANCE.value, + sub_sector=Question.QuestionSubSector.RELEVANCE.value, + question="test question" + ) + self.file = FileFactory.create() + self.project1.add_member(self.readonly_member_user, role=self.project_role_reader) + self.project1.add_member(self.member_user, role=self.project_role_member) + self.summary_issue1, self.summary_issue2, self.summary_issue3 = SummaryIssueFactory.create_batch(3) + self.assessment_registry = AssessmentRegistryFactory.create( + project=self.project1, + lead=self.lead1, + bg_crisis_type=AssessmentRegistry.CrisisType.EARTH_QUAKE, + bg_preparedness=AssessmentRegistry.PreparednessType.WITH_PREPAREDNESS, + confidentiality=AssessmentRegistry.ConfidentialityType.UNPROTECTED, + coordinated_joint=AssessmentRegistry.CoordinationType.COORDINATED, + status=AssessmentRegistry.StatusType.PLANNED, + details_type=AssessmentRegistry.Type.INITIAL, + external_support=AssessmentRegistry.ExternalSupportType.EXTERNAL_SUPPORT_RECIEVED, + family=AssessmentRegistry.FamilyType.DISPLACEMENT_TRAKING_MATRIX, + frequency=AssessmentRegistry.FrequencyType.ONE_OFF, + language=[ + AssessmentRegistry.Language.ENGLISH, + AssessmentRegistry.Language.SPANISH, + ], + bg_countries=[self.region.id], + metadata_complete=True, + additional_document_complete=True, + focus_complete=True, + methodology_complete=True, + summary_complete=True, + cna_complete=True, + score_complete=True, + focuses=[ + AssessmentRegistry.FocusType.CONTEXT, + AssessmentRegistry.FocusType.HUMANITERIAN_ACCESS, + AssessmentRegistry.FocusType.DISPLACEMENT + ], + sectors=[ + AssessmentRegistry.SectorType.HEALTH, + AssessmentRegistry.SectorType.SHELTER, + AssessmentRegistry.SectorType.WASH, + ], + protection_info_mgmts=[AssessmentRegistry.ProtectionInfoType.PROTECTION_MONITORING], + affected_groups=[AssessmentRegistry.AffectedGroupType.ALL_AFFECTED], + ) + self.m_input = dict( + bgCrisisType=self.genum(AssessmentRegistry.CrisisType.LANDSLIDE), + bgPreparedness=self.genum(AssessmentRegistry.PreparednessType.WITHOUT_PREPAREDNESS), + confidentiality=self.genum(AssessmentRegistry.ConfidentialityType.CONFIDENTIAL), + coordinatedJoint=self.genum(AssessmentRegistry.CoordinationType.HARMONIZED), + status=self.genum(AssessmentRegistry.StatusType.ONGOING), + detailsType=self.genum(AssessmentRegistry.Type.MONITORING), + externalSupport=self.genum(AssessmentRegistry.ExternalSupportType.NO_EXTERNAL_SUPPORT_RECEIVED), + family=self.genum(AssessmentRegistry.FamilyType.HUMANITARIAN_NEEDS_OVERVIEW), + frequency=self.genum(AssessmentRegistry.FrequencyType.REGULAR), + lead=self.lead2.id, + language=[ + self.genum(AssessmentRegistry.Language.ENGLISH), + self.genum(AssessmentRegistry.Language.FRENCH) + ], + bgCountries=[self.region.id], + ) + + def test_assessment_registry_update(self): + """ + This test makes sure only valid users can update AssessmentRegistry + """ + def _query_check(**kwargs): + return self.query_check( + self.UPDATE_ASSESSMENT_REGISTRY_QUERY, + minput=self.m_input, + variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, + **kwargs + ) + + # -- Without login + _query_check(assert_for_error=True) + + # -- With login (non-member) + self.force_login(self.non_member_user) + _query_check(assert_for_error=True) + + # --- member user (read-only) + self.force_login(self.readonly_member_user) + _query_check(assert_for_error=True) + + # --- member user + # Invalid input + self.force_login(self.member_user) + response = _query_check(okay=False) + self.assertMatchSnapshot(response, 'error') + + # Valid input + response = _query_check() + self.assertMatchSnapshot(response, 'success') diff --git a/schema.graphql b/schema.graphql index b69efbdeba..d9bcc791c0 100644 --- a/schema.graphql +++ b/schema.graphql @@ -5457,7 +5457,7 @@ type ProjectMutationType { id: ID! title: String! createAssessmentRegistry(data: AssessmentRegistryCreateInputType!): CreateAssessmentRegistry - updateAssessmentRegistry(data: AssessmentRegistryCreateInputType!, id: ID): UpdateAssessmentRegistry + updateAssessmentRegistry(data: AssessmentRegistryCreateInputType!, id: ID!): UpdateAssessmentRegistry deleteAssessmentRegistry(id: ID!): DeleteAssessmentRegistry analysisPillarUpdate(data: AnalysisPillarUpdateInputType!, id: ID!): UpdateAnalysisPillar discardedEntryCreate(data: DiscardedEntryCreateInputType!): CreateAnalysisPillarDiscardedEntry From 070726e6d1339f6c638ea286fe57bae6afd2d61e Mon Sep 17 00:00:00 2001 From: sauravsapkota Date: Mon, 5 Aug 2024 17:50:30 +0545 Subject: [PATCH 2/4] Change docker-compose to docker compose diff --git a/README.md b/README.md index 2ff399cc5..8e09211e4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Add this to your `.git/hooks/pre-commit` to generate latest graphql schema befor #!/bin/sh echo "pre-commit: Generating graphql schema." -if [ -z `docker ps -q --no-trunc | grep $(docker-compose ps -q web)` ]; then +if [ -z `docker ps -q --no-trunc | grep $(docker compose ps -q web)` ]; then docker compose run --rm web ./manage.py graphql_schema --out schema.graphql else docker compose exec -T web ./manage.py graphql_schema --out schema.graphql --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ff399cc57..8e09211e49 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Add this to your `.git/hooks/pre-commit` to generate latest graphql schema befor #!/bin/sh echo "pre-commit: Generating graphql schema." -if [ -z `docker ps -q --no-trunc | grep $(docker-compose ps -q web)` ]; then +if [ -z `docker ps -q --no-trunc | grep $(docker compose ps -q web)` ]; then docker compose run --rm web ./manage.py graphql_schema --out schema.graphql else docker compose exec -T web ./manage.py graphql_schema --out schema.graphql From c68f9d1cd11b162219b0b75ac98f7b1f663678f7 Mon Sep 17 00:00:00 2001 From: sauravsapkota Date: Tue, 6 Aug 2024 12:20:18 +0545 Subject: [PATCH 3/4] Add test case for update AssessmentRegistry using SnapShotTextCase --- apps/assessment_registry/factories.py | 8 + apps/assessment_registry/serializers.py | 5 + .../tests/snapshots/snap_test_mutation.py | 166 +++++------ .../tests/test_mutation.py | 276 +++++++++--------- 4 files changed, 222 insertions(+), 233 deletions(-) diff --git a/apps/assessment_registry/factories.py b/apps/assessment_registry/factories.py index d0d00c6107..f2dbc0d991 100644 --- a/apps/assessment_registry/factories.py +++ b/apps/assessment_registry/factories.py @@ -10,6 +10,7 @@ Question, Answer, AssessmentRegistry, + AssessmentRegistryOrganization, MethodologyAttribute, AdditionalDocument, ScoreRating, @@ -215,3 +216,10 @@ def bg_countries(self, create, extracted, **_): self.bg_countries.add( # pyright: ignore [reportGeneralTypeIssues] country ) + + +class AssessmentRegistryOrganizationFactory(DjangoModelFactory): + organization_type = fuzzy.FuzzyChoice(_choices(AssessmentRegistryOrganization.Type)) + + class Meta: + model = AssessmentRegistryOrganization diff --git a/apps/assessment_registry/serializers.py b/apps/assessment_registry/serializers.py index f8cfeb17a0..cd676fba61 100644 --- a/apps/assessment_registry/serializers.py +++ b/apps/assessment_registry/serializers.py @@ -278,6 +278,11 @@ def validate_cna(self, data): raise serializers.ValidationError('Dublicate question selected') question_list.append(question) + def validate_lead(self, lead): + if lead.project != self.project: + raise serializers.ValidationError('Only Source from current Project are allowed') + return lead + def validate(self, data): data['project'] = self.project return data diff --git a/apps/assessment_registry/tests/snapshots/snap_test_mutation.py b/apps/assessment_registry/tests/snapshots/snap_test_mutation.py index 9a35b862f0..baca8c0f2d 100644 --- a/apps/assessment_registry/tests/snapshots/snap_test_mutation.py +++ b/apps/assessment_registry/tests/snapshots/snap_test_mutation.py @@ -7,101 +7,79 @@ snapshots = Snapshot() -snapshots['TestAnalysisMutationSnapShotTestCase::test_assessment_registry_update error'] = { +snapshots['TestAssessmentRegistryMutationSnapShotTestCase::test_assessment_registry_update error'] = { 'data': { 'project': { 'updateAssessmentRegistry': { - 'errors': None, - 'ok': True, - 'result': { - 'additionalDocumentComplete': True, - 'additionalDocuments': [ - ], - 'affectedGroups': [ - 'ALL_AFFECTED' - ], - 'bgCountries': [ - { - 'id': '1' - } - ], - 'bgCrisisStartDate': '2019-07-03', - 'bgCrisisType': 'LANDSLIDE', - 'bgPreparedness': 'WITHOUT_PREPAREDNESS', - 'cna': [ - ], - 'cnaComplete': True, - 'confidentiality': 'CONFIDENTIAL', - 'confidentialityDisplay': 'Confidential', - 'coordinatedJoint': 'HARMONIZED', - 'coordinatedJointDisplay': 'Coordinated - Harmonized', - 'costEstimatesUsd': 0, - 'createdAt': '2021-01-01T00:00:00.123456+00:00', - 'dataCollectionEndDate': '2020-09-06', - 'dataCollectionStartDate': '2021-06-21', - 'dataCollectionTechniques': '''Current hear claim well two truth out major. Upon these story film. Drive note bad rule. -She campaign little near enter their institution. Up sense ready require human.''', - 'detailsType': 'MONITORING', - 'detailsTypeDisplay': 'Monitoring', - 'externalSupport': 'NO_EXTERNAL_SUPPORT_RECEIVED', - 'externalSupportDisplay': 'No external support received', - 'family': 'HUMANITARIAN_NEEDS_OVERVIEW', - 'familyDisplay': 'Humanitarian Needs Overview (HNO)', - 'focusComplete': True, - 'focuses': [ - 'CONTEXT', - 'HUMANITERIAN_ACCESS', - 'DISPLACEMENT' - ], - 'frequency': 'REGULAR', - 'frequencyDisplay': 'Regular', - 'id': '1', - 'language': [ - 'ENGLISH', - 'FRENCH' - ], - 'lead': { - 'id': '2' + 'errors': [ + { + 'arrayErrors': None, + 'clientId': None, + 'field': 'lead', + 'messages': 'Only Source from current Project are allowed', + 'objectErrors': None }, - 'limitations': '''Choice father why often my security arm. Live try most arm meet surface attention attack. Identify walk now often always. -Price north first end prove fire. How public feel first sell.''', - 'metadataComplete': True, - 'methodologyAttributes': [ - ], - 'methodologyComplete': True, - 'modifiedAt': '2021-01-01T00:00:00.123456+00:00', - 'noOfPages': 0, - 'objectives': '''Then fire pretty how trip learn enter. Seat much section investment on. -Young catch management sense technology. Physical society instead as. Other life edge network wall quite.''', - 'protectionInfoMgmts': [ - 'PROTECTION_MONITORING' - ], - 'protectionRisks': [ - ], - 'publicationDate': '2020-02-16', - 'sampling': '''Best issue interest level. Pull worker better. -Song body court movie cell contain. Economic type kitchen technology nearly anything yourself. Why unit support.''', - 'sectors': [ - 'HEALTH', - 'SHELTER', - 'WASH' - ], - 'status': 'ONGOING', - 'summaryComplete': True, - 'summaryDimensionMeta': [ - ], - 'summaryPillarMeta': None, - 'summarySubDimensionIssue': [ - ], - 'summarySubPillarIssue': [ - ] - } + { + 'arrayErrors': [ + { + 'clientId': 'nonMemberErrors', + 'messages': 'Dublicate organization selected', + 'objectErrors': None + } + ], + 'clientId': None, + 'field': 'stakeholders', + 'messages': None, + 'objectErrors': None + }, + { + 'arrayErrors': [ + { + 'clientId': 'nonMemberErrors', + 'messages': 'Score ratings should have unique score types', + 'objectErrors': None + } + ], + 'clientId': None, + 'field': 'scoreRatings', + 'messages': None, + 'objectErrors': None + }, + { + 'arrayErrors': [ + { + 'clientId': 'nonMemberErrors', + 'messages': 'Score analytical density should have unique sectors', + 'objectErrors': None + } + ], + 'clientId': None, + 'field': 'scoreAnalyticalDensity', + 'messages': None, + 'objectErrors': None + }, + { + 'arrayErrors': [ + { + 'clientId': 'nonMemberErrors', + 'messages': 'Dublicate question selected', + 'objectErrors': None + } + ], + 'clientId': None, + 'field': 'cna', + 'messages': None, + 'objectErrors': None + } + ], + 'ok': False, + 'result': None } } } } -snapshots['TestAnalysisMutationSnapShotTestCase::test_assessment_registry_update success'] = { +snapshots['TestAssessmentRegistryMutationSnapShotTestCase::test_assessment_registry_update success'] = { 'data': { 'project': { 'updateAssessmentRegistry': { @@ -123,6 +101,18 @@ 'bgCrisisType': 'LANDSLIDE', 'bgPreparedness': 'WITHOUT_PREPAREDNESS', 'cna': [ + { + 'answer': True, + 'id': '1', + 'question': { + 'id': '1', + 'question': 'test question', + 'sector': 'RELEVANCE', + 'sectorDisplay': 'Relevance', + 'subSector': 'RELEVANCE', + 'subSectorDisplay': 'Relevance' + } + } ], 'cnaComplete': True, 'confidentiality': 'CONFIDENTIAL', @@ -132,7 +122,7 @@ 'costEstimatesUsd': 0, 'createdAt': '2021-01-01T00:00:00.123456+00:00', 'dataCollectionEndDate': '2020-09-06', - 'dataCollectionStartDate': '2021-06-21', + 'dataCollectionStartDate': '2020-02-16', 'dataCollectionTechniques': '''Current hear claim well two truth out major. Upon these story film. Drive note bad rule. She campaign little near enter their institution. Up sense ready require human.''', 'detailsType': 'MONITORING', @@ -172,7 +162,7 @@ ], 'protectionRisks': [ ], - 'publicationDate': '2020-02-16', + 'publicationDate': '2021-06-21', 'sampling': '''Best issue interest level. Pull worker better. Song body court movie cell contain. Economic type kitchen technology nearly anything yourself. Why unit support.''', 'sectors': [ diff --git a/apps/assessment_registry/tests/test_mutation.py b/apps/assessment_registry/tests/test_mutation.py index c0069a7ddd..e31d256c3e 100644 --- a/apps/assessment_registry/tests/test_mutation.py +++ b/apps/assessment_registry/tests/test_mutation.py @@ -4,15 +4,18 @@ from geo.factories import GeoAreaFactory, AdminLevelFactory, RegionFactory from gallery.factories import FileFactory from project.factories import ProjectFactory +from project.models import ProjectOrganization from user.factories import UserFactory from lead.factories import LeadFactory from assessment_registry.factories import ( AssessmentRegistryFactory, + AssessmentRegistryOrganizationFactory, QuestionFactory, SummaryIssueFactory, ) from assessment_registry.models import ( AssessmentRegistry, + AssessmentRegistryOrganization, MethodologyAttribute, AdditionalDocument, ScoreRating, @@ -124,44 +127,12 @@ class TestAssessmentRegistryMutation(GraphQLTestCase): } } ''' - UPDATE_ASSESSMENT_REGISTRY_QUERY = ''' - mutation MyMutation ($projectId: ID!, $input: AssessmentRegistryCreateInputType!, $assessmentRegistryId: ID!) { - project(id: $projectId) { - updateAssessmentRegistry(data: $input, id: $assessmentRegistryId) { - ok - errors - result { - id - bgPreparedness - bgCountries { - id - } - bgCrisisType - confidentiality - coordinatedJoint - detailsType - externalSupport - family - frequency - language - status - lead { - id - } - } - } - } - } -''' def setUp(self): super().setUp() - # Users with different roles - self.non_member_user = UserFactory.create() - self.readonly_member_user = UserFactory.create() self.member_user = UserFactory.create() self.project1 = ProjectFactory.create() - self.lead1, self.lead2, self.lead3 = LeadFactory.create_batch(3, project=self.project1) + self.lead1 = LeadFactory.create(project=self.project1) self.organization1 = OrganizationFactory.create() self.organization2 = OrganizationFactory.create() self.region = RegionFactory.create() @@ -174,27 +145,8 @@ def setUp(self): question="test question" ) self.file = FileFactory.create() - self.project1.add_member(self.readonly_member_user, role=self.project_role_reader) self.project1.add_member(self.member_user, role=self.project_role_member) self.summary_issue1, self.summary_issue2, self.summary_issue3 = SummaryIssueFactory.create_batch(3) - self.assessment_registry = AssessmentRegistryFactory.create( - project=self.project1, - lead=self.lead3, - bg_crisis_type=AssessmentRegistry.CrisisType.EARTH_QUAKE, - bg_preparedness=AssessmentRegistry.PreparednessType.WITH_PREPAREDNESS, - confidentiality=AssessmentRegistry.ConfidentialityType.UNPROTECTED, - coordinated_joint=AssessmentRegistry.CoordinationType.COORDINATED, - status=AssessmentRegistry.StatusType.PLANNED, - details_type=AssessmentRegistry.Type.INITIAL, - external_support=AssessmentRegistry.ExternalSupportType.EXTERNAL_SUPPORT_RECIEVED, - family=AssessmentRegistry.FamilyType.DISPLACEMENT_TRAKING_MATRIX, - frequency=AssessmentRegistry.FrequencyType.ONE_OFF, - language=[ - AssessmentRegistry.Language.ENGLISH, - AssessmentRegistry.Language.SPANISH, - ], - bg_countries=[self.region.id], - ) def test_create_assessment_registry(self): def _query_check(minput, **kwargs): @@ -349,78 +301,8 @@ def _query_check(minput, **kwargs): self.assertEqual(data['metadataComplete'], True) self.assertIsNotNone(data['protectionRisks']) - def test_update_assessment_registry(self): - def _query_check(mutation, minput, variables, assert_for_error=False, **kwargs): - return self.query_check( - mutation, - minput=minput, - variables=variables, - assert_for_error=assert_for_error, - **kwargs - ) - update_minput = dict( - bgCrisisType=self.genum(AssessmentRegistry.CrisisType.LANDSLIDE), - bgPreparedness=self.genum(AssessmentRegistry.PreparednessType.WITHOUT_PREPAREDNESS), - confidentiality=self.genum(AssessmentRegistry.ConfidentialityType.CONFIDENTIAL), - coordinatedJoint=self.genum(AssessmentRegistry.CoordinationType.HARMONIZED), - status=self.genum(AssessmentRegistry.StatusType.ONGOING), - detailsType=self.genum(AssessmentRegistry.Type.MONITORING), - externalSupport=self.genum(AssessmentRegistry.ExternalSupportType.NO_EXTERNAL_SUPPORT_RECEIVED), - family=self.genum(AssessmentRegistry.FamilyType.HUMANITARIAN_NEEDS_OVERVIEW), - frequency=self.genum(AssessmentRegistry.FrequencyType.REGULAR), - lead=self.lead2.id, - language=[ - self.genum(AssessmentRegistry.Language.ENGLISH), - self.genum(AssessmentRegistry.Language.FRENCH) - ], - bgCountries=[self.region.id], - ) - # -- Without login - _query_check( - self.UPDATE_ASSESSMENT_REGISTRY_QUERY, - update_minput, - variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, - assert_for_error=True, - okay=False - ) - - user_roles = [self.non_member_user, self.readonly_member_user] - for user in user_roles: - self.force_login(user) - _query_check( - self.UPDATE_ASSESSMENT_REGISTRY_QUERY, - update_minput, - variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, - assert_for_error=True, - okay=False - ) - - # --- member user - self.force_login(self.member_user) - content = _query_check( - self.UPDATE_ASSESSMENT_REGISTRY_QUERY, - update_minput, - variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, - okay=False - ) - data = content['data']['project']['updateAssessmentRegistry']['result'] - self.assertEqual(data['id'], str(self.assessment_registry.id)) - self.assertEqual(data['bgCrisisType'], update_minput['bgCrisisType']) - self.assertEqual(data['bgPreparedness'], update_minput['bgPreparedness']) - self.assertEqual(data['confidentiality'], update_minput['confidentiality']) - self.assertEqual(data['coordinatedJoint'], update_minput['coordinatedJoint']) - self.assertEqual(data['status'], update_minput['status']) - self.assertEqual(data['detailsType'], update_minput['detailsType']) - self.assertEqual(data['externalSupport'], update_minput['externalSupport']) - self.assertEqual(data['family'], update_minput['family']) - self.assertEqual(data['frequency'], update_minput['frequency']) - self.assertEqual(data['lead']['id'], str(update_minput['lead'])) - self.assertEqual(data['language'], update_minput['language']) - self.assertEqual(data['bgCountries'][0]['id'], str(update_minput['bgCountries'][0])) - - -class TestAnalysisMutationSnapShotTestCase(GraphQLSnapShotTestCase): +class TestAssessmentRegistryMutationSnapShotTestCase(GraphQLSnapShotTestCase): UPDATE_ASSESSMENT_REGISTRY_QUERY = ''' mutation MyMutation( $projectId: ID!, @@ -538,27 +420,23 @@ def setUp(self): super().setUp() # Users with different roles self.non_member_user, self.readonly_member_user, self.member_user = UserFactory.create_batch(3) - self.project1 = ProjectFactory.create() + self.project = ProjectFactory.create() # leads - self.lead1, self.lead2 = LeadFactory.create_batch(2, project=self.project1) + self.lead1, self.lead2 = LeadFactory.create_batch(2, project=self.project) + self.lead3 = LeadFactory.create() # organizations self.organization1, self.organization2 = OrganizationFactory.create_batch(2) # region self.region = RegionFactory.create() - self.admin_level1 = AdminLevelFactory.create(region=self.region) - # geo_areas - self.geo_area1, self.geo_area2 = GeoAreaFactory.create_batch(2, admin_level=self.admin_level1) - self.question1 = QuestionFactory.create( + self.question = QuestionFactory.create( sector=Question.QuestionSector.RELEVANCE.value, sub_sector=Question.QuestionSubSector.RELEVANCE.value, question="test question" ) - self.file = FileFactory.create() - self.project1.add_member(self.readonly_member_user, role=self.project_role_reader) - self.project1.add_member(self.member_user, role=self.project_role_member) - self.summary_issue1, self.summary_issue2, self.summary_issue3 = SummaryIssueFactory.create_batch(3) + self.project.add_member(self.readonly_member_user, role=self.project_role_reader) + self.project.add_member(self.member_user, role=self.project_role_member) self.assessment_registry = AssessmentRegistryFactory.create( - project=self.project1, + project=self.project, lead=self.lead1, bg_crisis_type=AssessmentRegistry.CrisisType.EARTH_QUAKE, bg_preparedness=AssessmentRegistry.PreparednessType.WITH_PREPAREDNESS, @@ -581,6 +459,10 @@ def setUp(self): summary_complete=True, cna_complete=True, score_complete=True, + bg_crisis_start_date='2019-07-03', + data_collection_start_date='2020-02-16', + data_collection_end_date='2020-09-06', + publication_date='2021-06-21', focuses=[ AssessmentRegistry.FocusType.CONTEXT, AssessmentRegistry.FocusType.HUMANITERIAN_ACCESS, @@ -594,7 +476,12 @@ def setUp(self): protection_info_mgmts=[AssessmentRegistry.ProtectionInfoType.PROTECTION_MONITORING], affected_groups=[AssessmentRegistry.AffectedGroupType.ALL_AFFECTED], ) - self.m_input = dict( + self.stakeholders = AssessmentRegistryOrganizationFactory.create( + organization_type=AssessmentRegistryOrganization.Type.LEAD_ORGANIZATION, + organization=self.organization1, + assessment_registry=self.assessment_registry + ) + self.minput = dict( bgCrisisType=self.genum(AssessmentRegistry.CrisisType.LANDSLIDE), bgPreparedness=self.genum(AssessmentRegistry.PreparednessType.WITHOUT_PREPAREDNESS), confidentiality=self.genum(AssessmentRegistry.ConfidentialityType.CONFIDENTIAL), @@ -610,37 +497,136 @@ def setUp(self): self.genum(AssessmentRegistry.Language.FRENCH) ], bgCountries=[self.region.id], + scoreRatings=[ + dict( + scoreType=self.genum(ScoreRating.ScoreCriteria.ASSUMPTIONS), + rating=self.genum(ScoreRating.RatingType.VERY_POOR), + reason="test" + ), + dict( + scoreType=self.genum(ScoreRating.ScoreCriteria.RELEVANCE), + rating=self.genum(ScoreRating.RatingType.VERY_POOR), + reason="test" + ) + ], + scoreAnalyticalDensity=[ + dict( + sector=self.genum(AssessmentRegistry.SectorType.FOOD_SECURITY), + analysisLevelCovered=[ + self.genum(ScoreAnalyticalDensity.AnalysisLevelCovered.ISSUE_UNMET_NEEDS_ARE_DETAILED), + self.genum(ScoreAnalyticalDensity.AnalysisLevelCovered.ISSUE_UNMET_NEEDS_ARE_PRIORITIZED_RANKED), + ], + figureProvided=[ + self.genum(ScoreAnalyticalDensity.FigureProvidedByAssessment.TOTAL_POP_IN_THE_ASSESSED_AREAS), + ], + score=1, + ), + dict( + sector=self.genum(AssessmentRegistry.SectorType.SHELTER), + analysisLevelCovered=[], + score=2 + ) + ], + stakeholders=[ + dict( + organization=self.stakeholders.id, + organizationType=self.genum(ProjectOrganization.Type.LEAD_ORGANIZATION), + ), + dict( + organization=self.stakeholders.id, + organizationType=self.genum(ProjectOrganization.Type.INTERNATIONAL_PARTNER), + ), + ], + cna=[ + dict( + answer=True, + question=self.question.id, + ) + ], ) def test_assessment_registry_update(self): """ This test makes sure only valid users can update AssessmentRegistry """ - def _query_check(**kwargs): + def _query_check(minput, **kwargs): return self.query_check( self.UPDATE_ASSESSMENT_REGISTRY_QUERY, - minput=self.m_input, - variables={'projectId': self.project1.id, 'assessmentRegistryId': self.assessment_registry.id}, + minput=minput, + variables={'projectId': self.project.id, 'assessmentRegistryId': self.assessment_registry.id}, **kwargs ) # -- Without login - _query_check(assert_for_error=True) + _query_check(self.minput, assert_for_error=True) # -- With login (non-member) self.force_login(self.non_member_user) - _query_check(assert_for_error=True) + _query_check(self.minput, assert_for_error=True) # --- member user (read-only) self.force_login(self.readonly_member_user) - _query_check(assert_for_error=True) + _query_check(self.minput, assert_for_error=True) # --- member user - # Invalid input self.force_login(self.member_user) - response = _query_check(okay=False) - self.assertMatchSnapshot(response, 'error') # Valid input - response = _query_check() + response = _query_check(self.minput) self.assertMatchSnapshot(response, 'success') + + # Invalid inputs + self.minput['scoreRatings'] = [ + dict( + scoreType=self.genum(ScoreRating.ScoreCriteria.ASSUMPTIONS), + rating=self.genum(ScoreRating.RatingType.VERY_POOR), + reason="test" + ), + dict( + scoreType=self.genum(ScoreRating.ScoreCriteria.ASSUMPTIONS), + rating=self.genum(ScoreRating.RatingType.VERY_POOR), + reason="test" + ) + ] + self.minput['scoreAnalyticalDensity'] = [ + dict( + sector=self.genum(AssessmentRegistry.SectorType.FOOD_SECURITY), + analysisLevelCovered=[ + self.genum(ScoreAnalyticalDensity.AnalysisLevelCovered.ISSUE_UNMET_NEEDS_ARE_DETAILED), + self.genum(ScoreAnalyticalDensity.AnalysisLevelCovered.ISSUE_UNMET_NEEDS_ARE_PRIORITIZED_RANKED), + ], + figureProvided=[ + self.genum(ScoreAnalyticalDensity.FigureProvidedByAssessment.TOTAL_POP_IN_THE_ASSESSED_AREAS), + ], + score=1, + ), + dict( + sector=self.genum(AssessmentRegistry.SectorType.FOOD_SECURITY), + analysisLevelCovered=[], + score=1, + ) + ] + self.minput['stakeholders'] = [ + dict( + organization=self.stakeholders.id, + organizationType=self.genum(ProjectOrganization.Type.LEAD_ORGANIZATION), + ), + dict( + organization=self.stakeholders.id, + organizationType=self.genum(ProjectOrganization.Type.LEAD_ORGANIZATION), + ), + ] + self.minput['cna'] = [ + dict( + answer=True, + question=self.question.id, + ), + dict( + answer=True, + question=self.question.id, + ), + ] + self.minput['lead'] = self.lead3.id + + response = _query_check(self.minput, okay=False) + self.assertMatchSnapshot(response, "error") From 78bc43864118297d124002c9eb1bfec8150ccff2 Mon Sep 17 00:00:00 2001 From: thenav56 Date: Wed, 21 Aug 2024 10:49:08 +0545 Subject: [PATCH 4/4] Use lead.project_id instead of lead.project --- apps/assessment_registry/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/assessment_registry/serializers.py b/apps/assessment_registry/serializers.py index cd676fba61..6b486eff48 100644 --- a/apps/assessment_registry/serializers.py +++ b/apps/assessment_registry/serializers.py @@ -279,7 +279,7 @@ def validate_cna(self, data): question_list.append(question) def validate_lead(self, lead): - if lead.project != self.project: + if lead.project_id != self.project.id: raise serializers.ValidationError('Only Source from current Project are allowed') return lead