22 Test suite for the ns3 wrapper script
32 from functools
import partial
35 ns3_path = os.path.dirname(os.path.abspath(os.sep.join([__file__,
"../../"])))
36 ns3_lock_filename = os.path.join(ns3_path,
".lock-ns3_%s_build" % sys.platform)
37 ns3_script = os.sep.join([ns3_path,
"ns3"])
38 ns3rc_script = os.sep.join([ns3_path,
".ns3rc"])
39 usual_outdir = os.sep.join([ns3_path,
"build"])
40 usual_lib_outdir = os.sep.join([usual_outdir,
"lib"])
46 num_threads =
max(1, os.cpu_count() - 1)
47 cmake_build_project_command =
"cmake --build . -j".format(ns3_path=ns3_path)
48 cmake_build_target_command = partial(
"cmake --build . -j {jobs} --target {target}".format,
51 win32 = sys.platform ==
"win32"
52 platform_makefiles =
"MinGW Makefiles" if win32
else "Unix Makefiles"
53 ext =
".exe" if win32
else ""
56 def run_ns3(args, env=None, generator=platform_makefiles):
58 Runs the ns3 wrapper script with arguments
59 @param args: string containing arguments that will get split before calling ns3
60 @param env: environment variables dictionary
61 @param generator: CMake generator
62 @return tuple containing (error code, stdout and stderr)
65 possible_leftovers = [
"contrib/borked",
"contrib/calibre"]
66 for leftover
in possible_leftovers:
67 if os.path.exists(leftover):
68 shutil.rmtree(leftover, ignore_errors=
True)
70 args = args.format(generator=generator)
75 return run_program(ns3_script, args, python=
True, env=env)
79 def run_program(program, args, python=False, cwd=ns3_path, env=None):
81 Runs a program with the given arguments and returns a tuple containing (error code, stdout and stderr)
82 @param program: program to execute (or python script)
83 @param args: string containing arguments that will get split before calling the program
84 @param python: flag indicating whether the program is a python script
85 @param cwd: the working directory used that will be the root folder for the execution
86 @param env: environment variables dictionary
87 @return tuple containing (error code, stdout and stderr)
90 raise Exception(
"args should be a string")
94 arguments = [sys.executable, program]
99 arguments.extend(re.findall(
"(?:\".*?\"|\S)+", args))
101 for i
in range(len(arguments)):
102 arguments[i] = arguments[i].replace(
"\"",
"")
105 current_env = os.environ.copy()
109 current_env.update(env)
112 ret = subprocess.run(
114 stdin=subprocess.DEVNULL,
115 stdout=subprocess.PIPE,
116 stderr=subprocess.PIPE,
121 return ret.returncode, ret.stdout.decode(sys.stdout.encoding), ret.stderr.decode(sys.stderr.encoding)
126 Extracts the programs list from .lock-ns3
127 @return list of programs.
130 with open(ns3_lock_filename)
as f:
131 exec(f.read(), globals(), values)
133 programs_list = values[
"ns3_runnable_programs"]
137 programs_list =
list(map(
lambda x: x + ext, programs_list))
143 Gets a list of built libraries
144 @param lib_outdir: path containing libraries
145 @return list of built libraries.
147 libraries = glob.glob(lib_outdir +
'/*', recursive=
True)
148 return list(filter(
lambda x:
"scratch-nested-subdir-lib" not in x, libraries))
153 Gets a list of header files
154 @param outdir: path containing headers
155 @return list of headers.
157 return glob.glob(outdir +
'/**/*.h', recursive=
True)
162 Read interesting entries from the .lock-ns3 file
163 @param entry: entry to read from .lock-ns3
164 @return value of the requested entry.
167 with open(ns3_lock_filename)
as f:
168 exec(f.read(), globals(), values)
169 return values.get(entry,
None)
174 Check if tests are enabled in the .lock-ns3
182 Check if tests are enabled in the .lock-ns3
183 @return list of enabled modules (prefixed with 'ns3-').
190 Python-on-whales wrapper for Docker-based ns-3 tests
193 def __init__(self, currentTestCase: unittest.TestCase, containerName: str =
"ubuntu:latest"):
195 Create and start container with containerName in the current ns-3 directory
196 @param self: the current DockerContainerManager instance
197 @param currentTestCase: the test case instance creating the DockerContainerManager
198 @param containerName: name of the container image to be used
200 global DockerException
202 from python_on_whales
import docker
203 from python_on_whales.exceptions
import DockerException
204 except ModuleNotFoundError:
206 DockerException =
None
207 currentTestCase.skipTest(
"python-on-whales was not found")
210 with open(os.path.expanduser(
"~/.bashrc"),
"r")
as f:
211 docker_settings = re.findall(
"(DOCKER_.*=.*)", f.read())
212 for setting
in docker_settings:
213 key, value = setting.split(
"=")
214 os.environ[key] = value
215 del docker_settings, setting, key, value
220 interactive=
True, detach=
True,
222 volumes=[(ns3_path,
"/ns-3-dev")]
226 def split_exec(docker_container, cmd):
227 return docker_container._execute(cmd.split(), workdir=
"/ns-3-dev")
234 Return the managed container when entiring the block "with DockerContainerManager() as container"
235 @param self: the current DockerContainerManager instance
236 @return container managed by DockerContainerManager.
242 Clean up the managed container at the end of the block "with DockerContainerManager() as container"
243 @param self: the current DockerContainerManager instance
244 @param exc_type: unused parameter
245 @param exc_val: unused parameter
246 @param exc_tb: unused parameter
255 ns-3 tests related to checking if source files were left behind, not being used by CMake
259 directory_and_files = {}
263 Scan all C++ source files and add them to a list based on their path
266 for root, dirs, files
in os.walk(ns3_path):
267 if "gitlab-ci-local" in root:
270 if name.endswith(
".cc"):
271 path = os.path.join(root, name)
272 directory = os.path.dirname(path)
279 Test if all example source files are being used in their respective CMakeLists.txt
282 unused_sources = set()
285 if os.sep +
"examples" not in example_directory:
289 with open(os.path.join(example_directory,
"CMakeLists.txt"),
"r")
as f:
290 cmake_contents = f.read()
295 if os.path.basename(file).replace(
".cc",
"")
not in cmake_contents:
296 unused_sources.add(file)
298 self.assertListEqual([],
list(unused_sources))
302 Test if all module source files are being used in their respective CMakeLists.txt
305 unused_sources = set()
308 is_not_module =
not (
"src" in directory
or "contrib" in directory)
309 is_example = os.sep +
"examples" in directory
310 is_bindings = os.sep +
"bindings" in directory
312 if is_not_module
or is_bindings
or is_example:
317 cmake_path = os.path.join(directory,
"CMakeLists.txt")
318 while not os.path.exists(cmake_path):
319 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
320 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
323 with open(cmake_path,
"r")
as f:
324 cmake_contents = f.read()
328 if os.path.basename(file)
not in cmake_contents:
329 unused_sources.add(file)
332 exceptions = [
"win32-system-wall-clock-ms.cc",
334 for exception
in exceptions:
335 for unused_source
in unused_sources:
336 if os.path.basename(unused_source) == exception:
337 unused_sources.remove(unused_source)
340 self.assertListEqual([],
list(unused_sources))
344 Test if all utils source files are being used in their respective CMakeLists.txt
347 unused_sources = set()
350 is_module =
"src" in directory
or "contrib" in directory
351 if os.sep +
"utils" not in directory
or is_module:
356 cmake_path = os.path.join(directory,
"CMakeLists.txt")
357 while not os.path.exists(cmake_path):
358 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
359 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
362 with open(cmake_path,
"r")
as f:
363 cmake_contents = f.read()
367 if os.path.basename(file)
not in cmake_contents:
368 unused_sources.add(file)
370 self.assertListEqual([],
list(unused_sources))
375 ns-3 tests related to dependencies
380 Checks if headers from different modules (src/A, contrib/B) that are included by
381 the current module (src/C) source files correspond to the list of linked modules
383 LIBRARIES_TO_LINK A (missing B)
387 headers_to_modules = {}
388 module_paths = glob.glob(ns3_path +
"/src/*/") + glob.glob(ns3_path +
"/contrib/*/")
390 for path
in module_paths:
392 cmake_path = os.path.join(path,
"CMakeLists.txt")
393 with open(cmake_path,
"r")
as f:
394 cmake_contents = f.readlines()
396 module_name = os.path.relpath(path, ns3_path)
397 module_name_nodir = module_name.replace(
"src/",
"").replace(
"contrib/",
"")
398 modules[module_name_nodir] = {
"sources": set(),
401 "included_headers": set(),
402 "included_libraries": set(),
406 for line
in cmake_contents:
407 base_name = os.path.basename(line[:-1])
408 if not os.path.exists(os.path.join(path, line.strip())):
413 modules[module_name_nodir][
"headers"].add(base_name)
414 modules[module_name_nodir][
"sources"].add(base_name)
417 headers_to_modules[base_name] = module_name_nodir
421 modules[module_name_nodir][
"sources"].add(base_name)
423 if ".cc" in line
or ".h" in line:
425 source_file = os.path.join(ns3_path, module_name, line.strip())
426 with open(source_file,
"r", encoding=
"utf-8")
as f:
427 source_contents = f.read()
428 modules[module_name_nodir][
"included_headers"].update(map(
lambda x: x.replace(
"ns3/",
""),
429 re.findall(
"#include.*[\"|<](.*)[\"|>]",
436 modules[module_name_nodir][
"libraries"].update(re.findall(
"\\${lib(.*)}",
"".join(cmake_contents)))
439 all_project_headers = set(headers_to_modules.keys())
442 print(file=sys.stderr)
443 for module
in sorted(modules):
444 external_headers = modules[module][
"included_headers"].difference(all_project_headers)
445 project_headers_included = modules[module][
"included_headers"].difference(external_headers)
446 modules[module][
"included_libraries"] = set(
447 [headers_to_modules[x]
for x
in project_headers_included]).difference(
450 diff = modules[module][
"included_libraries"].difference(modules[module][
"libraries"])
452 print(
"Module %s includes modules that are not linked: %s" % (module,
", ".join(
list(diff))),
459 self.assertTrue(
True)
464 ns-3 tests to check if the source code, whitespaces and CMake formatting
465 are according to the coding style
475 Import GitRepo and load the original diff state of the repository before the tests
478 if not NS3StyleTestCase.starting_diff:
480 if shutil.which(
"git")
is None:
481 self.skipTest(
"Git is not available")
487 self.skipTest(
"GitPython is not available")
490 repo = Repo(ns3_path)
491 except git.exc.InvalidGitRepositoryError:
492 self.skipTest(
"ns-3 directory does not contain a .git directory")
494 hcommit = repo.head.commit
495 NS3StyleTestCase.starting_diff = hcommit.diff(
None)
496 NS3StyleTestCase.repo = repo
498 if NS3StyleTestCase.starting_diff
is None:
499 self.skipTest(
"Unmet dependencies")
503 Check if there is any difference between tracked file after
504 applying cmake-format
508 for required_program
in [
"cmake",
"cmake-format"]:
509 if shutil.which(required_program)
is None:
510 self.skipTest(
"%s was not found" % required_program)
513 return_code, stdout, stderr =
run_ns3(
"configure")
514 self.assertEqual(return_code, 0)
517 return_code, stdout, stderr =
run_ns3(
"build cmake-format")
518 self.assertEqual(return_code, 0)
521 return_code, stdout, stderr =
run_ns3(
"clean")
522 self.assertEqual(return_code, 0)
525 new_diff = NS3StyleTestCase.repo.head.commit.diff(
None)
526 self.assertEqual(NS3StyleTestCase.starting_diff, new_diff)
531 ns3 tests related to generic options
536 Clean configuration/build artifacts before common commands
545 Test not passing any arguments to
548 return_code, stdout, stderr =
run_ns3(
"")
549 self.assertEqual(return_code, 1)
550 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
554 Test only passing --quiet argument to ns3
557 return_code, stdout, stderr =
run_ns3(
"--quiet")
558 self.assertEqual(return_code, 1)
559 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
563 Test only passing 'show config' argument to ns3
566 return_code, stdout, stderr =
run_ns3(
"show config")
567 self.assertEqual(return_code, 1)
568 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
572 Test only passing 'show profile' argument to ns3
575 return_code, stdout, stderr =
run_ns3(
"show profile")
576 self.assertEqual(return_code, 1)
577 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
581 Test only passing 'show version' argument to ns3
584 return_code, stdout, stderr =
run_ns3(
"show version")
585 self.assertEqual(return_code, 1)
586 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
591 ns3 tests related to build profiles
596 Clean configuration/build artifacts before testing configuration settings
608 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d debug --enable-verbose")
609 self.assertEqual(return_code, 0)
610 self.assertIn(
"Build profile : debug", stdout)
611 self.assertIn(
"Build files have been written to", stdout)
614 return_code, stdout, stderr =
run_ns3(
"build core")
615 self.assertEqual(return_code, 0)
616 self.assertIn(
"Built target libcore", stdout)
619 self.assertGreater(len(libraries), 0)
620 self.assertIn(
"core-debug", libraries[0])
624 Test the release build
627 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d release")
628 self.assertEqual(return_code, 0)
629 self.assertIn(
"Build profile : release", stdout)
630 self.assertIn(
"Build files have been written to", stdout)
634 Test the optimized build
637 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d optimized --enable-verbose")
638 self.assertEqual(return_code, 0)
639 self.assertIn(
"Build profile : optimized", stdout)
640 self.assertIn(
"Build files have been written to", stdout)
643 return_code, stdout, stderr =
run_ns3(
"build core")
644 self.assertEqual(return_code, 0)
645 self.assertIn(
"Built target libcore", stdout)
648 self.assertGreater(len(libraries), 0)
649 self.assertIn(
"core-optimized", libraries[0])
653 Test a build type with a typo
656 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d Optimized")
657 self.assertEqual(return_code, 2)
658 self.assertIn(
"invalid choice: 'Optimized'", stderr)
662 Test a build type with another typo
665 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d OPTIMIZED")
666 self.assertEqual(return_code, 2)
667 self.assertIn(
"invalid choice: 'OPTIMIZED'", stderr)
671 Replace settings set by default (e.g. ASSERT/LOGs enabled in debug builds and disabled in default ones)
674 return_code, _, _ =
run_ns3(
"clean")
675 self.assertEqual(return_code, 0)
677 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --dry-run -d debug")
678 self.assertEqual(return_code, 0)
680 "-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON -DNS3_NATIVE_OPTIMIZATIONS=OFF",
683 return_code, stdout, stderr =
run_ns3(
684 "configure -G \"{generator}\" --dry-run -d debug --disable-asserts --disable-logs --disable-werror")
685 self.assertEqual(return_code, 0)
687 "-DCMAKE_BUILD_TYPE=debug -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF",
690 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --dry-run")
691 self.assertEqual(return_code, 0)
693 "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF -DNS3_NATIVE_OPTIMIZATIONS=OFF",
696 return_code, stdout, stderr =
run_ns3(
697 "configure -G \"{generator}\" --dry-run --enable-asserts --enable-logs --enable-werror")
698 self.assertEqual(return_code, 0)
700 "-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",
706 Generic test case with basic function inherited by more complex tests.
711 Check if configuration for release mode worked normally
712 @param return_code: return code from CMake
713 @param stdout: output from CMake.
716 self.assertEqual(return_code, 0)
717 self.assertIn(
"Build profile : release", stdout)
718 self.assertIn(
"Build files have been written to", stdout)
722 Clean configuration/build artifacts before testing configuration and build settings
723 After configuring the build as release,
724 check if configuration worked and check expected output files.
729 if os.path.exists(ns3rc_script):
730 os.remove(ns3rc_script)
734 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d release --enable-verbose")
735 self.
config_okconfig_ok(return_code, stdout)
738 self.assertTrue(os.path.exists(ns3_lock_filename))
743 self.assertTrue(os.path.exists(ns3_lock_filename))
750 Test ns3 configuration options
755 Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
762 Test enabling and disabling examples
765 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
768 self.
config_okconfig_ok(return_code, stdout)
774 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-examples")
777 self.
config_okconfig_ok(return_code, stdout)
784 Test enabling and disabling tests
788 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-tests")
789 self.
config_okconfig_ok(return_code, stdout)
792 return_code, stdout, stderr =
run_ns3(
"build core-test")
795 self.assertEqual(return_code, 0)
796 self.assertIn(
"Built target libcore-test", stdout)
799 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-tests")
800 self.
config_okconfig_ok(return_code, stdout)
803 return_code, stdout, stderr =
run_ns3(
"build core-test")
806 self.assertEqual(return_code, 1)
807 self.assertIn(
"Target to build does not exist: core-test", stdout)
811 Test enabling specific modules
815 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='network;wifi'")
816 self.
config_okconfig_ok(return_code, stdout)
821 self.assertIn(
"ns3-network", enabled_modules)
822 self.assertIn(
"ns3-wifi", enabled_modules)
825 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='core'")
826 self.
config_okconfig_ok(return_code, stdout)
830 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
831 self.
config_okconfig_ok(return_code, stdout)
838 Test disabling specific modules
842 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules='lte;wimax'")
843 self.
config_okconfig_ok(return_code, stdout)
847 self.assertLess(len(enabled_modules), len(self.
ns3_modulesns3_modules))
848 self.assertNotIn(
"ns3-lte", enabled_modules)
849 self.assertNotIn(
"ns3-wimax", enabled_modules)
852 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
853 self.
config_okconfig_ok(return_code, stdout)
860 Test enabling comma-separated (waf-style) examples
864 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='network,wifi'")
865 self.
config_okconfig_ok(return_code, stdout)
870 self.assertIn(
"ns3-network", enabled_modules)
871 self.assertIn(
"ns3-wifi", enabled_modules)
874 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
875 self.
config_okconfig_ok(return_code, stdout)
882 Test disabling comma-separated (waf-style) examples
886 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules='lte,mpi'")
887 self.
config_okconfig_ok(return_code, stdout)
891 self.assertLess(len(enabled_modules), len(self.
ns3_modulesns3_modules))
892 self.assertNotIn(
"ns3-lte", enabled_modules)
893 self.assertNotIn(
"ns3-mpi", enabled_modules)
896 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
897 self.
config_okconfig_ok(return_code, stdout)
904 Test loading settings from the ns3rc config file
910 ns3rc_python_template =
"# ! /usr/bin/env python\
912 # A list of the modules that will be enabled when ns-3 is run.\
913 # Modules that depend on the listed modules will be enabled also.\
915 # All modules can be enabled by choosing 'all_modules'.\
916 modules_enabled = [{modules}]\
918 # Set this equal to true if you want examples to be run.\
919 examples_enabled = {examples}\
921 # Set this equal to true if you want tests to be run.\
922 tests_enabled = {tests}\
926 ns3rc_cmake_template =
"set(ns3rc_tests_enabled {tests})\
927 \nset(ns3rc_examples_enabled {examples})\
928 \nset(ns3rc_enabled_modules {modules})\
933 "python": ns3rc_python_template,
934 "cmake": ns3rc_cmake_template
937 def __init__(self, type_ns3rc):
940 def format(self, **args):
942 if self.
typetype ==
"cmake":
943 args[
"modules"] = args[
"modules"].replace(
"'",
"").replace(
"\"",
"").replace(
",",
" ")
944 args[
"examples"] =
"ON" if args[
"examples"] ==
"True" else "OFF"
945 args[
"tests"] =
"ON" if args[
"tests"] ==
"True" else "OFF"
947 formatted_string = ns3rc_str.ns3rc_templates[self.
typetype].format(**args)
950 return formatted_string
954 return ns3rc_str.ns3rc_templates.keys()
956 for ns3rc_type
in ns3rc_str.types():
958 ns3rc_template = ns3rc_str(ns3rc_type)
961 with open(ns3rc_script,
"w")
as f:
962 f.write(ns3rc_template.format(modules=
"'lte'", examples=
"False", tests=
"True"))
965 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
966 self.
config_okconfig_ok(return_code, stdout)
971 self.assertIn(
"ns3-lte", enabled_modules)
976 with open(ns3rc_script,
"w")
as f:
977 f.write(ns3rc_template.format(modules=
"'wifi'", examples=
"True", tests=
"False"))
980 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
981 self.
config_okconfig_ok(return_code, stdout)
986 self.assertIn(
"ns3-wifi", enabled_modules)
991 with open(ns3rc_script,
"w")
as f:
992 f.write(ns3rc_template.format(modules=
"'core','network'", examples=
"True", tests=
"False"))
995 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
996 self.
config_okconfig_ok(return_code, stdout)
1001 self.assertIn(
"ns3-core", enabled_modules)
1002 self.assertIn(
"ns3-network", enabled_modules)
1008 with open(ns3rc_script,
"w")
as f:
1009 if ns3rc_type ==
"python":
1010 f.write(ns3rc_template.format(modules=
"""'core', #comment
1014 'network', 'internet','wimax'""", examples=
"True", tests=
"True"))
1016 f.write(ns3rc_template.format(modules=
"'core', 'lte', 'network', 'internet', 'wimax'",
1021 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1022 self.
config_okconfig_ok(return_code, stdout)
1027 self.assertIn(
"ns3-core", enabled_modules)
1028 self.assertIn(
"ns3-internet", enabled_modules)
1029 self.assertIn(
"ns3-lte", enabled_modules)
1030 self.assertIn(
"ns3-wimax", enabled_modules)
1035 os.remove(ns3rc_script)
1038 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1039 self.
config_okconfig_ok(return_code, stdout)
1048 Test dry-run (printing commands to be executed instead of running them)
1054 for positional_command
in [
"configure",
"build",
"clean"]:
1055 return_code, stdout, stderr =
run_ns3(
"--dry-run %s" % positional_command)
1056 return_code1, stdout1, stderr1 =
run_ns3(
"%s --dry-run" % positional_command)
1058 self.assertEqual(return_code, return_code1)
1059 self.assertEqual(stdout, stdout1)
1060 self.assertEqual(stderr, stderr1)
1065 run_ns3(
"configure -G \"{generator}\" -d release --enable-verbose")
1066 run_ns3(
"build scratch-simulator")
1069 return_code0, stdout0, stderr0 =
run_ns3(
"--dry-run run scratch-simulator")
1070 return_code1, stdout1, stderr1 =
run_ns3(
"run scratch-simulator")
1071 return_code2, stdout2, stderr2 =
run_ns3(
"--dry-run run scratch-simulator --no-build")
1072 return_code3, stdout3, stderr3 =
run_ns3(
"run scratch-simulator --no-build")
1075 self.assertEqual(sum([return_code0, return_code1, return_code2, return_code3]), 0)
1076 self.assertEqual([stderr0, stderr1, stderr2, stderr3], [
""] * 4)
1080 if "scratch-simulator" in program
and "subdir" not in program:
1081 scratch_path = program
1087 self.assertIn(scratch_path, stdout0)
1091 self.assertIn(
"Built target", stdout1)
1092 self.assertNotIn(scratch_path, stdout1)
1095 self.assertIn(
"The following commands would be executed:", stdout2)
1096 self.assertIn(scratch_path, stdout2)
1099 self.assertNotIn(
"Finished executing the following commands:", stdout3)
1100 self.assertNotIn(scratch_path, stdout3)
1104 Test if ns3 is propagating back the return code from the executables called with the run command
1108 return_code, _, _ =
run_ns3(
"clean")
1109 self.assertEqual(return_code, 0)
1111 return_code, _, _ =
run_ns3(
"configure -G \"{generator}\" --enable-examples --enable-tests")
1112 self.assertEqual(return_code, 0)
1115 return_code, stdout, stderr =
run_ns3(
"build command-line-example test-runner")
1116 self.assertEqual(return_code, 0)
1119 return_code, stdout, stderr =
run_ns3(
"run \"test-runner --test-name=command-line\" --no-build")
1120 self.assertEqual(return_code, 0)
1123 return_code, stdout, stderr =
run_ns3(
"run \"test-runner --test-name=command-line\" --no-build",
1124 env={
"NS_COMMANDLINE_INTROSPECTION":
".."}
1126 self.assertNotEqual(return_code, 0)
1129 sigsegv_example = os.path.join(ns3_path,
"scratch",
"sigsegv.cc")
1130 with open(sigsegv_example,
"w")
as f:
1132 int main (int argc, char *argv[])
1134 char *s = "hello world"; *s = 'H';
1138 return_code, stdout, stderr =
run_ns3(
"run sigsegv")
1140 self.assertEqual(return_code, 4294967295)
1141 self.assertIn(
"sigsegv-default.exe' returned non-zero exit status", stdout)
1143 self.assertEqual(return_code, 245)
1144 self.assertIn(
"sigsegv-default' died with <Signals.SIGSEGV: 11>", stdout)
1147 abort_example = os.path.join(ns3_path,
"scratch",
"abort.cc")
1148 with open(abort_example,
"w")
as f:
1150 #include "ns3/core-module.h"
1152 using namespace ns3;
1153 int main (int argc, char *argv[])
1159 return_code, stdout, stderr =
run_ns3(
"run abort")
1161 self.assertEqual(return_code, 3)
1162 self.assertIn(
"abort-default.exe' returned non-zero exit status", stdout)
1164 self.assertEqual(return_code, 250)
1165 self.assertIn(
"abort-default' died with <Signals.SIGABRT: 6>", stdout)
1167 os.remove(sigsegv_example)
1168 os.remove(abort_example)
1172 Test passing 'show config' argument to ns3 to get the configuration table
1175 return_code, stdout, stderr =
run_ns3(
"show config")
1176 self.assertEqual(return_code, 0)
1177 self.assertIn(
"Summary of ns-3 settings", stdout)
1181 Test passing 'show profile' argument to ns3 to get the build profile
1184 return_code, stdout, stderr =
run_ns3(
"show profile")
1185 self.assertEqual(return_code, 0)
1186 self.assertIn(
"Build profile: release", stdout)
1190 Test passing 'show version' argument to ns3 to get the build version
1193 if shutil.which(
"git")
is None:
1194 self.skipTest(
"git is not available")
1196 return_code, _, _ =
run_ns3(
"configure -G \"{generator}\" --enable-build-version")
1197 self.assertEqual(return_code, 0)
1199 return_code, stdout, stderr =
run_ns3(
"show version")
1200 self.assertEqual(return_code, 0)
1201 self.assertIn(
"ns-3 version:", stdout)
1205 Test if CMake target names for scratches and ns3 shortcuts
1206 are working correctly
1210 test_files = [
"scratch/main.cc",
1212 "scratch/subdir1/main.cc",
1213 "scratch/subdir2/main.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)
1257 for path
in test_files + backup_files:
1258 source_absolute_path = os.path.join(ns3_path, path)
1259 os.remove(source_absolute_path)
1260 if "empty" in path
or ".main" in path:
1262 filename = os.path.basename(path).replace(
".cc",
"")
1263 executable_absolute_path = os.path.dirname(os.path.join(ns3_path,
"build", path))
1264 executable_name =
list(filter(
lambda x: filename
in x,
1265 os.listdir(executable_absolute_path)
1269 os.remove(os.path.join(executable_absolute_path, executable_name))
1270 if path
not in [
"scratch/main.cc",
"scratch/empty.cc"]:
1271 os.rmdir(os.path.dirname(source_absolute_path))
1273 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1274 self.assertEqual(return_code, 0)
1278 Test if ns3 is inserting additional arguments by MPICH and OpenMPI to run on the CI
1282 if shutil.which(
"mpiexec")
is None or win32:
1283 self.skipTest(
"Mpi is not available")
1285 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
1286 self.assertEqual(return_code, 0)
1290 return_code, stdout, stderr =
run_ns3(
"build sample-simulator")
1291 self.assertEqual(return_code, 0)
1294 sample_simulator_path =
list(filter(
lambda x:
"sample-simulator" in x, executables))[0]
1296 mpi_command =
"--dry-run run sample-simulator --command-template=\"mpiexec -np 2 %s\""
1297 non_mpi_command =
"--dry-run run sample-simulator --command-template=\"echo %s\""
1300 return_code, stdout, stderr =
run_ns3(mpi_command)
1301 self.assertEqual(return_code, 0)
1302 self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
1305 return_code, stdout, stderr =
run_ns3(mpi_command)
1306 self.assertEqual(return_code, 0)
1307 if os.getenv(
"USER",
"") ==
"root":
1308 if shutil.which(
"ompi_info"):
1309 self.assertIn(
"mpiexec --allow-run-as-root --oversubscribe -np 2 %s" % sample_simulator_path, stdout)
1311 self.assertIn(
"mpiexec --allow-run-as-root -np 2 %s" % sample_simulator_path, stdout)
1313 self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
1316 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1317 self.assertEqual(return_code, 0)
1318 self.assertIn(
"echo %s" % sample_simulator_path, stdout)
1321 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1322 self.assertEqual(return_code, 0)
1323 self.assertIn(
"echo %s" % sample_simulator_path, stdout)
1325 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-examples")
1326 self.assertEqual(return_code, 0)
1330 Test if CMake and ns3 fail in the expected ways when:
1331 - examples from modules or general examples fail if they depend on a
1332 library with a name shorter than 4 characters or are disabled when
1333 a library is nonexistent
1334 - a module library passes the configuration but fails to build due to
1338 os.makedirs(
"contrib/borked", exist_ok=
True)
1339 os.makedirs(
"contrib/borked/examples", exist_ok=
True)
1342 with open(
"contrib/borked/examples/CMakeLists.txt",
"w")
as f:
1344 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1345 with open(
"contrib/borked/CMakeLists.txt",
"w")
as f:
1349 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1350 LIBRARIES_TO_LINK ${libcore} %s
1352 """ % invalid_or_nonexistent_library)
1354 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
1355 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1356 self.assertEqual(return_code, 0)
1357 elif invalid_or_nonexistent_library
in [
"lib"]:
1358 self.assertEqual(return_code, 1)
1359 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1363 return_code, stdout, stderr =
run_ns3(
"build borked")
1364 if invalid_or_nonexistent_library
in [
""]:
1365 self.assertEqual(return_code, 0)
1366 elif invalid_or_nonexistent_library
in [
"lib"]:
1367 self.assertEqual(return_code, 2)
1368 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1369 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1370 self.assertEqual(return_code, 2)
1373 if "lld" in stdout + stderr:
1374 self.assertIn(
"unable to find library -l%s" % invalid_or_nonexistent_library, stderr)
1376 self.assertIn(
"cannot find -l%s" % invalid_or_nonexistent_library, stderr)
1384 with open(
"contrib/borked/CMakeLists.txt",
"w")
as f:
1388 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1389 LIBRARIES_TO_LINK ${libcore}
1392 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1393 with open(
"contrib/borked/examples/CMakeLists.txt",
"w")
as f:
1397 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty-main.cc
1398 LIBRARIES_TO_LINK ${libborked} %s
1400 """ % invalid_or_nonexistent_library)
1402 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1403 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1404 self.assertEqual(return_code, 0)
1405 elif invalid_or_nonexistent_library
in [
"lib"]:
1406 self.assertEqual(return_code, 1)
1407 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1411 return_code, stdout, stderr =
run_ns3(
"build borked-example")
1412 if invalid_or_nonexistent_library
in [
""]:
1413 self.assertEqual(return_code, 0)
1414 elif invalid_or_nonexistent_library
in [
"libf"]:
1415 self.assertEqual(return_code, 2)
1416 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1417 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1418 self.assertEqual(return_code, 1)
1419 self.assertIn(
"Target to build does not exist: borked-example", stdout)
1423 shutil.rmtree(
"contrib/borked", ignore_errors=
True)
1427 Test if CMake can properly handle modules containing "lib",
1428 which is used internally as a prefix for module libraries
1432 os.makedirs(
"contrib/calibre", exist_ok=
True)
1433 os.makedirs(
"contrib/calibre/examples", exist_ok=
True)
1436 with open(
"contrib/calibre/examples/CMakeLists.txt",
"w")
as f:
1438 with open(
"contrib/calibre/CMakeLists.txt",
"w")
as f:
1442 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1443 LIBRARIES_TO_LINK ${libcore}
1447 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1450 self.assertEqual(return_code, 0)
1453 self.assertIn(
"calibre", stdout)
1457 self.assertNotIn(
"care", stdout)
1458 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"pkgconfig",
"ns3-calibre.pc")))
1461 return_code, stdout, stderr =
run_ns3(
"build calibre")
1462 self.assertEqual(return_code, 0)
1465 shutil.rmtree(
"contrib/calibre", ignore_errors=
True)
1469 Test if CMake performance tracing works and produces the
1470 cmake_performance_trace.log file
1473 return_code, stdout, stderr =
run_ns3(
"configure --trace-performance")
1474 self.assertEqual(return_code, 0)
1476 self.assertIn(
"--profiling-format=google-trace --profiling-output=", stdout)
1478 self.assertIn(
"--profiling-format=google-trace --profiling-output=../cmake_performance_trace.log", stdout)
1479 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake_performance_trace.log")))
1483 Check if ENABLE_BUILD_VERSION and version.cache are working
1491 container.execute(
"apt-get update")
1492 container.execute(
"apt-get install -y python3 ninja-build cmake g++")
1495 container.execute(
"./ns3 clean")
1498 version_cache_file = os.path.join(ns3_path,
"src/core/model/version.cache")
1501 if os.path.exists(version_cache_file):
1502 os.remove(version_cache_file)
1506 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1507 except DockerException:
1509 self.assertFalse(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1512 version_cache_contents = (
"CLOSEST_TAG = '\"ns-3.0.0\"'\n"
1513 "VERSION_COMMIT_HASH = '\"0000000000\"'\n"
1514 "VERSION_DIRTY_FLAG = '0'\n"
1515 "VERSION_MAJOR = '3'\n"
1516 "VERSION_MINOR = '0'\n"
1517 "VERSION_PATCH = '0'\n"
1518 "VERSION_RELEASE_CANDIDATE = '\"\"'\n"
1519 "VERSION_TAG = '\"ns-3.0.0\"'\n"
1520 "VERSION_TAG_DISTANCE = '0'\n"
1521 "VERSION_BUILD_PROFILE = 'debug'\n"
1523 with open(version_cache_file,
"w")
as version:
1524 version.write(version_cache_contents)
1527 container.execute(
"./ns3 clean")
1528 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1529 container.execute(
"./ns3 build core")
1530 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1533 with open(version_cache_file,
"r")
as version:
1534 self.assertEqual(version.read(), version_cache_contents)
1539 os.rename(os.path.join(ns3_path,
".git"), os.path.join(ns3_path,
"temp_git"))
1541 container.execute(
"apt-get install -y git")
1542 container.execute(
"./ns3 clean")
1543 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1544 container.execute(
"./ns3 build core")
1545 except DockerException:
1547 os.rename(os.path.join(ns3_path,
"temp_git"), os.path.join(ns3_path,
".git"))
1548 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1551 container.execute(
"./ns3 clean")
1552 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1553 container.execute(
"./ns3 build core")
1554 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1555 with open(version_cache_file,
"r")
as version:
1556 self.assertNotEqual(version.read(), version_cache_contents)
1559 if os.path.exists(version_cache_file):
1560 os.remove(version_cache_file)
1564 Test filtering in examples and tests from specific modules
1568 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples --enable-tests")
1569 self.
config_okconfig_ok(return_code, stdout)
1574 return_code, stdout, stderr =
run_ns3(
1575 "configure -G \"{generator}\" --filter-module-examples-and-tests='core;network'")
1576 self.
config_okconfig_ok(return_code, stdout)
1582 self.assertEqual(len(modules_after_filtering), len(modules_before_filtering))
1584 self.assertLess(len(programs_after_filtering), len(programs_before_filtering))
1587 return_code, stdout, stderr =
run_ns3(
1588 "configure -G \"{generator}\" --filter-module-examples-and-tests='core'")
1589 self.
config_okconfig_ok(return_code, stdout)
1597 return_code, stdout, stderr =
run_ns3(
1598 "configure -G \"{generator}\" --disable-examples --disable-tests --filter-module-examples-and-tests=''")
1599 self.
config_okconfig_ok(return_code, stdout)
1607 Check if fast linkers LLD and Mold are correctly found and configured
1614 container.execute(
"apt-get update")
1615 container.execute(
"apt-get install -y python3 ninja-build cmake g++ lld")
1618 container.execute(
"./ns3 configure -G Ninja")
1621 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1622 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1623 self.assertIn(
"-fuse-ld=lld", f.read())
1627 container.execute(
"./ns3 build core")
1628 except DockerException:
1629 self.assertTrue(
False,
"Build with lld failed")
1632 if not os.path.exists(
"./mold-1.4.2-x86_64-linux.tar.gz"):
1634 "wget https://github.com/rui314/mold/releases/download/v1.4.2/mold-1.4.2-x86_64-linux.tar.gz")
1635 container.execute(
"tar xzfC mold-1.4.2-x86_64-linux.tar.gz /usr/local --strip-components=1")
1639 container.execute(
"./ns3 configure -G Ninja")
1642 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1643 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1644 self.assertIn(
"-fuse-ld=mold", f.read())
1648 container.execute(
"./ns3 build core")
1649 except DockerException:
1650 self.assertTrue(
False,
"Build with mold failed")
1653 os.remove(
"./mold-1.4.2-x86_64-linux.tar.gz")
1656 container.execute(
"./ns3 configure -G Ninja -- -DNS3_FAST_LINKERS=OFF")
1659 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1660 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1661 self.assertNotIn(
"-fuse-ld=mold", f.read())
1665 Check if NS3_CLANG_TIMETRACE feature is working
1666 Clang's -ftime-trace plus ClangAnalyzer report
1672 container.execute(
"apt-get update")
1673 container.execute(
"apt-get install -y python3 ninja-build cmake clang-10")
1678 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON")
1679 except DockerException
as e:
1680 self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
1682 container.execute(
"apt-get install -y git")
1687 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON")
1688 except DockerException
as e:
1689 self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
1692 time_trace_report_path = os.path.join(ns3_path,
"ClangBuildAnalyzerReport.txt")
1693 if os.path.exists(time_trace_report_path):
1694 os.remove(time_trace_report_path)
1698 container.execute(
"./ns3 build timeTraceReport")
1699 except DockerException
as e:
1700 self.assertTrue(
False,
"Failed to build the ClangAnalyzer's time trace report")
1703 self.assertTrue(os.path.exists(time_trace_report_path))
1707 container.execute(
"apt-get install -y g++")
1708 container.execute(
"apt-get remove -y clang-10")
1712 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DNS3_CLANG_TIMETRACE=ON")
1713 self.assertTrue(
False,
"ClangTimeTrace requires Clang, but GCC just passed the checks too")
1714 except DockerException
as e:
1715 self.assertIn(
"TimeTrace is a Clang feature", e.stderr)
1719 Check if NS3_NINJA_TRACE feature is working
1720 Ninja's .ninja_log conversion to about://tracing
1721 json format conversion with Ninjatracing
1727 container.execute(
"apt-get update")
1728 container.execute(
"apt-get install -y python3 cmake clang-10")
1733 "./ns3 configure --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1734 except DockerException
as e:
1735 self.assertIn(
"Ninjatracing requires the Ninja generator", e.stderr)
1740 container.execute(
"apt-get install -y ninja-build")
1744 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1745 except DockerException
as e:
1746 self.assertIn(
"could not find git for clone of NinjaTracing", e.stderr)
1748 container.execute(
"apt-get install -y git")
1752 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1753 except DockerException
as e:
1754 self.assertTrue(
False,
"Failed to configure with Ninjatracing")
1757 ninja_trace_path = os.path.join(ns3_path,
"ninja_performance_trace.json")
1758 if os.path.exists(ninja_trace_path):
1759 os.remove(ninja_trace_path)
1762 container.execute(
"./ns3 build core")
1766 container.execute(
"./ns3 build ninjaTrace")
1767 except DockerException
as e:
1768 self.assertTrue(
False,
"Failed to run Ninjatracing's tool to build the trace")
1771 self.assertTrue(os.path.exists(ninja_trace_path))
1772 trace_size = os.stat(ninja_trace_path).st_size
1773 os.remove(ninja_trace_path)
1780 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON")
1781 except DockerException
as e:
1782 self.assertTrue(
False,
"Failed to configure Ninjatracing with Clang's TimeTrace")
1785 container.execute(
"./ns3 build core")
1789 container.execute(
"./ns3 build ninjaTrace")
1790 except DockerException
as e:
1791 self.assertTrue(
False,
"Failed to run Ninjatracing's tool to build the trace")
1793 self.assertTrue(os.path.exists(ninja_trace_path))
1794 timetrace_size = os.stat(ninja_trace_path).st_size
1795 os.remove(ninja_trace_path)
1798 self.assertGreater(timetrace_size, trace_size)
1802 Check if precompiled headers are being enabled correctly.
1811 container.execute(
"apt-get update")
1812 container.execute(
"apt-get install -y python3 cmake ccache clang-10")
1814 container.execute(
"./ns3 configure -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10")
1815 except DockerException
as e:
1816 self.assertIn(
"does not support precompiled headers", e.stderr)
1823 container.execute(
"apt-get update")
1824 container.execute(
"apt-get install -y python3 cmake ccache g++")
1826 container.execute(
"./ns3 configure")
1827 except DockerException
as e:
1828 self.assertIn(
"incompatible with ccache", e.stderr)
1835 container.execute(
"apt-get update")
1836 container.execute(
"apt-get install -y python3 cmake ccache g++")
1838 container.execute(
"./ns3 configure")
1839 except DockerException
as e:
1840 self.assertTrue(
False,
"Precompiled headers should have been enabled")
1845 Tests ns3 regarding building the project
1850 Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
1859 Try building the core library
1862 return_code, stdout, stderr =
run_ns3(
"build core")
1863 self.assertEqual(return_code, 0)
1864 self.assertIn(
"Built target libcore", stdout)
1868 Try building core-test library without tests enabled
1872 return_code, stdout, stderr =
run_ns3(
"build core-test")
1873 self.assertEqual(return_code, 1)
1874 self.assertIn(
"Target to build does not exist: core-test", stdout)
1878 Try building the project:
1881 return_code, stdout, stderr =
run_ns3(
"build")
1882 self.assertEqual(return_code, 0)
1883 self.assertIn(
"Built target", stdout)
1885 self.assertTrue(os.path.exists(program), program)
1886 self.assertIn(cmake_build_project_command, stdout)
1890 Try hiding task lines
1893 return_code, stdout, stderr =
run_ns3(
"--quiet build")
1894 self.assertEqual(return_code, 0)
1895 self.assertIn(cmake_build_project_command, stdout)
1899 Try removing an essential file to break the build
1903 attribute_cc_path = os.sep.join([ns3_path,
"src",
"core",
"model",
"attribute.cc"])
1904 attribute_cc_bak_path = attribute_cc_path +
".bak"
1905 shutil.move(attribute_cc_path, attribute_cc_bak_path)
1908 return_code, stdout, stderr =
run_ns3(
"build")
1909 self.assertNotEqual(return_code, 0)
1912 shutil.move(attribute_cc_bak_path, attribute_cc_path)
1915 return_code, stdout, stderr =
run_ns3(
"build")
1916 self.assertEqual(return_code, 0)
1920 Test if changing the version file affects the library names
1926 version_file = os.sep.join([ns3_path,
"VERSION"])
1927 with open(version_file,
"w")
as f:
1931 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1932 self.
config_okconfig_ok(return_code, stdout)
1935 return_code, stdout, stderr =
run_ns3(
"build")
1936 self.assertEqual(return_code, 0)
1937 self.assertIn(
"Built target", stdout)
1943 for program
in new_programs:
1944 self.assertTrue(os.path.exists(program))
1951 new_libraries =
list(set(libraries).difference(set(self.
ns3_librariesns3_libraries)))
1952 self.assertEqual(len(new_libraries), len(self.
ns3_librariesns3_libraries))
1953 for library
in new_libraries:
1954 self.assertNotIn(
"libns3-dev", library)
1955 self.assertIn(
"libns3-00", library)
1956 self.assertTrue(os.path.exists(library))
1959 with open(version_file,
"w")
as f:
1964 Try setting a different output directory and if everything is
1965 in the right place and still working correctly
1970 return_code, stdout, stderr =
run_ns3(
"build")
1971 self.assertEqual(return_code, 0)
1986 absolute_path = os.sep.join([ns3_path,
"build",
"release"])
1987 relative_path = os.sep.join([
"build",
"release"])
1988 for different_out_dir
in [absolute_path, relative_path]:
1989 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=%s" % different_out_dir)
1990 self.
config_okconfig_ok(return_code, stdout)
1991 self.assertIn(
"Build directory : %s" % absolute_path.replace(os.sep,
'/'), stdout)
1999 for program
in new_programs:
2000 self.assertTrue(os.path.exists(program))
2004 new_libraries =
list(set(libraries).difference(set(self.
ns3_librariesns3_libraries)))
2005 self.assertEqual(len(new_libraries), len(self.
ns3_librariesns3_libraries))
2006 for library
in new_libraries:
2007 self.assertTrue(os.path.exists(library))
2010 shutil.rmtree(absolute_path)
2013 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=''")
2014 self.
config_okconfig_ok(return_code, stdout)
2015 self.assertIn(
"Build directory : %s" % usual_outdir.replace(os.sep,
'/'), stdout)
2023 for program
in new_programs:
2024 self.assertTrue(os.path.exists(program))
2028 self.assertEqual(len(libraries), len(self.
ns3_librariesns3_libraries))
2029 for library
in libraries:
2030 self.assertTrue(os.path.exists(library))
2034 Tries setting a ns3 version, then installing it.
2035 After that, tries searching for ns-3 with CMake's find_package(ns3).
2036 Finally, tries using core library in a 3rd-party project
2041 for library
in libraries:
2045 version_file = os.sep.join([ns3_path,
"VERSION"])
2046 with open(version_file,
"w")
as f:
2050 install_prefix = os.sep.join([ns3_path,
"build",
"install"])
2051 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --prefix=%s" % install_prefix)
2052 self.
config_okconfig_ok(return_code, stdout)
2063 lib64 = os.path.exists(os.sep.join([install_prefix,
"lib64"]))
2064 installed_libdir = os.sep.join([install_prefix, (
"lib64" if lib64
else "lib")])
2068 installed_libraries_list =
";".join(installed_libraries)
2069 for library
in libraries:
2070 library_name = os.path.basename(library)
2071 self.assertIn(library_name, installed_libraries_list)
2075 missing_headers =
list(set([os.path.basename(x)
for x
in headers])
2076 - (set([os.path.basename(x)
for x
in installed_headers]))
2078 self.assertEqual(len(missing_headers), 0)
2081 test_main_file = os.sep.join([install_prefix,
"main.cpp"])
2082 with open(test_main_file,
"w")
as f:
2084 #include <ns3/core-module.h>
2085 using namespace ns3;
2088 Simulator::Stop (Seconds (1.0));
2090 Simulator::Destroy ();
2098 for version
in [
"",
"3.01",
"3.00"]:
2099 ns3_import_methods = []
2102 cmake_find_package_import =
"""
2103 list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3)
2104 find_package(ns3 {version} COMPONENTS libcore)
2105 target_link_libraries(test PRIVATE ns3::libcore)
2106 """.format(lib=(
"lib64" if lib64
else "lib"), version=version)
2107 ns3_import_methods.append(cmake_find_package_import)
2110 pkgconfig_import =
"""
2111 list(APPEND CMAKE_PREFIX_PATH ./)
2112 include(FindPkgConfig)
2113 pkg_check_modules(ns3 REQUIRED IMPORTED_TARGET ns3-core{version})
2114 target_link_libraries(test PUBLIC PkgConfig::ns3)
2115 """.format(lib=(
"lib64" if lib64
else "lib"),
2116 version=
"=" + version
if version
else ""
2118 if shutil.which(
"pkg-config"):
2119 ns3_import_methods.append(pkgconfig_import)
2122 for import_method
in ns3_import_methods:
2123 test_cmake_project =
"""
2124 cmake_minimum_required(VERSION 3.10..3.10)
2125 project(ns3_consumer CXX)
2126 set(CMAKE_CXX_STANDARD 17)
2127 set(CMAKE_CXX_STANDARD_REQUIRED ON)
2128 add_executable(test main.cpp)
2131 test_cmake_project_file = os.sep.join([install_prefix,
"CMakeLists.txt"])
2132 with open(test_cmake_project_file,
"w")
as f:
2133 f.write(test_cmake_project)
2136 cmake = shutil.which(
"cmake")
2139 "-DCMAKE_BUILD_TYPE=debug -G\"{generator}\" .".format(generator=platform_makefiles),
2143 if version ==
"3.00":
2144 self.assertEqual(return_code, 1)
2145 if import_method == cmake_find_package_import:
2146 self.assertIn(
'Could not find a configuration file for package "ns3" that is compatible',
2147 stderr.replace(
"\n",
""))
2148 elif import_method == pkgconfig_import:
2149 self.assertIn(
'A required package was not found',
2150 stderr.replace(
"\n",
""))
2152 raise Exception(
"Unknown import type")
2154 self.assertEqual(return_code, 0)
2155 self.assertIn(
"Build files", stdout)
2158 return_code, stdout, stderr =
run_program(
"cmake",
"--build .", cwd=install_prefix)
2160 if version ==
"3.00":
2161 self.assertEqual(return_code, 2)
2162 self.assertGreater(len(stderr), 0)
2164 self.assertEqual(return_code, 0)
2165 self.assertIn(
"Built target", stdout)
2169 test_program = os.path.join(install_prefix,
"test.exe")
2170 env_sep =
";" if ";" in os.environ[
"PATH"]
else ":"
2171 env = {
"PATH": env_sep.join([os.environ[
"PATH"], os.path.join(install_prefix,
"lib")])}
2173 test_program =
"./test"
2175 return_code, stdout, stderr =
run_program(test_program,
"", cwd=install_prefix, env=env)
2176 self.assertEqual(return_code, 0)
2179 return_code, stdout, stderr =
run_ns3(
"uninstall")
2180 self.assertIn(
"Built target uninstall", stdout)
2183 os.remove(version_file)
2184 with open(version_file,
"w")
as f:
2189 Tries to build scratch-simulator and subdir/scratch-simulator-subdir
2193 targets = {
"scratch/scratch-simulator":
"scratch-simulator",
2194 "scratch/scratch-simulator.cc":
"scratch-simulator",
2195 "scratch-simulator":
"scratch-simulator",
2196 "scratch/subdir/scratch-subdir":
"subdir_scratch-subdir",
2197 "subdir/scratch-subdir":
"subdir_scratch-subdir",
2198 "scratch-subdir":
"subdir_scratch-subdir",
2200 for (target_to_run, target_cmake)
in targets.items():
2202 build_line =
"target scratch_%s" % target_cmake
2203 return_code, stdout, stderr =
run_ns3(
"build %s" % target_to_run)
2204 self.assertEqual(return_code, 0)
2205 self.assertIn(build_line, stdout)
2208 return_code, stdout, stderr =
run_ns3(
"run %s --verbose" % target_to_run)
2209 self.assertEqual(return_code, 0)
2210 self.assertIn(build_line, stdout)
2211 stdout = stdout.replace(
"scratch_%s" % target_cmake,
"")
2212 self.assertIn(target_to_run.split(
"/")[-1].replace(
".cc",
""), stdout)
2216 Test if ns3 can alert correctly in case a shortcut collision happens
2221 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
2222 self.assertEqual(return_code, 0)
2225 shutil.copy(
"./examples/tutorial/second.cc",
"./scratch/second.cc")
2228 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
2229 self.assertEqual(return_code, 0)
2232 return_code, stdout, stderr =
run_ns3(
"build second")
2233 self.assertEqual(return_code, 1)
2235 'Build target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2236 stdout.replace(os.sep,
'/')
2240 return_code, stdout, stderr =
run_ns3(
"build scratch/second")
2241 self.assertEqual(return_code, 0)
2245 return_code, stdout, stderr =
run_ns3(
"build tutorial/second")
2246 self.assertEqual(return_code, 0)
2250 return_code, stdout, stderr =
run_ns3(
"run second")
2251 self.assertEqual(return_code, 1)
2253 'Run target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2254 stdout.replace(os.sep,
'/')
2258 return_code, stdout, stderr =
run_ns3(
"run scratch/second")
2259 self.assertEqual(return_code, 0)
2262 return_code, stdout, stderr =
run_ns3(
"run tutorial/second")
2263 self.assertEqual(return_code, 0)
2266 os.remove(
"./scratch/second.cc")
2270 Test if we can build a static ns-3 library and link it to static programs
2275 return_code, stdout, stderr =
run_ns3(
2276 "configure -G \"{generator}\" --enable-examples --disable-gtk --enable-static")
2281 self.assertEqual(return_code, 1)
2282 self.assertIn(
"Static builds are unsupported on Windows", stderr)
2285 self.assertEqual(return_code, 0)
2288 return_code, stdout, stderr =
run_ns3(
'build sample-simulator')
2289 self.assertEqual(return_code, 0)
2290 self.assertIn(
"Built target", stdout)
2296 Test if we can use python bindings
2301 except ModuleNotFoundError:
2302 self.skipTest(
"Cppyy was not found")
2305 return_code, stdout, stderr =
run_ns3(
2306 "configure -G \"{generator}\" --enable-python-bindings")
2309 self.assertEqual(return_code, 0)
2312 return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
2313 self.assertEqual(return_code, 0)
2316 return_code, stdout, stderr =
run_program(
"test.py",
"-p mixed-wired-wireless", python=
True)
2317 self.assertEqual(return_code, 0)
2320 return_code, stdout, stderr =
run_program(
"test.py",
"-p ./examples/wireless/mixed-wired-wireless", python=
True)
2321 self.assertEqual(return_code, 0)
2326 Tests ns3 usage in more realistic scenarios
2331 Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
2332 Here examples, tests and documentation are also enabled.
2339 return_code, stdout, stderr =
run_ns3(
2340 "configure -d release -G \"{generator}\" --enable-examples --enable-tests")
2341 self.
config_okconfig_ok(return_code, stdout)
2344 self.assertTrue(os.path.exists(ns3_lock_filename))
2350 self.assertTrue(os.path.exists(ns3_lock_filename))
2357 Try to build the project
2360 return_code, stdout, stderr =
run_ns3(
"build")
2361 self.assertEqual(return_code, 0)
2362 self.assertIn(
"Built target", stdout)
2364 self.assertTrue(os.path.exists(program))
2367 self.assertIn(module.replace(
"ns3-",
""),
";".join(libraries))
2368 self.assertIn(cmake_build_project_command, stdout)
2372 Try to build and run test-runner
2375 return_code, stdout, stderr =
run_ns3(
'run "test-runner --list" --verbose')
2376 self.assertEqual(return_code, 0)
2377 self.assertIn(
"Built target test-runner", stdout)
2382 Try to build and run a library
2385 return_code, stdout, stderr =
run_ns3(
"run core")
2386 self.assertEqual(return_code, 1)
2387 self.assertIn(
"Couldn't find the specified program: core", stderr)
2391 Try to build and run an unknown target
2394 return_code, stdout, stderr =
run_ns3(
"run nonsense")
2395 self.assertEqual(return_code, 1)
2396 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2400 Try to run test-runner without building
2403 return_code, stdout, stderr =
run_ns3(
'build test-runner')
2404 self.assertEqual(return_code, 0)
2406 return_code, stdout, stderr =
run_ns3(
'run "test-runner --list" --no-build --verbose')
2407 self.assertEqual(return_code, 0)
2408 self.assertNotIn(
"Built target test-runner", stdout)
2413 Test ns3 fails to run a library
2416 return_code, stdout, stderr =
run_ns3(
"run core --no-build")
2417 self.assertEqual(return_code, 1)
2418 self.assertIn(
"Couldn't find the specified program: core", stderr)
2422 Test ns3 fails to run an unknown program
2425 return_code, stdout, stderr =
run_ns3(
"run nonsense --no-build")
2426 self.assertEqual(return_code, 1)
2427 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2431 Test if scratch simulator is executed through gdb and lldb
2434 if shutil.which(
"gdb")
is None:
2435 self.skipTest(
"Missing gdb")
2437 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
2438 self.assertEqual(return_code, 0)
2440 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --gdb --verbose --no-build", env={
"gdb_eval":
"1"})
2441 self.assertEqual(return_code, 0)
2442 self.assertIn(
"scratch-simulator", stdout)
2444 self.assertIn(
"GNU gdb", stdout)
2446 self.assertIn(
"No debugging symbols found", stdout)
2450 Test if scratch simulator is executed through valgrind
2453 if shutil.which(
"valgrind")
is None:
2454 self.skipTest(
"Missing valgrind")
2456 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
2457 self.assertEqual(return_code, 0)
2459 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --valgrind --verbose --no-build")
2460 self.assertEqual(return_code, 0)
2461 self.assertIn(
"scratch-simulator", stderr)
2462 self.assertIn(
"Memcheck", stderr)
2466 Test the doxygen target that does trigger a full build
2469 if shutil.which(
"doxygen")
is None:
2470 self.skipTest(
"Missing doxygen")
2472 if shutil.which(
"bash")
is None:
2473 self.skipTest(
"Missing bash")
2475 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2477 doxygen_files = [
"introspected-command-line.h",
"introspected-doxygen.h"]
2478 for filename
in doxygen_files:
2479 file_path = os.sep.join([doc_folder, filename])
2480 if os.path.exists(file_path):
2481 os.remove(file_path)
2488 return_code, stdout, stderr =
run_ns3(
"docs doxygen")
2489 self.assertEqual(return_code, 0)
2491 self.assertIn(
"Built target doxygen", stdout)
2495 Test the doxygen target that doesn't trigger a full build
2498 if shutil.which(
"doxygen")
is None:
2499 self.skipTest(
"Missing doxygen")
2507 return_code, stdout, stderr =
run_ns3(
"docs doxygen-no-build")
2508 self.assertEqual(return_code, 0)
2510 self.assertIn(
"Built target doxygen-no-build", stdout)
2514 Test every individual target for Sphinx-based documentation
2517 if shutil.which(
"sphinx-build")
is None:
2518 self.skipTest(
"Missing sphinx")
2520 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2523 for target
in [
"installation",
"contributing",
"manual",
"models",
"tutorial"]:
2525 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2526 doc_temp_folder = os.sep.join([doc_folder, target,
"source-temp"])
2527 if os.path.exists(doc_build_folder):
2528 shutil.rmtree(doc_build_folder)
2529 if os.path.exists(doc_temp_folder):
2530 shutil.rmtree(doc_temp_folder)
2533 return_code, stdout, stderr =
run_ns3(
"docs %s" % target)
2534 self.assertEqual(return_code, 0, target)
2536 self.assertIn(
"Built target sphinx_%s" % target, stdout)
2539 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2540 self.assertTrue(os.path.exists(doc_build_folder))
2543 for build_type
in [
"latex",
"html",
"singlehtml"]:
2544 self.assertTrue(os.path.exists(os.sep.join([doc_build_folder, build_type])))
2548 Test the documentation target that builds
2549 both doxygen and sphinx based documentation
2552 if shutil.which(
"doxygen")
is None:
2553 self.skipTest(
"Missing doxygen")
2554 if shutil.which(
"sphinx-build")
is None:
2555 self.skipTest(
"Missing sphinx")
2557 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2566 for target
in [
"manual",
"models",
"tutorial"]:
2567 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2568 if os.path.exists(doc_build_folder):
2569 shutil.rmtree(doc_build_folder)
2571 return_code, stdout, stderr =
run_ns3(
"docs all")
2572 self.assertEqual(return_code, 0)
2574 self.assertIn(
"Built target sphinx", stdout)
2576 self.assertIn(
"Built target doxygen", stdout)
2580 Try to set ownership of scratch-simulator from current user to root,
2581 and change execution permissions
2586 sudo_password = os.getenv(
"SUDO_PASSWORD",
None)
2589 if sudo_password
is None:
2590 self.skipTest(
"SUDO_PASSWORD environment variable was not specified")
2593 self.assertFalse(enable_sudo
is True)
2596 return_code, stdout, stderr =
run_ns3(
'run scratch-simulator')
2597 self.assertEqual(return_code, 0)
2598 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2600 scratch_simulator_path =
list(filter(
lambda x: x
if "scratch-simulator" in x
else None,
2604 prev_fstat = os.stat(scratch_simulator_path)
2607 return_code, stdout, stderr =
run_ns3(
'run scratch-simulator --enable-sudo',
2608 env={
"SUDO_PASSWORD": sudo_password})
2609 self.assertEqual(return_code, 0)
2610 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2612 fstat = os.stat(scratch_simulator_path)
2617 likely_fuse_mount = ((prev_fstat.st_mode & stat.S_ISUID) == (fstat.st_mode & stat.S_ISUID))
and \
2618 prev_fstat.st_uid == 0
2620 if win32
or likely_fuse_mount:
2621 self.skipTest(
"Windows or likely a FUSE mount")
2624 self.assertEqual(fstat.st_uid, 0)
2625 self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID)
2628 return_code, stdout, stderr =
run_ns3(
'configure --enable-sudo')
2629 self.assertEqual(return_code, 0)
2633 self.assertTrue(enable_sudo)
2637 if os.path.exists(executable):
2638 os.remove(executable)
2641 return_code, stdout, stderr =
run_ns3(
'build', env={
"SUDO_PASSWORD": sudo_password})
2642 self.assertEqual(return_code, 0)
2645 self.assertIn(
"chown root", stdout)
2646 self.assertIn(
"chmod u+s", stdout)
2648 self.assertIn(os.path.basename(executable), stdout)
2651 fstat = os.stat(scratch_simulator_path)
2652 self.assertEqual(fstat.st_uid, 0)
2653 self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID)
2657 Check if command template is working
2662 return_code0, stdout0, stderr0 =
run_ns3(
'run sample-simulator --command-template')
2663 self.assertEqual(return_code0, 2)
2664 self.assertIn(
"argument --command-template: expected one argument", stderr0)
2666 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template=" "')
2667 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --command-template " "')
2668 return_code3, stdout3, stderr3 =
run_ns3(
'run sample-simulator --command-template "echo "')
2669 self.assertEqual((return_code1, return_code2, return_code3), (1, 1, 1))
2670 for stderr
in [stderr1, stderr2, stderr3]:
2671 self.assertIn(
"not all arguments converted during string formatting", stderr)
2674 return_code4, stdout4, _ =
run_ns3(
'run sample-simulator --command-template "%s --PrintVersion" --verbose')
2675 return_code5, stdout5, _ =
run_ns3(
'run sample-simulator --command-template="%s --PrintVersion" --verbose')
2676 self.assertEqual((return_code4, return_code5), (0, 0))
2678 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout4)
2679 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout5)
2683 Check if all flavors of different argument passing to
2684 executable targets are working
2689 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --verbose')
2690 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template="%s --help" --verbose')
2691 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --verbose -- --help')
2693 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2694 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout0)
2695 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout1)
2696 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout2)
2699 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --no-build')
2700 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template="%s --help" --no-build')
2701 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --no-build -- --help')
2702 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2703 self.assertEqual(stdout0, stdout1)
2704 self.assertEqual(stdout1, stdout2)
2705 self.assertEqual(stderr0, stderr1)
2706 self.assertEqual(stderr1, stderr2)
2709 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --PrintGlobals" --verbose')
2710 return_code1, stdout1, stderr1 =
run_ns3(
'run "sample-simulator --PrintGroups" --verbose')
2711 return_code2, stdout2, stderr2 =
run_ns3(
'run "sample-simulator --PrintTypeIds" --verbose')
2713 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2714 self.assertIn(
"sample-simulator{ext} --PrintGlobals".format(ext=ext), stdout0)
2715 self.assertIn(
"sample-simulator{ext} --PrintGroups".format(ext=ext), stdout1)
2716 self.assertIn(
"sample-simulator{ext} --PrintTypeIds".format(ext=ext), stdout2)
2719 cmd =
'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" --verbose -- --PrintTypeIds'
2720 return_code, stdout, stderr =
run_ns3(cmd)
2721 self.assertEqual(return_code, 0)
2726 self.assertIn(
"sample-simulator{ext} --PrintGroups --PrintGlobals --PrintTypeIds".format(ext=ext), stdout)
2729 cmd0 =
'run sample-simulator --command-template="%s " --PrintTypeIds'
2730 cmd1 =
'run sample-simulator --PrintTypeIds'
2732 return_code0, stdout0, stderr0 =
run_ns3(cmd0)
2733 return_code1, stdout1, stderr1 =
run_ns3(cmd1)
2734 self.assertEqual((return_code0, return_code1), (1, 1))
2735 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr0)
2736 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr1)
2740 Test if scratch simulator is executed through lldb
2743 if shutil.which(
"lldb")
is None:
2744 self.skipTest(
"Missing lldb")
2746 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --lldb --verbose --no-build")
2747 self.assertEqual(return_code, 0)
2748 self.assertIn(
"scratch-simulator", stdout)
2749 self.assertIn(
"(lldb) target create", stdout)
2754 ns-3 tests to control the quality of the repository over time,
2755 by checking the state of URLs listed and more
2760 Test if all urls in source files are alive
2769 self.skipTest(
"Django URL validators are not available")
2775 urllib3.disable_warnings()
2778 self.skipTest(
"Requests library is not available")
2780 regex = re.compile(
r'((http|https)://[^\ \n\)\"\'\}><\]\;\`\\]*)')
2783 whitelisted_urls = {
"https://gitlab.com/your-user-name/ns-3-dev",
2784 "https://www.nsnam.org/release/ns-allinone-3.31.rc1.tar.bz2",
2785 "https://www.nsnam.org/release/ns-allinone-3.X.rcX.tar.bz2",
2786 "https://www.nsnam.org/releases/ns-3-x",
2787 "https://www.nsnam.org/releases/ns-allinone-3.(x-1",
2788 "https://www.nsnam.org/releases/ns-allinone-3.x.tar.bz2",
2790 "https://cmake.org/cmake/help/latest/manual/cmake-",
2791 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_",
2793 "http://www.lysator.liu.se/~alla/dia/",
2795 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_Digital_Terrestrial_Television_Broadcasting_(DTTB",
2796 "http://en.wikipedia.org/wiki/Namespace_(computer_science",
2797 "http://en.wikipedia.org/wiki/Bonobo_(component_model",
2798 "http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85",
2800 "http://www.research.att.com/info/kpv/",
2801 "http://www.research.att.com/~gsf/",
2805 files_and_urls = set()
2807 for topdir
in [
"bindings",
"doc",
"examples",
"src",
"utils"]:
2808 for root, dirs, files
in os.walk(topdir):
2810 if "build" in root
or "_static" in root
or "source-temp" in root
or 'html' in root:
2814 if file.endswith(
".svg"):
2816 filepath = os.path.join(root, file)
2819 with open(filepath,
"r")
as f:
2820 matches = regex.findall(f.read())
2825 urls =
list(map(
lambda x: x[0][:-1]
if x[0][-1]
in ".," else x[0], matches))
2826 except UnicodeDecodeError:
2827 skipped_files.append(filepath)
2831 for url
in set(urls) - unique_urls - whitelisted_urls:
2832 unique_urls.add(url)
2833 files_and_urls.add((filepath, url))
2836 from django.core.validators
import URLValidator
2837 from django.core.exceptions
import ValidationError
2838 validate_url = URLValidator()
2842 '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'
2846 def test_file_url(args):
2847 test_filepath, test_url = args
2848 dead_link_msg =
None
2852 validate_url(test_url)
2853 except ValidationError:
2854 dead_link_msg =
"%s: URL %s, invalid URL" % (test_filepath, test_url)
2855 except Exception
as e:
2856 self.assertEqual(
False,
True, msg=e.__str__())
2858 if dead_link_msg
is not None:
2859 return dead_link_msg
2867 response = requests.get(test_url, verify=
False, headers=headers, timeout=50)
2870 if response.status_code
in [200, 301]:
2871 dead_link_msg =
None
2876 if response.status_code
in [302, 308, 500, 503]:
2877 if response.reason.lower()
in [
'found',
2878 'moved temporarily',
2879 'permanent redirect',
2881 'service temporarily unavailable'
2883 dead_link_msg =
None
2887 dead_link_msg =
"%s: URL %s: returned code %d" % (test_filepath, test_url, response.status_code)
2888 except requests.exceptions.InvalidURL:
2889 dead_link_msg =
"%s: URL %s: invalid URL" % (test_filepath, test_url)
2890 except requests.exceptions.SSLError:
2891 dead_link_msg =
"%s: URL %s: SSL error" % (test_filepath, test_url)
2892 except requests.exceptions.TooManyRedirects:
2893 dead_link_msg =
"%s: URL %s: too many redirects" % (test_filepath, test_url)
2894 except Exception
as e:
2896 error_msg = e.args[0].reason.__str__()
2897 except AttributeError:
2898 error_msg = e.args[0]
2899 dead_link_msg =
"%s: URL %s: failed with exception: %s" % (test_filepath, test_url, error_msg)
2901 return dead_link_msg
2904 from concurrent.futures
import ThreadPoolExecutor
2905 with ThreadPoolExecutor(max_workers=100)
as executor:
2906 dead_links =
list(executor.map(test_file_url,
list(files_and_urls)))
2909 dead_links =
list(sorted(filter(
lambda x: x
is not None, dead_links)))
2910 self.assertEqual(len(dead_links), 0, msg=
"\n".join([
"Dead links found:", *dead_links]))
2914 Test if all tests can be executed without hitting major memory bugs
2917 return_code, stdout, stderr =
run_ns3(
2918 "configure --enable-tests --enable-examples --enable-sanitizers -d optimized")
2919 self.assertEqual(return_code, 0)
2921 test_return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
2922 self.assertEqual(test_return_code, 0)
2926 Check if images in the docs are above a brightness threshold.
2927 This should prevent screenshots with dark UI themes.
2930 if shutil.which(
"convert")
is None:
2931 self.skipTest(
"Imagemagick was not found")
2933 from pathlib
import Path
2936 image_extensions = [
"png",
"jpg"]
2938 for extension
in image_extensions:
2939 images +=
list(Path(
"./doc").glob(
"**/figures/*.{ext}".format(ext=extension)))
2940 images +=
list(Path(
"./doc").glob(
"**/figures/**/*.{ext}".format(ext=extension)))
2943 imagemagick_get_image_brightness = \
2944 'convert {image} -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]" info:'
2948 brightness_threshold = 50
2949 for image
in images:
2950 brightness = subprocess.check_output(imagemagick_get_image_brightness.format(image=image).split())
2951 brightness = float(brightness.decode().strip(
"'\""))
2952 self.assertGreater(brightness, brightness_threshold,
2953 "Image darker than threshold (%d < %d): %s" % (brightness, brightness_threshold, image)
2963 test_completeness = {
2964 "style": [NS3UnusedSourcesTestCase,
2967 "build": [NS3CommonSettingsTestCase,
2968 NS3ConfigureBuildProfileTestCase,
2969 NS3ConfigureTestCase,
2970 NS3BuildBaseTestCase,
2971 NS3ExpectedUseTestCase,
2973 "complete": [NS3UnusedSourcesTestCase,
2975 NS3CommonSettingsTestCase,
2976 NS3ConfigureBuildProfileTestCase,
2977 NS3ConfigureTestCase,
2978 NS3BuildBaseTestCase,
2979 NS3ExpectedUseTestCase,
2980 NS3QualityControlTestCase,
2982 "extras": [NS3DependenciesTestCase,
2988 parser = argparse.ArgumentParser(
"Test suite for the ns-3 buildsystem")
2989 parser.add_argument(
"-c",
"--completeness",
2990 choices=test_completeness.keys(),
2992 parser.add_argument(
"-tn",
"--test-name",
2996 parser.add_argument(
"-rtn",
"--resume-from-test-name",
3000 parser.add_argument(
"-q",
"--quiet",
3001 action=
"store_true",
3003 args = parser.parse_args(sys.argv[1:])
3005 loader = unittest.TestLoader()
3006 suite = unittest.TestSuite()
3009 for testCase
in test_completeness[args.completeness]:
3010 suite.addTests(loader.loadTestsFromTestCase(testCase))
3015 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
3017 tests_to_run = set(map(
lambda x: x
if args.test_name
in x
else None, tests.keys()))
3018 tests_to_remove = set(tests) - set(tests_to_run)
3019 for test_to_remove
in tests_to_remove:
3020 suite._tests.remove(tests[test_to_remove])
3023 if args.resume_from_test_name:
3025 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
3026 keys =
list(tests.keys())
3028 while args.resume_from_test_name
not in keys[0]
and len(tests) > 0:
3029 suite._tests.remove(tests[keys[0]])
3033 ns3rc_script_bak = ns3rc_script +
".bak"
3034 if os.path.exists(ns3rc_script)
and not os.path.exists(ns3rc_script_bak):
3035 shutil.move(ns3rc_script, ns3rc_script_bak)
3038 runner = unittest.TextTestRunner(failfast=
True, verbosity=1
if args.quiet
else 2)
3042 if os.path.exists(ns3rc_script_bak):
3043 shutil.move(ns3rc_script_bak, ns3rc_script)
3046 if __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_03_BuildProject(self)
Try building the project:
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
dictionary 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.
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.
cmake_build_target_command
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()