10Test suite for the ns3 wrapper script
21from functools
import partial
24ns3_path = os.path.dirname(os.path.abspath(os.sep.join([__file__,
"../../"])))
25ns3_lock_filename = os.path.join(ns3_path,
".lock-ns3_%s_build" % sys.platform)
26ns3_script = os.sep.join([ns3_path,
"ns3"])
27ns3rc_script = os.sep.join([ns3_path,
".ns3rc"])
28usual_outdir = os.sep.join([ns3_path,
"build"])
29usual_lib_outdir = os.sep.join([usual_outdir,
"lib"])
35num_threads = max(1, os.cpu_count() - 1)
36cmake_build_project_command =
"cmake --build {cmake_cache} -j".format(
37 ns3_path=ns3_path, cmake_cache=os.path.abspath(os.path.join(ns3_path,
"cmake-cache"))
39cmake_build_target_command = partial(
40 "cmake --build {cmake_cache} -j {jobs} --target {target}".format,
42 cmake_cache=os.path.abspath(os.path.join(ns3_path,
"cmake-cache")),
44win32 = sys.platform ==
"win32"
45macos = sys.platform ==
"darwin"
46platform_makefiles =
"MinGW Makefiles" if win32
else "Unix Makefiles"
47ext =
".exe" if win32
else ""
48arch = platform.machine()
51def run_ns3(args, env=None, generator=platform_makefiles):
53 Runs the ns3 wrapper script with arguments
54 @param args: string containing arguments that will get split before calling ns3
55 @param env: environment variables dictionary
56 @param generator: CMake generator
57 @return tuple containing (error code, stdout and stderr)
61 possible_leftovers = [
"contrib/borked",
"contrib/calibre"]
62 for leftover
in possible_leftovers:
63 if os.path.exists(leftover):
64 shutil.rmtree(leftover, ignore_errors=
True)
66 args = args.format(generator=generator)
71 return run_program(ns3_script, args, python=
True, env=env)
75def run_program(program, args, python=False, cwd=ns3_path, env=None):
77 Runs a program with the given arguments and returns a tuple containing (error code, stdout and stderr)
78 @param program: program to execute (or python script)
79 @param args: string containing arguments that will get split before calling the program
80 @param python: flag indicating whether the program is a python script
81 @param cwd: the working directory used that will be the root folder for the execution
82 @param env: environment variables dictionary
83 @return tuple containing (error code, stdout and stderr)
86 raise Exception(
"args should be a string")
90 arguments = [sys.executable, program]
95 arguments.extend(re.findall(
r'(?:".*?"|\S)+', args))
97 for i
in range(len(arguments)):
98 arguments[i] = arguments[i].replace(
'"',
"")
101 current_env = os.environ.copy()
105 current_env.update(env)
108 ret = subprocess.run(
110 stdin=subprocess.DEVNULL,
111 stdout=subprocess.PIPE,
112 stderr=subprocess.PIPE,
119 ret.stdout.decode(sys.stdout.encoding),
120 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, encoding=
"utf-8")
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 if not os.path.exists(lib_outdir):
149 libraries = glob.glob(lib_outdir +
"/*", recursive=
True)
150 return list(filter(
lambda x:
"scratch-nested-subdir-lib" not in x, libraries))
155 Gets a list of header files
156 @param outdir: path containing headers
157 @return list of headers.
159 return glob.glob(outdir +
"/**/*.h", recursive=
True)
164 Read interesting entries from the .lock-ns3 file
165 @param entry: entry to read from .lock-ns3
166 @return value of the requested entry.
169 with open(ns3_lock_filename, encoding=
"utf-8")
as f:
170 exec(f.read(), globals(), values)
171 return values.get(entry,
None)
176 Check if tests are enabled in the .lock-ns3
184 Check if tests are enabled in the .lock-ns3
185 @return list of enabled modules (prefixed with 'ns3-').
192 Python-on-whales wrapper for Docker-based ns-3 tests
195 def __init__(self, currentTestCase: unittest.TestCase, containerName: str =
"ubuntu:latest"):
197 Create and start container with containerName in the current ns-3 directory
198 @param self: the current DockerContainerManager instance
199 @param currentTestCase: the test case instance creating the DockerContainerManager
200 @param containerName: name of the container image to be used
202 global DockerException
204 from python_on_whales
import docker
205 from python_on_whales.exceptions
import DockerException
206 except ModuleNotFoundError:
208 DockerException =
None
209 currentTestCase.skipTest(
"python-on-whales was not found")
212 with open(os.path.expanduser(
"~/.bashrc"),
"r", encoding=
"utf-8")
as f:
213 docker_settings = re.findall(
"(DOCKER_.*=.*)", f.read())
215 for setting
in docker_settings:
216 key, value = setting.split(
"=")
217 os.environ[key] = value
218 del setting, key, value
223 except DockerException
as e:
224 currentTestCase.skipTest(f
"python-on-whales returned:{e.__str__()}")
233 volumes=[(ns3_path,
"/ns-3-dev")],
237 def split_exec(docker_container, cmd, workdir="/ns-3-dev"):
238 cmd_split = re.findall(
r'(?:".*?"|\S)+', cmd)
239 cmd_split = list(map(
lambda x: x.replace(
'"',
""), cmd_split))
240 return docker_container._execute(cmd_split, workdir=workdir)
247 Return the managed container when entiring the block "with DockerContainerManager() as container"
248 @param self: the current DockerContainerManager instance
249 @return container managed by DockerContainerManager.
255 Clean up the managed container at the end of the block "with DockerContainerManager() as container"
256 @param self: the current DockerContainerManager instance
257 @param exc_type: unused parameter
258 @param exc_val: unused parameter
259 @param exc_tb: unused parameter
268 ns-3 tests related to checking if source files were left behind, not being used by CMake
272 directory_and_files = {}
276 Scan all C++ source files and add them to a list based on their path
279 for root, dirs, files
in os.walk(ns3_path):
280 if "gitlab-ci-local" in root:
283 if name.endswith(
".cc"):
284 path = os.path.join(root, name)
285 directory = os.path.dirname(path)
292 Test if all example source files are being used in their respective CMakeLists.txt
295 unused_sources = set()
298 if os.sep +
"examples" not in example_directory:
302 if not os.path.exists(os.path.join(example_directory,
"CMakeLists.txt")):
307 os.path.join(example_directory,
"CMakeLists.txt"),
"r", encoding=
"utf-8"
309 cmake_contents = f.read()
314 if os.path.basename(file).replace(
".cc",
"")
not in cmake_contents:
315 unused_sources.add(file)
317 self.assertListEqual([], list(unused_sources))
321 Test if all module source files are being used in their respective CMakeLists.txt
324 unused_sources = set()
327 is_not_module =
not (
"src" in directory
or "contrib" in directory)
328 is_example = os.sep +
"examples" in directory
329 is_bindings = os.sep +
"bindings" in directory
331 if is_not_module
or is_bindings
or is_example:
336 cmake_path = os.path.join(directory,
"CMakeLists.txt")
337 while not os.path.exists(cmake_path):
338 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
339 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
342 with open(cmake_path,
"r", encoding=
"utf-8")
as f:
343 cmake_contents = f.read()
347 if os.path.basename(file)
not in cmake_contents:
348 unused_sources.add(file)
352 "win32-system-wall-clock-ms.cc",
354 for exception
in exceptions:
355 for unused_source
in unused_sources:
356 if os.path.basename(unused_source) == exception:
357 unused_sources.remove(unused_source)
360 self.assertListEqual([], list(unused_sources))
364 Test if all utils source files are being used in their respective CMakeLists.txt
367 unused_sources = set()
370 is_module =
"src" in directory
or "contrib" in directory
371 if os.sep +
"utils" not in directory
or is_module:
376 cmake_path = os.path.join(directory,
"CMakeLists.txt")
377 while not os.path.exists(cmake_path):
378 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
379 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
382 with open(cmake_path,
"r", encoding=
"utf-8")
as f:
383 cmake_contents = f.read()
387 if os.path.basename(file)
not in cmake_contents:
388 unused_sources.add(file)
390 self.assertListEqual([], list(unused_sources))
395 ns-3 tests related to dependencies
400 Checks if headers from different modules (src/A, contrib/B) that are included by
401 the current module (src/C) source files correspond to the list of linked modules
403 LIBRARIES_TO_LINK A (missing B)
407 headers_to_modules = {}
408 module_paths = glob.glob(ns3_path +
"/src/*/") + glob.glob(ns3_path +
"/contrib/*/")
410 for path
in module_paths:
412 cmake_path = os.path.join(path,
"CMakeLists.txt")
413 with open(cmake_path,
"r", encoding=
"utf-8")
as f:
414 cmake_contents = f.readlines()
416 module_name = os.path.relpath(path, ns3_path)
417 module_name_nodir = module_name.replace(
"src/",
"").replace(
"contrib/",
"")
418 modules[module_name_nodir] = {
422 "included_headers": set(),
423 "included_libraries": set(),
427 for line
in cmake_contents:
428 source_file_path = re.findall(
r"\b(?:[^\s]+\.[ch]{1,2})\b", line.strip())
429 if not source_file_path:
431 source_file_path = source_file_path[0]
432 base_name = os.path.basename(source_file_path)
433 if not os.path.exists(os.path.join(path, source_file_path)):
436 if ".h" in source_file_path:
438 modules[module_name_nodir][
"headers"].add(base_name)
439 modules[module_name_nodir][
"sources"].add(base_name)
442 headers_to_modules[base_name] = module_name_nodir
444 if ".cc" in source_file_path:
446 modules[module_name_nodir][
"sources"].add(base_name)
448 if ".cc" in source_file_path
or ".h" in source_file_path:
450 source_file = os.path.join(ns3_path, module_name, source_file_path)
451 with open(source_file,
"r", encoding=
"utf-8")
as f:
452 source_contents = f.read()
453 modules[module_name_nodir][
"included_headers"].update(
455 lambda x: x.replace(
"ns3/",
""),
456 re.findall(
'#include.*["|<](.*)["|>]', source_contents),
462 modules[module_name_nodir][
"libraries"].update(
463 re.findall(
r"\${lib(.*?)}",
"".join(cmake_contents))
465 modules[module_name_nodir][
"libraries"] = list(
468 not in [
"raries_to_link", module_name_nodir, module_name_nodir +
"-obj"],
469 modules[module_name_nodir][
"libraries"],
474 all_project_headers = set(headers_to_modules.keys())
477 print(file=sys.stderr)
478 for module
in sorted(modules):
479 external_headers = modules[module][
"included_headers"].difference(all_project_headers)
480 project_headers_included = modules[module][
"included_headers"].difference(
483 modules[module][
"included_libraries"] = set(
484 [headers_to_modules[x]
for x
in project_headers_included]
485 ).difference({module})
487 diff = modules[module][
"included_libraries"].difference(modules[module][
"libraries"])
490 def recursive_check_dependencies(checked_module):
492 for module_to_link
in modules[checked_module][
"included_libraries"]:
493 modules[checked_module][
"included_libraries"] = set(
494 modules[checked_module][
"included_libraries"]
495 ) - set(modules[module_to_link][
"included_libraries"])
497 for module_to_link
in modules[checked_module][
"included_libraries"]:
498 recursive_check_dependencies(module_to_link)
501 def is_implicitly_linked(searched_module, current_module):
502 if len(modules[current_module][
"included_libraries"]) == 0:
504 if searched_module
in modules[current_module][
"included_libraries"]:
506 for module
in modules[current_module][
"included_libraries"]:
507 if is_implicitly_linked(searched_module, module):
511 from itertools
import combinations
513 implicitly_linked = set()
514 for dep1, dep2
in combinations(modules[checked_module][
"included_libraries"], 2):
515 if is_implicitly_linked(dep1, dep2):
516 implicitly_linked.add(dep1)
517 if is_implicitly_linked(dep2, dep1):
518 implicitly_linked.add(dep2)
520 modules[checked_module][
"included_libraries"] = (
521 set(modules[checked_module][
"included_libraries"]) - implicitly_linked
524 for module
in modules:
525 recursive_check_dependencies(module)
528 for module
in sorted(modules):
531 minimal_linking_set =
", ".join(modules[module][
"included_libraries"])
532 unnecessarily_linked =
", ".join(
533 set(modules[module][
"libraries"]) - set(modules[module][
"included_libraries"])
535 missing_linked =
", ".join(
536 set(modules[module][
"included_libraries"]) - set(modules[module][
"libraries"])
538 if unnecessarily_linked:
539 print(f
"Module '{module}' unnecessarily linked: {unnecessarily_linked}.")
541 print(f
"Module '{module}' missing linked: {missing_linked}.")
542 if unnecessarily_linked
or missing_linked:
543 print(f
"Module '{module}' minimal linking set: {minimal_linking_set}.")
544 self.assertTrue(
True)
549 ns-3 tests to check if the source code, whitespaces and CMake formatting
550 are according to the coding style
560 Import GitRepo and load the original diff state of the repository before the tests
563 if not NS3StyleTestCase.starting_diff:
564 if shutil.which(
"git")
is None:
565 self.skipTest(
"Git is not available")
571 self.skipTest(
"GitPython is not available")
574 repo = Repo(ns3_path)
575 except git.exc.InvalidGitRepositoryError:
576 self.skipTest(
"ns-3 directory does not contain a .git directory")
578 hcommit = repo.head.commit
579 NS3StyleTestCase.starting_diff = hcommit.diff(
None)
580 NS3StyleTestCase.repo = repo
582 if NS3StyleTestCase.starting_diff
is None:
583 self.skipTest(
"Unmet dependencies")
587 Check if there is any difference between tracked file after
588 applying cmake-format
592 for required_program
in [
"cmake",
"cmake-format"]:
593 if shutil.which(required_program)
is None:
594 self.skipTest(
"%s was not found" % required_program)
597 return_code, stdout, stderr =
run_ns3(
"configure")
598 self.assertEqual(return_code, 0)
601 return_code, stdout, stderr =
run_ns3(
"build cmake-format")
602 self.assertEqual(return_code, 0)
605 return_code, stdout, stderr =
run_ns3(
"clean")
606 self.assertEqual(return_code, 0)
609 new_diff = NS3StyleTestCase.repo.head.commit.diff(
None)
610 self.assertEqual(NS3StyleTestCase.starting_diff, new_diff)
615 ns3 tests related to generic options
620 Clean configuration/build artifacts before common commands
629 Test not passing any arguments to
632 return_code, stdout, stderr =
run_ns3(
"")
633 self.assertEqual(return_code, 1)
634 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
638 Test only passing --quiet argument to ns3
641 return_code, stdout, stderr =
run_ns3(
"--quiet")
642 self.assertEqual(return_code, 1)
643 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
647 Test only passing 'show config' argument to ns3
650 return_code, stdout, stderr =
run_ns3(
"show config")
651 self.assertEqual(return_code, 1)
652 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
656 Test only passing 'show profile' argument to ns3
659 return_code, stdout, stderr =
run_ns3(
"show profile")
660 self.assertEqual(return_code, 1)
661 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
665 Test only passing 'show version' argument to ns3
668 return_code, stdout, stderr =
run_ns3(
"show version")
669 self.assertEqual(return_code, 1)
670 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
675 ns3 tests related to build profiles
680 Clean configuration/build artifacts before testing configuration settings
692 return_code, stdout, stderr =
run_ns3(
693 'configure -G "{generator}" -d debug --enable-verbose'
695 self.assertEqual(return_code, 0)
696 self.assertIn(
"Build profile : debug", stdout)
697 self.assertIn(
"Build files have been written to", stdout)
700 return_code, stdout, stderr =
run_ns3(
"build core")
701 self.assertEqual(return_code, 0)
702 self.assertIn(
"Built target core", stdout)
705 self.assertGreater(len(libraries), 0)
706 self.assertIn(
"core-debug", libraries[0])
710 Test the release build
713 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" -d release')
714 self.assertEqual(return_code, 0)
715 self.assertIn(
"Build profile : release", stdout)
716 self.assertIn(
"Build files have been written to", stdout)
720 Test the optimized build
723 return_code, stdout, stderr =
run_ns3(
724 'configure -G "{generator}" -d optimized --enable-verbose'
726 self.assertEqual(return_code, 0)
727 self.assertIn(
"Build profile : optimized", stdout)
728 self.assertIn(
"Build files have been written to", stdout)
731 return_code, stdout, stderr =
run_ns3(
"build core")
732 self.assertEqual(return_code, 0)
733 self.assertIn(
"Built target core", stdout)
736 self.assertGreater(len(libraries), 0)
737 self.assertIn(
"core-optimized", libraries[0])
741 Test a build type with a typo
744 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" -d Optimized')
745 self.assertEqual(return_code, 2)
746 self.assertIn(
"invalid choice: 'Optimized'", stderr)
750 Test a build type with another typo
753 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" -d OPTIMIZED')
754 self.assertEqual(return_code, 2)
755 self.assertIn(
"invalid choice: 'OPTIMIZED'", stderr)
759 Replace settings set by default (e.g. ASSERT/LOGs enabled in debug builds and disabled in default ones)
762 return_code, _, _ =
run_ns3(
"clean")
763 self.assertEqual(return_code, 0)
765 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --dry-run -d debug')
766 self.assertEqual(return_code, 0)
768 "-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON -DNS3_NATIVE_OPTIMIZATIONS=OFF",
772 return_code, stdout, stderr =
run_ns3(
773 'configure -G "{generator}" --dry-run -d debug --disable-asserts --disable-logs --disable-werror'
775 self.assertEqual(return_code, 0)
777 "-DCMAKE_BUILD_TYPE=debug -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF",
781 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --dry-run')
782 self.assertEqual(return_code, 0)
784 "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF -DNS3_NATIVE_OPTIMIZATIONS=OFF",
788 return_code, stdout, stderr =
run_ns3(
789 'configure -G "{generator}" --dry-run --enable-asserts --enable-logs --enable-werror'
791 self.assertEqual(return_code, 0)
793 "-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",
800 Generic test case with basic function inherited by more complex tests.
805 Check if configuration for release mode worked normally
806 @param return_code: return code from CMake
807 @param stdout: output from CMake.
808 @param stderr: error from CMake.
811 self.assertEqual(return_code, 0)
812 self.assertIn(
"Build profile : release", stdout)
813 self.assertIn(
"Build files have been written to", stdout)
814 self.assertNotIn(
"uninitialized variable", stderr)
818 Clean configuration/build artifacts before testing configuration and build settings
819 After configuring the build as release,
820 check if configuration worked and check expected output files.
825 if os.path.exists(ns3rc_script):
826 os.remove(ns3rc_script)
830 return_code, stdout, stderr =
run_ns3(
831 'configure -G "{generator}" -d release --enable-verbose'
833 self.
config_ok(return_code, stdout, stderr)
836 self.assertTrue(os.path.exists(ns3_lock_filename))
841 self.assertTrue(os.path.exists(ns3_lock_filename))
848 Test ns3 configuration options
853 Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
860 Test enabling and disabling examples
863 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --enable-examples')
866 self.
config_ok(return_code, stdout, stderr)
873 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --disable-examples')
876 self.
config_ok(return_code, stdout, stderr)
883 Test enabling and disabling tests
887 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --enable-tests')
888 self.
config_ok(return_code, stdout, stderr)
891 return_code, stdout, stderr =
run_ns3(
"build core-test")
894 self.assertEqual(return_code, 0)
895 self.assertIn(
"Built target core-test", stdout)
898 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --disable-tests')
899 self.
config_ok(return_code, stdout, stderr)
902 return_code, stdout, stderr =
run_ns3(
"build core-test")
905 self.assertEqual(return_code, 1)
906 self.assertIn(
"Target to build does not exist: core-test", stdout)
910 Test enabling specific modules
914 return_code, stdout, stderr =
run_ns3(
915 "configure -G \"{generator}\" --enable-modules='network;wifi'"
917 self.
config_ok(return_code, stdout, stderr)
923 self.assertIn(
"ns3-network", enabled_modules)
924 self.assertIn(
"ns3-wifi", enabled_modules)
927 return_code, stdout, stderr =
run_ns3(
928 "configure -G \"{generator}\" --enable-modules='core'"
930 self.
config_ok(return_code, stdout, stderr)
934 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
935 self.
config_ok(return_code, stdout, stderr)
942 Test disabling specific modules
946 return_code, stdout, stderr =
run_ns3(
947 "configure -G \"{generator}\" --disable-modules='lte;wifi'"
949 self.
config_ok(return_code, stdout, stderr)
953 self.assertLess(len(enabled_modules), len(self.
ns3_modules))
954 self.assertNotIn(
"ns3-lte", enabled_modules)
955 self.assertNotIn(
"ns3-wifi", enabled_modules)
958 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
959 self.
config_ok(return_code, stdout, stderr)
966 Test enabling comma-separated (waf-style) examples
970 return_code, stdout, stderr =
run_ns3(
971 "configure -G \"{generator}\" --enable-modules='network,wifi'"
973 self.
config_ok(return_code, stdout, stderr)
978 self.assertIn(
"ns3-network", enabled_modules)
979 self.assertIn(
"ns3-wifi", enabled_modules)
982 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
983 self.
config_ok(return_code, stdout, stderr)
990 Test disabling comma-separated (waf-style) examples
994 return_code, stdout, stderr =
run_ns3(
995 "configure -G \"{generator}\" --disable-modules='lte,mpi'"
997 self.
config_ok(return_code, stdout, stderr)
1001 self.assertLess(len(enabled_modules), len(self.
ns3_modules))
1002 self.assertNotIn(
"ns3-lte", enabled_modules)
1003 self.assertNotIn(
"ns3-mpi", enabled_modules)
1006 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
1007 self.
config_ok(return_code, stdout, stderr)
1014 Test loading settings from the ns3rc config file
1020 ns3rc_python_template =
"# ! /usr/bin/env python\
1022 # A list of the modules that will be enabled when ns-3 is run.\
1023 # Modules that depend on the listed modules will be enabled also.\
1025 # All modules can be enabled by choosing 'all_modules'.\
1026 modules_enabled = [{modules}]\
1028 # Set this equal to true if you want examples to be run.\
1029 examples_enabled = {examples}\
1031 # Set this equal to true if you want tests to be run.\
1032 tests_enabled = {tests}\
1036 ns3rc_cmake_template =
"set(ns3rc_tests_enabled {tests})\
1037 \nset(ns3rc_examples_enabled {examples})\
1038 \nset(ns3rc_enabled_modules {modules})\
1042 ns3rc_templates = {
"python": ns3rc_python_template,
"cmake": ns3rc_cmake_template}
1044 def __init__(self, type_ns3rc):
1048 def format(self, **args):
1050 if self.
type ==
"cmake":
1052 args[
"modules"].replace(
"'",
"").replace(
'"',
"").replace(
",",
" ")
1054 args[
"examples"] =
"ON" if args[
"examples"] ==
"True" else "OFF"
1055 args[
"tests"] =
"ON" if args[
"tests"] ==
"True" else "OFF"
1057 formatted_string = ns3rc_str.ns3rc_templates[self.
type].format(**args)
1060 return formatted_string
1064 return ns3rc_str.ns3rc_templates.keys()
1066 for ns3rc_type
in ns3rc_str.types():
1068 ns3rc_template = ns3rc_str(ns3rc_type)
1071 with open(ns3rc_script,
"w", encoding=
"utf-8")
as f:
1072 f.write(ns3rc_template.format(modules=
"'lte'", examples=
"False", tests=
"True"))
1076 return_code, stdout, stderr =
run_ns3(
1077 'configure -G "{generator}" -d release --enable-verbose'
1079 self.
config_ok(return_code, stdout, stderr)
1084 self.assertIn(
"ns3-lte", enabled_modules)
1088 self.assertLessEqual(
1095 with open(ns3rc_script,
"w", encoding=
"utf-8")
as f:
1096 f.write(ns3rc_template.format(modules=
"'wifi'", examples=
"True", tests=
"False"))
1099 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1100 self.
config_ok(return_code, stdout, stderr)
1105 self.assertIn(
"ns3-wifi", enabled_modules)
1110 with open(ns3rc_script,
"w", encoding=
"utf-8")
as f:
1112 ns3rc_template.format(
1113 modules=
"'core','network'", examples=
"True", tests=
"False"
1118 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1119 self.
config_ok(return_code, stdout, stderr)
1124 self.assertIn(
"ns3-core", enabled_modules)
1125 self.assertIn(
"ns3-network", enabled_modules)
1131 with open(ns3rc_script,
"w", encoding=
"utf-8")
as f:
1132 if ns3rc_type ==
"python":
1134 ns3rc_template.format(
1135 modules=
"""'core', #comment
1139 'network', 'internet','wifi'""",
1146 ns3rc_template.format(
1147 modules=
"'core', 'lte', 'network', 'internet', 'wifi'",
1153 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1154 self.
config_ok(return_code, stdout, stderr)
1159 self.assertIn(
"ns3-core", enabled_modules)
1160 self.assertIn(
"ns3-internet", enabled_modules)
1161 self.assertIn(
"ns3-lte", enabled_modules)
1162 self.assertIn(
"ns3-wifi", enabled_modules)
1167 os.remove(ns3rc_script)
1170 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1171 self.
config_ok(return_code, stdout, stderr)
1180 Test dry-run (printing commands to be executed instead of running them)
1186 for positional_command
in [
"configure",
"build",
"clean"]:
1187 return_code, stdout, stderr =
run_ns3(
"--dry-run %s" % positional_command)
1188 return_code1, stdout1, stderr1 =
run_ns3(
"%s --dry-run" % positional_command)
1190 self.assertEqual(return_code, return_code1)
1191 self.assertEqual(stdout, stdout1)
1192 self.assertEqual(stderr, stderr1)
1197 run_ns3(
'configure -G "{generator}" -d release --enable-verbose')
1198 run_ns3(
"build scratch-simulator")
1201 return_code0, stdout0, stderr0 =
run_ns3(
"--dry-run run scratch-simulator")
1202 return_code1, stdout1, stderr1 =
run_ns3(
"run scratch-simulator")
1203 return_code2, stdout2, stderr2 =
run_ns3(
"--dry-run run scratch-simulator --no-build")
1204 return_code3, stdout3, stderr3 =
run_ns3(
"run scratch-simulator --no-build")
1207 self.assertEqual(sum([return_code0, return_code1, return_code2, return_code3]), 0)
1208 self.assertEqual([stderr0, stderr1, stderr2, stderr3], [
""] * 4)
1212 if "scratch-simulator" in program
and "subdir" not in program:
1213 scratch_path = program
1219 self.assertIn(scratch_path, stdout0)
1223 self.assertIn(
"Built target", stdout1)
1224 self.assertNotIn(scratch_path, stdout1)
1227 self.assertIn(
"The following commands would be executed:", stdout2)
1228 self.assertIn(scratch_path, stdout2)
1231 self.assertNotIn(
"Finished executing the following commands:", stdout3)
1232 self.assertNotIn(scratch_path, stdout3)
1236 Test if ns3 is propagating back the return code from the executables called with the run command
1240 return_code, _, _ =
run_ns3(
"clean")
1241 self.assertEqual(return_code, 0)
1243 return_code, _, _ =
run_ns3(
'configure -G "{generator}" --enable-examples --enable-tests')
1244 self.assertEqual(return_code, 0)
1247 return_code, stdout, stderr =
run_ns3(
"build command-line-example test-runner")
1248 self.assertEqual(return_code, 0)
1251 return_code, stdout, stderr =
run_ns3(
1252 'run "test-runner --test-name=command-line" --no-build'
1254 self.assertEqual(return_code, 0)
1257 return_code, stdout, stderr =
run_ns3(
1258 'run "test-runner --test-name=command-line" --no-build',
1259 env={
"NS_COMMANDLINE_INTROSPECTION":
".."},
1261 self.assertNotEqual(return_code, 0)
1264 sigsegv_example = os.path.join(ns3_path,
"scratch",
"sigsegv.cc")
1265 with open(sigsegv_example,
"w", encoding=
"utf-8")
as f:
1267 int main (int argc, char *argv[])
1269 char *s = "hello world"; *s = 'H';
1273 return_code, stdout, stderr =
run_ns3(
"run sigsegv")
1275 self.assertEqual(return_code, 4294967295)
1276 self.assertIn(
"sigsegv-default.exe' returned non-zero exit status", stdout)
1278 self.assertEqual(return_code, 245)
1279 self.assertIn(
"sigsegv-default' died with <Signals.SIGSEGV: 11>", stdout)
1282 abort_example = os.path.join(ns3_path,
"scratch",
"abort.cc")
1283 with open(abort_example,
"w", encoding=
"utf-8")
as f:
1285 #include "ns3/core-module.h"
1287 using namespace ns3;
1288 int main (int argc, char *argv[])
1294 return_code, stdout, stderr =
run_ns3(
"run abort")
1296 self.assertNotEqual(return_code, 0)
1297 self.assertIn(
"abort-default.exe' returned non-zero exit status", stdout)
1299 self.assertEqual(return_code, 250)
1300 self.assertIn(
"abort-default' died with <Signals.SIGABRT: 6>", stdout)
1302 os.remove(sigsegv_example)
1303 os.remove(abort_example)
1307 Test passing 'show config' argument to ns3 to get the configuration table
1310 return_code, stdout, stderr =
run_ns3(
"show config")
1311 self.assertEqual(return_code, 0)
1312 self.assertIn(
"Summary of ns-3 settings", stdout)
1316 Test passing 'show profile' argument to ns3 to get the build profile
1319 return_code, stdout, stderr =
run_ns3(
"show profile")
1320 self.assertEqual(return_code, 0)
1321 self.assertIn(
"Build profile: release", stdout)
1325 Test passing 'show version' argument to ns3 to get the build version
1328 if shutil.which(
"git")
is None:
1329 self.skipTest(
"git is not available")
1331 return_code, _, _ =
run_ns3(
'configure -G "{generator}" --enable-build-version')
1332 self.assertEqual(return_code, 0)
1334 return_code, stdout, stderr =
run_ns3(
"show version")
1335 self.assertEqual(return_code, 0)
1336 self.assertIn(
"ns-3 version:", stdout)
1340 Test if CMake target names for scratches and ns3 shortcuts
1341 are working correctly
1348 "scratch/subdir1/main.cc",
1349 "scratch/subdir2/main.cc",
1350 "scratch/main.test.dots.in.name.cc",
1352 backup_files = [
"scratch/.main.cc"]
1355 for path
in test_files + backup_files:
1356 filepath = os.path.join(ns3_path, path)
1357 os.makedirs(os.path.dirname(filepath), exist_ok=
True)
1358 with open(filepath,
"w", encoding=
"utf-8")
as f:
1360 f.write(
"int main (int argc, char *argv[]){}")
1369 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1370 self.assertEqual(return_code, 1)
1373 empty =
"scratch/empty.cc"
1375 test_files.remove(empty)
1376 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1377 self.assertEqual(return_code, 0)
1380 for path
in test_files + backup_files:
1381 path = path.replace(
".cc",
"")
1384 "--build . --target %s -j %d" % (path.replace(
"/",
"_"), num_threads),
1385 cwd=os.path.join(ns3_path,
"cmake-cache"),
1387 return_code2, stdout2, stderr2 =
run_ns3(
"build %s" % path)
1388 if "main" in path
and ".main" not in path:
1389 self.assertEqual(return_code1, 0)
1390 self.assertEqual(return_code2, 0)
1392 self.assertEqual(return_code1, 2)
1393 self.assertEqual(return_code2, 1)
1396 for path
in test_files:
1397 path = path.replace(
".cc",
"")
1398 return_code, stdout, stderr =
run_ns3(
"run %s --no-build" % path)
1400 self.assertEqual(return_code, 0)
1402 self.assertEqual(return_code, 1)
1406 container.execute(
"apt-get update")
1407 container.execute(
"apt-get install -y python3 cmake g++ ninja-build python3-pip")
1408 container.execute(
"pip3 install cmake==3.25.2")
1411 "./ns3 configure --enable-modules=core,network,internet -- -DCMAKE_CXX_COMPILER=/usr/bin/g++"
1413 except DockerException
as e:
1415 for path
in test_files:
1416 path = path.replace(
".cc",
"")
1418 container.execute(f
"./ns3 run {path}")
1419 except DockerException
as e:
1425 for path
in test_files + backup_files:
1426 source_absolute_path = os.path.join(ns3_path, path)
1427 os.remove(source_absolute_path)
1428 if "empty" in path
or ".main" in path:
1430 filename = os.path.basename(path).replace(
".cc",
"")
1431 executable_absolute_path = os.path.dirname(os.path.join(ns3_path,
"build", path))
1432 if os.path.exists(executable_absolute_path):
1433 executable_name = list(
1434 filter(
lambda x: filename
in x, os.listdir(executable_absolute_path))
1437 os.remove(os.path.join(executable_absolute_path, executable_name))
1438 if not os.listdir(os.path.dirname(path)):
1439 os.rmdir(os.path.dirname(source_absolute_path))
1441 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1442 self.assertEqual(return_code, 0)
1446 Test if ns3 is inserting additional arguments by MPICH and OpenMPI to run on the CI
1450 if shutil.which(
"mpiexec")
is None or win32:
1451 self.skipTest(
"Mpi is not available")
1453 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --enable-examples')
1454 self.assertEqual(return_code, 0)
1458 return_code, stdout, stderr =
run_ns3(
"build sample-simulator")
1459 self.assertEqual(return_code, 0)
1462 sample_simulator_path = list(filter(
lambda x:
"sample-simulator" in x, executables))[0]
1464 mpi_command =
'--dry-run run sample-simulator --command-template="mpiexec -np 2 %s"'
1465 non_mpi_command =
'--dry-run run sample-simulator --command-template="echo %s"'
1468 return_code, stdout, stderr =
run_ns3(mpi_command)
1469 self.assertEqual(return_code, 0)
1470 self.assertIn(
'mpiexec -np 2 "%s"' % sample_simulator_path, stdout)
1473 return_code, stdout, stderr =
run_ns3(mpi_command)
1474 self.assertEqual(return_code, 0)
1475 if os.getenv(
"USER",
"") ==
"root":
1476 if shutil.which(
"ompi_info"):
1478 'mpiexec --allow-run-as-root --oversubscribe -np 2 "%s"'
1479 % sample_simulator_path,
1484 'mpiexec --allow-run-as-root -np 2 "%s"' % sample_simulator_path, stdout
1487 self.assertIn(
'mpiexec -np 2 "%s"' % sample_simulator_path, stdout)
1490 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1491 self.assertEqual(return_code, 0)
1492 self.assertIn(
'echo "%s"' % sample_simulator_path, stdout)
1495 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1496 self.assertEqual(return_code, 0)
1497 self.assertIn(
'echo "%s"' % sample_simulator_path, stdout)
1499 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --disable-examples')
1500 self.assertEqual(return_code, 0)
1504 Test if CMake and ns3 fail in the expected ways when:
1505 - examples from modules or general examples fail if they depend on a
1506 library with a name shorter than 4 characters or are disabled when
1507 a library is nonexistent
1508 - a module library passes the configuration but fails to build due to
1512 os.makedirs(
"contrib/borked", exist_ok=
True)
1513 os.makedirs(
"contrib/borked/examples", exist_ok=
True)
1516 with open(
"contrib/borked/examples/CMakeLists.txt",
"w", encoding=
"utf-8")
as f:
1518 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1519 with open(
"contrib/borked/CMakeLists.txt",
"w", encoding=
"utf-8")
as f:
1523 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1524 LIBRARIES_TO_LINK ${libcore} %s
1526 """ % invalid_or_nonexistent_library)
1528 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --enable-examples')
1529 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1530 self.assertEqual(return_code, 0)
1531 elif invalid_or_nonexistent_library
in [
"lib"]:
1532 self.assertEqual(return_code, 1)
1533 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1537 return_code, stdout, stderr =
run_ns3(
"build borked")
1538 if invalid_or_nonexistent_library
in [
""]:
1539 self.assertEqual(return_code, 0)
1540 elif invalid_or_nonexistent_library
in [
"lib"]:
1541 self.assertEqual(return_code, 2)
1542 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1543 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1544 self.assertEqual(return_code, 2)
1545 if "lld" in stdout + stderr:
1547 "unable to find library -l%s" % invalid_or_nonexistent_library, stderr
1549 elif "mold" in stdout + stderr:
1550 self.assertIn(
"library not found: %s" % invalid_or_nonexistent_library, stderr)
1553 "library not found for -l%s" % invalid_or_nonexistent_library, stderr
1556 self.assertIn(
"cannot find -l%s" % invalid_or_nonexistent_library, stderr)
1564 with open(
"contrib/borked/CMakeLists.txt",
"w", encoding=
"utf-8")
as f:
1568 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1569 LIBRARIES_TO_LINK ${libcore}
1572 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1573 with open(
"contrib/borked/examples/CMakeLists.txt",
"w", encoding=
"utf-8")
as f:
1577 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty-main.cc
1578 LIBRARIES_TO_LINK ${libborked} %s
1580 """ % invalid_or_nonexistent_library)
1582 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1583 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1584 self.assertEqual(return_code, 0)
1585 elif invalid_or_nonexistent_library
in [
"lib"]:
1586 self.assertEqual(return_code, 1)
1587 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1591 return_code, stdout, stderr =
run_ns3(
"build borked-example")
1592 if invalid_or_nonexistent_library
in [
""]:
1593 self.assertEqual(return_code, 0)
1594 elif invalid_or_nonexistent_library
in [
"libf"]:
1595 self.assertEqual(return_code, 2)
1596 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1597 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1598 self.assertEqual(return_code, 1)
1599 self.assertIn(
"Target to build does not exist: borked-example", stdout)
1603 shutil.rmtree(
"contrib/borked", ignore_errors=
True)
1607 Test if CMake can properly handle modules containing "lib",
1608 which is used internally as a prefix for module libraries
1612 os.makedirs(
"contrib/calibre", exist_ok=
True)
1613 os.makedirs(
"contrib/calibre/examples", exist_ok=
True)
1616 with open(
"contrib/calibre/examples/CMakeLists.txt",
"w", encoding=
"utf-8")
as f:
1618 with open(
"contrib/calibre/CMakeLists.txt",
"w", encoding=
"utf-8")
as f:
1622 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1623 LIBRARIES_TO_LINK ${libcore}
1627 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
1630 self.assertEqual(return_code, 0)
1633 self.assertIn(
"calibre", stdout)
1637 self.assertNotIn(
"care", stdout)
1639 os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"pkgconfig",
"ns3-calibre.pc"))
1643 return_code, stdout, stderr =
run_ns3(
"build calibre")
1644 self.assertEqual(return_code, 0)
1647 shutil.rmtree(
"contrib/calibre", ignore_errors=
True)
1651 Test if CMake performance tracing works and produces the
1652 cmake_performance_trace.log file
1655 cmake_performance_trace_log = os.path.join(ns3_path,
"cmake_performance_trace.log")
1656 if os.path.exists(cmake_performance_trace_log):
1657 os.remove(cmake_performance_trace_log)
1659 return_code, stdout, stderr =
run_ns3(
"configure --trace-performance")
1660 self.assertEqual(return_code, 0)
1662 self.assertIn(
"--profiling-format=google-trace --profiling-output=", stdout)
1665 "--profiling-format=google-trace --profiling-output=./cmake_performance_trace.log",
1668 self.assertTrue(os.path.exists(cmake_performance_trace_log))
1672 Check if ENABLE_BUILD_VERSION and version.cache are working
1680 container.execute(
"apt-get update")
1681 container.execute(
"apt-get install -y python3 ninja-build cmake g++ python3-pip")
1682 container.execute(
"pip3 install cmake==3.25.2")
1685 container.execute(
"./ns3 clean")
1688 version_cache_file = os.path.join(ns3_path,
"src/core/model/version.cache")
1691 if os.path.exists(version_cache_file):
1692 os.remove(version_cache_file)
1696 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1697 except DockerException:
1699 self.assertFalse(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1702 version_cache_contents = (
1703 "CLOSEST_TAG = '\"ns-3.0.0\"'\n"
1704 "VERSION_COMMIT_HASH = '\"0000000000\"'\n"
1705 "VERSION_DIRTY_FLAG = '0'\n"
1706 "VERSION_MAJOR = '3'\n"
1707 "VERSION_MINOR = '0'\n"
1708 "VERSION_PATCH = '0'\n"
1709 "VERSION_RELEASE_CANDIDATE = '\"\"'\n"
1710 "VERSION_TAG = '\"ns-3.0.0\"'\n"
1711 "VERSION_TAG_DISTANCE = '0'\n"
1712 "VERSION_BUILD_PROFILE = 'debug'\n"
1714 with open(version_cache_file,
"w", encoding=
"utf-8")
as version:
1715 version.write(version_cache_contents)
1718 container.execute(
"./ns3 clean")
1719 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1720 container.execute(
"./ns3 build core")
1721 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1724 with open(version_cache_file,
"r", encoding=
"utf-8")
as version:
1725 self.assertEqual(version.read(), version_cache_contents)
1730 os.rename(os.path.join(ns3_path,
".git"), os.path.join(ns3_path,
"temp_git"))
1732 container.execute(
"apt-get install -y git")
1733 container.execute(
"./ns3 clean")
1734 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1735 container.execute(
"./ns3 build core")
1736 except DockerException:
1738 os.rename(os.path.join(ns3_path,
"temp_git"), os.path.join(ns3_path,
".git"))
1739 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1742 container.execute(
"./ns3 clean")
1743 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1744 container.execute(
"./ns3 build core")
1745 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1746 with open(version_cache_file,
"r", encoding=
"utf-8")
as version:
1747 self.assertNotEqual(version.read(), version_cache_contents)
1750 if os.path.exists(version_cache_file):
1751 os.remove(version_cache_file)
1755 Test filtering in examples and tests from specific modules
1759 return_code, stdout, stderr =
run_ns3(
1760 'configure -G "{generator}" --enable-examples --enable-tests'
1762 self.
config_ok(return_code, stdout, stderr)
1767 return_code, stdout, stderr =
run_ns3(
1768 "configure -G \"{generator}\" --filter-module-examples-and-tests='core;network'"
1770 self.
config_ok(return_code, stdout, stderr)
1776 self.assertEqual(len(modules_after_filtering), len(modules_before_filtering))
1778 self.assertLess(len(programs_after_filtering), len(programs_before_filtering))
1781 return_code, stdout, stderr =
run_ns3(
1782 "configure -G \"{generator}\" --filter-module-examples-and-tests='core'"
1784 self.
config_ok(return_code, stdout, stderr)
1792 return_code, stdout, stderr =
run_ns3(
1793 "configure -G \"{generator}\" --disable-examples --disable-tests --filter-module-examples-and-tests=''"
1795 self.
config_ok(return_code, stdout, stderr)
1803 Check if fast linkers LLD and Mold are correctly found and configured
1810 container.execute(
"apt-get update")
1811 container.execute(
"apt-get install -y python3 ninja-build cmake g++ lld")
1814 container.execute(
"./ns3 configure -G Ninja")
1817 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1819 os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r", encoding=
"utf-8"
1821 self.assertIn(
"-fuse-ld=lld", f.read())
1825 container.execute(
"./ns3 build core")
1826 except DockerException:
1827 self.assertTrue(
False,
"Build with lld failed")
1830 if not os.path.exists(f
"./mold-1.4.2-{arch}-linux.tar.gz"):
1832 f
"wget https://github.com/rui314/mold/releases/download/v1.4.2/mold-1.4.2-{arch}-linux.tar.gz"
1835 f
"tar xzfC mold-1.4.2-{arch}-linux.tar.gz /usr/local --strip-components=1"
1840 container.execute(
"./ns3 configure -G Ninja")
1843 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1845 os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r", encoding=
"utf-8"
1847 self.assertIn(
"-fuse-ld=mold", f.read())
1851 container.execute(
"./ns3 build core")
1852 except DockerException:
1853 self.assertTrue(
False,
"Build with mold failed")
1856 os.remove(f
"./mold-1.4.2-{arch}-linux.tar.gz")
1859 container.execute(
"./ns3 configure -G Ninja -- -DNS3_FAST_LINKERS=OFF")
1862 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1864 os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r", encoding=
"utf-8"
1866 self.assertNotIn(
"-fuse-ld=mold", f.read())
1870 Check if NS3_CLANG_TIMETRACE feature is working
1871 Clang's -ftime-trace plus ClangAnalyzer report
1877 container.execute(
"apt-get update")
1878 container.execute(
"apt-get install -y python3 ninja-build cmake clang-18")
1883 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18 -DNS3_CLANG_TIMETRACE=ON"
1885 except DockerException
as e:
1886 self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
1888 container.execute(
"apt-get install -y git")
1893 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18 -DNS3_CLANG_TIMETRACE=ON"
1895 except DockerException
as e:
1896 self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
1899 time_trace_report_path = os.path.join(ns3_path,
"ClangBuildAnalyzerReport.txt")
1900 if os.path.exists(time_trace_report_path):
1901 os.remove(time_trace_report_path)
1905 container.execute(
"./ns3 build timeTraceReport")
1906 except DockerException
as e:
1907 self.assertTrue(
False,
"Failed to build the ClangAnalyzer's time trace report")
1910 self.assertTrue(os.path.exists(time_trace_report_path))
1914 container.execute(
"apt-get install -y g++")
1915 container.execute(
"apt-get remove -y clang-18")
1919 "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DNS3_CLANG_TIMETRACE=ON"
1922 False,
"ClangTimeTrace requires Clang, but GCC just passed the checks too"
1924 except DockerException
as e:
1925 self.assertIn(
"TimeTrace is a Clang feature", e.stderr)
1929 Check if NS3_NINJA_TRACE feature is working
1930 Ninja's .ninja_log conversion to about://tracing
1931 json format conversion with Ninjatracing
1937 container.execute(
"apt-get update")
1938 container.execute(
"apt-get remove -y g++")
1939 container.execute(
"apt-get install -y python3 cmake g++-11 clang-18")
1944 "./ns3 configure --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18"
1946 except DockerException
as e:
1947 self.assertIn(
"Ninjatracing requires the Ninja generator", e.stderr)
1952 container.execute(
"apt-get install -y ninja-build")
1956 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18"
1958 except DockerException
as e:
1959 self.assertIn(
"could not find git for clone of NinjaTracing", e.stderr)
1961 container.execute(
"apt-get install -y git")
1965 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18"
1967 except DockerException
as e:
1968 self.assertTrue(
False,
"Failed to configure with Ninjatracing")
1971 ninja_trace_path = os.path.join(ns3_path,
"ninja_performance_trace.json")
1972 if os.path.exists(ninja_trace_path):
1973 os.remove(ninja_trace_path)
1976 container.execute(
"./ns3 build core")
1980 container.execute(
"./ns3 build ninjaTrace")
1981 except DockerException
as e:
1982 self.assertTrue(
False,
"Failed to run Ninjatracing's tool to build the trace")
1985 self.assertTrue(os.path.exists(ninja_trace_path))
1986 trace_size = os.stat(ninja_trace_path).st_size
1987 os.remove(ninja_trace_path)
1994 "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-18 -DNS3_CLANG_TIMETRACE=ON"
1996 except DockerException
as e:
1997 self.assertTrue(
False,
"Failed to configure Ninjatracing with Clang's TimeTrace")
2000 container.execute(
"./ns3 build core")
2004 container.execute(
"./ns3 build ninjaTrace")
2005 except DockerException
as e:
2006 self.assertTrue(
False,
"Failed to run Ninjatracing's tool to build the trace")
2008 self.assertTrue(os.path.exists(ninja_trace_path))
2009 timetrace_size = os.stat(ninja_trace_path).st_size
2010 os.remove(ninja_trace_path)
2013 self.assertGreater(timetrace_size, trace_size)
2017 Check if precompiled headers are being enabled correctly.
2027 container.execute(
"apt-get update")
2028 container.execute(
"apt-get install -y python3 cmake ccache g++ python3-pip")
2029 container.execute(
"pip3 install cmake==3.25.2")
2031 container.execute(
"./ns3 configure")
2032 except DockerException
as e:
2033 self.assertTrue(
False,
"Precompiled headers should have been enabled")
2037 Check for regressions in test object build.
2040 return_code, stdout, stderr =
run_ns3(
"configure")
2041 self.assertEqual(return_code, 0)
2043 test_module_cache = os.path.join(ns3_path,
"cmake-cache",
"src",
"test")
2044 self.assertFalse(os.path.exists(test_module_cache))
2046 return_code, stdout, stderr =
run_ns3(
"configure --enable-tests")
2047 self.assertEqual(return_code, 0)
2048 self.assertTrue(os.path.exists(test_module_cache))
2052 Check for regressions in a bare ns-3 configuration.
2059 container.execute(
"apt-get update")
2060 container.execute(
"apt-get install -y python3 cmake g++ python3-pip")
2061 container.execute(
"pip3 install cmake==3.25.2")
2065 stdout = container.execute(
"./ns3 configure -d release")
2066 except DockerException
as e:
2068 self.
config_ok(return_code, stdout, stdout)
2075 Tests ns3 regarding building the project
2080 Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
2089 Try building the core library
2092 return_code, stdout, stderr =
run_ns3(
"build core")
2093 self.assertEqual(return_code, 0)
2094 self.assertIn(
"Built target core", stdout)
2098 Try building core-test library without tests enabled
2102 return_code, stdout, stderr =
run_ns3(
"build core-test")
2103 self.assertEqual(return_code, 1)
2104 self.assertIn(
"Target to build does not exist: core-test", stdout)
2108 Try building the project:
2111 return_code, stdout, stderr =
run_ns3(
"build")
2112 self.assertEqual(return_code, 0)
2113 self.assertIn(
"Built target", stdout)
2115 self.assertTrue(os.path.exists(program), program)
2116 self.assertIn(cmake_build_project_command, stdout)
2120 Try hiding task lines
2123 return_code, stdout, stderr =
run_ns3(
"--quiet build")
2124 self.assertEqual(return_code, 0)
2125 self.assertIn(cmake_build_project_command, stdout)
2129 Try removing an essential file to break the build
2133 attribute_cc_path = os.sep.join([ns3_path,
"src",
"core",
"model",
"attribute.cc"])
2134 attribute_cc_bak_path = attribute_cc_path +
".bak"
2135 shutil.move(attribute_cc_path, attribute_cc_bak_path)
2138 return_code, stdout, stderr =
run_ns3(
"build")
2139 self.assertNotEqual(return_code, 0)
2142 shutil.move(attribute_cc_bak_path, attribute_cc_path)
2145 return_code, stdout, stderr =
run_ns3(
"build")
2146 self.assertEqual(return_code, 0)
2150 Test if changing the version file affects the library names
2156 version_file = os.sep.join([ns3_path,
"VERSION"])
2157 with open(version_file,
"w", encoding=
"utf-8")
as f:
2161 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}"')
2162 self.
config_ok(return_code, stdout, stderr)
2165 return_code, stdout, stderr =
run_ns3(
"build")
2166 self.assertEqual(return_code, 0)
2167 self.assertIn(
"Built target", stdout)
2173 for program
in new_programs:
2174 self.assertTrue(os.path.exists(program))
2181 new_libraries = list(set(libraries).difference(set(self.
ns3_libraries)))
2182 self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
2183 for library
in new_libraries:
2184 self.assertNotIn(
"libns3-dev", library)
2185 self.assertIn(
"libns3-00", library)
2186 self.assertTrue(os.path.exists(library))
2189 with open(version_file,
"w", encoding=
"utf-8")
as f:
2194 Try setting a different output directory and if everything is
2195 in the right place and still working correctly
2200 return_code, stdout, stderr =
run_ns3(
"build")
2201 self.assertEqual(return_code, 0)
2216 absolute_path = os.sep.join([ns3_path,
"build",
"release"])
2217 relative_path = os.sep.join([
"build",
"release"])
2218 for different_out_dir
in [absolute_path, relative_path]:
2219 return_code, stdout, stderr =
run_ns3(
2220 'configure -G "{generator}" --out="%s"' % different_out_dir
2222 self.
config_ok(return_code, stdout, stderr)
2224 "Build directory : %s" % absolute_path.replace(os.sep,
"/"), stdout
2233 for program
in new_programs:
2234 self.assertTrue(os.path.exists(program))
2238 new_libraries = list(set(libraries).difference(set(self.
ns3_libraries)))
2239 self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
2240 for library
in new_libraries:
2241 self.assertTrue(os.path.exists(library))
2244 shutil.rmtree(absolute_path)
2247 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=''")
2248 self.
config_ok(return_code, stdout, stderr)
2250 "Build directory : %s" % usual_outdir.replace(os.sep,
"/"), stdout
2259 for program
in new_programs:
2260 self.assertTrue(os.path.exists(program))
2265 for library
in libraries:
2266 self.assertTrue(os.path.exists(library))
2270 Tries setting a ns3 version, then installing it.
2271 After that, tries searching for ns-3 with CMake's find_package(ns3).
2272 Finally, tries using core library in a 3rd-party project
2277 for library
in libraries:
2281 version_file = os.sep.join([ns3_path,
"VERSION"])
2282 with open(version_file,
"w", encoding=
"utf-8")
as f:
2286 install_prefix = os.sep.join([ns3_path,
"build",
"install"])
2287 return_code, stdout, stderr =
run_ns3(
2288 'configure -G "{generator}" --prefix="%s"' % install_prefix
2290 self.
config_ok(return_code, stdout, stderr)
2301 lib64 = os.path.exists(os.sep.join([install_prefix,
"lib64"]))
2302 installed_libdir = os.sep.join([install_prefix, (
"lib64" if lib64
else "lib")])
2306 installed_libraries_list =
";".join(installed_libraries)
2307 for library
in libraries:
2308 library_name = os.path.basename(library)
2309 self.assertIn(library_name, installed_libraries_list)
2313 missing_headers = list(
2314 set([os.path.basename(x)
for x
in headers])
2315 - (set([os.path.basename(x)
for x
in installed_headers]))
2317 self.assertEqual(len(missing_headers), 0)
2320 test_main_file = os.sep.join([install_prefix,
"main.cpp"])
2321 with open(test_main_file,
"w", encoding=
"utf-8")
as f:
2323 #include <ns3/core-module.h>
2324 using namespace ns3;
2327 Simulator::Stop (Seconds (1.0));
2329 Simulator::Destroy ();
2337 for version
in [
"",
"3.01",
"3.00"]:
2338 ns3_import_methods = []
2341 cmake_find_package_import =
"""
2342 list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3)
2343 find_package(ns3 {version} COMPONENTS core)
2344 target_link_libraries(test PRIVATE ns3::core)
2345 """.format(lib=(
"lib64" if lib64
else "lib"), version=version)
2346 ns3_import_methods.append(cmake_find_package_import)
2349 pkgconfig_import =
"""
2350 list(APPEND CMAKE_PREFIX_PATH ./)
2351 include(FindPkgConfig)
2352 pkg_check_modules(ns3 REQUIRED IMPORTED_TARGET ns3-core{version})
2353 target_link_libraries(test PUBLIC PkgConfig::ns3)
2355 lib=(
"lib64" if lib64
else "lib"), version=
"=" + version
if version
else ""
2357 if shutil.which(
"pkg-config"):
2358 ns3_import_methods.append(pkgconfig_import)
2361 for import_method
in ns3_import_methods:
2362 test_cmake_project =
"""
2363 cmake_minimum_required(VERSION 3.20..3.20)
2364 project(ns3_consumer CXX)
2365 set(CMAKE_CXX_STANDARD 23)
2366 set(CMAKE_CXX_STANDARD_REQUIRED ON)
2367 add_executable(test main.cpp)
2370 test_cmake_project_file = os.sep.join([install_prefix,
"CMakeLists.txt"])
2371 with open(test_cmake_project_file,
"w", encoding=
"utf-8")
as f:
2372 f.write(test_cmake_project)
2375 cmake = shutil.which(
"cmake")
2378 '-DCMAKE_BUILD_TYPE=debug -G"{generator}" .'.format(
2379 generator=platform_makefiles
2384 if version ==
"3.00":
2385 self.assertEqual(return_code, 1)
2386 if import_method == cmake_find_package_import:
2388 'Could not find a configuration file for package "ns3" that is compatible',
2389 stderr.replace(
"\n",
""),
2391 elif import_method == pkgconfig_import:
2392 self.assertIn(
"not found", stderr.replace(
"\n",
""))
2394 raise Exception(
"Unknown import type")
2396 self.assertEqual(return_code, 0)
2397 self.assertIn(
"Build files", stdout)
2400 return_code, stdout, stderr =
run_program(
"cmake",
"--build .", cwd=install_prefix)
2402 if version ==
"3.00":
2403 self.assertEqual(return_code, 2, msg=stdout + stderr)
2404 self.assertGreater(len(stderr), 0)
2406 self.assertEqual(return_code, 0)
2407 self.assertIn(
"Built target", stdout)
2411 test_program = os.path.join(install_prefix,
"test.exe")
2412 env_sep =
";" if ";" in os.environ[
"PATH"]
else ":"
2414 "PATH": env_sep.join(
2415 [os.environ[
"PATH"], os.path.join(install_prefix,
"lib")]
2419 test_program =
"./test"
2422 test_program,
"", cwd=install_prefix, env=env
2424 self.assertEqual(return_code, 0)
2427 return_code, stdout, stderr =
run_ns3(
"uninstall")
2428 self.assertIn(
"Built target uninstall", stdout)
2431 os.remove(version_file)
2432 with open(version_file,
"w", encoding=
"utf-8")
as f:
2437 Tries to build scratch-simulator and subdir/scratch-simulator-subdir
2442 "scratch/scratch-simulator":
"scratch-simulator",
2443 "scratch/scratch-simulator.cc":
"scratch-simulator",
2444 "scratch-simulator":
"scratch-simulator",
2445 "scratch/subdir/scratch-subdir":
"subdir_scratch-subdir",
2446 "subdir/scratch-subdir":
"subdir_scratch-subdir",
2447 "scratch-subdir":
"subdir_scratch-subdir",
2449 for target_to_run, target_cmake
in targets.items():
2451 build_line =
"target scratch_%s" % target_cmake
2452 return_code, stdout, stderr =
run_ns3(
"build %s" % target_to_run)
2453 self.assertEqual(return_code, 0)
2454 self.assertIn(build_line, stdout)
2457 return_code, stdout, stderr =
run_ns3(
"run %s --verbose" % target_to_run)
2458 self.assertEqual(return_code, 0)
2459 self.assertIn(build_line, stdout)
2460 stdout = stdout.replace(
"scratch_%s" % target_cmake,
"")
2461 self.assertIn(target_to_run.split(
"/")[-1].replace(
".cc",
""), stdout)
2465 Test if ns3 can alert correctly in case a shortcut collision happens
2470 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --enable-examples')
2471 self.assertEqual(return_code, 0)
2474 shutil.copy(
"./examples/tutorial/second.cc",
"./scratch/second.cc")
2477 return_code, stdout, stderr =
run_ns3(
'configure -G "{generator}" --enable-examples')
2478 self.assertEqual(return_code, 0)
2481 return_code, stdout, stderr =
run_ns3(
"build second")
2482 self.assertEqual(return_code, 1)
2484 'Build target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2485 stdout.replace(os.sep,
"/"),
2489 return_code, stdout, stderr =
run_ns3(
"build scratch/second")
2490 self.assertEqual(return_code, 0)
2494 return_code, stdout, stderr =
run_ns3(
"build tutorial/second")
2495 self.assertEqual(return_code, 0)
2499 return_code, stdout, stderr =
run_ns3(
"run second")
2500 self.assertEqual(return_code, 1)
2502 'Run target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2503 stdout.replace(os.sep,
"/"),
2507 return_code, stdout, stderr =
run_ns3(
"run scratch/second")
2508 self.assertEqual(return_code, 0)
2511 return_code, stdout, stderr =
run_ns3(
"run tutorial/second")
2512 self.assertEqual(return_code, 0)
2515 os.remove(
"./scratch/second.cc")
2519 Test if we can build a static ns-3 library and link it to static programs
2522 if (
not win32)
and (arch ==
"aarch64"):
2523 if platform.libc_ver()[0] ==
"glibc":
2524 from packaging.version
import Version
2526 if Version(platform.libc_ver()[1]) < Version(
"2.37"):
2528 "Static linking on ARM64 requires glibc 2.37 where fPIC was enabled (fpic is limited in number of GOT entries)"
2532 return_code, stdout, stderr =
run_ns3(
2533 'configure -G "{generator}" --enable-examples --disable-gtk --enable-static'
2539 self.assertEqual(return_code, 1)
2540 self.assertIn(
"Static builds are unsupported on Windows", stderr)
2543 self.assertEqual(return_code, 0)
2546 return_code, stdout, stderr =
run_ns3(
"build sample-simulator")
2547 self.assertEqual(return_code, 0)
2548 self.assertIn(
"Built target", stdout)
2554 Test if we can use python bindings
2559 except ModuleNotFoundError:
2560 self.skipTest(
"Cppyy was not found")
2563 return_code, stdout, stderr =
run_ns3(
2564 'configure -G "{generator}" --enable-examples --enable-python-bindings'
2568 self.assertEqual(return_code, 0)
2571 return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
2572 self.assertEqual(return_code, 0)
2575 return_code, stdout, stderr =
run_program(
"test.py",
"-p mixed-wired-wireless", python=
True)
2576 self.assertEqual(return_code, 0)
2580 "test.py",
"-p ./examples/wireless/mixed-wired-wireless", python=
True
2582 self.assertEqual(return_code, 0)
2586 Test if we had regressions with brite, click and openflow modules
2587 that depend on homonymous libraries
2590 if shutil.which(
"git")
is None:
2591 self.skipTest(
"Missing git")
2594 self.skipTest(
"Optional components are not supported on Windows")
2597 return_code, stdout, stderr =
run_ns3(
2598 "configure --disable-werror -- -DNS3_FETCH_OPTIONAL_COMPONENTS=ON"
2600 self.assertEqual(return_code, 0)
2604 return_code, stdout, stderr =
run_ns3(
"build brite click openflow")
2605 self.assertEqual(return_code, 0)
2609 Test if we can link contrib modules to src modules
2612 if shutil.which(
"git")
is None:
2613 self.skipTest(
"Missing git")
2615 destination_contrib = os.path.join(ns3_path,
"contrib/test-contrib-dependency")
2616 destination_src = os.path.join(ns3_path,
"src/test-src-dependent-on-contrib")
2618 if os.path.exists(destination_contrib):
2619 shutil.rmtree(destination_contrib)
2620 if os.path.exists(destination_src):
2621 shutil.rmtree(destination_src)
2625 os.path.join(ns3_path,
"build-support/test-files/test-contrib-dependency"),
2626 destination_contrib,
2629 os.path.join(ns3_path,
"build-support/test-files/test-src-dependent-on-contrib"),
2634 return_code, stdout, stderr =
run_ns3(
"configure --enable-examples")
2635 self.assertEqual(return_code, 0)
2638 return_code, stdout, stderr =
run_ns3(
"run source-example")
2639 self.assertEqual(return_code, 0)
2642 shutil.rmtree(destination_contrib)
2643 shutil.rmtree(destination_src)
2648 Tests ns3 usage in more realistic scenarios
2653 Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned
2654 Here examples, tests and documentation are also enabled.
2661 return_code, stdout, stderr =
run_ns3(
2662 'configure -d release -G "{generator}" --enable-examples --enable-tests'
2664 self.
config_ok(return_code, stdout, stderr)
2667 self.assertTrue(os.path.exists(ns3_lock_filename))
2673 self.assertTrue(os.path.exists(ns3_lock_filename))
2680 Try to build the project
2683 return_code, stdout, stderr =
run_ns3(
"build")
2684 self.assertEqual(return_code, 0)
2685 self.assertIn(
"Built target", stdout)
2687 self.assertTrue(os.path.exists(program))
2690 self.assertIn(module.replace(
"ns3-",
""),
";".join(libraries))
2691 self.assertIn(cmake_build_project_command, stdout)
2695 Try to build and run test-runner
2698 return_code, stdout, stderr =
run_ns3(
'run "test-runner --list" --verbose')
2699 self.assertEqual(return_code, 0)
2700 self.assertIn(
"Built target test-runner", stdout)
2705 Try to build and run a library
2708 return_code, stdout, stderr =
run_ns3(
"run core")
2709 self.assertEqual(return_code, 1)
2710 self.assertIn(
"Couldn't find the specified program: core", stderr)
2714 Try to build and run an unknown target
2717 return_code, stdout, stderr =
run_ns3(
"run nonsense")
2718 self.assertEqual(return_code, 1)
2719 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2723 Try to run test-runner without building
2726 return_code, stdout, stderr =
run_ns3(
"build test-runner")
2727 self.assertEqual(return_code, 0)
2729 return_code, stdout, stderr =
run_ns3(
'run "test-runner --list" --no-build --verbose')
2730 self.assertEqual(return_code, 0)
2731 self.assertNotIn(
"Built target test-runner", stdout)
2736 Test ns3 fails to run a library
2739 return_code, stdout, stderr =
run_ns3(
"run core --no-build")
2740 self.assertEqual(return_code, 1)
2741 self.assertIn(
"Couldn't find the specified program: core", stderr)
2745 Test ns3 fails to run an unknown program
2748 return_code, stdout, stderr =
run_ns3(
"run nonsense --no-build")
2749 self.assertEqual(return_code, 1)
2750 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2754 Test if scratch simulator is executed through gdb and lldb
2757 if shutil.which(
"gdb")
is None:
2758 self.skipTest(
"Missing gdb")
2760 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
2761 self.assertEqual(return_code, 0)
2763 return_code, stdout, stderr =
run_ns3(
2764 "run scratch-simulator --gdb --verbose --no-build", env={
"gdb_eval":
"1"}
2766 self.assertEqual(return_code, 0)
2767 self.assertIn(
"scratch-simulator", stdout)
2769 self.assertIn(
"GNU gdb", stdout)
2771 self.assertIn(
"No debugging symbols found", stdout)
2775 Test if scratch simulator is executed through valgrind
2778 if shutil.which(
"valgrind")
is None:
2779 self.skipTest(
"Missing valgrind")
2781 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
2782 self.assertEqual(return_code, 0)
2784 return_code, stdout, stderr =
run_ns3(
2785 "run scratch-simulator --valgrind --verbose --no-build"
2787 self.assertEqual(return_code, 0)
2788 self.assertIn(
"scratch-simulator", stderr)
2789 self.assertIn(
"Memcheck", stderr)
2793 Test the doxygen target that does trigger a full build
2796 if shutil.which(
"doxygen")
is None:
2797 self.skipTest(
"Missing doxygen")
2799 if shutil.which(
"bash")
is None:
2800 self.skipTest(
"Missing bash")
2802 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2804 doxygen_files = [
"introspected-command-line.h",
"introspected-doxygen.h"]
2805 for filename
in doxygen_files:
2806 file_path = os.sep.join([doc_folder, filename])
2807 if os.path.exists(file_path):
2808 os.remove(file_path)
2815 return_code, stdout, stderr =
run_ns3(
"docs doxygen")
2816 self.assertEqual(return_code, 0)
2818 self.assertIn(
"Built target doxygen", stdout)
2822 Test the doxygen target that doesn't trigger a full build
2825 if shutil.which(
"doxygen")
is None:
2826 self.skipTest(
"Missing doxygen")
2834 return_code, stdout, stderr =
run_ns3(
"docs doxygen-no-build")
2835 self.assertEqual(return_code, 0)
2837 self.assertIn(
"Built target doxygen-no-build", stdout)
2841 Test every individual target for Sphinx-based documentation
2844 if shutil.which(
"sphinx-build")
is None:
2845 self.skipTest(
"Missing sphinx")
2847 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2850 for target
in [
"installation",
"contributing",
"manual",
"models",
"tutorial"]:
2852 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2853 doc_temp_folder = os.sep.join([doc_folder, target,
"source-temp"])
2854 if os.path.exists(doc_build_folder):
2855 shutil.rmtree(doc_build_folder)
2856 if os.path.exists(doc_temp_folder):
2857 shutil.rmtree(doc_temp_folder)
2860 return_code, stdout, stderr =
run_ns3(
"docs %s" % target)
2861 self.assertEqual(return_code, 0, target)
2863 self.assertIn(
"Built target sphinx_%s" % target, stdout)
2866 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2867 self.assertTrue(os.path.exists(doc_build_folder))
2870 for build_type
in [
"latex",
"html",
"singlehtml"]:
2871 self.assertTrue(os.path.exists(os.sep.join([doc_build_folder, build_type])))
2875 Test the documentation target that builds
2876 both doxygen and sphinx based documentation
2879 if shutil.which(
"doxygen")
is None:
2880 self.skipTest(
"Missing doxygen")
2881 if shutil.which(
"sphinx-build")
is None:
2882 self.skipTest(
"Missing sphinx")
2884 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2893 for target
in [
"manual",
"models",
"tutorial"]:
2894 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2895 if os.path.exists(doc_build_folder):
2896 shutil.rmtree(doc_build_folder)
2898 return_code, stdout, stderr =
run_ns3(
"docs all")
2899 self.assertEqual(return_code, 0)
2901 self.assertIn(
"Built target sphinx", stdout)
2903 self.assertIn(
"Built target doxygen", stdout)
2907 Try to set ownership of scratch-simulator from current user to root,
2908 and change execution permissions
2913 sudo_password = os.getenv(
"SUDO_PASSWORD",
None)
2916 if sudo_password
is None:
2917 self.skipTest(
"SUDO_PASSWORD environment variable was not specified")
2920 self.assertFalse(enable_sudo
is True)
2923 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator")
2924 self.assertEqual(return_code, 0)
2925 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2927 scratch_simulator_path = list(
2928 filter(
lambda x: x
if "scratch-simulator" in x
else None, self.
ns3_executables)
2930 prev_fstat = os.stat(scratch_simulator_path)
2933 return_code, stdout, stderr =
run_ns3(
2934 "run scratch-simulator --enable-sudo", env={
"SUDO_PASSWORD": sudo_password}
2936 self.assertEqual(return_code, 0)
2937 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2939 fstat = os.stat(scratch_simulator_path)
2945 likely_fuse_mount = (
2946 (prev_fstat.st_mode & stat.S_ISUID) == (fstat.st_mode & stat.S_ISUID)
2947 )
and prev_fstat.st_uid == 0
2949 if win32
or likely_fuse_mount:
2950 self.skipTest(
"Windows or likely a FUSE mount")
2953 self.assertEqual(fstat.st_uid, 0)
2955 fstat.st_mode & stat.S_ISUID, stat.S_ISUID
2959 return_code, stdout, stderr =
run_ns3(
"configure --enable-sudo")
2960 self.assertEqual(return_code, 0)
2964 self.assertTrue(enable_sudo)
2968 if os.path.exists(executable):
2969 os.remove(executable)
2972 return_code, stdout, stderr =
run_ns3(
"build", env={
"SUDO_PASSWORD": sudo_password})
2973 self.assertEqual(return_code, 0)
2976 self.assertIn(
"chown root", stdout)
2977 self.assertIn(
"chmod u+s", stdout)
2979 self.assertIn(os.path.basename(executable), stdout)
2982 fstat = os.stat(scratch_simulator_path)
2983 self.assertEqual(fstat.st_uid, 0)
2985 fstat.st_mode & stat.S_ISUID, stat.S_ISUID
2990 Check if command template is working
2995 return_code0, stdout0, stderr0 =
run_ns3(
"run sample-simulator --command-template")
2996 self.assertEqual(return_code0, 2)
2997 self.assertIn(
"argument --command-template: expected one argument", stderr0)
2999 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template=" "')
3000 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --command-template " "')
3001 return_code3, stdout3, stderr3 =
run_ns3(
'run sample-simulator --command-template "echo "')
3002 self.assertEqual((return_code1, return_code2, return_code3), (1, 1, 1))
3003 for stderr
in [stderr1, stderr2, stderr3]:
3004 self.assertIn(
"not all arguments converted during string formatting", stderr)
3007 return_code4, stdout4, _ =
run_ns3(
3008 'run sample-simulator --command-template "%s --PrintVersion" --verbose'
3010 return_code5, stdout5, _ =
run_ns3(
3011 'run sample-simulator --command-template="%s --PrintVersion" --verbose'
3013 self.assertEqual((return_code4, return_code5), (0, 0))
3015 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout4)
3016 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout5)
3020 Check if all flavors of different argument passing to
3021 executable targets are working
3026 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --verbose')
3027 return_code1, stdout1, stderr1 =
run_ns3(
3028 'run sample-simulator --command-template="%s --help" --verbose'
3030 return_code2, stdout2, stderr2 =
run_ns3(
"run sample-simulator --verbose -- --help")
3032 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
3033 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout0)
3034 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout1)
3035 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout2)
3038 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --no-build')
3039 return_code1, stdout1, stderr1 =
run_ns3(
3040 'run sample-simulator --command-template="%s --help" --no-build'
3042 return_code2, stdout2, stderr2 =
run_ns3(
"run sample-simulator --no-build -- --help")
3043 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
3044 self.assertEqual(stdout0, stdout1)
3045 self.assertEqual(stdout1, stdout2)
3046 self.assertEqual(stderr0, stderr1)
3047 self.assertEqual(stderr1, stderr2)
3050 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --PrintGlobals" --verbose')
3051 return_code1, stdout1, stderr1 =
run_ns3(
'run "sample-simulator --PrintGroups" --verbose')
3052 return_code2, stdout2, stderr2 =
run_ns3(
'run "sample-simulator --PrintTypeIds" --verbose')
3054 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
3055 self.assertIn(
"sample-simulator{ext} --PrintGlobals".format(ext=ext), stdout0)
3056 self.assertIn(
"sample-simulator{ext} --PrintGroups".format(ext=ext), stdout1)
3057 self.assertIn(
"sample-simulator{ext} --PrintTypeIds".format(ext=ext), stdout2)
3060 cmd =
'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" --verbose -- --PrintTypeIds'
3061 return_code, stdout, stderr =
run_ns3(cmd)
3062 self.assertEqual(return_code, 0)
3068 "sample-simulator{ext} --PrintGroups --PrintGlobals --PrintTypeIds".format(ext=ext),
3073 cmd0 =
'run sample-simulator --command-template="%s " --PrintTypeIds'
3074 cmd1 =
"run sample-simulator --PrintTypeIds"
3076 return_code0, stdout0, stderr0 =
run_ns3(cmd0)
3077 return_code1, stdout1, stderr1 =
run_ns3(cmd1)
3078 self.assertEqual((return_code0, return_code1), (1, 1))
3079 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr0)
3080 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr1)
3084 Test if scratch simulator is executed through lldb
3087 if shutil.which(
"lldb")
is None:
3088 self.skipTest(
"Missing lldb")
3090 return_code, stdout, stderr =
run_ns3(
"build scratch-simulator")
3091 self.assertEqual(return_code, 0)
3093 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --lldb --verbose --no-build")
3094 self.assertEqual(return_code, 0)
3095 self.assertIn(
"scratch-simulator", stdout)
3096 self.assertIn(
"(lldb) target create", stdout)
3100 Test if CPM and Vcpkg package managers are working properly
3104 return_code, stdout, stderr =
run_ns3(
"clean")
3105 self.assertEqual(return_code, 0)
3108 if os.path.exists(
"vcpkg"):
3109 shutil.rmtree(
"vcpkg")
3112 destination_src = os.path.join(ns3_path,
"src/test-package-managers")
3114 if os.path.exists(destination_src):
3115 shutil.rmtree(destination_src)
3119 os.path.join(ns3_path,
"build-support/test-files/test-package-managers"),
3125 container.execute(
"apt-get update")
3126 container.execute(
"apt-get install -y python3 cmake g++ ninja-build python3-pip")
3127 container.execute(
"pip3 install cmake==3.25.2")
3132 container.execute(
"./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=ON")
3133 self.skipTest(
"Armadillo is already installed")
3134 except DockerException
as e:
3138 return_code, stdout, stderr =
run_ns3(
"clean")
3139 self.assertEqual(return_code, 0)
3142 container.execute(
"apt-get install -y git")
3147 "./ns3 configure -- -DNS3_CPM=ON -DTEST_PACKAGE_MANAGER:STRING=CPM"
3149 except DockerException
as e:
3154 container.execute(
"./ns3 build test-package-managers")
3155 except DockerException
as e:
3159 return_code, stdout, stderr =
run_ns3(
"clean")
3160 self.assertEqual(return_code, 0)
3162 if arch !=
"aarch64":
3164 container.execute(
"apt-get install -y zip unzip tar curl")
3167 container.execute(
"apt-get install -y pkg-config gfortran")
3171 container.execute(
"./ns3 configure -- -DNS3_VCPKG=ON")
3172 except DockerException
as e:
3177 container.execute(
"./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=VCPKG")
3178 except DockerException
as e:
3183 container.execute(
"./ns3 build test-package-managers")
3184 except DockerException
as e:
3188 if os.path.exists(destination_src):
3189 shutil.rmtree(destination_src)
3193 Test if test.py and command-template handles empty spaces in executable paths correctly
3197 return_code, stdout, stderr =
run_ns3(
"clean")
3198 self.assertEqual(return_code, 0)
3202 container.execute(
"apt-get update")
3203 container.execute(
"apt-get install -y python3 cmake g++ ninja-build python3-pip")
3204 container.execute(
"pip3 install cmake==3.25.2")
3207 test_path =
"/path with empty spaces/ns-3-dev"
3209 container.execute(f
'mkdir -p "{test_path}"')
3210 container.execute(f
'cp -R ./ "{test_path}"')
3211 except DockerException
as e:
3217 './ns3 configure --enable-examples --enable-tests --filter-module-examples-and-tests="core;sixlowpan"',
3220 except DockerException
as e:
3225 container.execute(
"./test.py", workdir=test_path)
3226 except DockerException
as e:
3230 return_code, stdout, stderr =
run_ns3(
"clean")
3231 self.assertEqual(return_code, 0)
3236 ns-3 tests to control the quality of the repository over time
3241 Check if images in the docs are above a brightness threshold.
3242 This should prevent screenshots with dark UI themes.
3245 if shutil.which(
"convert")
is None:
3246 self.skipTest(
"Imagemagick was not found")
3248 from pathlib
import Path
3251 image_extensions = [
"png",
"jpg"]
3253 for extension
in image_extensions:
3254 images += list(Path(
"./doc").glob(
"**/figures/*.{ext}".format(ext=extension)))
3255 images += list(Path(
"./doc").glob(
"**/figures/**/*.{ext}".format(ext=extension)))
3258 imagemagick_get_image_brightness =
'convert {image} -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]" info:'
3262 brightness_threshold = 50
3263 for image
in images:
3264 brightness = subprocess.check_output(
3265 imagemagick_get_image_brightness.format(image=image).split()
3267 brightness = float(brightness.decode().strip(
"'\""))
3270 brightness_threshold,
3271 "Image darker than threshold (%d < %d): %s"
3272 % (brightness, brightness_threshold, image),
3277 Check if one of the log statements of examples/tests contains/exposes a bug.
3281 return_code, stdout, stderr =
run_ns3(
3282 'configure -G "{generator}" -d release --enable-examples --enable-tests --enable-sanitizers'
3284 self.assertEqual(return_code, 0)
3288 "test.py",
"", python=
True, env={
"TEST_LOGS":
"1"}
3290 self.assertEqual(return_code, 0)
3295 ns-3 complementary tests, allowed to fail, to help control
3296 the quality of the repository over time, by checking the
3297 state of URLs listed and more
3302 Test if all urls in source files are alive
3311 self.skipTest(
"Django URL validators are not available")
3318 urllib3.disable_warnings()
3321 self.skipTest(
"Requests library is not available")
3323 regex = re.compile(
r"((http|https)://[^\ \n\)\"\'\}><\]\;\`\\]*)")
3326 whitelisted_urls = {
3327 "https://gitlab.com/your-user-name/ns-3-dev",
3328 "https://www.nsnam.org/release/ns-allinone-3.31.rc1.tar.bz2",
3329 "https://www.nsnam.org/release/ns-allinone-3.X.rcX.tar.bz2",
3330 "https://www.nsnam.org/releases/ns-3-x",
3331 "https://www.nsnam.org/releases/ns-allinone-3.(x-1",
3332 "https://www.nsnam.org/releases/ns-allinone-3.x.tar.bz2",
3333 "https://ns-buildmaster.ee.washington.edu:8010/",
3335 "https://cmake.org/cmake/help/latest/manual/cmake-",
3336 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_",
3338 "http://www.lysator.liu.se/~alla/dia/",
3340 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_Digital_Terrestrial_Television_Broadcasting_(DTTB",
3341 "http://en.wikipedia.org/wiki/Namespace_(computer_science",
3342 "http://en.wikipedia.org/wiki/Bonobo_(component_model",
3343 "http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85",
3344 "https://github.com/rui314/mold/releases/download/v1.4.2/mold-1.4.2-{arch",
3345 "http://www.nsnam.org/bugzilla/show_bug.cgi?id=",
3347 "http://www.research.att.com/info/kpv/",
3348 "http://www.research.att.com/~gsf/",
3349 "http://nsnam.isi.edu/nsnam/index.php/Contributed_Code",
3350 "http://scan5.coverity.com/cgi-bin/upload.py",
3352 "https://github.com/Kitware/CMake/releases/download/v3.27.1/cmake-3.27.1-linux-x86_64.tar.gz-",
3353 "http://mirrors.kernel.org/fedora/releases/11/Everything/i386/os/Packages/",
3357 files_and_urls = set()
3359 for topdir
in [
"bindings",
"doc",
"examples",
"src",
"utils"]:
3360 for root, dirs, files
in os.walk(topdir):
3362 if "build" in root
or "_static" in root
or "source-temp" in root
or "html" in root:
3365 filepath = os.path.join(root, file)
3368 if not os.path.isfile(filepath):
3372 if file.endswith(
".svg"):
3376 with open(filepath,
"r", encoding=
"utf-8")
as f:
3377 matches = regex.findall(f.read())
3383 map(
lambda x: x[0][:-1]
if x[0][-1]
in ".," else x[0], matches)
3385 except UnicodeDecodeError:
3386 skipped_files.append(filepath)
3390 for url
in set(urls) - unique_urls - whitelisted_urls:
3391 unique_urls.add(url)
3392 files_and_urls.add((filepath, url))
3395 from django.core.exceptions
import ValidationError
3396 from django.core.validators
import URLValidator
3398 validate_url = URLValidator()
3402 "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"
3406 def test_file_url(args):
3407 test_filepath, test_url = args
3408 dead_link_msg =
None
3412 validate_url(test_url)
3413 except ValidationError:
3414 dead_link_msg =
"%s: URL %s, invalid URL" % (test_filepath, test_url)
3415 except Exception
as e:
3416 self.assertEqual(
False,
True, msg=e.__str__())
3418 if dead_link_msg
is not None:
3419 return dead_link_msg
3427 response = requests.get(test_url, verify=
False, headers=headers, timeout=50)
3430 if response.status_code
in [200, 301]:
3431 dead_link_msg =
None
3436 if response.status_code
in [302, 308, 500, 503]:
3437 if response.reason.lower()
in [
3439 "moved temporarily",
3440 "permanent redirect",
3442 "service temporarily unavailable",
3444 dead_link_msg =
None
3448 dead_link_msg =
"%s: URL %s: returned code %d" % (
3451 response.status_code,
3453 except requests.exceptions.InvalidURL:
3454 dead_link_msg =
"%s: URL %s: invalid URL" % (test_filepath, test_url)
3455 except requests.exceptions.SSLError:
3456 dead_link_msg =
"%s: URL %s: SSL error" % (test_filepath, test_url)
3457 except requests.exceptions.TooManyRedirects:
3458 dead_link_msg =
"%s: URL %s: too many redirects" % (test_filepath, test_url)
3459 except Exception
as e:
3461 error_msg = e.args[0].reason.__str__()
3462 except AttributeError:
3463 error_msg = e.args[0]
3464 dead_link_msg =
"%s: URL %s: failed with exception: %s" % (
3470 return dead_link_msg
3473 from concurrent.futures
import ThreadPoolExecutor
3475 with ThreadPoolExecutor(max_workers=100)
as executor:
3476 dead_links = list(executor.map(test_file_url, list(files_and_urls)))
3479 dead_links = list(sorted(filter(
lambda x: x
is not None, dead_links)))
3480 self.assertEqual(len(dead_links), 0, msg=
"\n".join([
"Dead links found:", *dead_links]))
3484 Test if all tests can be executed without hitting major memory bugs
3487 return_code, stdout, stderr =
run_ns3(
3488 "configure --enable-tests --enable-examples --enable-sanitizers -d optimized"
3490 self.assertEqual(return_code, 0)
3492 test_return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
3493 self.assertEqual(test_return_code, 0)
3502 test_completeness = {
3504 NS3UnusedSourcesTestCase,
3508 NS3CommonSettingsTestCase,
3509 NS3ConfigureBuildProfileTestCase,
3510 NS3ConfigureTestCase,
3511 NS3BuildBaseTestCase,
3512 NS3ExpectedUseTestCase,
3515 NS3UnusedSourcesTestCase,
3517 NS3CommonSettingsTestCase,
3518 NS3ConfigureBuildProfileTestCase,
3519 NS3ConfigureTestCase,
3520 NS3BuildBaseTestCase,
3521 NS3ExpectedUseTestCase,
3522 NS3QualityControlTestCase,
3525 NS3DependenciesTestCase,
3526 NS3QualityControlThatCanFailTestCase,
3532 parser = argparse.ArgumentParser(
"Test suite for the ns-3 buildsystem")
3533 parser.add_argument(
3534 "-c",
"--completeness", choices=test_completeness.keys(), default=
"complete"
3536 parser.add_argument(
"-tn",
"--test-name", action=
"store", default=
None, type=str)
3537 parser.add_argument(
"-rtn",
"--resume-from-test-name", action=
"store", default=
None, type=str)
3538 parser.add_argument(
"-q",
"--quiet", action=
"store_true", default=
False)
3539 parser.add_argument(
"-f",
"--failfast", action=
"store_true", default=
False)
3540 args = parser.parse_args(sys.argv[1:])
3542 loader = unittest.TestLoader()
3543 suite = unittest.TestSuite()
3546 for testCase
in test_completeness[args.completeness]:
3547 suite.addTests(loader.loadTestsFromTestCase(testCase))
3552 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
3554 tests_to_run = set(map(
lambda x: x
if args.test_name
in x
else None, tests.keys()))
3555 tests_to_remove = set(tests) - set(tests_to_run)
3556 for test_to_remove
in tests_to_remove:
3557 suite._tests.remove(tests[test_to_remove])
3560 if args.resume_from_test_name:
3562 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
3563 keys = list(tests.keys())
3565 while args.resume_from_test_name
not in keys[0]
and len(tests) > 0:
3566 suite._tests.remove(tests[keys[0]])
3570 ns3rc_script_bak = ns3rc_script +
".bak"
3571 if os.path.exists(ns3rc_script)
and not os.path.exists(ns3rc_script_bak):
3572 shutil.move(ns3rc_script, ns3rc_script_bak)
3575 runner = unittest.TextTestRunner(failfast=args.failfast, verbosity=1
if args.quiet
else 2)
3579 if os.path.exists(ns3rc_script_bak):
3580 shutil.move(ns3rc_script_bak, ns3rc_script)
3583if __name__ ==
"__main__":
Python-on-whales wrapper for Docker-based ns-3 tests.
__init__(self, unittest.TestCase currentTestCase, str containerName="ubuntu:latest")
Create and start container with containerName in the current ns-3 directory.
__enter__(self)
Return the managed container when entiring the block "with DockerContainerManager() as container".
__exit__(self, exc_type, exc_val, exc_tb)
Clean up the managed container at the end of the block "with DockerContainerManager() as container".
container
The Python-on-whales container instance.
Generic test case with basic function inherited by more complex tests.
config_ok(self, return_code, stdout, stderr)
Check if configuration for release mode worked normally.
setUp(self)
Clean configuration/build artifacts before testing configuration and build settings After configuring...
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
Tests ns3 regarding building the project.
test_08_InstallationAndUninstallation(self)
Tries setting a ns3 version, then installing it.
test_12_CppyyBindings(self)
Test if we can use python bindings.
test_13_FetchOptionalComponents(self)
Test if we had regressions with brite, click and openflow modules that depend on homonymous libraries...
test_07_OutputDirectory(self)
Try setting a different output directory and if everything is in the right place and still working co...
test_02_BuildNonExistingTargets(self)
Try building core-test library without tests enabled.
test_01_BuildExistingTargets(self)
Try building the core library.
setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned.
test_04_BuildProjectNoTaskLines(self)
Try hiding task lines.
test_11_StaticBuilds(self)
Test if we can build a static ns-3 library and link it to static programs.
test_06_TestVersionFile(self)
Test if changing the version file affects the library names.
test_14_LinkContribModuleToSrcModule(self)
Test if we can link contrib modules to src modules.
test_03_BuildProject(self)
Try building the project:
test_09_Scratches(self)
Tries to build scratch-simulator and subdir/scratch-simulator-subdir.
test_05_BreakBuild(self)
Try removing an essential file to break the build.
test_10_AmbiguityCheck(self)
Test if ns3 can alert correctly in case a shortcut collision happens.
ns3_libraries
ns3_libraries holds a list of built module libraries # noqa
ns3 tests related to generic options
test_01_NoOption(self)
Test not passing any arguments to.
test_05_CheckVersion(self)
Test only passing 'show version' argument to ns3.
test_04_CheckProfile(self)
Test only passing 'show profile' argument to ns3.
test_03_CheckConfig(self)
Test only passing 'show config' argument to ns3.
setUp(self)
Clean configuration/build artifacts before common commands.
test_02_NoTaskLines(self)
Test only passing –quiet argument to ns3.
ns-3 tests related to dependencies
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.
test_12_SphinxDocumentation(self)
Test every individual target for Sphinx-based documentation.
test_03_BuildAndRunExistingLibraryTarget(self)
Try to build and run a library.
test_01_BuildProject(self)
Try to build the project.
test_08_RunNoBuildGdb(self)
Test if scratch simulator is executed through gdb and lldb.
test_11_DoxygenWithoutBuild(self)
Test the doxygen target that doesn't trigger a full build.
test_06_RunNoBuildExistingLibraryTarget(self)
Test ns3 fails to run a library.
test_14_EnableSudo(self)
Try to set ownership of scratch-simulator from current user to root, and change execution permissions...
setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned Here examples,...
test_02_BuildAndRunExistingExecutableTarget(self)
Try to build and run test-runner.
test_18_CpmAndVcpkgManagers(self)
Test if CPM and Vcpkg package managers are working properly.
test_15_CommandTemplate(self)
Check if command template is working.
test_07_RunNoBuildNonExistingExecutableTarget(self)
Test ns3 fails to run an unknown program.
test_05_RunNoBuildExistingExecutableTarget(self)
Try to run test-runner without building.
test_16_ForwardArgumentsToRunTargets(self)
Check if all flavors of different argument passing to executable targets are working.
test_17_RunNoBuildLldb(self)
Test if scratch simulator is executed through lldb.
test_19_EmptySpaceHandlingOnTestAndCommandTemplate(self)
Test if test.py and command-template handles empty spaces in executable paths correctly.
test_09_RunNoBuildValgrind(self)
Test if scratch simulator is executed through valgrind.
test_04_BuildAndRunNonExistingTarget(self)
Try to build and run an unknown target.
test_13_Documentation(self)
Test the documentation target that builds both doxygen and sphinx based documentation.
test_10_DoxygenWithBuild(self)
Test the doxygen target that does trigger a full build.
ns-3 tests to control the quality of the repository over time
test_02_CheckForBrokenLogs(self)
Check if one of the log statements of examples/tests contains/exposes a bug.
test_01_CheckImageBrightness(self)
Check if images in the docs are above a brightness threshold.
ns-3 complementary tests, allowed to fail, to help control the quality of the repository over time,...
test_01_CheckForDeadLinksInSources(self)
Test if all urls in source files are alive.
test_02_MemoryCheckWithSanitizers(self)
Test if all tests can be executed without hitting major memory bugs.
ns-3 tests to check if the source code, whitespaces and CMake formatting are according to the coding ...
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
test_01_UnusedExampleSources(self)
Test if all example source files are being used in their respective CMakeLists.txt.
test_03_UnusedUtilsSources(self)
Test if all utils source files are being used in their respective CMakeLists.txt.
setUp(self)
Scan all C++ source files and add them to a list based on their path.
test_02_UnusedModuleSources(self)
Test if all module source files are being used in their respective CMakeLists.txt.
read_lock_entry(entry)
Read interesting entries from the .lock-ns3 file.
get_libraries_list(lib_outdir=usual_lib_outdir)
Gets a list of built libraries.
get_headers_list(outdir=usual_outdir)
Gets a list of header files.
cmake_build_target_command
run_ns3(args, env=None, generator=platform_makefiles)
Runs the ns3 wrapper script with arguments.
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,...
get_programs_list()
Extracts the programs list from .lock-ns3.
get_test_enabled()
Check if tests are enabled in the .lock-ns3.