21Test suite for the ns3 wrapper script
31from functools
import partial
34ns3_path = os.path.dirname(os.path.abspath(os.sep.join([__file__,
"../../"])))
35ns3_lock_filename = os.path.join(ns3_path,
".lock-ns3_%s_build" % sys.platform)
36ns3_script = os.sep.join([ns3_path,
"ns3"])
37ns3rc_script = os.sep.join([ns3_path,
".ns3rc"])
38usual_outdir = os.sep.join([ns3_path,
"build"])
39usual_lib_outdir = os.sep.join([usual_outdir,
"lib"])
45num_threads =
max(1, os.cpu_count() - 1)
46cmake_build_project_command =
"cmake --build . -j".format(ns3_path=ns3_path)
47cmake_build_target_command = partial(
"cmake --build . -j {jobs} --target {target}".format,
50win32 = sys.platform ==
"win32"
51platform_makefiles =
"MinGW Makefiles" if win32
else "Unix Makefiles"
52ext =
".exe" if win32
else ""
55def run_ns3(args, env=None, generator=platform_makefiles):
57 Runs the ns3 wrapper script with arguments
58 @param args: string containing arguments that will get split before calling ns3
59 @param env: environment variables dictionary
60 @param generator: CMake generator
61 @return tuple containing (error code, stdout
and stderr)
64 possible_leftovers = [
"contrib/borked",
"contrib/calibre"]
65 for leftover
in possible_leftovers:
66 if os.path.exists(leftover):
67 shutil.rmtree(leftover, ignore_errors=
True)
69 args = args.format(generator=generator)
74 return run_program(ns3_script, args, python=
True, env=env)
78def run_program(program, args, python=False, cwd=ns3_path, env=None):
80 Runs a program with the given arguments
and returns a tuple containing (error code, stdout
and stderr)
81 @param program: program to execute (
or python script)
82 @param args: string containing arguments that will get split before calling the program
83 @param python: flag indicating whether the program
is a python script
84 @param cwd: the working directory used that will be the root folder
for the execution
85 @param env: environment variables dictionary
86 @return tuple containing (error code, stdout
and stderr)
89 raise Exception(
"args should be a string")
93 arguments = [sys.executable, program]
98 arguments.extend(re.findall(
"(?:\".*?\"|\S)+", args))
100 for i
in range(len(arguments)):
101 arguments[i] = arguments[i].replace(
"\"",
"")
104 current_env = os.environ.copy()
108 current_env.update(env)
111 ret = subprocess.run(
113 stdin=subprocess.DEVNULL,
114 stdout=subprocess.PIPE,
115 stderr=subprocess.PIPE,
120 return ret.returncode, ret.stdout.decode(sys.stdout.encoding), ret.stderr.decode(sys.stderr.encoding)
125 Extracts the programs list from .lock-ns3
126 @return list of programs.
129 with open(ns3_lock_filename)
as f:
130 exec(f.read(), globals(), values)
132 programs_list = values[
"ns3_runnable_programs"]
136 programs_list =
list(map(
lambda x: x + ext, programs_list))
142 Gets a list of built libraries
143 @param lib_outdir: path containing libraries
144 @return list of built libraries.
146 libraries = glob.glob(lib_outdir + '/*', recursive=
True)
147 return list(filter(
lambda x:
"scratch-nested-subdir-lib" not in x, libraries))
152 Gets a list of header files
153 @param outdir: path containing headers
154 @return list of headers.
156 return glob.glob(outdir +
'/**/*.h', recursive=
True)
161 Read interesting entries from the .lock-ns3 file
162 @param entry: entry to read
from .lock-ns3
163 @return value of the requested entry.
166 with open(ns3_lock_filename)
as f:
167 exec(f.read(), globals(), values)
168 return values.get(entry,
None)
173 Check if tests are enabled
in the .lock-ns3
181 Check if tests are enabled
in the .lock-ns3
182 @return list of enabled modules (prefixed
with 'ns3-').
189 Python-on-whales wrapper for Docker-based ns-3 tests
192 def __init__(self, currentTestCase: unittest.TestCase, containerName: str =
"ubuntu:latest"):
194 Create and start container
with containerName
in the current ns-3 directory
195 @param self: the current DockerContainerManager instance
196 @param currentTestCase: the test case instance creating the DockerContainerManager
197 @param containerName: name of the container image to be used
199 global DockerException
201 from python_on_whales
import docker
202 from python_on_whales.exceptions
import DockerException
203 except ModuleNotFoundError:
205 DockerException =
None
206 currentTestCase.skipTest(
"python-on-whales was not found")
209 with open(os.path.expanduser(
"~/.bashrc"),
"r")
as f:
210 docker_settings = re.findall(
"(DOCKER_.*=.*)", f.read())
211 for setting
in docker_settings:
212 key, value = setting.split(
"=")
213 os.environ[key] = value
214 del docker_settings, setting, key, value
219 interactive=
True, detach=
True,
221 volumes=[(ns3_path,
"/ns-3-dev")]
225 def split_exec(docker_container, cmd):
226 return docker_container._execute(cmd.split(), workdir=
"/ns-3-dev")
233 Return the managed container when entiring the block "with DockerContainerManager() as container"
234 @param self: the current DockerContainerManager instance
235 @return container managed by DockerContainerManager.
241 Clean up the managed container at the end of the block "with DockerContainerManager() as container"
242 @param self: the current DockerContainerManager instance
243 @param exc_type: unused parameter
244 @param exc_val: unused parameter
245 @param exc_tb: unused parameter
254 ns-3 tests related to checking if source files were left behind,
not being used by CMake
258 directory_and_files = {}
262 Scan all C++ source files and add them to a list based on their path
265 for root, dirs, files
in os.walk(ns3_path):
266 if "gitlab-ci-local" in root:
269 if name.endswith(
".cc"):
270 path = os.path.join(root, name)
271 directory = os.path.dirname(path)
278 Test if all example source files are being used
in their respective CMakeLists.txt
281 unused_sources = set()
284 if os.sep +
"examples" not in example_directory:
288 with open(os.path.join(example_directory,
"CMakeLists.txt"),
"r")
as f:
289 cmake_contents = f.read()
294 if os.path.basename(file).replace(
".cc",
"")
not in cmake_contents:
295 unused_sources.add(file)
297 self.assertListEqual([],
list(unused_sources))
301 Test if all module source files are being used
in their respective CMakeLists.txt
304 unused_sources = set()
307 is_not_module =
not (
"src" in directory
or "contrib" in directory)
308 is_example = os.sep +
"examples" in directory
309 is_bindings = os.sep +
"bindings" in directory
311 if is_not_module
or is_bindings
or is_example:
316 cmake_path = os.path.join(directory,
"CMakeLists.txt")
317 while not os.path.exists(cmake_path):
318 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
319 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
322 with open(cmake_path,
"r")
as f:
323 cmake_contents = f.read()
327 if os.path.basename(file)
not in cmake_contents:
328 unused_sources.add(file)
331 exceptions = [
"win32-system-wall-clock-ms.cc",
333 for exception
in exceptions:
334 for unused_source
in unused_sources:
335 if os.path.basename(unused_source) == exception:
336 unused_sources.remove(unused_source)
339 self.assertListEqual([],
list(unused_sources))
343 Test if all utils source files are being used
in their respective CMakeLists.txt
346 unused_sources = set()
349 is_module =
"src" in directory
or "contrib" in directory
350 if os.sep +
"utils" not in directory
or is_module:
355 cmake_path = os.path.join(directory,
"CMakeLists.txt")
356 while not os.path.exists(cmake_path):
357 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
358 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
361 with open(cmake_path,
"r")
as f:
362 cmake_contents = f.read()
366 if os.path.basename(file)
not in cmake_contents:
367 unused_sources.add(file)
369 self.assertListEqual([],
list(unused_sources))
374 ns-3 tests related to dependencies
379 Checks if headers
from different modules (src/A, contrib/B) that are included by
380 the current module (src/C) source files correspond to the list of linked modules
382 LIBRARIES_TO_LINK A (missing B)
386 headers_to_modules = {}
387 module_paths = glob.glob(ns3_path + "/src/*/") + glob.glob(ns3_path +
"/contrib/*/")
389 for path
in module_paths:
391 cmake_path = os.path.join(path,
"CMakeLists.txt")
392 with open(cmake_path,
"r")
as f:
393 cmake_contents = f.readlines()
395 module_name = os.path.relpath(path, ns3_path)
396 module_name_nodir = module_name.replace(
"src/",
"").replace(
"contrib/",
"")
397 modules[module_name_nodir] = {
"sources": set(),
400 "included_headers": set(),
401 "included_libraries": set(),
405 for line
in cmake_contents:
406 base_name = os.path.basename(line[:-1])
407 if not os.path.exists(os.path.join(path, line.strip())):
412 modules[module_name_nodir][
"headers"].add(base_name)
413 modules[module_name_nodir][
"sources"].add(base_name)
416 headers_to_modules[base_name] = module_name_nodir
420 modules[module_name_nodir][
"sources"].add(base_name)
422 if ".cc" in line
or ".h" in line:
424 source_file = os.path.join(ns3_path, module_name, line.strip())
425 with open(source_file,
"r", encoding=
"utf-8")
as f:
426 source_contents = f.read()
427 modules[module_name_nodir][
"included_headers"].update(map(
lambda x: x.replace(
"ns3/",
""),
428 re.findall(
"#include.*[\"|<](.*)[\"|>]",
435 modules[module_name_nodir][
"libraries"].update(re.findall(
"\\${lib(.*)}",
"".join(cmake_contents)))
438 all_project_headers = set(headers_to_modules.keys())
441 print(file=sys.stderr)
442 for module
in sorted(modules):
443 external_headers = modules[module][
"included_headers"].difference(all_project_headers)
444 project_headers_included = modules[module][
"included_headers"].difference(external_headers)
445 modules[module][
"included_libraries"] = set(
446 [headers_to_modules[x]
for x
in project_headers_included]).difference(
449 diff = modules[module][
"included_libraries"].difference(modules[module][
"libraries"])
451 print(
"Module %s includes modules that are not linked: %s" % (module,
", ".join(
list(diff))),
458 self.assertTrue(
True)
463 ns-3 tests to check if the source code, whitespaces
and CMake formatting
464 are according to the coding style
474 Import GitRepo and load the original diff state of the repository before the tests
477 if not NS3StyleTestCase.starting_diff:
479 if shutil.which(
"git")
is None:
480 self.skipTest(
"Git is not available")
486 self.skipTest(
"GitPython is not available")
489 repo = Repo(ns3_path)
490 except git.exc.InvalidGitRepositoryError:
491 self.skipTest(
"ns-3 directory does not contain a .git directory")
493 hcommit = repo.head.commit
494 NS3StyleTestCase.starting_diff = hcommit.diff(
None)
495 NS3StyleTestCase.repo = repo
497 if NS3StyleTestCase.starting_diff
is None:
498 self.skipTest(
"Unmet dependencies")
502 Check if there
is any difference between tracked file after
503 applying cmake-format
507 for required_program
in [
"cmake",
"cmake-format"]:
508 if shutil.which(required_program)
is None:
509 self.skipTest(
"%s was not found" % required_program)
512 return_code, stdout, stderr =
run_ns3(
"configure")
513 self.assertEqual(return_code, 0)
516 return_code, stdout, stderr =
run_ns3(
"build cmake-format")
517 self.assertEqual(return_code, 0)
520 return_code, stdout, stderr =
run_ns3(
"clean")
521 self.assertEqual(return_code, 0)
524 new_diff = NS3StyleTestCase.repo.head.commit.diff(
None)
525 self.assertEqual(NS3StyleTestCase.starting_diff, new_diff)
530 ns3 tests related to generic options
535 Clean configuration/build artifacts before common commands
544 Test not passing any arguments to
547 return_code, stdout, stderr = run_ns3("")
548 self.assertEqual(return_code, 1)
549 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
553 Test only passing --quiet argument to ns3
556 return_code, stdout, stderr = run_ns3("--quiet")
557 self.assertEqual(return_code, 1)
558 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
562 Test only passing 'show config' argument to ns3
565 return_code, stdout, stderr = run_ns3("show config")
566 self.assertEqual(return_code, 1)
567 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
571 Test only passing 'show profile' argument to ns3
574 return_code, stdout, stderr = run_ns3("show profile")
575 self.assertEqual(return_code, 1)
576 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
580 Test only passing 'show version' argument to ns3
583 return_code, stdout, stderr = run_ns3("show version")
584 self.assertEqual(return_code, 1)
585 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
590 ns3 tests related to build profiles
595 Clean configuration/build artifacts before testing configuration settings
607 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d debug --enable-verbose")
608 self.assertEqual(return_code, 0)
609 self.assertIn(
"Build profile : debug", stdout)
610 self.assertIn(
"Build files have been written to", stdout)
613 return_code, stdout, stderr =
run_ns3(
"build core")
614 self.assertEqual(return_code, 0)
615 self.assertIn(
"Built target libcore", stdout)
618 self.assertGreater(len(libraries), 0)
619 self.assertIn(
"core-debug", libraries[0])
623 Test the release build
626 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d release")
627 self.assertEqual(return_code, 0)
628 self.assertIn(
"Build profile : release", stdout)
629 self.assertIn(
"Build files have been written to", stdout)
633 Test the optimized build
636 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d optimized --enable-verbose")
637 self.assertEqual(return_code, 0)
638 self.assertIn(
"Build profile : optimized", stdout)
639 self.assertIn(
"Build files have been written to", stdout)
642 return_code, stdout, stderr =
run_ns3(
"build core")
643 self.assertEqual(return_code, 0)
644 self.assertIn(
"Built target libcore", stdout)
647 self.assertGreater(len(libraries), 0)
648 self.assertIn(
"core-optimized", libraries[0])
652 Test a build type with a typo
655 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d Optimized")
656 self.assertEqual(return_code, 2)
657 self.assertIn(
"invalid choice: 'Optimized'", stderr)
661 Test a build type with another typo
664 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d OPTIMIZED")
665 self.assertEqual(return_code, 2)
666 self.assertIn(
"invalid choice: 'OPTIMIZED'", stderr)
670 Replace settings set by default (e.g. ASSERT/LOGs enabled in debug builds
and disabled
in default ones)
673 return_code, _, _ = run_ns3("clean")
674 self.assertEqual(return_code, 0)
676 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --dry-run -d debug")
677 self.assertEqual(return_code, 0)
679 "-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON -DNS3_NATIVE_OPTIMIZATIONS=OFF",
682 return_code, stdout, stderr =
run_ns3(
683 "configure -G \"{generator}\" --dry-run -d debug --disable-asserts --disable-logs --disable-werror")
684 self.assertEqual(return_code, 0)
686 "-DCMAKE_BUILD_TYPE=debug -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF",
689 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --dry-run")
690 self.assertEqual(return_code, 0)
692 "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF -DNS3_NATIVE_OPTIMIZATIONS=OFF",
695 return_code, stdout, stderr =
run_ns3(
696 "configure -G \"{generator}\" --dry-run --enable-asserts --enable-logs --enable-werror")
697 self.assertEqual(return_code, 0)
699 "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON",
705 Generic test case with basic function inherited by more complex tests.
710 Check if configuration
for release mode worked normally
711 @param return_code:
return code
from CMake
712 @param stdout: output
from CMake.
715 self.assertEqual(return_code, 0)
716 self.assertIn("Build profile : release", stdout)
717 self.assertIn(
"Build files have been written to", stdout)
721 Clean configuration/build artifacts before testing configuration and build settings
722 After configuring the build
as release,
723 check
if configuration worked
and check expected output files.
728 if os.path.exists(ns3rc_script):
729 os.remove(ns3rc_script)
733 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d release --enable-verbose")
737 self.assertTrue(os.path.exists(ns3_lock_filename))
742 self.assertTrue(os.path.exists(ns3_lock_filename))
749 Test ns3 configuration options
754 Reuse cleaning/release configuration from NS3BaseTestCase
if flag
is cleaned
761 Test enabling and disabling examples
764 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" --enable-examples")
773 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-examples")
783 Test enabling and disabling tests
787 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-tests")
791 return_code, stdout, stderr =
run_ns3(
"build core-test")
794 self.assertEqual(return_code, 0)
795 self.assertIn(
"Built target libcore-test", stdout)
798 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-tests")
802 return_code, stdout, stderr =
run_ns3(
"build core-test")
805 self.assertEqual(return_code, 1)
806 self.assertIn(
"Target to build does not exist: core-test", stdout)
810 Test enabling specific modules
814 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='network;wifi'")
820 self.assertIn(
"ns3-network", enabled_modules)
821 self.assertIn(
"ns3-wifi", enabled_modules)
824 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='core'")
829 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
837 Test disabling specific modules
841 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules='lte;wimax'")
846 self.assertLess(len(enabled_modules), len(self.
ns3_modules))
847 self.assertNotIn(
"ns3-lte", enabled_modules)
848 self.assertNotIn(
"ns3-wimax", enabled_modules)
851 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
859 Test enabling comma-separated (waf-style) examples
863 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='network,wifi'")
869 self.assertIn(
"ns3-network", enabled_modules)
870 self.assertIn(
"ns3-wifi", enabled_modules)
873 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
881 Test disabling comma-separated (waf-style) examples
885 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules='lte,mpi'")
890 self.assertLess(len(enabled_modules), len(self.
ns3_modules))
891 self.assertNotIn(
"ns3-lte", enabled_modules)
892 self.assertNotIn(
"ns3-mpi", enabled_modules)
895 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
903 Test loading settings from the ns3rc config file
909 ns3rc_python_template =
"# ! /usr/bin/env python\
911 # A list of the modules that will be enabled when ns-3 is run.\
912 # Modules that depend on the listed modules will be enabled also.\
914 # All modules can be enabled by choosing 'all_modules'.\
915 modules_enabled = [{modules}]\
917 # Set this equal to true if you want examples to be run.\
918 examples_enabled = {examples}\
920 # Set this equal to true if you want tests to be run.\
921 tests_enabled = {tests}\
925 ns3rc_cmake_template =
"set(ns3rc_tests_enabled {tests})\
926 \nset(ns3rc_examples_enabled {examples})\
927 \nset(ns3rc_enabled_modules {modules})\
932 "python": ns3rc_python_template,
933 "cmake": ns3rc_cmake_template
936 def __init__(self, type_ns3rc):
939 def format(self, **args):
941 if self.
type ==
"cmake":
942 args[
"modules"] = args[
"modules"].replace(
"'",
"").replace(
"\"",
"").replace(
",",
" ")
943 args[
"examples"] =
"ON" if args[
"examples"] ==
"True" else "OFF"
944 args[
"tests"] =
"ON" if args[
"tests"] ==
"True" else "OFF"
946 formatted_string = ns3rc_str.ns3rc_templates[self.
type].format(**args)
949 return formatted_string
953 return ns3rc_str.ns3rc_templates.keys()
955 for ns3rc_type
in ns3rc_str.types():
957 ns3rc_template = ns3rc_str(ns3rc_type)
960 with open(ns3rc_script,
"w")
as f:
961 f.write(ns3rc_template.format(modules=
"'lte'", examples=
"False", tests=
"True"))
964 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
970 self.assertIn(
"ns3-lte", enabled_modules)
975 with open(ns3rc_script,
"w")
as f:
976 f.write(ns3rc_template.format(modules=
"'wifi'", examples=
"True", tests=
"False"))
979 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
985 self.assertIn(
"ns3-wifi", enabled_modules)
990 with open(ns3rc_script,
"w")
as f:
991 f.write(ns3rc_template.format(modules=
"'core','network'", examples=
"True", tests=
"False"))
994 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1000 self.assertIn(
"ns3-core", enabled_modules)
1001 self.assertIn(
"ns3-network", enabled_modules)
1007 with open(ns3rc_script,
"w")
as f:
1008 if ns3rc_type ==
"python":
1009 f.write(ns3rc_template.format(modules=
"""'core', #comment
1013 'network',
'internet',
'wimax'""", examples="True", tests="True"))
1015 f.write(ns3rc_template.format(modules=
"'core', 'lte', 'network', 'internet', 'wimax'",
1020 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1026 self.assertIn(
"ns3-core", enabled_modules)
1027 self.assertIn(
"ns3-internet", enabled_modules)
1028 self.assertIn(
"ns3-lte", enabled_modules)
1029 self.assertIn(
"ns3-wimax", enabled_modules)
1034 os.remove(ns3rc_script)
1037 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1047 Test dry-run (printing commands to be executed instead of running them)
1053 for positional_command
in [
"configure",
"build",
"clean"]:
1054 return_code, stdout, stderr =
run_ns3(
"--dry-run %s" % positional_command)
1055 return_code1, stdout1, stderr1 =
run_ns3(
"%s --dry-run" % positional_command)
1057 self.assertEqual(return_code, return_code1)
1058 self.assertEqual(stdout, stdout1)
1059 self.assertEqual(stderr, stderr1)
1064 run_ns3(
"configure -G \"{generator}\" -d release --enable-verbose")
1065 run_ns3(
"build scratch-simulator")
1068 return_code0, stdout0, stderr0 =
run_ns3(
"--dry-run run scratch-simulator")
1069 return_code1, stdout1, stderr1 =
run_ns3(
"run scratch-simulator")
1070 return_code2, stdout2, stderr2 =
run_ns3(
"--dry-run run scratch-simulator --no-build")
1071 return_code3, stdout3, stderr3 =
run_ns3(
"run scratch-simulator --no-build")
1074 self.assertEqual(sum([return_code0, return_code1, return_code2, return_code3]), 0)
1075 self.assertEqual([stderr0, stderr1, stderr2, stderr3], [
""] * 4)
1079 if "scratch-simulator" in program
and "subdir" not in program:
1080 scratch_path = program
1086 self.assertIn(scratch_path, stdout0)
1090 self.assertIn(
"Built target", stdout1)
1091 self.assertNotIn(scratch_path, stdout1)
1094 self.assertIn(
"The following commands would be executed:", stdout2)
1095 self.assertIn(scratch_path, stdout2)
1098 self.assertNotIn(
"Finished executing the following commands:", stdout3)
1099 self.assertNotIn(scratch_path, stdout3)
1103 Test if ns3
is propagating back the
return code
from the executables called
with the run command
1107 return_code, _, _ =
run_ns3(
"clean")
1108 self.assertEqual(return_code, 0)
1110 return_code, _, _ =
run_ns3(
"configure -G \"{generator}\" --enable-examples --enable-tests")
1111 self.assertEqual(return_code, 0)
1114 return_code, stdout, stderr =
run_ns3(
"build command-line-example test-runner")
1115 self.assertEqual(return_code, 0)
1118 return_code, stdout, stderr =
run_ns3(
"run \"test-runner --test-name=command-line\" --no-build")
1119 self.assertEqual(return_code, 0)
1122 return_code, stdout, stderr =
run_ns3(
"run \"test-runner --test-name=command-line\" --no-build",
1123 env={
"NS_COMMANDLINE_INTROSPECTION":
".."}
1125 self.assertNotEqual(return_code, 0)
1128 sigsegv_example = os.path.join(ns3_path,
"scratch",
"sigsegv.cc")
1129 with open(sigsegv_example,
"w")
as f:
1131 int main (int argc, char *argv[])
1133 char *s = "hello world"; *s =
'H';
1137 return_code, stdout, stderr = run_ns3("run sigsegv")
1139 self.assertEqual(return_code, 4294967295)
1140 self.assertIn(
"sigsegv-default.exe' returned non-zero exit status", stdout)
1142 self.assertEqual(return_code, 245)
1143 self.assertIn(
"sigsegv-default' died with <Signals.SIGSEGV: 11>", stdout)
1146 abort_example = os.path.join(ns3_path,
"scratch",
"abort.cc")
1147 with open(abort_example,
"w")
as f:
1151 using namespace ns3;
1152 int main (int argc, char *argv[])
1158 return_code, stdout, stderr = run_ns3("run abort")
1160 self.assertEqual(return_code, 3)
1161 self.assertIn(
"abort-default.exe' returned non-zero exit status", stdout)
1163 self.assertEqual(return_code, 250)
1164 self.assertIn(
"abort-default' died with <Signals.SIGABRT: 6>", stdout)
1166 os.remove(sigsegv_example)
1167 os.remove(abort_example)
1171 Test passing 'show config' argument to ns3 to get the configuration table
1174 return_code, stdout, stderr = run_ns3("show config")
1175 self.assertEqual(return_code, 0)
1176 self.assertIn(
"Summary of ns-3 settings", stdout)
1180 Test passing 'show profile' argument to ns3 to get the build profile
1183 return_code, stdout, stderr = run_ns3("show profile")
1184 self.assertEqual(return_code, 0)
1185 self.assertIn(
"Build profile: release", stdout)
1189 Test passing 'show version' argument to ns3 to get the build version
1192 if shutil.which(
"git")
is None:
1193 self.skipTest(
"git is not available")
1195 return_code, _, _ =
run_ns3(
"configure -G \"{generator}\" --enable-build-version")
1196 self.assertEqual(return_code, 0)
1198 return_code, stdout, stderr =
run_ns3(
"show version")
1199 self.assertEqual(return_code, 0)
1200 self.assertIn(
"ns-3 version:", stdout)
1204 Test if CMake target names
for scratches
and ns3 shortcuts
1205 are working correctly
1209 test_files = ["scratch/main.cc",
1211 "scratch/subdir1/main.cc",
1212 "scratch/subdir2/main.cc",
1213 "scratch/main.test.dots.in.name.cc"]
1214 backup_files = [
"scratch/.main.cc"]
1217 for path
in test_files + backup_files:
1218 filepath = os.path.join(ns3_path, path)
1219 os.makedirs(os.path.dirname(filepath), exist_ok=
True)
1220 with open(filepath,
"w")
as f:
1222 f.write(
"int main (int argc, char *argv[]){}")
1230 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1231 self.assertEqual(return_code, 0)
1234 for path
in test_files + backup_files:
1235 path = path.replace(
".cc",
"")
1236 return_code1, stdout1, stderr1 =
run_program(
"cmake",
"--build . --target %s -j %d"
1237 % (path.replace(
"/",
"_"), num_threads),
1238 cwd=os.path.join(ns3_path,
"cmake-cache"))
1239 return_code2, stdout2, stderr2 =
run_ns3(
"build %s" % path)
1240 if "main" in path
and ".main" not in path:
1241 self.assertEqual(return_code1, 0)
1242 self.assertEqual(return_code2, 0)
1244 self.assertEqual(return_code1, 2)
1245 self.assertEqual(return_code2, 1)
1248 for path
in test_files:
1249 path = path.replace(
".cc",
"")
1250 return_code, stdout, stderr =
run_ns3(
"run %s --no-build" % path)
1252 self.assertEqual(return_code, 0)
1254 self.assertEqual(return_code, 1)
1259 container.execute(
"apt-get update")
1260 container.execute(
"apt-get install -y python3 cmake g++-8 ninja-build")
1263 "./ns3 configure --enable-modules=core,network,internet -- -DCMAKE_CXX_COMPILER=/usr/bin/g++-8")
1264 except DockerException
as e:
1266 for path
in test_files:
1267 path = path.replace(
".cc",
"")
1269 container.execute(f
"./ns3 run {path}")
1270 except DockerException
as e:
1276 for path
in test_files + backup_files:
1277 source_absolute_path = os.path.join(ns3_path, path)
1278 os.remove(source_absolute_path)
1279 if "empty" in path
or ".main" in path:
1281 filename = os.path.basename(path).replace(
".cc",
"")
1282 executable_absolute_path = os.path.dirname(os.path.join(ns3_path,
"build", path))
1283 executable_name =
list(filter(
lambda x: filename
in x,
1284 os.listdir(executable_absolute_path)
1288 os.remove(os.path.join(executable_absolute_path, executable_name))
1289 if not os.listdir(os.path.dirname(path)):
1290 os.rmdir(os.path.dirname(source_absolute_path))
1292 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1293 self.assertEqual(return_code, 0)
1297 Test if ns3
is inserting additional arguments by MPICH
and OpenMPI to run on the CI
1301 if shutil.which(
"mpiexec")
is None or win32:
1302 self.skipTest(
"Mpi is not available")
1304 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
1305 self.assertEqual(return_code, 0)
1309 return_code, stdout, stderr =
run_ns3(
"build sample-simulator")
1310 self.assertEqual(return_code, 0)
1313 sample_simulator_path =
list(filter(
lambda x:
"sample-simulator" in x, executables))[0]
1315 mpi_command =
"--dry-run run sample-simulator --command-template=\"mpiexec -np 2 %s\""
1316 non_mpi_command =
"--dry-run run sample-simulator --command-template=\"echo %s\""
1319 return_code, stdout, stderr =
run_ns3(mpi_command)
1320 self.assertEqual(return_code, 0)
1321 self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
1324 return_code, stdout, stderr =
run_ns3(mpi_command)
1325 self.assertEqual(return_code, 0)
1326 if os.getenv(
"USER",
"") ==
"root":
1327 if shutil.which(
"ompi_info"):
1328 self.assertIn(
"mpiexec --allow-run-as-root --oversubscribe -np 2 %s" % sample_simulator_path, stdout)
1330 self.assertIn(
"mpiexec --allow-run-as-root -np 2 %s" % sample_simulator_path, stdout)
1332 self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
1335 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1336 self.assertEqual(return_code, 0)
1337 self.assertIn(
"echo %s" % sample_simulator_path, stdout)
1340 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1341 self.assertEqual(return_code, 0)
1342 self.assertIn(
"echo %s" % sample_simulator_path, stdout)
1344 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-examples")
1345 self.assertEqual(return_code, 0)
1349 Test if CMake
and ns3 fail
in the expected ways when:
1350 - examples
from modules
or general examples fail
if they depend on a
1351 library
with a name shorter than 4 characters
or are disabled when
1352 a library
is nonexistent
1353 - a module library passes the configuration but fails to build due to
1357 os.makedirs("contrib/borked", exist_ok=
True)
1358 os.makedirs(
"contrib/borked/examples", exist_ok=
True)
1361 with open(
"contrib/borked/examples/CMakeLists.txt",
"w")
as f:
1363 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1364 with open(
"contrib/borked/CMakeLists.txt",
"w")
as f:
1368 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1369 LIBRARIES_TO_LINK ${libcore} %s
1371 """ % invalid_or_nonexistent_library)
1373 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" --enable-examples")
1374 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1375 self.assertEqual(return_code, 0)
1376 elif invalid_or_nonexistent_library
in [
"lib"]:
1377 self.assertEqual(return_code, 1)
1378 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1382 return_code, stdout, stderr =
run_ns3(
"build borked")
1383 if invalid_or_nonexistent_library
in [
""]:
1384 self.assertEqual(return_code, 0)
1385 elif invalid_or_nonexistent_library
in [
"lib"]:
1386 self.assertEqual(return_code, 2)
1387 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1388 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1389 self.assertEqual(return_code, 2)
1390 if "lld" in stdout + stderr:
1391 self.assertIn(
"unable to find library -l%s" % invalid_or_nonexistent_library, stderr)
1392 elif "mold" in stdout + stderr:
1393 self.assertIn(
"library not found: %s" % invalid_or_nonexistent_library, stderr)
1395 self.assertIn(
"cannot find -l%s" % invalid_or_nonexistent_library, stderr)
1403 with open(
"contrib/borked/CMakeLists.txt",
"w")
as f:
1407 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1408 LIBRARIES_TO_LINK ${libcore}
1411 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1412 with open(
"contrib/borked/examples/CMakeLists.txt",
"w")
as f:
1416 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty-main.cc
1417 LIBRARIES_TO_LINK ${libborked} %s
1419 """ % invalid_or_nonexistent_library)
1421 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\"")
1422 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1423 self.assertEqual(return_code, 0)
1424 elif invalid_or_nonexistent_library
in [
"lib"]:
1425 self.assertEqual(return_code, 1)
1426 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1430 return_code, stdout, stderr =
run_ns3(
"build borked-example")
1431 if invalid_or_nonexistent_library
in [
""]:
1432 self.assertEqual(return_code, 0)
1433 elif invalid_or_nonexistent_library
in [
"libf"]:
1434 self.assertEqual(return_code, 2)
1435 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1436 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1437 self.assertEqual(return_code, 1)
1438 self.assertIn(
"Target to build does not exist: borked-example", stdout)
1442 shutil.rmtree(
"contrib/borked", ignore_errors=
True)
1446 Test if CMake can properly handle modules containing
"lib",
1447 which
is used internally
as a prefix
for module libraries
1451 os.makedirs("contrib/calibre", exist_ok=
True)
1452 os.makedirs(
"contrib/calibre/examples", exist_ok=
True)
1455 with open(
"contrib/calibre/examples/CMakeLists.txt",
"w")
as f:
1457 with open(
"contrib/calibre/CMakeLists.txt",
"w")
as f:
1461 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1462 LIBRARIES_TO_LINK ${libcore}
1466 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\"")
1469 self.assertEqual(return_code, 0)
1472 self.assertIn(
"calibre", stdout)
1476 self.assertNotIn(
"care", stdout)
1477 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"pkgconfig",
"ns3-calibre.pc")))
1480 return_code, stdout, stderr =
run_ns3(
"build calibre")
1481 self.assertEqual(return_code, 0)
1484 shutil.rmtree(
"contrib/calibre", ignore_errors=
True)
1488 Test if CMake performance tracing works
and produces the
1489 cmake_performance_trace.log file
1492 return_code, stdout, stderr = run_ns3("configure --trace-performance")
1493 self.assertEqual(return_code, 0)
1495 self.assertIn(
"--profiling-format=google-trace --profiling-output=", stdout)
1497 self.assertIn(
"--profiling-format=google-trace --profiling-output=../cmake_performance_trace.log", stdout)
1498 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake_performance_trace.log")))
1502 Check if ENABLE_BUILD_VERSION
and version.cache are working
1510 container.execute(
"apt-get update")
1511 container.execute(
"apt-get install -y python3 ninja-build cmake g++")
1514 container.execute(
"./ns3 clean")
1517 version_cache_file = os.path.join(ns3_path,
"src/core/model/version.cache")
1520 if os.path.exists(version_cache_file):
1521 os.remove(version_cache_file)
1525 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1526 except DockerException:
1528 self.assertFalse(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1531 version_cache_contents = (
"CLOSEST_TAG = '\"ns-3.0.0\"'\n"
1532 "VERSION_COMMIT_HASH = '\"0000000000\"'\n"
1533 "VERSION_DIRTY_FLAG = '0'\n"
1534 "VERSION_MAJOR = '3'\n"
1535 "VERSION_MINOR = '0'\n"
1536 "VERSION_PATCH = '0'\n"
1537 "VERSION_RELEASE_CANDIDATE = '\"\"'\n"
1538 "VERSION_TAG = '\"ns-3.0.0\"'\n"
1539 "VERSION_TAG_DISTANCE = '0'\n"
1540 "VERSION_BUILD_PROFILE = 'debug'\n"
1542 with open(version_cache_file,
"w")
as version:
1543 version.write(version_cache_contents)
1546 container.execute(
"./ns3 clean")
1547 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1548 container.execute(
"./ns3 build core")
1549 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1552 with open(version_cache_file,
"r")
as version:
1553 self.assertEqual(version.read(), version_cache_contents)
1558 os.rename(os.path.join(ns3_path,
".git"), os.path.join(ns3_path,
"temp_git"))
1560 container.execute(
"apt-get install -y git")
1561 container.execute(
"./ns3 clean")
1562 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1563 container.execute(
"./ns3 build core")
1564 except DockerException:
1566 os.rename(os.path.join(ns3_path,
"temp_git"), os.path.join(ns3_path,
".git"))
1567 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1570 container.execute(
"./ns3 clean")
1571 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1572 container.execute(
"./ns3 build core")
1573 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1574 with open(version_cache_file,
"r")
as version:
1575 self.assertNotEqual(version.read(), version_cache_contents)
1578 if os.path.exists(version_cache_file):
1579 os.remove(version_cache_file)
1583 Test filtering in examples
and tests
from specific modules
1587 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples --enable-tests")
1593 return_code, stdout, stderr =
run_ns3(
1594 "configure -G \"{generator}\" --filter-module-examples-and-tests='core;network'")
1601 self.assertEqual(len(modules_after_filtering), len(modules_before_filtering))
1603 self.assertLess(len(programs_after_filtering), len(programs_before_filtering))
1606 return_code, stdout, stderr =
run_ns3(
1607 "configure -G \"{generator}\" --filter-module-examples-and-tests='core'")
1616 return_code, stdout, stderr =
run_ns3(
1617 "configure -G \"{generator}\" --disable-examples --disable-tests --filter-module-examples-and-tests=''")
1626 Check if fast linkers LLD
and Mold are correctly found
and configured
1633 container.execute(
"apt-get update")
1634 container.execute(
"apt-get install -y python3 ninja-build cmake g++ lld")
1637 container.execute(
"./ns3 configure -G Ninja")
1640 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1641 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1642 self.assertIn(
"-fuse-ld=lld", f.read())
1646 container.execute(
"./ns3 build core")
1647 except DockerException:
1648 self.assertTrue(
False,
"Build with lld failed")
1651 if not os.path.exists(
"./mold-1.4.2-x86_64-linux.tar.gz"):
1653 "wget https://github.com/rui314/mold/releases/download/v1.4.2/mold-1.4.2-x86_64-linux.tar.gz")
1654 container.execute(
"tar xzfC mold-1.4.2-x86_64-linux.tar.gz /usr/local --strip-components=1")
1658 container.execute(
"./ns3 configure -G Ninja")
1661 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1662 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1663 self.assertIn(
"-fuse-ld=mold", f.read())
1667 container.execute(
"./ns3 build core")
1668 except DockerException:
1669 self.assertTrue(
False,
"Build with mold failed")
1672 os.remove(
"./mold-1.4.2-x86_64-linux.tar.gz")
1675 container.execute(
"./ns3 configure -G Ninja -- -DNS3_FAST_LINKERS=OFF")
1678 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1679 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1680 self.assertNotIn(
"-fuse-ld=mold", f.read())
1684 Check if NS3_CLANG_TIMETRACE feature
is working
1685 Clang
's -ftime-trace plus ClangAnalyzer report
1691 container.execute(
"apt-get update")
1692 container.execute(
"apt-get install -y python3 ninja-build cmake clang-10")
1697 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON")
1698 except DockerException
as e:
1699 self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
1701 container.execute(
"apt-get install -y git")
1706 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON")
1707 except DockerException
as e:
1708 self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
1711 time_trace_report_path = os.path.join(ns3_path,
"ClangBuildAnalyzerReport.txt")
1712 if os.path.exists(time_trace_report_path):
1713 os.remove(time_trace_report_path)
1717 container.execute(
"./ns3 build timeTraceReport")
1718 except DockerException
as e:
1719 self.assertTrue(
False,
"Failed to build the ClangAnalyzer's time trace report")
1722 self.assertTrue(os.path.exists(time_trace_report_path))
1726 container.execute(
"apt-get install -y g++")
1727 container.execute(
"apt-get remove -y clang-10")
1731 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DNS3_CLANG_TIMETRACE=ON")
1732 self.assertTrue(
False,
"ClangTimeTrace requires Clang, but GCC just passed the checks too")
1733 except DockerException
as e:
1734 self.assertIn(
"TimeTrace is a Clang feature", e.stderr)
1738 Check if NS3_NINJA_TRACE feature
is working
1739 Ninja
's .ninja_log conversion to about://tracing
1740 json format conversion with Ninjatracing
1746 container.execute(
"apt-get update")
1747 container.execute(
"apt-get install -y python3 cmake clang-10")
1752 "./ns3 configure --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1753 except DockerException
as e:
1754 self.assertIn(
"Ninjatracing requires the Ninja generator", e.stderr)
1759 container.execute(
"apt-get install -y ninja-build")
1763 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1764 except DockerException
as e:
1765 self.assertIn(
"could not find git for clone of NinjaTracing", e.stderr)
1767 container.execute(
"apt-get install -y git")
1771 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1772 except DockerException
as e:
1773 self.assertTrue(
False,
"Failed to configure with Ninjatracing")
1776 ninja_trace_path = os.path.join(ns3_path,
"ninja_performance_trace.json")
1777 if os.path.exists(ninja_trace_path):
1778 os.remove(ninja_trace_path)
1781 container.execute(
"./ns3 build core")
1785 container.execute(
"./ns3 build ninjaTrace")
1786 except DockerException
as e:
1787 self.assertTrue(
False,
"Failed to run Ninjatracing's tool to build the trace")
1790 self.assertTrue(os.path.exists(ninja_trace_path))
1791 trace_size = os.stat(ninja_trace_path).st_size
1792 os.remove(ninja_trace_path)
1799 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON")
1800 except DockerException
as e:
1801 self.assertTrue(
False,
"Failed to configure Ninjatracing with Clang's TimeTrace")
1804 container.execute(
"./ns3 build core")
1808 container.execute(
"./ns3 build ninjaTrace")
1809 except DockerException
as e:
1810 self.assertTrue(
False,
"Failed to run Ninjatracing's tool to build the trace")
1812 self.assertTrue(os.path.exists(ninja_trace_path))
1813 timetrace_size = os.stat(ninja_trace_path).st_size
1814 os.remove(ninja_trace_path)
1817 self.assertGreater(timetrace_size, trace_size)
1821 Check if precompiled headers are being enabled correctly.
1830 container.execute(
"apt-get update")
1831 container.execute(
"apt-get install -y python3 cmake ccache clang-10")
1833 container.execute(
"./ns3 configure -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1834 except DockerException
as e:
1835 self.assertIn(
"does not support precompiled headers", e.stderr)
1842 container.execute(
"apt-get update")
1843 container.execute(
"apt-get install -y python3 cmake ccache g++")
1845 container.execute(
"./ns3 configure")
1846 except DockerException
as e:
1847 self.assertIn(
"incompatible with ccache", e.stderr)
1854 container.execute(
"apt-get update")
1855 container.execute(
"apt-get install -y python3 cmake ccache g++")
1857 container.execute(
"./ns3 configure")
1858 except DockerException
as e:
1859 self.assertTrue(
False,
"Precompiled headers should have been enabled")
1863 Check for regressions
in test object build.
1866 return_code, stdout, stderr = run_ns3('configure')
1867 self.assertEqual(return_code, 0)
1869 test_module_cache = os.path.join(ns3_path,
"cmake-cache",
"src",
"test")
1870 self.assertFalse(os.path.exists(test_module_cache))
1872 return_code, stdout, stderr =
run_ns3(
'configure --enable-tests')
1873 self.assertEqual(return_code, 0)
1874 self.assertTrue(os.path.exists(test_module_cache))
1879 Tests ns3 regarding building the project
1884 Reuse cleaning/release configuration from NS3BaseTestCase
if flag
is cleaned
1893 Try building the core library
1896 return_code, stdout, stderr = run_ns3("build core")
1897 self.assertEqual(return_code, 0)
1898 self.assertIn(
"Built target libcore", stdout)
1902 Try building core-test library without tests enabled
1906 return_code, stdout, stderr =
run_ns3(
"build core-test")
1907 self.assertEqual(return_code, 1)
1908 self.assertIn(
"Target to build does not exist: core-test", stdout)
1912 Try building the project:
1915 return_code, stdout, stderr = run_ns3("build")
1916 self.assertEqual(return_code, 0)
1917 self.assertIn(
"Built target", stdout)
1919 self.assertTrue(os.path.exists(program), program)
1920 self.assertIn(cmake_build_project_command, stdout)
1924 Try hiding task lines
1927 return_code, stdout, stderr = run_ns3("--quiet build")
1928 self.assertEqual(return_code, 0)
1929 self.assertIn(cmake_build_project_command, stdout)
1933 Try removing an essential file to break the build
1937 attribute_cc_path = os.sep.join([ns3_path,
"src",
"core",
"model",
"attribute.cc"])
1938 attribute_cc_bak_path = attribute_cc_path +
".bak"
1939 shutil.move(attribute_cc_path, attribute_cc_bak_path)
1942 return_code, stdout, stderr =
run_ns3(
"build")
1943 self.assertNotEqual(return_code, 0)
1946 shutil.move(attribute_cc_bak_path, attribute_cc_path)
1949 return_code, stdout, stderr =
run_ns3(
"build")
1950 self.assertEqual(return_code, 0)
1954 Test if changing the version file affects the library names
1960 version_file = os.sep.join([ns3_path,
"VERSION"])
1961 with open(version_file,
"w")
as f:
1965 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1969 return_code, stdout, stderr =
run_ns3(
"build")
1970 self.assertEqual(return_code, 0)
1971 self.assertIn(
"Built target", stdout)
1977 for program
in new_programs:
1978 self.assertTrue(os.path.exists(program))
1986 self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
1987 for library
in new_libraries:
1988 self.assertNotIn(
"libns3-dev", library)
1989 self.assertIn(
"libns3-00", library)
1990 self.assertTrue(os.path.exists(library))
1993 with open(version_file,
"w")
as f:
1998 Try setting a different output directory and if everything
is
1999 in the right place
and still working correctly
2004 return_code, stdout, stderr =
run_ns3(
"build")
2005 self.assertEqual(return_code, 0)
2020 absolute_path = os.sep.join([ns3_path,
"build",
"release"])
2021 relative_path = os.sep.join([
"build",
"release"])
2022 for different_out_dir
in [absolute_path, relative_path]:
2023 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=%s" % different_out_dir)
2025 self.assertIn(
"Build directory : %s" % absolute_path.replace(os.sep,
'/'), stdout)
2033 for program
in new_programs:
2034 self.assertTrue(os.path.exists(program))
2039 self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
2040 for library
in new_libraries:
2041 self.assertTrue(os.path.exists(library))
2044 shutil.rmtree(absolute_path)
2047 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=''")
2049 self.assertIn(
"Build directory : %s" % usual_outdir.replace(os.sep,
'/'), stdout)
2057 for program
in new_programs:
2058 self.assertTrue(os.path.exists(program))
2063 for library
in libraries:
2064 self.assertTrue(os.path.exists(library))
2068 Tries setting a ns3 version, then installing it.
2069 After that, tries searching for ns-3
with CMake
's find_package(ns3).
2070 Finally, tries using core library in a 3rd-party project
2075 for library
in libraries:
2079 version_file = os.sep.join([ns3_path,
"VERSION"])
2080 with open(version_file,
"w")
as f:
2084 install_prefix = os.sep.join([ns3_path,
"build",
"install"])
2085 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --prefix=%s" % install_prefix)
2097 lib64 = os.path.exists(os.sep.join([install_prefix,
"lib64"]))
2098 installed_libdir = os.sep.join([install_prefix, (
"lib64" if lib64
else "lib")])
2102 installed_libraries_list =
";".join(installed_libraries)
2103 for library
in libraries:
2104 library_name = os.path.basename(library)
2105 self.assertIn(library_name, installed_libraries_list)
2109 missing_headers =
list(set([os.path.basename(x)
for x
in headers])
2110 - (set([os.path.basename(x)
for x
in installed_headers]))
2112 self.assertEqual(len(missing_headers), 0)
2115 test_main_file = os.sep.join([install_prefix,
"main.cpp"])
2116 with open(test_main_file,
"w")
as f:
2119 using namespace ns3;
2122 Simulator::Stop (Seconds (1.0));
2124 Simulator::Destroy ();
2132 for version
in [
"",
"3.01",
"3.00"]:
2133 ns3_import_methods = []
2136 cmake_find_package_import =
"""
2137 list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3)
2138 find_package(ns3 {version} COMPONENTS libcore)
2139 target_link_libraries(test PRIVATE ns3::libcore)
2140 """.format(lib=("lib64" if lib64 else "lib"), version=version)
2141 ns3_import_methods.append(cmake_find_package_import)
2144 pkgconfig_import =
"""
2145 list(APPEND CMAKE_PREFIX_PATH ./)
2146 include(FindPkgConfig)
2147 pkg_check_modules(ns3 REQUIRED IMPORTED_TARGET ns3-core{version})
2148 target_link_libraries(test PUBLIC PkgConfig::ns3)
2149 """.format(lib=("lib64" if lib64 else "lib"),
2150 version="=" + version
if version
else ""
2152 if shutil.which(
"pkg-config"):
2153 ns3_import_methods.append(pkgconfig_import)
2156 for import_method
in ns3_import_methods:
2157 test_cmake_project =
"""
2158 cmake_minimum_required(VERSION 3.10..3.10)
2159 project(ns3_consumer CXX)
2160 set(CMAKE_CXX_STANDARD 17)
2161 set(CMAKE_CXX_STANDARD_REQUIRED ON)
2162 add_executable(test main.cpp)
2165 test_cmake_project_file = os.sep.join([install_prefix, "CMakeLists.txt"])
2166 with open(test_cmake_project_file,
"w")
as f:
2167 f.write(test_cmake_project)
2170 cmake = shutil.which(
"cmake")
2173 "-DCMAKE_BUILD_TYPE=debug -G\"{generator}\" .".format(generator=platform_makefiles),
2177 if version ==
"3.00":
2178 self.assertEqual(return_code, 1)
2179 if import_method == cmake_find_package_import:
2180 self.assertIn(
'Could not find a configuration file for package "ns3" that is compatible',
2181 stderr.replace(
"\n",
""))
2182 elif import_method == pkgconfig_import:
2183 self.assertIn(
'A required package was not found',
2184 stderr.replace(
"\n",
""))
2186 raise Exception(
"Unknown import type")
2188 self.assertEqual(return_code, 0)
2189 self.assertIn(
"Build files", stdout)
2192 return_code, stdout, stderr =
run_program(
"cmake",
"--build .", cwd=install_prefix)
2194 if version ==
"3.00":
2195 self.assertEqual(return_code, 2)
2196 self.assertGreater(len(stderr), 0)
2198 self.assertEqual(return_code, 0)
2199 self.assertIn(
"Built target", stdout)
2203 test_program = os.path.join(install_prefix,
"test.exe")
2204 env_sep =
";" if ";" in os.environ[
"PATH"]
else ":"
2205 env = {
"PATH": env_sep.join([os.environ[
"PATH"], os.path.join(install_prefix,
"lib")])}
2207 test_program =
"./test"
2209 return_code, stdout, stderr =
run_program(test_program,
"", cwd=install_prefix, env=env)
2210 self.assertEqual(return_code, 0)
2213 return_code, stdout, stderr =
run_ns3(
"uninstall")
2214 self.assertIn(
"Built target uninstall", stdout)
2217 os.remove(version_file)
2218 with open(version_file,
"w")
as f:
2223 Tries to build scratch-simulator and subdir/scratch-simulator-subdir
2227 targets = {
"scratch/scratch-simulator":
"scratch-simulator",
2228 "scratch/scratch-simulator.cc":
"scratch-simulator",
2229 "scratch-simulator":
"scratch-simulator",
2230 "scratch/subdir/scratch-subdir":
"subdir_scratch-subdir",
2231 "subdir/scratch-subdir":
"subdir_scratch-subdir",
2232 "scratch-subdir":
"subdir_scratch-subdir",
2234 for (target_to_run, target_cmake)
in targets.items():
2236 build_line =
"target scratch_%s" % target_cmake
2237 return_code, stdout, stderr =
run_ns3(
"build %s" % target_to_run)
2238 self.assertEqual(return_code, 0)
2239 self.assertIn(build_line, stdout)
2242 return_code, stdout, stderr =
run_ns3(
"run %s --verbose" % target_to_run)
2243 self.assertEqual(return_code, 0)
2244 self.assertIn(build_line, stdout)
2245 stdout = stdout.replace(
"scratch_%s" % target_cmake,
"")
2246 self.assertIn(target_to_run.split(
"/")[-1].replace(
".cc",
""), stdout)
2250 Test if ns3 can alert correctly
in case a shortcut collision happens
2255 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
2256 self.assertEqual(return_code, 0)
2259 shutil.copy(
"./examples/tutorial/second.cc",
"./scratch/second.cc")
2262 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
2263 self.assertEqual(return_code, 0)
2266 return_code, stdout, stderr =
run_ns3(
"build second")
2267 self.assertEqual(return_code, 1)
2269 'Build target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2270 stdout.replace(os.sep,
'/')
2274 return_code, stdout, stderr =
run_ns3(
"build scratch/second")
2275 self.assertEqual(return_code, 0)
2279 return_code, stdout, stderr =
run_ns3(
"build tutorial/second")
2280 self.assertEqual(return_code, 0)
2284 return_code, stdout, stderr =
run_ns3(
"run second")
2285 self.assertEqual(return_code, 1)
2287 'Run target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2288 stdout.replace(os.sep,
'/')
2292 return_code, stdout, stderr =
run_ns3(
"run scratch/second")
2293 self.assertEqual(return_code, 0)
2296 return_code, stdout, stderr =
run_ns3(
"run tutorial/second")
2297 self.assertEqual(return_code, 0)
2300 os.remove(
"./scratch/second.cc")
2304 Test if we can build a static ns-3 library
and link it to static programs
2309 return_code, stdout, stderr =
run_ns3(
2310 "configure -G \"{generator}\" --enable-examples --disable-gtk --enable-static")
2315 self.assertEqual(return_code, 1)
2316 self.assertIn(
"Static builds are unsupported on Windows", stderr)
2319 self.assertEqual(return_code, 0)
2322 return_code, stdout, stderr =
run_ns3(
'build sample-simulator')
2323 self.assertEqual(return_code, 0)
2324 self.assertIn(
"Built target", stdout)
2330 Test if we can use python bindings
2335 except ModuleNotFoundError:
2336 self.skipTest(
"Cppyy was not found")
2339 return_code, stdout, stderr =
run_ns3(
2340 "configure -G \"{generator}\" --enable-examples --enable-python-bindings")
2343 self.assertEqual(return_code, 0)
2346 return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
2347 self.assertEqual(return_code, 0)
2350 return_code, stdout, stderr =
run_program(
"test.py",
"-p mixed-wired-wireless", python=
True)
2351 self.assertEqual(return_code, 0)
2354 return_code, stdout, stderr =
run_program(
"test.py",
"-p ./examples/wireless/mixed-wired-wireless", python=
True)
2355 self.assertEqual(return_code, 0)
2359 Test if we had regressions
with brite, click
and openflow modules
2360 that depend on homonymous libraries
2363 if shutil.which(
"git")
is None:
2364 self.skipTest(
"Missing git")
2367 return_code, stdout, stderr =
run_ns3(
"configure -- -DNS3_FETCH_OPTIONAL_COMPONENTS=ON")
2368 self.assertEqual(return_code, 0)
2372 return_code, stdout, stderr =
run_ns3(
"build brite click openflow")
2373 self.assertEqual(return_code, 0)
2377 Test if we can link contrib modules to src modules
2380 if shutil.which(
"git")
is None:
2381 self.skipTest(
"Missing git")
2383 destination_contrib = os.path.join(ns3_path,
"contrib/test-contrib-dependency")
2384 destination_src = os.path.join(ns3_path,
"src/test-src-dependant-on-contrib")
2386 if os.path.exists(destination_contrib):
2387 shutil.rmtree(destination_contrib)
2388 if os.path.exists(destination_src):
2389 shutil.rmtree(destination_src)
2392 shutil.copytree(os.path.join(ns3_path,
"build-support/test-files/test-contrib-dependency"),
2393 destination_contrib)
2394 shutil.copytree(os.path.join(ns3_path,
"build-support/test-files/test-src-dependant-on-contrib"),
2398 return_code, stdout, stderr =
run_ns3(
"configure --enable-examples")
2399 self.assertEqual(return_code, 0)
2402 return_code, stdout, stderr =
run_ns3(
"run source-example")
2403 self.assertEqual(return_code, 0)
2406 shutil.rmtree(destination_contrib)
2407 shutil.rmtree(destination_src)
2412 Tests ns3 usage in more realistic scenarios
2417 Reuse cleaning/release configuration from NS3BaseTestCase
if flag
is cleaned
2418 Here examples, tests
and documentation are also enabled.
2425 return_code, stdout, stderr =
run_ns3(
2426 "configure -d release -G \"{generator}\" --enable-examples --enable-tests")
2430 self.assertTrue(os.path.exists(ns3_lock_filename))
2436 self.assertTrue(os.path.exists(ns3_lock_filename))
2443 Try to build the project
2446 return_code, stdout, stderr = run_ns3("build")
2447 self.assertEqual(return_code, 0)
2448 self.assertIn(
"Built target", stdout)
2450 self.assertTrue(os.path.exists(program))
2453 self.assertIn(module.replace(
"ns3-",
""),
";".join(libraries))
2454 self.assertIn(cmake_build_project_command, stdout)
2458 Try to build and run test-runner
2461 return_code, stdout, stderr = run_ns3('run "test-runner --list" --verbose')
2462 self.assertEqual(return_code, 0)
2463 self.assertIn(
"Built target test-runner", stdout)
2468 Try to build and run a library
2471 return_code, stdout, stderr = run_ns3("run core")
2472 self.assertEqual(return_code, 1)
2473 self.assertIn(
"Couldn't find the specified program: core", stderr)
2477 Try to build and run an unknown target
2480 return_code, stdout, stderr = run_ns3("run nonsense")
2481 self.assertEqual(return_code, 1)
2482 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2486 Try to run test-runner without building
2489 return_code, stdout, stderr = run_ns3('build test-runner')
2490 self.assertEqual(return_code, 0)
2492 return_code, stdout, stderr =
run_ns3(
'run "test-runner --list" --no-build --verbose')
2493 self.assertEqual(return_code, 0)
2494 self.assertNotIn(
"Built target test-runner", stdout)
2499 Test ns3 fails to run a library
2502 return_code, stdout, stderr = run_ns3("run core --no-build")
2503 self.assertEqual(return_code, 1)
2504 self.assertIn(
"Couldn't find the specified program: core", stderr)
2508 Test ns3 fails to run an unknown program
2511 return_code, stdout, stderr = run_ns3("run nonsense --no-build")
2512 self.assertEqual(return_code, 1)
2513 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2517 Test if scratch simulator
is executed through gdb
and lldb
2520 if shutil.which(
"gdb")
is None:
2521 self.skipTest(
"Missing gdb")
2523 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
2524 self.assertEqual(return_code, 0)
2526 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --gdb --verbose --no-build", env={
"gdb_eval":
"1"})
2527 self.assertEqual(return_code, 0)
2528 self.assertIn(
"scratch-simulator", stdout)
2530 self.assertIn(
"GNU gdb", stdout)
2532 self.assertIn(
"No debugging symbols found", stdout)
2536 Test if scratch simulator
is executed through valgrind
2539 if shutil.which(
"valgrind")
is None:
2540 self.skipTest(
"Missing valgrind")
2542 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
2543 self.assertEqual(return_code, 0)
2545 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --valgrind --verbose --no-build")
2546 self.assertEqual(return_code, 0)
2547 self.assertIn(
"scratch-simulator", stderr)
2548 self.assertIn(
"Memcheck", stderr)
2552 Test the doxygen target that does trigger a full build
2555 if shutil.which(
"doxygen")
is None:
2556 self.skipTest(
"Missing doxygen")
2558 if shutil.which(
"bash")
is None:
2559 self.skipTest(
"Missing bash")
2561 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2563 doxygen_files = [
"introspected-command-line.h",
"introspected-doxygen.h"]
2564 for filename
in doxygen_files:
2565 file_path = os.sep.join([doc_folder, filename])
2566 if os.path.exists(file_path):
2567 os.remove(file_path)
2574 return_code, stdout, stderr =
run_ns3(
"docs doxygen")
2575 self.assertEqual(return_code, 0)
2577 self.assertIn(
"Built target doxygen", stdout)
2581 Test the doxygen target that doesn't trigger a full build
2584 if shutil.which(
"doxygen")
is None:
2585 self.skipTest(
"Missing doxygen")
2593 return_code, stdout, stderr =
run_ns3(
"docs doxygen-no-build")
2594 self.assertEqual(return_code, 0)
2596 self.assertIn(
"Built target doxygen-no-build", stdout)
2600 Test every individual target for Sphinx-based documentation
2603 if shutil.which(
"sphinx-build")
is None:
2604 self.skipTest(
"Missing sphinx")
2606 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2609 for target
in [
"installation",
"contributing",
"manual",
"models",
"tutorial"]:
2611 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2612 doc_temp_folder = os.sep.join([doc_folder, target,
"source-temp"])
2613 if os.path.exists(doc_build_folder):
2614 shutil.rmtree(doc_build_folder)
2615 if os.path.exists(doc_temp_folder):
2616 shutil.rmtree(doc_temp_folder)
2619 return_code, stdout, stderr =
run_ns3(
"docs %s" % target)
2620 self.assertEqual(return_code, 0, target)
2622 self.assertIn(
"Built target sphinx_%s" % target, stdout)
2625 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2626 self.assertTrue(os.path.exists(doc_build_folder))
2629 for build_type
in [
"latex",
"html",
"singlehtml"]:
2630 self.assertTrue(os.path.exists(os.sep.join([doc_build_folder, build_type])))
2634 Test the documentation target that builds
2635 both doxygen and sphinx based documentation
2638 if shutil.which(
"doxygen")
is None:
2639 self.skipTest(
"Missing doxygen")
2640 if shutil.which(
"sphinx-build")
is None:
2641 self.skipTest(
"Missing sphinx")
2643 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2652 for target
in [
"manual",
"models",
"tutorial"]:
2653 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2654 if os.path.exists(doc_build_folder):
2655 shutil.rmtree(doc_build_folder)
2657 return_code, stdout, stderr =
run_ns3(
"docs all")
2658 self.assertEqual(return_code, 0)
2660 self.assertIn(
"Built target sphinx", stdout)
2662 self.assertIn(
"Built target doxygen", stdout)
2666 Try to set ownership of scratch-simulator from current user to root,
2667 and change execution permissions
2672 sudo_password = os.getenv(
"SUDO_PASSWORD",
None)
2675 if sudo_password
is None:
2676 self.skipTest(
"SUDO_PASSWORD environment variable was not specified")
2679 self.assertFalse(enable_sudo
is True)
2682 return_code, stdout, stderr =
run_ns3(
'run scratch-simulator')
2683 self.assertEqual(return_code, 0)
2684 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2686 scratch_simulator_path =
list(filter(
lambda x: x
if "scratch-simulator" in x
else None,
2690 prev_fstat = os.stat(scratch_simulator_path)
2693 return_code, stdout, stderr =
run_ns3(
'run scratch-simulator --enable-sudo',
2694 env={
"SUDO_PASSWORD": sudo_password})
2695 self.assertEqual(return_code, 0)
2696 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2698 fstat = os.stat(scratch_simulator_path)
2703 likely_fuse_mount = ((prev_fstat.st_mode & stat.S_ISUID) == (fstat.st_mode & stat.S_ISUID))
and \
2704 prev_fstat.st_uid == 0
2706 if win32
or likely_fuse_mount:
2707 self.skipTest(
"Windows or likely a FUSE mount")
2710 self.assertEqual(fstat.st_uid, 0)
2711 self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID)
2714 return_code, stdout, stderr =
run_ns3(
'configure --enable-sudo')
2715 self.assertEqual(return_code, 0)
2719 self.assertTrue(enable_sudo)
2723 if os.path.exists(executable):
2724 os.remove(executable)
2727 return_code, stdout, stderr =
run_ns3(
'build', env={
"SUDO_PASSWORD": sudo_password})
2728 self.assertEqual(return_code, 0)
2731 self.assertIn(
"chown root", stdout)
2732 self.assertIn(
"chmod u+s", stdout)
2734 self.assertIn(os.path.basename(executable), stdout)
2737 fstat = os.stat(scratch_simulator_path)
2738 self.assertEqual(fstat.st_uid, 0)
2739 self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID)
2743 Check if command template
is working
2748 return_code0, stdout0, stderr0 =
run_ns3(
'run sample-simulator --command-template')
2749 self.assertEqual(return_code0, 2)
2750 self.assertIn(
"argument --command-template: expected one argument", stderr0)
2752 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template=" "')
2753 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --command-template " "')
2754 return_code3, stdout3, stderr3 =
run_ns3(
'run sample-simulator --command-template "echo "')
2755 self.assertEqual((return_code1, return_code2, return_code3), (1, 1, 1))
2756 for stderr
in [stderr1, stderr2, stderr3]:
2757 self.assertIn(
"not all arguments converted during string formatting", stderr)
2760 return_code4, stdout4, _ =
run_ns3(
'run sample-simulator --command-template "%s --PrintVersion" --verbose')
2761 return_code5, stdout5, _ =
run_ns3(
'run sample-simulator --command-template="%s --PrintVersion" --verbose')
2762 self.assertEqual((return_code4, return_code5), (0, 0))
2764 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout4)
2765 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout5)
2769 Check if all flavors of different argument passing to
2770 executable targets are working
2775 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --verbose')
2776 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template="%s --help" --verbose')
2777 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --verbose -- --help')
2779 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2780 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout0)
2781 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout1)
2782 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout2)
2785 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --no-build')
2786 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template="%s --help" --no-build')
2787 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --no-build -- --help')
2788 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2789 self.assertEqual(stdout0, stdout1)
2790 self.assertEqual(stdout1, stdout2)
2791 self.assertEqual(stderr0, stderr1)
2792 self.assertEqual(stderr1, stderr2)
2795 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --PrintGlobals" --verbose')
2796 return_code1, stdout1, stderr1 =
run_ns3(
'run "sample-simulator --PrintGroups" --verbose')
2797 return_code2, stdout2, stderr2 =
run_ns3(
'run "sample-simulator --PrintTypeIds" --verbose')
2799 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2800 self.assertIn(
"sample-simulator{ext} --PrintGlobals".format(ext=ext), stdout0)
2801 self.assertIn(
"sample-simulator{ext} --PrintGroups".format(ext=ext), stdout1)
2802 self.assertIn(
"sample-simulator{ext} --PrintTypeIds".format(ext=ext), stdout2)
2805 cmd =
'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" --verbose -- --PrintTypeIds'
2806 return_code, stdout, stderr =
run_ns3(cmd)
2807 self.assertEqual(return_code, 0)
2812 self.assertIn(
"sample-simulator{ext} --PrintGroups --PrintGlobals --PrintTypeIds".format(ext=ext), stdout)
2815 cmd0 =
'run sample-simulator --command-template="%s " --PrintTypeIds'
2816 cmd1 =
'run sample-simulator --PrintTypeIds'
2818 return_code0, stdout0, stderr0 =
run_ns3(cmd0)
2819 return_code1, stdout1, stderr1 =
run_ns3(cmd1)
2820 self.assertEqual((return_code0, return_code1), (1, 1))
2821 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr0)
2822 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr1)
2826 Test if scratch simulator
is executed through lldb
2829 if shutil.which(
"lldb")
is None:
2830 self.skipTest(
"Missing lldb")
2832 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --lldb --verbose --no-build")
2833 self.assertEqual(return_code, 0)
2834 self.assertIn(
"scratch-simulator", stdout)
2835 self.assertIn(
"(lldb) target create", stdout)
2840 ns-3 tests to control the quality of the repository over time,
2841 by checking the state of URLs listed and more
2846 Test if all urls
in source files are alive
2855 self.skipTest(
"Django URL validators are not available")
2861 urllib3.disable_warnings()
2864 self.skipTest(
"Requests library is not available")
2866 regex = re.compile(
r'((http|https)://[^\ \n\)\"\'\}><\]\;\`\\]*)')
2869 whitelisted_urls = {
"https://gitlab.com/your-user-name/ns-3-dev",
2870 "https://www.nsnam.org/release/ns-allinone-3.31.rc1.tar.bz2",
2871 "https://www.nsnam.org/release/ns-allinone-3.X.rcX.tar.bz2",
2872 "https://www.nsnam.org/releases/ns-3-x",
2873 "https://www.nsnam.org/releases/ns-allinone-3.(x-1",
2874 "https://www.nsnam.org/releases/ns-allinone-3.x.tar.bz2",
2876 "https://cmake.org/cmake/help/latest/manual/cmake-",
2877 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_",
2879 "http://www.lysator.liu.se/~alla/dia/",
2881 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_Digital_Terrestrial_Television_Broadcasting_(DTTB",
2882 "http://en.wikipedia.org/wiki/Namespace_(computer_science",
2883 "http://en.wikipedia.org/wiki/Bonobo_(component_model",
2884 "http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85",
2886 "http://www.research.att.com/info/kpv/",
2887 "http://www.research.att.com/~gsf/",
2891 files_and_urls = set()
2893 for topdir
in [
"bindings",
"doc",
"examples",
"src",
"utils"]:
2894 for root, dirs, files
in os.walk(topdir):
2896 if "build" in root
or "_static" in root
or "source-temp" in root
or 'html' in root:
2899 filepath = os.path.join(root, file)
2902 if not os.path.isfile(filepath):
2906 if file.endswith(
".svg"):
2910 with open(filepath,
"r")
as f:
2911 matches = regex.findall(f.read())
2916 urls =
list(map(
lambda x: x[0][:-1]
if x[0][-1]
in ".," else x[0], matches))
2917 except UnicodeDecodeError:
2918 skipped_files.append(filepath)
2922 for url
in set(urls) - unique_urls - whitelisted_urls:
2923 unique_urls.add(url)
2924 files_and_urls.add((filepath, url))
2927 from django.core.validators
import URLValidator
2928 from django.core.exceptions
import ValidationError
2929 validate_url = URLValidator()
2933 'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
2937 def test_file_url(args):
2938 test_filepath, test_url = args
2939 dead_link_msg =
None
2943 validate_url(test_url)
2944 except ValidationError:
2945 dead_link_msg =
"%s: URL %s, invalid URL" % (test_filepath, test_url)
2946 except Exception
as e:
2947 self.assertEqual(
False,
True, msg=e.__str__())
2949 if dead_link_msg
is not None:
2950 return dead_link_msg
2958 response = requests.get(test_url, verify=
False, headers=headers, timeout=50)
2961 if response.status_code
in [200, 301]:
2962 dead_link_msg =
None
2967 if response.status_code
in [302, 308, 500, 503]:
2968 if response.reason.lower()
in [
'found',
2969 'moved temporarily',
2970 'permanent redirect',
2972 'service temporarily unavailable'
2974 dead_link_msg =
None
2978 dead_link_msg =
"%s: URL %s: returned code %d" % (test_filepath, test_url, response.status_code)
2979 except requests.exceptions.InvalidURL:
2980 dead_link_msg =
"%s: URL %s: invalid URL" % (test_filepath, test_url)
2981 except requests.exceptions.SSLError:
2982 dead_link_msg =
"%s: URL %s: SSL error" % (test_filepath, test_url)
2983 except requests.exceptions.TooManyRedirects:
2984 dead_link_msg =
"%s: URL %s: too many redirects" % (test_filepath, test_url)
2985 except Exception
as e:
2987 error_msg = e.args[0].reason.__str__()
2988 except AttributeError:
2989 error_msg = e.args[0]
2990 dead_link_msg =
"%s: URL %s: failed with exception: %s" % (test_filepath, test_url, error_msg)
2992 return dead_link_msg
2995 from concurrent.futures
import ThreadPoolExecutor
2996 with ThreadPoolExecutor(max_workers=100)
as executor:
2997 dead_links =
list(executor.map(test_file_url,
list(files_and_urls)))
3000 dead_links =
list(sorted(filter(
lambda x: x
is not None, dead_links)))
3001 self.assertEqual(len(dead_links), 0, msg=
"\n".join([
"Dead links found:", *dead_links]))
3005 Test if all tests can be executed without hitting major memory bugs
3008 return_code, stdout, stderr = run_ns3(
3009 "configure --enable-tests --enable-examples --enable-sanitizers -d optimized")
3010 self.assertEqual(return_code, 0)
3012 test_return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
3013 self.assertEqual(test_return_code, 0)
3017 Check if images
in the docs are above a brightness threshold.
3018 This should prevent screenshots
with dark UI themes.
3021 if shutil.which(
"convert")
is None:
3022 self.skipTest(
"Imagemagick was not found")
3024 from pathlib
import Path
3027 image_extensions = [
"png",
"jpg"]
3029 for extension
in image_extensions:
3030 images +=
list(Path(
"./doc").glob(
"**/figures/*.{ext}".format(ext=extension)))
3031 images +=
list(Path(
"./doc").glob(
"**/figures/**/*.{ext}".format(ext=extension)))
3034 imagemagick_get_image_brightness = \
3035 'convert {image} -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]" info:'
3039 brightness_threshold = 50
3040 for image
in images:
3041 brightness = subprocess.check_output(imagemagick_get_image_brightness.format(image=image).split())
3042 brightness = float(brightness.decode().strip(
"'\""))
3043 self.assertGreater(brightness, brightness_threshold,
3044 "Image darker than threshold (%d < %d): %s" % (brightness, brightness_threshold, image)
3054 test_completeness = {
3055 "style": [NS3UnusedSourcesTestCase,
3058 "build": [NS3CommonSettingsTestCase,
3059 NS3ConfigureBuildProfileTestCase,
3060 NS3ConfigureTestCase,
3061 NS3BuildBaseTestCase,
3062 NS3ExpectedUseTestCase,
3064 "complete": [NS3UnusedSourcesTestCase,
3066 NS3CommonSettingsTestCase,
3067 NS3ConfigureBuildProfileTestCase,
3068 NS3ConfigureTestCase,
3069 NS3BuildBaseTestCase,
3070 NS3ExpectedUseTestCase,
3071 NS3QualityControlTestCase,
3073 "extras": [NS3DependenciesTestCase,
3079 parser = argparse.ArgumentParser(
"Test suite for the ns-3 buildsystem")
3080 parser.add_argument(
"-c",
"--completeness",
3081 choices=test_completeness.keys(),
3083 parser.add_argument(
"-tn",
"--test-name",
3087 parser.add_argument(
"-rtn",
"--resume-from-test-name",
3091 parser.add_argument(
"-q",
"--quiet",
3092 action=
"store_true",
3094 args = parser.parse_args(sys.argv[1:])
3096 loader = unittest.TestLoader()
3097 suite = unittest.TestSuite()
3100 for testCase
in test_completeness[args.completeness]:
3101 suite.addTests(loader.loadTestsFromTestCase(testCase))
3106 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
3108 tests_to_run = set(map(
lambda x: x
if args.test_name
in x
else None, tests.keys()))
3109 tests_to_remove = set(tests) - set(tests_to_run)
3110 for test_to_remove
in tests_to_remove:
3111 suite._tests.remove(tests[test_to_remove])
3114 if args.resume_from_test_name:
3116 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
3117 keys =
list(tests.keys())
3119 while args.resume_from_test_name
not in keys[0]
and len(tests) > 0:
3120 suite._tests.remove(tests[keys[0]])
3124 ns3rc_script_bak = ns3rc_script +
".bak"
3125 if os.path.exists(ns3rc_script)
and not os.path.exists(ns3rc_script_bak):
3126 shutil.move(ns3rc_script, ns3rc_script_bak)
3129 runner = unittest.TextTestRunner(failfast=
True, verbosity=1
if args.quiet
else 2)
3133 if os.path.exists(ns3rc_script_bak):
3134 shutil.move(ns3rc_script_bak, ns3rc_script)
3137if __name__ ==
'__main__':
Python-on-whales wrapper for Docker-based ns-3 tests.
def __exit__(self, exc_type, exc_val, exc_tb)
Clean up the managed container at the end of the block "with DockerContainerManager() as container".
def __init__(self, unittest.TestCase currentTestCase, str containerName="ubuntu:latest")
Create and start container with containerName in the current ns-3 directory.
def __enter__(self)
Return the managed container when entiring the block "with DockerContainerManager() as container".
container
The Python-on-whales container instance.
Generic test case with basic function inherited by more complex tests.
def config_ok(self, return_code, stdout)
Check if configuration for release mode worked normally.
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
def setUp(self)
Clean configuration/build artifacts before testing configuration and build settings After configuring...
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
Tests ns3 regarding building the project.
def test_06_TestVersionFile(self)
Test if changing the version file affects the library names.
def test_10_AmbiguityCheck(self)
Test if ns3 can alert correctly in case a shortcut collision happens.
def test_01_BuildExistingTargets(self)
Try building the core library.
def test_12_CppyyBindings(self)
Test if we can use python bindings.
def test_08_InstallationAndUninstallation(self)
Tries setting a ns3 version, then installing it.
def test_11_StaticBuilds(self)
Test if we can build a static ns-3 library and link it to static programs.
def setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned.
def test_02_BuildNonExistingTargets(self)
Try building core-test library without tests enabled.
def test_04_BuildProjectNoTaskLines(self)
Try hiding task lines.
def test_14_LinkContribModuleToSrcModule(self)
Test if we can link contrib modules to src modules.
def test_03_BuildProject(self)
Try building the project:
def test_13_FetchOptionalComponents(self)
Test if we had regressions with brite, click and openflow modules that depend on homonymous libraries...
def test_09_Scratches(self)
Tries to build scratch-simulator and subdir/scratch-simulator-subdir.
def test_05_BreakBuild(self)
Try removing an essential file to break the build.
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
def test_07_OutputDirectory(self)
Try setting a different output directory and if everything is in the right place and still working co...
ns3_libraries
ns3_libraries holds a list of built module libraries # noqa
ns3 tests related to generic options
def test_05_CheckVersion(self)
Test only passing 'show version' argument to ns3.
def setUp(self)
Clean configuration/build artifacts before common commands.
def test_01_NoOption(self)
Test not passing any arguments to.
def test_02_NoTaskLines(self)
Test only passing –quiet argument to ns3.
def test_03_CheckConfig(self)
Test only passing 'show config' argument to ns3.
def test_04_CheckProfile(self)
Test only passing 'show profile' argument to ns3.
ns-3 tests related to dependencies
def test_01_CheckIfIncludedHeadersMatchLinkedModules(self)
Checks if headers from different modules (src/A, contrib/B) that are included by the current module (...
Tests ns3 usage in more realistic scenarios.
def test_10_DoxygenWithBuild(self)
Test the doxygen target that does trigger a full build.
def test_02_BuildAndRunExistingExecutableTarget(self)
Try to build and run test-runner.
def test_08_RunNoBuildGdb(self)
Test if scratch simulator is executed through gdb and lldb.
def test_05_RunNoBuildExistingExecutableTarget(self)
Try to run test-runner without building.
def test_06_RunNoBuildExistingLibraryTarget(self)
Test ns3 fails to run a library.
def test_03_BuildAndRunExistingLibraryTarget(self)
Try to build and run a library.
def test_01_BuildProject(self)
Try to build the project.
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
def test_14_EnableSudo(self)
Try to set ownership of scratch-simulator from current user to root, and change execution permissions...
def test_16_ForwardArgumentsToRunTargets(self)
Check if all flavors of different argument passing to executable targets are working.
def test_17_RunNoBuildLldb(self)
Test if scratch simulator is executed through lldb.
def test_15_CommandTemplate(self)
Check if command template is working.
def test_04_BuildAndRunNonExistingTarget(self)
Try to build and run an unknown target.
def test_07_RunNoBuildNonExistingExecutableTarget(self)
Test ns3 fails to run an unknown program.
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
def test_09_RunNoBuildValgrind(self)
Test if scratch simulator is executed through valgrind.
def test_13_Documentation(self)
Test the documentation target that builds both doxygen and sphinx based documentation.
def setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned Here examples,...
def test_11_DoxygenWithoutBuild(self)
Test the doxygen target that doesn't trigger a full build.
def test_12_SphinxDocumentation(self)
Test every individual target for Sphinx-based documentation.
ns-3 tests to control the quality of the repository over time, by checking the state of URLs listed a...
def test_03_CheckImageBrightness(self)
Check if images in the docs are above a brightness threshold.
def test_02_MemoryCheckWithSanitizers(self)
Test if all tests can be executed without hitting major memory bugs.
def test_01_CheckForDeadLinksInSources(self)
Test if all urls in source files are alive.
ns-3 tests to check if the source code, whitespaces and CMake formatting are according to the coding ...
def test_01_CheckCMakeFormat(self)
Check if there is any difference between tracked file after applying cmake-format.
None setUp(self)
Import GitRepo and load the original diff state of the repository before the tests.
ns-3 tests related to checking if source files were left behind, not being used by CMake
dict directory_and_files
dictionary containing directories with .cc source files # noqa
def test_01_UnusedExampleSources(self)
Test if all example source files are being used in their respective CMakeLists.txt.
def setUp(self)
Scan all C++ source files and add them to a list based on their path.
def test_02_UnusedModuleSources(self)
Test if all module source files are being used in their respective CMakeLists.txt.
def test_03_UnusedUtilsSources(self)
Test if all utils source files are being used in their respective CMakeLists.txt.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
def run_ns3(args, env=None, generator=platform_makefiles)
Runs the ns3 wrapper script with arguments.
def get_programs_list()
Extracts the programs list from .lock-ns3.
def get_libraries_list(lib_outdir=usual_lib_outdir)
Gets a list of built libraries.
def get_test_enabled()
Check if tests are enabled in the .lock-ns3.
def read_lock_entry(entry)
Read interesting entries from the .lock-ns3 file.
def get_headers_list(outdir=usual_outdir)
Gets a list of header files.
def run_program(program, args, python=False, cwd=ns3_path, env=None)
Runs a program with the given arguments and returns a tuple containing (error code,...
def get_enabled_modules()
partial cmake_build_target_command