def test_upwards_relocation_with_one_level_must_return_expected_result( basic_trees, basic_types): root, new_root = basic_trees new_element = entities.Element(name='Employee', element_type=basic_types['token_type']) # New element was moved from network upwards new_root.add_child(new_element) root.get_child_by_name('Network').add_child(new_element) recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_relocations = [('/Root/Network/Employee', '/Root/Employee')] expected_removals = ['/Root/Network/Employee'] assert result['relocations'] == expected_relocations assert result['removals'] == expected_removals others_empty(result, 'relocations', 'removals')
def test_relocation_with_one_level_must_return_expected_result( basic_trees, basic_types): root, new_root = basic_trees service = new_root.children[3] # Moving Root->Service to Root->Network->Service new_root.children[0].add_child(service) new_root.remove_child(service) recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_relocations = [('/Root/Service', '/Root/Network/Service')] expected_removals = ['/Root/Service'] assert result['relocations'] == expected_relocations assert result['removals'] == expected_removals others_empty(result, 'relocations', 'removals')
def test_simple_mdl_versions_must_return_expected_compare_result( simple_mdl_versions): v17_tree, v19_tree = simple_mdl_versions result = diff.compare(v17_tree, v19_tree) expected_result = { 'additions': [ '/MDLRoot/NetworkDomains/Network/NetworkNode/InternalStructure', '/MDLRoot/NetworkDomains/Domain', '/MDLRoot/IPV4' ], 'relocations': [('/MDLRoot/NetworkDomains/Network/NetworkNode/Routes', '/MDLRoot/NetworkDomains/Network/NetworkNode/InternalStructure/Module/Routes' ), ('/MDLRoot/DatabaseID', '/MDLRoot/NetworkDomains/DatabaseID')], 'removals': sorted([ '/MDLRoot/NetworkDomains/Network/NetworkNode/NetworkName', '/MDLRoot/NetworkDomains/Network/NetworkNode/Routes', '/MDLRoot/DatabaseID', ]), 'renames': [('/MDLRoot/ConfigurationVersion', '/MDLRoot/ConfigVersion')], 'reorders': [ '/MDLRoot/NetworkDomains', '/MDLRoot/NetworkDomains/Network/Description' ] } result['removals'].sort() assert result == expected_result
def test_rename_in_two_different_levels_must_return_expected_operation( basic_trees): root, new_root = basic_trees # Let's remove Root->Network->Person new_root.children[0].children[0].name = 'Person' # Change name of Root->ReadOnly new_root.children[2].name = 'DisableChanges' recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_renames = [ ('/Root/Network/Owner', '/Root/Network/Person'), ('/Root/ReadOnly', '/Root/DisableChanges'), ] # As we are using sets, we need to sort our result to compare it. result['renames'].sort(key=lambda x: x[0]) assert result['renames'] == expected_renames others_empty(result, 'renames')
def test_rename_and_sub_tree_changes_must_return_expected_renames( basic_trees, basic_types): root, new_root = basic_trees # Renaming Network to another name assert new_root.children[0].name == 'Network' new_root.children[0].name = 'NewNetwork' # Inside network, lets change Owner to Person assert new_root.children[0].children[0].name == 'Owner' new_root.children[0].children[0].name = 'Person' recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_renames = [ ('/Root/Network', '/Root/NewNetwork'), ('/Root/Network/Owner', '/Root/Network/Person'), ] # As we are using sets, we need to sort our result to compare it. result['renames'].sort(key=lambda x: x[0]) assert result['renames'] == expected_renames others_empty(result, 'renames')
def test_removal_with_no_changes_must_return_empty(basic_trees): root, new_root = basic_trees result = compare(root, new_root) assert result['removals'] == [] others_empty(result, 'removals')
def test_rename_with_similiar_name_must_return_expected_association( basic_trees, basic_types): root, new_root = basic_trees # Renaming other fields new_root.children[1].name = 'NewOwner' new_root.children[3].name = 'ServiceNew' # Two new fields with same type but different names to be used in renames root_name = entities.Element(name='Name', element_type=basic_types['token_type']) root_foo = entities.Element(name='Foo', element_type=basic_types['token_type']) root_operation = entities.Element(name='Operation', element_type=basic_types['token_type']) new_root_name = entities.Element(name='NewName', element_type=basic_types['token_type']) new_root_foo = entities.Element(name='Bar', element_type=basic_types['token_type']) new_root_operation = entities.Element( name='OperationNew', element_type=basic_types['token_type']) root.add_child(root_name) root.add_child(root_foo) root.add_child(root_operation) new_root.add_child(new_root_name) new_root.add_child(new_root_foo) new_root.add_child(new_root_operation) recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_renames = [ ('/Root/Foo', '/Root/Bar'), ('/Root/Name', '/Root/NewName'), ('/Root/Operation', '/Root/OperationNew'), ('/Root/Owner', '/Root/NewOwner'), ('/Root/Service', '/Root/ServiceNew'), ] # As we are using sets, we need to sort our result to compare it. result['renames'].sort(key=lambda x: x[0]) assert result['renames'] == expected_renames others_empty(result, 'renames')
def test_full_mdl_versions_must_has_no_intersections_between_additions_and_removals( full_mdl_versions): v17_tree, v19_tree = full_mdl_versions result = diff.compare(v17_tree, v19_tree) # Checking if we have some item in more than one operation additions_set = set(result['additions']) removals_set = set(result['removals']) intersect = additions_set & removals_set assert len(intersect) == 0
def test_generate_xslt_with_simple_example_must_add_a_new_target_namespace(simple_versions, shared_datadir): first_result, second_result = simple_versions first_tree = first_result['element'] second_tree = second_result['element'] compare_result = compare(first_tree, second_tree) xslt = generate_xslt(first_tree, second_tree, compare_result, first_result['namespaces'], 'MDL19.xsd') assert '<xsl:template match="/mdl:MDLRoot/@xsi:schemaLocation">' in xslt relocation = ('<xsl:attribute name="xsi:schemaLocation">' 'http://inetprogram.org/projects/MDL MDL19.xsd</xsl:attribute>') assert relocation in xslt
def test_reorder_with_only_order_changes(basic_trees, basic_types): root, new_root = basic_trees network = new_root.get_child_by_name('Network') network.element_type.children = list(reversed(network.children)) recalculate_hashes(new_root) recalculate_hashes(root) result = compare(root, new_root) expected_reorder = ['/Root/Network'] assert result['reorders'] == expected_reorder others_empty(result, 'reorders')
def test_generate_xslt_with_full_example(full_versions, shared_datadir): first_result, second_result = full_versions first_tree = first_result['element'] second_tree = second_result['element'] compare_result = compare(first_tree, second_tree) xslt = generate_xslt(first_tree, second_tree, compare_result, first_result['namespaces'], 'MDL19.xsd') with open(shared_datadir / 'MDL_17_x_19_result.xslt', 'r') as mdl_result: xslt_expected = mdl_result.read() xslt = xslt.strip() xslt_expected = xslt_expected.strip() assert xslt == xslt_expected
def test_imediate_circular_dependency_rename_must_return_expected_result( basic_trees, basic_types): root, new_root = basic_trees # Circular dependency of network just inside network root_network = root.get_child_by_name('Network') root_network.add_child(root_network) # Add a new module node inside network of our ORIGINAL tree root_module_type = entities.ElementType( name='ModuleType', children=[ entities.Element(name='Owner', element_type=basic_types['token_type']), ]) root_network.add_child( entities.Element(name='Module', element_type=root_module_type)) # Add a new module node inside network of our NEW tree module_type = entities.ElementType( name='ModuleType', children=[ entities.Element(name='Name', element_type=basic_types['token_type']), ]) network = new_root.get_child_by_name('Network') # Adding a circular dependency network.add_child(network) network.add_child(entities.Element(name='Module', element_type=module_type)) recalculate_hashes(new_root) recalculate_hashes(root) result = compare(root, new_root) expected_renames = [('/Root/Network/Module/Owner', '/Root/Network/Module/Name')] assert result['renames'] == expected_renames others_empty(result, 'renames')
def test_full_mdl_versions_must_return_expected_compare_result( full_mdl_versions): v17_tree, v19_tree = full_mdl_versions result = diff.compare(v17_tree, v19_tree) expected_keys = { 'renames', 'additions', 'relocations', 'removals', 'reorders' } current_keys = set(result.keys()) assert current_keys == expected_keys assert len(result['additions']) == 59 assert len(result['removals']) == 68 assert len(result['relocations']) == 59 assert len(result['renames']) == 4 assert len(result['reorders']) == 0
def test_additions_in_two_levels_must_return_expected_operation( basic_trees, basic_types): root, new_root = basic_trees enabled = entities.Element(name='Enabled', element_type=basic_types['boolean_type']) new_root.children[0].add_child(enabled) recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_additions = ['/Root/Network/Enabled'] assert result['additions'] == expected_additions others_empty(result, 'additions')
def test_rename_with_one_level_must_return_expected_operation(basic_trees): root, new_root = basic_trees # Change name of network node to Net new_root.children[0].name = 'Net' recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_renames = [ ('/Root/Network', '/Root/Net'), ] assert result['renames'] == expected_renames others_empty(result, 'renames')
def test_rename_with_two_levels_must_return_expected_operation(basic_trees): root, new_root = basic_trees # Let's remove Root->Network->Person new_root.children[0].children[0].name = 'Person' recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_renames = [ ('/Root/Network/Owner', '/Root/Network/Person'), ] assert result['renames'] == expected_renames others_empty(result, 'renames')
def test_relocation_with_new_sub_element_must_return_expected_result( basic_trees, basic_types): root, new_root = basic_trees # Moving Root->Service to new node Root->Module->Service service = new_root.children[3] new_root.remove_child(service) module_children = [ entities.Element(name='Owner', element_type=basic_types['token_type']), service ] module_type = entities.ElementType(name='ModuleType', children=module_children) module = entities.Element(name='Module', element_type=module_type) new_root.add_child(module) recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_relocations = [('/Root/Service', '/Root/Module/Service')] expected_additions = ['/Root/Module'] expected_removals = ['/Root/Service'] assert result['relocations'] == expected_relocations assert result['additions'] == expected_additions assert result['removals'] == expected_removals others_empty(result, 'relocations', 'additions', 'removals')
def test_removal_with_one_level(basic_trees): root, new_root = basic_trees # Let's remove RootType->Owner children = new_root.element_type.children del children[1] new_root.element_type.children = children recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_removals = [ '/Root/Owner', ] assert result['removals'] == expected_removals others_empty(result, 'removals')
def test_removal_two_levels(basic_trees): root, new_root = basic_trees # Let's remove RootType->Network->Owner network = new_root.get_child_by_name('Network') del network.children[0] network.element_type.children = network.children recalculate_hashes(new_root) recalculate_hashes(root) # Now, they must be different assert root != new_root result = compare(root, new_root) expected_removals = [ '/Root/Network/Owner', ] assert result['removals'] == expected_removals others_empty(result, 'removals')
def test_circular_dependency_rename_tag_must_return_expected_result( basic_trees, basic_types): root, new_root = basic_trees network = new_root.children[0] # Rename Root->Network->ReadOnly attr network.children[1].name = 'OnlyRead' module_children = [ entities.Element(name='Owner', element_type=basic_types['token_type']), network # Adding a ciclic dependency here ] module_type = entities.ElementType(name='ModuleType', children=module_children) module = entities.Element(name='Module', element_type=module_type) network.add_child(module) recalculate_hashes(new_root) recalculate_hashes(root) expected_renames = [ ('/Root/Network/ReadOnly', '/Root/Network/OnlyRead'), ] expected_additions = [ '/Root/Network/Module', ] result = compare(root, new_root) assert result['renames'] == expected_renames assert result['additions'] == expected_additions others_empty(result, 'renames', 'additions')
def get_xslt(): if not request.is_json: return jsonify({ 'error': 'Bad Request, json expected', 'xslt': '' }), 400 data = request.get_json() if 'srcSchema' not in data: return jsonify({ 'error': 'Bad Request, "srcSchema" expected', 'xslt': '' }), 400 if 'dstSchema' not in data: return jsonify({ 'error': 'Bad Request, "dstSchema" expected', 'xslt': '' }), 400 if 'documents' not in data['srcSchema']: return jsonify({ 'error': 'Bad Request, "srcSchema/documents" expected', 'xslt': '' }), 400 if 'documents' not in data['dstSchema']: return jsonify({ 'error': 'Bad Request, "dstSchema/documents" expected', 'xslt': '' }), 400 if len(data['srcSchema']['documents']) == 0: return jsonify({ 'error': 'Bad Request, expected at least one document', 'xslt': '' }), 400 if len(data['dstSchema']['documents']) == 0: return jsonify({ 'error': 'Bad Request, expected at least one document', 'xslt': '' }), 400 repo_src = _build_repository(data['srcSchema']['documents']) repo_dst = _build_repository(data['dstSchema']['documents']) src_result = repo_src.get_main_element() dst_result = repo_dst.get_main_element() if not src_result: return jsonify({ 'error': 'Bad Request, expected at least one document as primary in "srcSchema"', 'xslt': '' }), 400 if not dst_result: return jsonify({ 'error': 'Bad Request, expected at least one document as primary in "dstSchema"', 'xslt': '' }), 400 src_element = src_result['element'] dst_element = dst_result['element'] recalculate_hashes(src_element) recalculate_hashes(dst_element) compare_result = compare(src_element, dst_element) xslt = generate_xslt(src_element, dst_element, compare_result, src_result['namespaces'], dst_result['location']) # TODO old_field_count = None new_field_count = None unchanged_count = None typerenamed_count = None graph_similar = None add_graph_similar = None similar_doc = None # TODO (handle nodes in additions and removals) removed_count = len(compare_result['removals']) added_count = len(compare_result['additions']) relocations = len(compare_result['relocations']) reorders = len(compare_result['reorders']) renamed_count = len(compare_result['renames']) return jsonify({ 'xslt': xslt, 'translationMetrics': { 'oldFieldCount': old_field_count, 'newFieldCount': new_field_count, 'removedFields': removed_count, 'addedFields': added_count, 'reorders': reorders, 'renamedFields': renamed_count, 'relocatedFields': relocations, 'renamedTypes': typerenamed_count, 'percentMapped': None # TODO } })