#!/usr/bin/env python # # Copyright (C) 2016 GNS3 Technologies Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # This will test the conversion from old topology format to the new # # Read tests/topologies/README.rst for documentation import os import json import pytest import shutil from gns3server.controller.topology import load_topology, GNS3_FILE_FORMAT_REVISION from gns3server.version import __version__ topologies_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), "topologies") def topologies(): dirs = [] for directory in os.listdir(topologies_directory): if os.path.isdir(os.path.join(topologies_directory, directory)): dirs.append(directory) return dirs @pytest.mark.parametrize("directory", topologies()) def test_convert(directory, tmpdir): before_directory = os.path.join(topologies_directory, directory, "before") after_directory = os.path.join(topologies_directory, directory, "after") assert os.path.exists(before_directory), "No before directory found file for {}".format(directory) assert os.path.exists(after_directory), "No after directory found file for {}".format(directory) gns3_file = None for file in os.listdir(before_directory): if file.endswith(".gns3"): gns3_file = file assert gns3_file, "No .gns3 found file for {}".format(before_directory) with open(os.path.join(before_directory, gns3_file)) as f: before_topology = json.load(f) # We use a temporary directory for conversion operation to not corrupt our files work_directory = str(tmpdir / "work") shutil.copytree(before_directory, work_directory) work_topology = load_topology(os.path.join(work_directory, gns3_file)) assert work_topology if "revision" not in before_topology or before_topology["revision"] < GNS3_FILE_FORMAT_REVISION: assert os.path.exists(os.path.join(work_directory, gns3_file + ".backup{}".format(before_topology.get("revision", 0)))) # We should have the same file in after directory and the work directory for root, dirs, files in os.walk(after_directory): for file in files: directory = os.path.relpath(root, after_directory) file_path = os.path.join(work_directory, directory, file) assert os.path.exists(file_path), "{} is missing".format(os.path.join(directory, file)) # For gns3project we check if size are not too much differents if file_path.endswith(".gns3project"): size = os.stat(file_path).st_size other_size = os.stat(os.path.join(os.path.join(root, file))).st_size assert size in range(other_size - 100, other_size + 100), "File {} is different".format(os.path.join(directory, file)) # For non .gns3 file we check if the file are the same elif not file_path.endswith(".gns3"): assert os.stat(file_path).st_size == os.stat(os.path.join(os.path.join(root, file))).st_size, "File {} is different".format(os.path.join(directory, file)) # Check if we don't have unexpected file in work directory for root, dirs, files in os.walk(work_directory): for file in files: directory = os.path.relpath(root, work_directory) file_path = os.path.join(after_directory, directory, file) # .backup are created by the conversion process if ".backup" not in file_path: assert os.path.exists(file_path), "{} should not be here".format(os.path.join(directory, file)) with open(os.path.join(after_directory, gns3_file)) as f: after_topology = json.load(f) compare_dict("/", work_topology, after_topology) def compare_dict(path, source, reference): """ Compare two dictionary of a topology """ assert isinstance(source, dict), "Source is not a dict in {}".format(path) for key in source: assert key in reference, "Unexpected {} in {} it should be {}".format(key, source, reference) for key in sorted(reference.keys()): val = reference[key] assert key in source, "{} is missing in {}".format(key, source) if isinstance(val, str) or isinstance(val, float) or isinstance(val, int) or isinstance(val, bool) or val is None: if val == "ANYSTR": pass elif val == "ANYUUID" and len(source[key]) == 36: pass # We test that the revision number has been bumped to last version. This avoid modifying all the tests # at each new revision bump. elif key == "revision": assert source[key] == GNS3_FILE_FORMAT_REVISION elif key == "version": assert source[key] == __version__ else: assert val == source[key], "Wrong value for {}: \n{}\nit should be\n{}".format(key, source[key], val) elif isinstance(val, dict): compare_dict(path + key + "/", source[key], val) elif isinstance(val, list): assert len(val) == len(source[key]), "Not enough value in {} ({}/{}) it shoud be {} not {}".format(key, len(val), len(source[key]), val, source[key]) for idx, element in enumerate(source[key]): if isinstance(element, dict): compare_dict(path + key + "/", element, val[idx]) else: assert element == val[idx] else: assert False, "Value type for {} is not supported".format(key)