gns3-server/tests/test_topologies.py

150 lines
6.1 KiB
Python

#!/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 <http://www.gnu.org/licenses/>.
#
# This will test the conversion from old topology format to the new
#
# Read tests/topologies/README.rst for documentation
import json
import os
import shutil
import pytest
from gns3server.controller.topology import GNS3_FILE_FORMAT_REVISION, load_topology
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), f"No before directory found file for {directory}"
assert os.path.exists(after_directory), f"No after directory found file for {directory}"
gns3_file = None
for file in os.listdir(before_directory):
if file.endswith(".gns3"):
gns3_file = file
assert gns3_file, f"No .gns3 found file for {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), f"{os.path.join(directory, file)} is missing"
# 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), (
f"File {os.path.join(directory, file)} is different"
)
# 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, (
f"File {os.path.join(directory, file)} is different"
)
# 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), f"{os.path.join(directory, file)} should not be here"
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), f"Source is not a dict in {path}"
for key in source:
assert key in reference, f"Unexpected {key} in {source} it should be {reference}"
for key in sorted(reference.keys()):
val = reference[key]
assert key in source, f"{key} is missing in {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], f"Wrong value for {key}: \n{source[key]}\nit should be\n{val}"
elif isinstance(val, dict):
compare_dict(path + key + "/", source[key], val)
elif isinstance(val, list):
assert len(val) == len(source[key]), (
f"Not enough value in {key} ({len(val)}/{len(source[key])}) it shoud be {val} not {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, f"Value type for {key} is not supported"