def handle(self, *args, **options): # take snapshot snapper = ResourceStateSnapper() snapshot = snapper.take_snapshot() # check whether is first make migrations loader = ResourceMigrationLoader() is_first_make = loader.is_first_make() last_migration = None # check snapshot equality if is not first make if not is_first_make: last_migration = loader.last_migration() reader = ResourceSnapshotReader(last_migration.snapshot_json) last_snapshot = reader.read() differ = SnapshotDiffer(last_snapshot=last_snapshot, snapshot=snapshot) if not differ.has_change(): self.stdout.write("No changes detected") return # write snapshot json and migration py self.write_migration_files(last_migration, snapshot)
def test_diff_operations__init(self): differ = SnapshotDiffer(last_snapshot=None, snapshot=self.snapshot) return_token = 'TOKEN' differ.init_diff_operations = MagicMock(return_value=return_token) operations = differ.diff_operations() differ.init_diff_operations.assert_called_once() self.assertEqual(operations, return_token)
def test_diff_operations__resource_delete(self): new_snapshot = { 'system': [ { "resource_type_name": "资源A", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "编辑", "is_related_resource": True, "action_id": "edit" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "project", "resource_type": "resource_a" }, ], 'business': [ { "resource_type_name": "资源C", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "", "resource_type": "resource_c" }, ] } expect = [{ 'operation': 'delete_resource_type', 'data': { 'scope_type': 'system', 'resource_type': 'resource_b' } }] differ = SnapshotDiffer(last_snapshot=self.snapshot, snapshot=new_snapshot) operations = differ.diff_operations() self.assertEqual(expect, operations)
def forward_func(apps, schema_editor): reader = ResourceSnapshotReader(Migration.snapshot_json) snapshot = reader.read() last_snapshot = None if Migration.dependencies: loader = MigrationLoader(None, ignore_no_migrations=True) last_migration = loader.disk_migrations[Migration.dependencies[0]] last_reader = ResourceSnapshotReader(last_migration.snapshot_json) last_snapshot = last_reader.read() differ = SnapshotDiffer(last_snapshot, snapshot) operations = differ.diff_operations() migration = ResourceMigration.get_migration(operations) migration.apply()
def test_has_change(self): change_differ = SnapshotDiffer(last_snapshot={'a': 1}, snapshot={'a': 2}) no_change_differ = SnapshotDiffer(last_snapshot={'a': 1}, snapshot={'a': 1}) self.assertTrue(change_differ.has_change()) self.assertFalse(no_change_differ.has_change())
def test_init_diff_operations(self): differ = SnapshotDiffer(last_snapshot=None, snapshot=self.snapshot) operations = differ.init_diff_operations() expect = [{ 'data': { 'creator': 'admin', 'desc': '', 'managers': 'admin', 'query_interface': '', 'related_scope_types': 'system', 'system_id': 'bk_sops', 'system_name': '标准运维' }, 'operation': 'register_system' }, { 'data': { 'resource_types': [{ 'actions': [{ 'action_id': 'view', 'action_name': '查看', 'is_related_resource': True }, { 'action_id': 'edit', 'action_name': '编辑', 'is_related_resource': True }, { 'action_id': 'delete', 'action_name': '删除', 'is_related_resource': True }], 'parent_resource_type': 'project', 'resource_type': 'resource_a', 'resource_type_name': '资源A' }, { 'actions': [{ 'action_id': 'view', 'action_name': '查看', 'is_related_resource': True }, { 'action_id': 'delete', 'action_name': '删除', 'is_related_resource': True }], 'parent_resource_type': 'project', 'resource_type': 'resource_b', 'resource_type_name': '资源B' }], 'scope_type': 'system' }, 'operation': 'batch_upsert_resource_types' }, { 'data': { 'resource_types': [{ 'actions': [{ 'action_id': 'view', 'action_name': '查看', 'is_related_resource': True }, { 'action_id': 'delete', 'action_name': '删除', 'is_related_resource': True }], 'parent_resource_type': '', 'resource_type': 'resource_c', 'resource_type_name': '资源C' }], 'scope_type': 'business' }, 'operation': 'batch_upsert_resource_types' }] self.assertEqual(operations, expect)
def test_diff_operations__new_resource(self): new_snapshot = { 'system': [ { "resource_type_name": "资源A", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "编辑", "is_related_resource": True, "action_id": "edit" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "project", "resource_type": "resource_a" }, { "resource_type_name": "资源B", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "project", "resource_type": "resource_b" }, { "resource_type_name": "资源D", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "project", "resource_type": "resource_d" }, ], 'business': [ { "resource_type_name": "资源C", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "", "resource_type": "resource_c" }, { "resource_type_name": "资源E", "actions": [{ "action_name": "查看", "is_related_resource": True, "action_id": "view" }, { "action_name": "删除", "is_related_resource": True, "action_id": "delete" }], "parent_resource_type": "", "resource_type": "resource_e" }, ] } expect = [{ 'data': { 'resource_types': [{ 'actions': [{ 'action_id': 'view', 'action_name': '查看', 'is_related_resource': True }, { 'action_id': 'delete', 'action_name': '删除', 'is_related_resource': True }], 'parent_resource_type': 'project', 'resource_type': 'resource_d', 'resource_type_name': '资源D' }], 'scope_type': 'system' }, 'operation': 'batch_upsert_resource_types' }, { 'data': { 'resource_types': [{ 'actions': [{ 'action_id': 'view', 'action_name': '查看', 'is_related_resource': True }, { 'action_id': 'delete', 'action_name': '删除', 'is_related_resource': True }], 'parent_resource_type': '', 'resource_type': 'resource_e', 'resource_type_name': '资源E' }], 'scope_type': 'business' }, 'operation': 'batch_upsert_resource_types' }] differ = SnapshotDiffer(last_snapshot=self.snapshot, snapshot=new_snapshot) operations = differ.diff_operations() self.assertEqual(expect, operations)
def test_diff_operations__resource_not_change(self): differ = SnapshotDiffer(last_snapshot=self.snapshot, snapshot=self.snapshot) expect = [] operations = differ.diff_operations() self.assertEqual(expect, operations)