-
Notifications
You must be signed in to change notification settings - Fork 48
Test: start a test suite for migration utils functions #8225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
CarolineDenis
wants to merge
91
commits into
v7_12_0_7_base
Choose a base branch
from
issue-8224
base: v7_12_0_7_base
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+4,261
−8
Open
Changes from all commits
Commits
Show all changes
91 commits
Select commit
Hold shift + click to select a range
9a86fe8
Test: start a test suite for migration utils functions
CarolineDenis fe23a15
Merge remote-tracking branch 'origin/issue-8058' into issue-8224
CarolineDenis ea17a32
Test: create seperate test for bulk_create_splocaleitemstr_idempotent
CarolineDenis 3867ead
Test: create tests for schema_writer
CarolineDenis 0a09095
Test: create tests for migration helper 0003r
CarolineDenis a10438b
Test: Fix helper 0003 tests
CarolineDenis 8b86924
Reverts
CarolineDenis bc80a06
Merge remote-tracking branch 'origin/issue-8058' into issue-8224
CarolineDenis 3d76f47
Change schema_Reader tests
CarolineDenis 7950165
Update schema_reader tests
CarolineDenis c14c0f4
Revert
CarolineDenis d5f1dbb
Fix test_bulk_create
CarolineDenis 404bc2e
Fix test_0003 helper
CarolineDenis 6c779a5
Comment
CarolineDenis db7216a
fix: fix mock
CarolineDenis 51ac810
fix: update mock functions
CarolineDenis a8e9662
Refactor: bulk create tests
CarolineDenis 8467571
Refactor: bulk create tests
CarolineDenis 7f8257a
fix: improve schema reader tests
CarolineDenis b2be20a
fix: update schema writer tests
CarolineDenis fcdf255
Refactor: bulk create tests rename kwargs
CarolineDenis 410864a
fix: remove unecessary patch
CarolineDenis c4bc5d0
Test: test assert delete in schema writer
CarolineDenis efabfd6
Merge remote-tracking branch 'origin/issue-8058' into issue-8224
CarolineDenis 49b0371
Test: mock apps
CarolineDenis f85a824
Todo
CarolineDenis 8968e0c
Add test for deduplication
CarolineDenis 17459b3
Add test for default cots
CarolineDenis 9060ef5
fix: add test for tectonic ranks
CarolineDenis 999f8da
fix: add default for selectseries migration
CarolineDenis 4ad3ce5
fix: add tests for run key migration
CarolineDenis 053b06c
fix: Clear cached schema override state between tests
CarolineDenis ffdf85f
fix: Assert call
CarolineDenis d7161ec
fix: Revert run_key_migration chnages
CarolineDenis c3cf4d7
Merge remote-tracking branch 'origin/issue-8058' into issue-8224
CarolineDenis faae90d
Add second test file for run_key_migration_functions
CarolineDenis 8d8622c
Add test suite for select series migration helper 0031
CarolineDenis e8f1eb7
Test: Update test_run_key_migration_functions_2
CarolineDenis 4409b79
Fix: Add decorator
CarolineDenis b6a523e
Fix: Import ApiTest
CarolineDenis a831e7e
Test: Add tests for helper_0039
CarolineDenis 1e95d61
Refactor: Remove unecessary agent-loan-gift test
CarolineDenis 72eaaff
Refactor: Move dedup logic to deduplication file
CarolineDenis ba79e48
Test: Add a new test suite for run key migration indepotency
CarolineDenis 8dbe71b
Fix: Update cots_tests.py
CarolineDenis 06e8f30
Fix: Align expected migration function names
CarolineDenis f7bb933
Fix: assertion
CarolineDenis ec885eb
Fix: fix keeper logic
CarolineDenis 88d3588
Fix: Change tectonic class
CarolineDenis 9d48f36
Fix: Adjust bulk-create assertions
CarolineDenis 59f0ecb
Fix: Renaming wrong migration helper title
CarolineDenis be044b4
Fix: Renaming wrong migration helper title import
CarolineDenis 8202bc1
Test: Add test suite for migration helper 0007
CarolineDenis 42b37a9
Test: Add test suite for migration helper 0017
CarolineDenis 7c8b866
Test: Add test suite for migration helper 0008, 0004, 0012
CarolineDenis b65e892
Test: Add test for helper_0013_collectionobjectgroup_parentcog
CarolineDenis d698e09
Fix: Deduplicate discipline test
CarolineDenis 9630fcb
Test: Skip run_key_migration test
CarolineDenis 0ad2b28
Fix: Fix failing migration tests by initializing required system pick…
CarolineDenis 4b24248
Merge remote-tracking branch 'origin/issue-8058' into issue-8224
CarolineDenis bfeb633
fix: update test_default_cots
CarolineDenis d8748e3
fix: update test_default_cots
CarolineDenis 7a60c83
fix: use database for picklist agetype tests
melton-jason acf8bc8
fix: cogtype picklist test
melton-jason 1bab9ba
Merge branch 'issue-8058' into issue-8224
melton-jason 492a6ff
fix: use all on queryset over manager in test
melton-jason cd4af73
fix: improve previous migration test file
CarolineDenis 206ba5b
Test: Add test suite for migration helper 0020
CarolineDenis a6757ce
Test: Add test suite for migration helper 0024
CarolineDenis d7e6f58
Test: Add test suite for migration helper 0027
CarolineDenis a872096
Test: Add test suite for migration helper 0035
CarolineDenis 38a5f6f
Test: Add test suite for migration helper 0018
CarolineDenis 3d9f34e
Test: Add test suite for migration helper 0021
CarolineDenis 910d73c
Test: Add test suite for migration helper 0021 -2
CarolineDenis b37b179
Test: Add test suite for migration helper 0032
CarolineDenis 3334863
Test: Add test suite for migration helper 0033
CarolineDenis f0d04f9
Test: Add test suite for migration helper 0042
CarolineDenis 8cdc580
fix: remove import
CarolineDenis b077f0d
Test
e7f4071
Test: Add test suite for migration helper_0015
0663b28
Test: Add test suite for migration helper_0023
57f2355
Test: Add test suite for migration helper_0034
7a77b3d
Test: Add test suite for migration helper_0023
2b5a896
Test: Add test suite for migration helper_0040
5b33006
Test: Improve test suite for migration helpers
adcf24d
Test: Fix assert test suite for migration helper_0040
bcebcb3
Test: Add container desc to test suite
6fa769f
Test: Fix age citation test
95aaefe
Test: Improve test_run_key order
68e7fb3
Test: Improve helper test 0042
118e4b3
Test: Assert first run of key migration
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
76 changes: 76 additions & 0 deletions
76
specifyweb/specify/management/commands/tests/app_resource_tests.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| from unittest.mock import Mock, patch, sentinel, call | ||
| from specifyweb.specify.management.commands import run_key_migration_functions as rkm | ||
| from specifyweb.specify.management.commands.tests.test_migration_base import MigrationCommandTestCase | ||
|
|
||
|
|
||
| class AppResourceTests(MigrationCommandTestCase): | ||
| def test_create_missing_app_resource_dirs_writes_summary(self): | ||
| stdout = Mock() | ||
|
|
||
| ensure_dirs_path = ( | ||
| "specifyweb.backend.setup_tool.app_resource_defaults." | ||
| "ensure_all_discipline_resource_dirs" | ||
| ) | ||
| with patch( | ||
| ensure_dirs_path, | ||
| return_value={"total_disciplines": 4, "created": 2, "updated": 1}, | ||
| ) as ensure_dirs: | ||
| rkm.create_missing_app_resource_dirs(stdout, sentinel.apps) | ||
|
|
||
| ensure_dirs.assert_called_once_with() | ||
| stdout.assert_called_once_with( | ||
| "Ensured discipline app resource directories: total=4, created=2, updated=1" | ||
| ) | ||
|
|
||
| def test_create_missing_app_resource_dirs_without_stdout_writes_nothing(self): | ||
| ensure_dirs_path = ( | ||
| "specifyweb.backend.setup_tool.app_resource_defaults." | ||
| "ensure_all_discipline_resource_dirs" | ||
| ) | ||
| with patch( | ||
| ensure_dirs_path, | ||
| return_value={"total_disciplines": 4, "created": 2, "updated": 1}, | ||
| ) as ensure_dirs: | ||
| rkm.create_missing_app_resource_dirs(None, sentinel.apps) | ||
|
|
||
| ensure_dirs.assert_called_once_with() | ||
|
|
||
| def test_fix_app_resource_dirs_runs_creation_then_deduplication(self): | ||
| calls = [] | ||
| stdout = Mock() | ||
|
|
||
| def create_missing_app_resource_dirs(stdout_arg, apps): | ||
| calls.append(("create_missing_app_resource_dirs", stdout_arg, apps)) | ||
|
|
||
| def deduplicate_discipline_resource_dirs(apps): | ||
| calls.append(("deduplicate_discipline_resource_dirs", apps)) | ||
|
|
||
| with ( | ||
| patch.object(rkm, "apps", sentinel.apps), | ||
| patch.object( | ||
| rkm, | ||
| "create_missing_app_resource_dirs", | ||
| create_missing_app_resource_dirs, | ||
| ), | ||
| patch.object( | ||
| rkm, | ||
| "deduplicate_discipline_resource_dirs", | ||
| deduplicate_discipline_resource_dirs, | ||
| ), | ||
| ): | ||
| rkm.fix_app_resource_dirs(stdout) | ||
|
|
||
| self.assertEqual( | ||
| calls, | ||
| [ | ||
| ("create_missing_app_resource_dirs", stdout, sentinel.apps), | ||
| ("deduplicate_discipline_resource_dirs", sentinel.apps), | ||
| ], | ||
| ) | ||
| self.assertEqual( | ||
| stdout.call_args_list, | ||
| [ | ||
| call("Running <lambda>..."), | ||
| call("Running deduplicate_discipline_resource_dirs..."), | ||
| ], | ||
| ) |
105 changes: 105 additions & 0 deletions
105
specifyweb/specify/management/commands/tests/business_rules_tests.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| from unittest.mock import patch | ||
| from types import SimpleNamespace | ||
|
|
||
| from django.apps import apps as django_apps | ||
| from django.test import TestCase | ||
|
|
||
| from specifyweb.backend.businessrules.models import UniquenessRule, UniquenessRuleField | ||
| from specifyweb.specify.models import Discipline | ||
| from specifyweb.specify.management.commands import run_key_migration_functions as rkm | ||
| from specifyweb.specify.management.commands.tests.test_migration_base import MigrationCommandTestCase | ||
|
|
||
|
|
||
| class BusinessRulesMigrationTests(MigrationCommandTestCase): | ||
| def test_fix_business_rules_runs_migrations_in_order(self): | ||
| names = [ | ||
| "apply_default_uniqueness_rules_to_disciplines", | ||
| "catnum_rule_editable", | ||
| "fix_global_default_rules", | ||
| ] | ||
| self._assert_section_calls( | ||
| rkm.fix_business_rules, | ||
| [(rkm, name) for name in names], | ||
| names, | ||
| ) | ||
|
|
||
| def test_apply_default_uniqueness_rules_skips_existing_db_constraints(self): | ||
| discipline_without_constraint = SimpleNamespace(id=1) | ||
| discipline_with_constraint = SimpleNamespace(id=2) | ||
|
|
||
| class FakeDiscipline: | ||
| objects = SimpleNamespace( | ||
| all=lambda: [discipline_without_constraint, discipline_with_constraint] | ||
| ) | ||
|
|
||
| class FakeUniquenessRuleManager: | ||
| def filter(self, discipline, isDatabaseConstraint): | ||
| self.last_is_database_constraint = isDatabaseConstraint | ||
| return SimpleNamespace( | ||
| exists=lambda: discipline is discipline_with_constraint | ||
| ) | ||
|
|
||
| fake_uniqueness_rule_manager = FakeUniquenessRuleManager() | ||
|
|
||
| class FakeUniquenessRule: | ||
| objects = fake_uniqueness_rule_manager | ||
|
|
||
| class FakeApps: | ||
| def get_model(self, app_label, model_name): | ||
| return { | ||
| ("specify", "Discipline"): FakeDiscipline, | ||
| ("businessrules", "UniquenessRule"): FakeUniquenessRule, | ||
| }[(app_label, model_name)] | ||
|
|
||
| fake_apps = FakeApps() | ||
|
|
||
| with patch.object(rkm, "apply_default_uniqueness_rules") as apply_rules: | ||
| rkm.apply_default_uniqueness_rules_to_disciplines(fake_apps) | ||
|
|
||
| apply_rules.assert_called_once_with( | ||
| discipline_without_constraint, | ||
| registry=fake_apps, | ||
| ) | ||
| self.assertIs(fake_uniqueness_rule_manager.last_is_database_constraint, True) | ||
|
|
||
|
|
||
| class BusinessRulesDatabaseTests(TestCase): | ||
| def test_catnum_rule_editable_only_updates_matching_catalog_number_rule(self): | ||
| discipline = Discipline.objects.create(name="Test Discipline") | ||
| matching_rule = UniquenessRule.objects.create( | ||
| modelName="Collectionobject", | ||
| discipline=discipline, | ||
| isDatabaseConstraint=True, | ||
| ) | ||
| UniquenessRuleField.objects.create( | ||
| uniquenessrule=matching_rule, | ||
| fieldPath="catalogNumber", | ||
| isScope=False, | ||
| ) | ||
| UniquenessRuleField.objects.create( | ||
| uniquenessrule=matching_rule, | ||
| fieldPath="collection", | ||
| isScope=True, | ||
| ) | ||
| nonmatching_rule = UniquenessRule.objects.create( | ||
| modelName="Collectionobject", | ||
| discipline=discipline, | ||
| isDatabaseConstraint=True, | ||
| ) | ||
| UniquenessRuleField.objects.create( | ||
| uniquenessrule=nonmatching_rule, | ||
| fieldPath="catalogNumber", | ||
| isScope=False, | ||
| ) | ||
| UniquenessRuleField.objects.create( | ||
| uniquenessrule=nonmatching_rule, | ||
| fieldPath="discipline", | ||
| isScope=True, | ||
| ) | ||
|
|
||
| rkm.catnum_rule_editable(django_apps) | ||
|
|
||
| matching_rule.refresh_from_db() | ||
| nonmatching_rule.refresh_from_db() | ||
| self.assertFalse(matching_rule.isDatabaseConstraint) | ||
| self.assertTrue(nonmatching_rule.isDatabaseConstraint) | ||
66 changes: 66 additions & 0 deletions
66
specifyweb/specify/management/commands/tests/command_tests.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| from io import StringIO | ||
| from unittest.mock import Mock, patch, sentinel | ||
|
|
||
| from specifyweb.specify.management.commands import run_key_migration_functions as rkm | ||
| from specifyweb.specify.management.commands.tests.test_migration_base import MigrationCommandTestCase | ||
|
|
||
|
|
||
| class KeyMigrationCommandTests(MigrationCommandTestCase): | ||
| def test_full_pipeline_dispatches_sections_in_order_with_verbose_stdout(self): | ||
| calls = [] | ||
|
|
||
| def section(name): | ||
| def wrapped(stdout): | ||
| calls.append((name, stdout is not None)) | ||
| return wrapped | ||
|
|
||
| command = self._command() | ||
| command.funcs = {name: section(name) for name in self.section_names} | ||
|
|
||
| command.handle(functions=[], verbose=True) | ||
|
|
||
| self.assertEqual(calls, [(name, True) for name in self.section_names]) | ||
|
|
||
| def test_selected_sections_run_in_requested_order_without_verbose_stdout(self): | ||
| calls = [] | ||
|
|
||
| def section(name): | ||
| def wrapped(stdout): | ||
| calls.append((name, stdout)) | ||
| return wrapped | ||
|
|
||
| command = self._command() | ||
| command.funcs = {name: section(name) for name in self.section_names} | ||
|
|
||
| command.handle( | ||
| functions=["fix_misc", "fix_cots", "fix_permissions"], | ||
| verbose=False, | ||
| ) | ||
|
|
||
| self.assertEqual( | ||
| calls, | ||
| [ | ||
| ("fix_misc", None), | ||
| ("fix_cots", None), | ||
| ("fix_permissions", None), | ||
| ], | ||
| ) | ||
|
|
||
| def test_apply_patches_dispatch_passes_apps_registry_not_stdout(self): | ||
| command = self._command() | ||
|
|
||
| with patch.object(rkm, "apps", sentinel.apps), patch.object(rkm, "apply_patches") as apply_patches: | ||
| command.handle(functions=["apply_patches"], verbose=True) | ||
|
|
||
| apply_patches.assert_called_once_with(sentinel.apps) | ||
|
|
||
| def test_unknown_function_writes_error_and_dispatches_nothing(self): | ||
| stdout = StringIO() | ||
| stderr = StringIO() | ||
| command = rkm.Command(stdout=stdout, stderr=stderr) | ||
| command.funcs = {"known": Mock()} | ||
|
|
||
| command.handle(functions=["unknown"], verbose=True) | ||
|
|
||
| command.funcs["known"].assert_not_called() | ||
| self.assertIn("Unknown function: unknown", stderr.getvalue()) |
94 changes: 94 additions & 0 deletions
94
specifyweb/specify/management/commands/tests/cots_tests.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| from django.apps import apps as django_apps | ||
| from specifyweb.specify import models | ||
| from specifyweb.specify.management.commands import run_key_migration_functions as rkm | ||
| from specifyweb.specify.management.commands.tests.test_migration_base import ( | ||
| MigrationCommandTestCase, | ||
| MigrationDatabaseTestCase, | ||
| ) | ||
|
|
||
| class CotsMigrationTests(MigrationCommandTestCase): | ||
| def test_fix_cots_runs_migrations_in_order(self): | ||
| names = [ | ||
| "create_default_collection_types", | ||
| "create_default_discipline_for_tree_defs", | ||
| "create_cogtype_type_picklist", | ||
| "set_discipline_for_taxon_treedefs", | ||
| "fix_taxon_treedef_discipline_links", | ||
| "create_cotype_picklist" | ||
| ] | ||
|
|
||
| self._assert_section_calls( | ||
| rkm.fix_cots, | ||
| [(rkm, name) for name in names], | ||
| names, | ||
| ) | ||
|
|
||
|
|
||
| class CotsDatabaseTests(MigrationDatabaseTestCase): | ||
| def test_set_discipline_for_taxon_treedefs_uses_collection_discipline(self): | ||
| taxon_tree_def = models.Taxontreedef.objects.create( | ||
| name=f"Unlinked Taxon Tree {self.collection.id}", | ||
| ) | ||
| self.collectionobjecttype.taxontreedef = taxon_tree_def | ||
| self.collectionobjecttype.save() | ||
|
|
||
| rkm.set_discipline_for_taxon_treedefs(django_apps) | ||
|
|
||
| taxon_tree_def.refresh_from_db() | ||
| self.assertEqual(taxon_tree_def.discipline_id, self.discipline.id) | ||
|
|
||
| def test_create_cotype_picklist_creates_readonly_system_picklist_idempotently(self): | ||
| new_collection = models.Collection.objects.create( | ||
| catalognumformatname="test", | ||
| collectionname=f"TestCollection{self.collection.id}", | ||
| isembeddedcollectingevent=False, | ||
| discipline=self.discipline, | ||
| ) | ||
| models.Picklist.objects.filter( | ||
| collection__in=[self.collection, new_collection], | ||
| name="CollectionObjectType", | ||
| ).delete() | ||
|
|
||
| rkm.create_cotype_picklist(django_apps) | ||
| rkm.create_cotype_picklist(django_apps) | ||
|
|
||
| for collection in [self.collection, new_collection]: | ||
| picklists = models.Picklist.objects.filter( | ||
| collection=collection, | ||
| name="CollectionObjectType", | ||
| ) | ||
| self.assertEqual(picklists.count(), 1) | ||
| picklist = picklists.get() | ||
| self.assertTrue(picklist.issystem) | ||
| self.assertTrue(picklist.readonly) | ||
| self.assertEqual(picklist.type, 1) | ||
| self.assertEqual(picklist.tablename, "collectionobjecttype") | ||
| self.assertEqual(picklist.sizelimit, -1) | ||
| self.assertEqual(picklist.sorttype, 1) | ||
| self.assertEqual(picklist.formatter, "CollectionObjectType") | ||
|
|
||
| def test_create_cogtype_type_picklist_creates_default_items_idempotently(self): | ||
| models.Picklist.objects.filter( | ||
| collection=self.collection, | ||
| name="SystemCOGTypes", | ||
| ).delete() | ||
|
|
||
| rkm.create_cogtype_type_picklist(django_apps) | ||
| rkm.create_cogtype_type_picklist(django_apps) | ||
|
|
||
| picklist = models.Picklist.objects.get( | ||
| collection=self.collection, | ||
| name="SystemCOGTypes", | ||
| ) | ||
| self.assertFalse(picklist.issystem) | ||
| self.assertFalse(picklist.readonly) | ||
| self.assertEqual(picklist.type, 0) | ||
| self.assertEqual( | ||
| set(picklist.picklistitems.values_list("title", "value")), | ||
| { | ||
| ("Discrete", "Discrete"), | ||
| ("Consolidated", "Consolidated"), | ||
| ("Drill Core", "Drill Core"), | ||
| }, | ||
| ) | ||
| self.assertEqual(picklist.picklistitems.count(), 3) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: specify/specify7
Length of output: 4331
🏁 Script executed:
Repository: specify/specify7
Length of output: 4291
🏁 Script executed:
Repository: specify/specify7
Length of output: 2063
🏁 Script executed:
Repository: specify/specify7
Length of output: 16030
Populate the required
Disciplinefields here.Disciplinerequiresdivision,datatype,geographytreedef, andgeologictimeperiodtreedef;objects.create(name=...)will fail before this test reachescatnum_rule_editable.🤖 Prompt for AI Agents