22Test suite for the ns3 wrapper script
32from functools
import partial
35ns3_path = os.path.dirname(os.path.abspath(os.sep.join([__file__,
"../../"])))
36ns3_lock_filename = os.path.join(ns3_path,
".lock-ns3_%s_build" % sys.platform)
37ns3_script = os.sep.join([ns3_path,
"ns3"])
38ns3rc_script = os.sep.join([ns3_path,
".ns3rc"])
39usual_outdir = os.sep.join([ns3_path,
"build"])
40usual_lib_outdir = os.sep.join([usual_outdir,
"lib"])
46num_threads =
max(1, os.cpu_count() - 1)
47cmake_build_project_command =
"cmake --build . -j".format(ns3_path=ns3_path)
48cmake_build_target_command = partial(
"cmake --build . -j {jobs} --target {target}".format,
51win32 = sys.platform ==
"win32"
52platform_makefiles =
"MinGW Makefiles" if win32
else "Unix Makefiles"
53ext =
".exe" if win32
else ""
56def run_ns3(args, env=None, generator=platform_makefiles):
58 Runs the ns3 wrapper script with arguments
59 @param args: string containing arguments that will get split before calling ns3
60 @param env: environment variables dictionary
61 @param generator: CMake generator
62 @return tuple containing (error code, stdout
and stderr)
65 possible_leftovers = [
"contrib/borked",
"contrib/calibre"]
66 for leftover
in possible_leftovers:
67 if os.path.exists(leftover):
68 shutil.rmtree(leftover, ignore_errors=
True)
70 args = args.format(generator=generator)
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(
"(?:\".*?\"|\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,
117 return ret.returncode, ret.stdout.decode(sys.stdout.encoding), ret.stderr.decode(sys.stderr.encoding)
122 Extracts the programs list from .lock-ns3
123 @return list of programs.
126 with open(ns3_lock_filename)
as f:
127 exec(f.read(), globals(), values)
129 programs_list = values[
"ns3_runnable_programs"]
133 programs_list =
list(map(
lambda x: x + ext, programs_list))
139 Gets a list of built libraries
140 @param lib_outdir: path containing libraries
141 @return list of built libraries.
143 return glob.glob(lib_outdir +
'/*', recursive=
True)
148 Gets a list of header files
149 @param outdir: path containing headers
150 @return list of headers.
152 return glob.glob(outdir +
'/**/*.h', recursive=
True)
157 Read interesting entries from the .lock-ns3 file
158 @param entry: entry to read
from .lock-ns3
159 @return value of the requested entry.
162 with open(ns3_lock_filename)
as f:
163 exec(f.read(), globals(), values)
164 return values.get(entry,
None)
169 Check if tests are enabled
in the .lock-ns3
177 Check if tests are enabled
in the .lock-ns3
178 @return list of enabled modules (prefixed
with 'ns3-').
185 ns-3 tests related to checking if source files were left behind,
not being used by CMake
189 directory_and_files = {}
193 Scan all C++ source files and add them to a list based on their path
196 for root, dirs, files
in os.walk(ns3_path):
197 if "gitlab-ci-local" in root:
200 if name.endswith(
".cc"):
201 path = os.path.join(root, name)
202 directory = os.path.dirname(path)
209 Test if all example source files are being used
in their respective CMakeLists.txt
212 unused_sources = set()
215 if os.sep +
"examples" not in example_directory:
219 with open(os.path.join(example_directory,
"CMakeLists.txt"),
"r")
as f:
220 cmake_contents = f.read()
225 if os.path.basename(file).replace(
".cc",
"")
not in cmake_contents:
226 unused_sources.add(file)
228 self.assertListEqual([],
list(unused_sources))
232 Test if all module source files are being used
in their respective CMakeLists.txt
235 unused_sources = set()
238 is_not_module =
not (
"src" in directory
or "contrib" in directory)
239 is_example = os.sep +
"examples" in directory
240 is_bindings = os.sep +
"bindings" in directory
242 if is_not_module
or is_bindings
or is_example:
247 cmake_path = os.path.join(directory,
"CMakeLists.txt")
248 while not os.path.exists(cmake_path):
249 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
250 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
253 with open(cmake_path,
"r")
as f:
254 cmake_contents = f.read()
258 if os.path.basename(file)
not in cmake_contents:
259 unused_sources.add(file)
262 exceptions = [
"win32-system-wall-clock-ms.cc",
264 for exception
in exceptions:
265 for unused_source
in unused_sources:
266 if os.path.basename(unused_source) == exception:
267 unused_sources.remove(unused_source)
270 self.assertListEqual([],
list(unused_sources))
274 Test if all utils source files are being used
in their respective CMakeLists.txt
277 unused_sources = set()
280 is_module =
"src" in directory
or "contrib" in directory
281 if os.sep +
"utils" not in directory
or is_module:
286 cmake_path = os.path.join(directory,
"CMakeLists.txt")
287 while not os.path.exists(cmake_path):
288 parent_directory = os.path.dirname(os.path.dirname(cmake_path))
289 cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
292 with open(cmake_path,
"r")
as f:
293 cmake_contents = f.read()
297 if os.path.basename(file)
not in cmake_contents:
298 unused_sources.add(file)
300 self.assertListEqual([],
list(unused_sources))
305 ns-3 tests related to dependencies
310 Checks if headers
from different modules (src/A, contrib/B) that are included by
311 the current module (src/C) source files correspond to the list of linked modules
313 LIBRARIES_TO_LINK A (missing B)
317 headers_to_modules = {}
318 module_paths = glob.glob(ns3_path + "/src/*/") + glob.glob(ns3_path +
"/contrib/*/")
320 for path
in module_paths:
322 cmake_path = os.path.join(path,
"CMakeLists.txt")
323 with open(cmake_path,
"r")
as f:
324 cmake_contents = f.readlines()
326 module_name = os.path.relpath(path, ns3_path)
327 module_name_nodir = module_name.replace(
"src/",
"").replace(
"contrib/",
"")
328 modules[module_name_nodir] = {
"sources": set(),
331 "included_headers": set(),
332 "included_libraries": set(),
336 for line
in cmake_contents:
337 base_name = os.path.basename(line[:-1])
338 if not os.path.exists(os.path.join(path, line.strip())):
343 modules[module_name_nodir][
"headers"].add(base_name)
344 modules[module_name_nodir][
"sources"].add(base_name)
347 headers_to_modules[base_name] = module_name_nodir
351 modules[module_name_nodir][
"sources"].add(base_name)
353 if ".cc" in line
or ".h" in line:
355 source_file = os.path.join(ns3_path, module_name, line.strip())
356 with open(source_file,
"r", encoding=
"utf-8")
as f:
357 source_contents = f.read()
358 modules[module_name_nodir][
"included_headers"].update(map(
lambda x: x.replace(
"ns3/",
""),
359 re.findall(
"#include.*[\"|<](.*)[\"|>]",
366 modules[module_name_nodir][
"libraries"].update(re.findall(
"\\${lib(.*)}",
"".join(cmake_contents)))
369 all_project_headers = set(headers_to_modules.keys())
372 print(file=sys.stderr)
373 for module
in sorted(modules):
374 external_headers = modules[module][
"included_headers"].difference(all_project_headers)
375 project_headers_included = modules[module][
"included_headers"].difference(external_headers)
376 modules[module][
"included_libraries"] = set(
377 [headers_to_modules[x]
for x
in project_headers_included]).difference(
380 diff = modules[module][
"included_libraries"].difference(modules[module][
"libraries"])
382 print(
"Module %s includes modules that are not linked: %s" % (module,
", ".join(
list(diff))),
389 self.assertTrue(
True)
394 ns-3 tests to check if the source code, whitespaces
and CMake formatting
395 are according to the coding style
405 Import GitRepo and load the original diff state of the repository before the tests
408 if not NS3StyleTestCase.starting_diff:
410 if shutil.which(
"git")
is None:
411 self.skipTest(
"Git is not available")
417 self.skipTest(
"GitPython is not available")
420 repo = Repo(ns3_path)
421 except git.exc.InvalidGitRepositoryError:
422 self.skipTest(
"ns-3 directory does not contain a .git directory")
424 hcommit = repo.head.commit
425 NS3StyleTestCase.starting_diff = hcommit.diff(
None)
426 NS3StyleTestCase.repo = repo
428 if NS3StyleTestCase.starting_diff
is None:
429 self.skipTest(
"Unmet dependencies")
433 Check if there
is any difference between tracked file after
434 applying cmake-format
438 for required_program
in [
"cmake",
"cmake-format"]:
439 if shutil.which(required_program)
is None:
440 self.skipTest(
"%s was not found" % required_program)
443 return_code, stdout, stderr =
run_ns3(
"configure")
444 self.assertEqual(return_code, 0)
447 return_code, stdout, stderr =
run_ns3(
"build cmake-format")
448 self.assertEqual(return_code, 0)
451 return_code, stdout, stderr =
run_ns3(
"clean")
452 self.assertEqual(return_code, 0)
455 new_diff = NS3StyleTestCase.repo.head.commit.diff(
None)
456 self.assertEqual(NS3StyleTestCase.starting_diff, new_diff)
461 ns3 tests related to generic options
466 Clean configuration/build artifacts before common commands
475 Test not passing any arguments to
478 return_code, stdout, stderr = run_ns3("")
479 self.assertEqual(return_code, 1)
480 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
484 Test only passing --quiet argument to ns3
487 return_code, stdout, stderr = run_ns3("--quiet")
488 self.assertEqual(return_code, 1)
489 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
493 Test only passing 'show config' argument to ns3
496 return_code, stdout, stderr = run_ns3("show config")
497 self.assertEqual(return_code, 1)
498 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
502 Test only passing 'show profile' argument to ns3
505 return_code, stdout, stderr = run_ns3("show profile")
506 self.assertEqual(return_code, 1)
507 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
511 Test only passing 'show version' argument to ns3
514 return_code, stdout, stderr = run_ns3("show version")
515 self.assertEqual(return_code, 1)
516 self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
521 ns3 tests related to build profiles
526 Clean configuration/build artifacts before testing configuration settings
538 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d debug --enable-verbose")
539 self.assertEqual(return_code, 0)
540 self.assertIn(
"Build profile : debug", stdout)
541 self.assertIn(
"Build files have been written to", stdout)
544 return_code, stdout, stderr =
run_ns3(
"build core")
545 self.assertEqual(return_code, 0)
546 self.assertIn(
"Built target libcore", stdout)
549 self.assertGreater(len(libraries), 0)
550 self.assertIn(
"core-debug", libraries[0])
554 Test the release build
557 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d release")
558 self.assertEqual(return_code, 0)
559 self.assertIn(
"Build profile : release", stdout)
560 self.assertIn(
"Build files have been written to", stdout)
564 Test the optimized build
567 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d optimized --enable-verbose")
568 self.assertEqual(return_code, 0)
569 self.assertIn(
"Build profile : optimized", stdout)
570 self.assertIn(
"Build files have been written to", stdout)
573 return_code, stdout, stderr =
run_ns3(
"build core")
574 self.assertEqual(return_code, 0)
575 self.assertIn(
"Built target libcore", stdout)
578 self.assertGreater(len(libraries), 0)
579 self.assertIn(
"core-optimized", libraries[0])
583 Test a build type with a typo
586 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d Optimized")
587 self.assertEqual(return_code, 2)
588 self.assertIn(
"invalid choice: 'Optimized'", stderr)
592 Test a build type with another typo
595 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" -d OPTIMIZED")
596 self.assertEqual(return_code, 2)
597 self.assertIn(
"invalid choice: 'OPTIMIZED'", stderr)
602 Generic test case with basic function inherited by more complex tests.
610 Check if configuration
for release mode worked normally
611 @param return_code:
return code
from CMake
612 @param stdout: output
from CMake.
615 self.assertEqual(return_code, 0)
616 self.assertIn("Build profile : release", stdout)
617 self.assertIn(
"Build files have been written to", stdout)
621 Clean configuration/build artifacts before testing configuration and build settings
622 After configuring the build
as release,
623 check
if configuration worked
and check expected output files.
628 if os.path.exists(ns3rc_script):
629 os.remove(ns3rc_script)
632 if not NS3BaseTestCase.cleaned_once:
633 NS3BaseTestCase.cleaned_once =
True
635 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" -d release --enable-verbose")
639 self.assertTrue(os.path.exists(ns3_lock_filename))
644 self.assertTrue(os.path.exists(ns3_lock_filename))
651 Test ns3 configuration options
659 Reuse cleaning/release configuration from NS3BaseTestCase
if flag
is cleaned
662 if not NS3ConfigureTestCase.cleaned_once:
663 NS3ConfigureTestCase.cleaned_once =
True
664 NS3BaseTestCase.cleaned_once =
False
669 Test enabling and disabling examples
672 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" --enable-examples")
681 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-examples")
691 Test enabling and disabling tests
695 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-tests")
699 return_code, stdout, stderr =
run_ns3(
"build core-test")
702 self.assertEqual(return_code, 0)
703 self.assertIn(
"Built target libcore-test", stdout)
706 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-tests")
710 return_code, stdout, stderr =
run_ns3(
"build core-test")
713 self.assertEqual(return_code, 1)
714 self.assertIn(
"Target to build does not exist: core-test", stdout)
718 Test enabling specific modules
722 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='network;wifi'")
728 self.assertIn(
"ns3-network", enabled_modules)
729 self.assertIn(
"ns3-wifi", enabled_modules)
732 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='core'")
737 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
745 Test disabling specific modules
749 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules='lte;wimax'")
754 self.assertLess(len(enabled_modules), len(self.
ns3_modules))
755 self.assertNotIn(
"ns3-lte", enabled_modules)
756 self.assertNotIn(
"ns3-wimax", enabled_modules)
759 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
767 Test enabling comma-separated (waf-style) examples
771 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules='network,wifi'")
777 self.assertIn(
"ns3-network", enabled_modules)
778 self.assertIn(
"ns3-wifi", enabled_modules)
781 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
789 Test disabling comma-separated (waf-style) examples
793 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules='lte,mpi'")
798 self.assertLess(len(enabled_modules), len(self.
ns3_modules))
799 self.assertNotIn(
"ns3-lte", enabled_modules)
800 self.assertNotIn(
"ns3-mpi", enabled_modules)
803 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
811 Test loading settings from the ns3rc config file
817 ns3rc_python_template =
"# ! /usr/bin/env python\
819 # A list of the modules that will be enabled when ns-3 is run.\
820 # Modules that depend on the listed modules will be enabled also.\
822 # All modules can be enabled by choosing 'all_modules'.\
823 modules_enabled = [{modules}]\
825 # Set this equal to true if you want examples to be run.\
826 examples_enabled = {examples}\
828 # Set this equal to true if you want tests to be run.\
829 tests_enabled = {tests}\
833 ns3rc_cmake_template =
"set(ns3rc_tests_enabled {tests})\
834 \nset(ns3rc_examples_enabled {examples})\
835 \nset(ns3rc_enabled_modules {modules})\
840 "python": ns3rc_python_template,
841 "cmake": ns3rc_cmake_template
844 def __init__(self, type_ns3rc):
847 def format(self, **args):
849 if self.
type ==
"cmake":
850 args[
"modules"] = args[
"modules"].replace(
"'",
"").replace(
"\"",
"").replace(
",",
" ")
851 args[
"examples"] =
"ON" if args[
"examples"] ==
"True" else "OFF"
852 args[
"tests"] =
"ON" if args[
"tests"] ==
"True" else "OFF"
854 formatted_string = ns3rc_str.ns3rc_templates[self.
type].format(**args)
857 return formatted_string
861 return ns3rc_str.ns3rc_templates.keys()
863 for ns3rc_type
in ns3rc_str.types():
865 ns3rc_template = ns3rc_str(ns3rc_type)
868 with open(ns3rc_script,
"w")
as f:
869 f.write(ns3rc_template.format(modules=
"'lte'", examples=
"False", tests=
"True"))
872 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
878 self.assertIn(
"ns3-lte", enabled_modules)
883 with open(ns3rc_script,
"w")
as f:
884 f.write(ns3rc_template.format(modules=
"'wifi'", examples=
"True", tests=
"False"))
887 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
893 self.assertIn(
"ns3-wifi", enabled_modules)
898 with open(ns3rc_script,
"w")
as f:
899 f.write(ns3rc_template.format(modules=
"'core','network'", examples=
"True", tests=
"False"))
902 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
908 self.assertIn(
"ns3-core", enabled_modules)
909 self.assertIn(
"ns3-network", enabled_modules)
915 with open(ns3rc_script,
"w")
as f:
916 if ns3rc_type ==
"python":
917 f.write(ns3rc_template.format(modules=
"""'core', #comment
921 'network',
'internet',
'wimax'""", examples="True", tests="True"))
923 f.write(ns3rc_template.format(modules=
"'core', 'lte', 'network', 'internet', 'wimax'",
928 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
934 self.assertIn(
"ns3-core", enabled_modules)
935 self.assertIn(
"ns3-internet", enabled_modules)
936 self.assertIn(
"ns3-lte", enabled_modules)
937 self.assertIn(
"ns3-wimax", enabled_modules)
942 os.remove(ns3rc_script)
945 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
955 Test dry-run (printing commands to be executed instead of running them)
961 for positional_command
in [
"configure",
"build",
"clean"]:
962 return_code, stdout, stderr =
run_ns3(
"--dry-run %s" % positional_command)
963 return_code1, stdout1, stderr1 =
run_ns3(
"%s --dry-run" % positional_command)
965 self.assertEqual(return_code, return_code1)
966 self.assertEqual(stdout, stdout1)
967 self.assertEqual(stderr, stderr1)
972 run_ns3(
"configure -G \"{generator}\" -d release --enable-verbose")
973 run_ns3(
"build scratch-simulator")
976 return_code0, stdout0, stderr0 =
run_ns3(
"--dry-run run scratch-simulator")
977 return_code1, stdout1, stderr1 =
run_ns3(
"run scratch-simulator")
978 return_code2, stdout2, stderr2 =
run_ns3(
"--dry-run run scratch-simulator --no-build")
979 return_code3, stdout3, stderr3 =
run_ns3(
"run scratch-simulator --no-build")
982 self.assertEqual(sum([return_code0, return_code1, return_code2, return_code3]), 0)
983 self.assertEqual([stderr0, stderr1, stderr2, stderr3], [
""] * 4)
987 if "scratch-simulator" in program
and "subdir" not in program:
988 scratch_path = program
994 self.assertIn(scratch_path, stdout0)
998 self.assertIn(
"Built target", stdout1)
999 self.assertNotIn(scratch_path, stdout1)
1002 self.assertIn(
"The following commands would be executed:", stdout2)
1003 self.assertIn(scratch_path, stdout2)
1006 self.assertNotIn(
"Finished executing the following commands:", stdout3)
1007 self.assertNotIn(scratch_path, stdout3)
1011 Test if ns3
is propagating back the
return code
from the executables called
with the run command
1015 return_code, _, _ =
run_ns3(
"clean")
1016 self.assertEqual(return_code, 0)
1018 return_code, _, _ =
run_ns3(
"configure -G \"{generator}\" --enable-examples --enable-tests")
1019 self.assertEqual(return_code, 0)
1022 return_code, stdout, stderr =
run_ns3(
"build command-line-example test-runner")
1023 self.assertEqual(return_code, 0)
1026 return_code, stdout, stderr =
run_ns3(
"run \"test-runner --test-name=command-line\" --no-build")
1027 self.assertEqual(return_code, 0)
1030 return_code, stdout, stderr =
run_ns3(
"run \"test-runner --test-name=command-line\" --no-build",
1031 env={
"NS_COMMANDLINE_INTROSPECTION":
".."}
1033 self.assertNotEqual(return_code, 0)
1036 sigsegv_example = os.path.join(ns3_path,
"scratch",
"sigsegv.cc")
1037 with open(sigsegv_example,
"w")
as f:
1039 int main (int argc, char *argv[])
1041 char *s = "hello world"; *s =
'H';
1045 return_code, stdout, stderr = run_ns3("run sigsegv")
1047 self.assertEqual(return_code, 4294967295)
1048 self.assertIn(
"sigsegv-default.exe' returned non-zero exit status", stdout)
1050 self.assertEqual(return_code, 245)
1051 self.assertIn(
"sigsegv-default' died with <Signals.SIGSEGV: 11>", stdout)
1054 abort_example = os.path.join(ns3_path,
"scratch",
"abort.cc")
1055 with open(abort_example,
"w")
as f:
1059 using namespace ns3;
1060 int main (int argc, char *argv[])
1066 return_code, stdout, stderr = run_ns3("run abort")
1068 self.assertEqual(return_code, 3)
1069 self.assertIn(
"abort-default.exe' returned non-zero exit status", stdout)
1071 self.assertEqual(return_code, 250)
1072 self.assertIn(
"abort-default' died with <Signals.SIGABRT: 6>", stdout)
1074 os.remove(sigsegv_example)
1075 os.remove(abort_example)
1079 Test passing 'show config' argument to ns3 to get the configuration table
1082 return_code, stdout, stderr = run_ns3("show config")
1083 self.assertEqual(return_code, 0)
1084 self.assertIn(
"Summary of optional ns-3 features", stdout)
1088 Test passing 'show profile' argument to ns3 to get the build profile
1091 return_code, stdout, stderr = run_ns3("show profile")
1092 self.assertEqual(return_code, 0)
1093 self.assertIn(
"Build profile: default", stdout)
1097 Test passing 'show version' argument to ns3 to get the build version
1100 if shutil.which(
"git")
is None:
1101 self.skipTest(
"git is not available")
1103 return_code, _, _ =
run_ns3(
"configure -G \"{generator}\" --enable-build-version")
1104 self.assertEqual(return_code, 0)
1106 return_code, stdout, stderr =
run_ns3(
"show version")
1107 self.assertEqual(return_code, 0)
1108 self.assertIn(
"ns-3 version:", stdout)
1112 Test if CMake target names
for scratches
and ns3 shortcuts
1113 are working correctly
1117 test_files = ["scratch/main.cc",
1119 "scratch/subdir1/main.cc",
1120 "scratch/subdir2/main.cc"]
1121 backup_files = [
"scratch/.main.cc"]
1124 for path
in test_files + backup_files:
1125 filepath = os.path.join(ns3_path, path)
1126 os.makedirs(os.path.dirname(filepath), exist_ok=
True)
1127 with open(filepath,
"w")
as f:
1129 f.write(
"int main (int argc, char *argv[]){}")
1137 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1138 self.assertEqual(return_code, 0)
1141 for path
in test_files + backup_files:
1142 path = path.replace(
".cc",
"")
1143 return_code1, stdout1, stderr1 =
run_program(
"cmake",
"--build . --target %s -j %d"
1144 % (path.replace(
"/",
"_"), num_threads),
1145 cwd=os.path.join(ns3_path,
"cmake-cache"))
1146 return_code2, stdout2, stderr2 =
run_ns3(
"build %s" % path)
1147 if "main" in path
and ".main" not in path:
1148 self.assertEqual(return_code1, 0)
1149 self.assertEqual(return_code2, 0)
1151 self.assertEqual(return_code1, 2)
1152 self.assertEqual(return_code2, 1)
1155 for path
in test_files:
1156 path = path.replace(
".cc",
"")
1157 return_code, stdout, stderr =
run_ns3(
"run %s --no-build" % path)
1159 self.assertEqual(return_code, 0)
1161 self.assertEqual(return_code, 1)
1164 for path
in test_files + backup_files:
1165 source_absolute_path = os.path.join(ns3_path, path)
1166 os.remove(source_absolute_path)
1167 if "empty" in path
or ".main" in path:
1169 filename = os.path.basename(path).replace(
".cc",
"")
1170 executable_absolute_path = os.path.dirname(os.path.join(ns3_path,
"build", path))
1171 executable_name =
list(filter(
lambda x: filename
in x,
1172 os.listdir(executable_absolute_path)
1176 os.remove(os.path.join(executable_absolute_path, executable_name))
1177 if path
not in [
"scratch/main.cc",
"scratch/empty.cc"]:
1178 os.rmdir(os.path.dirname(source_absolute_path))
1180 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1181 self.assertEqual(return_code, 0)
1185 Test if ns3
is inserting additional arguments by MPICH
and OpenMPI to run on the CI
1189 if shutil.which(
"mpiexec")
is None or win32:
1190 self.skipTest(
"Mpi is not available")
1192 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
1193 self.assertEqual(return_code, 0)
1197 return_code, stdout, stderr =
run_ns3(
"build sample-simulator")
1198 self.assertEqual(return_code, 0)
1201 sample_simulator_path =
list(filter(
lambda x:
"sample-simulator" in x, executables))[0]
1203 mpi_command =
"--dry-run run sample-simulator --command-template=\"mpiexec -np 2 %s\""
1204 non_mpi_command =
"--dry-run run sample-simulator --command-template=\"echo %s\""
1207 return_code, stdout, stderr =
run_ns3(mpi_command)
1208 self.assertEqual(return_code, 0)
1209 self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
1212 return_code, stdout, stderr =
run_ns3(mpi_command)
1213 self.assertEqual(return_code, 0)
1214 if os.getenv(
"USER",
"") ==
"root":
1215 if shutil.which(
"ompi_info"):
1216 self.assertIn(
"mpiexec --allow-run-as-root --oversubscribe -np 2 %s" % sample_simulator_path, stdout)
1218 self.assertIn(
"mpiexec --allow-run-as-root -np 2 %s" % sample_simulator_path, stdout)
1220 self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
1223 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1224 self.assertEqual(return_code, 0)
1225 self.assertIn(
"echo %s" % sample_simulator_path, stdout)
1228 return_code, stdout, stderr =
run_ns3(non_mpi_command)
1229 self.assertEqual(return_code, 0)
1230 self.assertIn(
"echo %s" % sample_simulator_path, stdout)
1232 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --disable-examples")
1233 self.assertEqual(return_code, 0)
1237 Test if CMake
and ns3 fail
in the expected ways when:
1238 - examples
from modules
or general examples fail
if they depend on a
1239 library
with a name shorter than 4 characters
or are disabled when
1240 a library
is nonexistent
1241 - a module library passes the configuration but fails to build due to
1245 os.makedirs("contrib/borked", exist_ok=
True)
1246 os.makedirs(
"contrib/borked/examples", exist_ok=
True)
1249 with open(
"contrib/borked/examples/CMakeLists.txt",
"w")
as f:
1251 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1252 with open(
"contrib/borked/CMakeLists.txt",
"w")
as f:
1256 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1257 LIBRARIES_TO_LINK ${libcore} %s
1259 """ % invalid_or_nonexistent_library)
1261 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\" --enable-examples")
1262 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1263 self.assertEqual(return_code, 0)
1264 elif invalid_or_nonexistent_library
in [
"lib"]:
1265 self.assertEqual(return_code, 1)
1266 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1270 return_code, stdout, stderr =
run_ns3(
"build borked")
1271 if invalid_or_nonexistent_library
in [
""]:
1272 self.assertEqual(return_code, 0)
1273 elif invalid_or_nonexistent_library
in [
"lib"]:
1274 self.assertEqual(return_code, 2)
1275 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1276 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1277 self.assertEqual(return_code, 2)
1280 if "lld" in stdout + stderr:
1281 self.assertIn(
"unable to find library -l%s" % invalid_or_nonexistent_library, stderr)
1283 self.assertIn(
"cannot find -l%s" % invalid_or_nonexistent_library, stderr)
1291 with open(
"contrib/borked/CMakeLists.txt",
"w")
as f:
1295 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1296 LIBRARIES_TO_LINK ${libcore}
1299 for invalid_or_nonexistent_library
in [
"",
"gsd",
"lib",
"libfi",
"calibre"]:
1300 with open(
"contrib/borked/examples/CMakeLists.txt",
"w")
as f:
1304 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty-main.cc
1305 LIBRARIES_TO_LINK ${libborked} %s
1307 """ % invalid_or_nonexistent_library)
1309 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\"")
1310 if invalid_or_nonexistent_library
in [
"",
"gsd",
"libfi",
"calibre"]:
1311 self.assertEqual(return_code, 0)
1312 elif invalid_or_nonexistent_library
in [
"lib"]:
1313 self.assertEqual(return_code, 1)
1314 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1318 return_code, stdout, stderr =
run_ns3(
"build borked-example")
1319 if invalid_or_nonexistent_library
in [
""]:
1320 self.assertEqual(return_code, 0)
1321 elif invalid_or_nonexistent_library
in [
"libf"]:
1322 self.assertEqual(return_code, 2)
1323 self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
1324 elif invalid_or_nonexistent_library
in [
"gsd",
"libfi",
"calibre"]:
1325 self.assertEqual(return_code, 1)
1326 self.assertIn(
"Target to build does not exist: borked-example", stdout)
1330 shutil.rmtree(
"contrib/borked", ignore_errors=
True)
1334 Test if CMake can properly handle modules containing
"lib",
1335 which
is used internally
as a prefix
for module libraries
1339 os.makedirs("contrib/calibre", exist_ok=
True)
1340 os.makedirs(
"contrib/calibre/examples", exist_ok=
True)
1343 with open(
"contrib/calibre/examples/CMakeLists.txt",
"w")
as f:
1345 with open(
"contrib/calibre/CMakeLists.txt",
"w")
as f:
1349 SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc
1350 LIBRARIES_TO_LINK ${libcore}
1354 return_code, stdout, stderr = run_ns3("configure -G \"{generator}\"")
1357 self.assertEqual(return_code, 0)
1360 self.assertIn(
"calibre", stdout)
1364 self.assertNotIn(
"care", stdout)
1365 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"pkgconfig",
"ns3-calibre.pc")))
1368 return_code, stdout, stderr =
run_ns3(
"build calibre")
1369 self.assertEqual(return_code, 0)
1372 shutil.rmtree(
"contrib/calibre", ignore_errors=
True)
1376 Test if CMake performance tracing works
and produces the
1377 cmake_performance_trace.log file
1380 return_code, stdout, stderr = run_ns3("configure --trace-performance")
1381 self.assertEqual(return_code, 0)
1383 self.assertIn(
"--profiling-format=google-trace --profiling-output=", stdout)
1385 self.assertIn(
"--profiling-format=google-trace --profiling-output=../cmake_performance_trace.log", stdout)
1386 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake_performance_trace.log")))
1389 NS3ConfigureTestCase.cleaned_once =
False
1393 Check if ENABLE_BUILD_VERSION
and version.cache are working
1399 from python_on_whales
import docker
1400 from python_on_whales.exceptions
import DockerException
1401 except ModuleNotFoundError:
1403 DockerException =
None
1404 self.skipTest(
"python-on-whales was not found")
1407 with open(os.path.expanduser(
"~/.bashrc"),
"r")
as f:
1408 docker_settings = re.findall(
"(DOCKER_.*=.*)", f.read())
1409 for setting
in docker_settings:
1410 key, value = setting.split(
"=")
1411 os.environ[key] = value
1412 del docker_settings, setting, key, value
1415 with docker.run(
"ubuntu:22.04",
1416 interactive=
True, detach=
True,
1418 volumes=[(ns3_path,
"/ns-3-dev")]
1421 def split_exec(docker_container, cmd):
1422 return docker_container._execute(cmd.split(), workdir=
"/ns-3-dev")
1424 container._execute = container.execute
1425 container.execute = partial(split_exec, container)
1428 container.execute(
"apt-get update")
1429 container.execute(
"apt-get install -y python3 ninja-build cmake g++")
1432 container.execute(
"./ns3 clean")
1435 version_cache_file = os.path.join(ns3_path,
"src/core/model/version.cache")
1438 if os.path.exists(version_cache_file):
1439 os.remove(version_cache_file)
1443 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1444 except DockerException:
1446 self.assertFalse(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1449 version_cache_contents = (
"CLOSEST_TAG = '\"ns-3.0.0\"'\n"
1450 "VERSION_COMMIT_HASH = '\"0000000000\"'\n"
1451 "VERSION_DIRTY_FLAG = '0'\n"
1452 "VERSION_MAJOR = '3'\n"
1453 "VERSION_MINOR = '0'\n"
1454 "VERSION_PATCH = '0'\n"
1455 "VERSION_RELEASE_CANDIDATE = '\"\"'\n"
1456 "VERSION_TAG = '\"ns-3.0.0\"'\n"
1457 "VERSION_TAG_DISTANCE = '0'\n"
1458 "VERSION_BUILD_PROFILE = 'debug'\n"
1460 with open(version_cache_file,
"w")
as version:
1461 version.write(version_cache_contents)
1464 container.execute(
"./ns3 clean")
1465 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1466 container.execute(
"./ns3 build core")
1467 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1470 with open(version_cache_file,
"r")
as version:
1471 self.assertEqual(version.read(), version_cache_contents)
1476 os.rename(os.path.join(ns3_path,
".git"), os.path.join(ns3_path,
"temp_git"))
1478 container.execute(
"apt-get install -y git")
1479 container.execute(
"./ns3 clean")
1480 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1481 container.execute(
"./ns3 build core")
1482 except DockerException:
1484 os.rename(os.path.join(ns3_path,
"temp_git"), os.path.join(ns3_path,
".git"))
1485 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1488 container.execute(
"./ns3 clean")
1489 container.execute(
"./ns3 configure -G Ninja --enable-build-version")
1490 container.execute(
"./ns3 build core")
1491 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1492 with open(version_cache_file,
"r")
as version:
1493 self.assertNotEqual(version.read(), version_cache_contents)
1496 if os.path.exists(version_cache_file):
1497 os.remove(version_cache_file)
1500 NS3ConfigureTestCase.cleaned_once =
False
1504 Test filtering in examples
and tests
from specific modules
1508 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples --enable-tests")
1514 return_code, stdout, stderr =
run_ns3(
1515 "configure -G \"{generator}\" --filter-module-examples-and-tests='core;network'")
1522 self.assertEqual(len(modules_after_filtering), len(modules_before_filtering))
1524 self.assertLess(len(programs_after_filtering), len(programs_before_filtering))
1527 return_code, stdout, stderr =
run_ns3(
1528 "configure -G \"{generator}\" --filter-module-examples-and-tests='core'")
1537 return_code, stdout, stderr =
run_ns3(
1538 "configure -G \"{generator}\" --disable-examples --disable-tests --filter-module-examples-and-tests=''")
1547 Check if fast linkers LLD
and Mold are correctly found
and configured
1552 from python_on_whales
import docker
1553 from python_on_whales.exceptions
import DockerException
1554 except ModuleNotFoundError:
1556 DockerException =
None
1557 self.skipTest(
"python-on-whales was not found")
1562 with open(os.path.expanduser(
"~/.bashrc"),
"r")
as f:
1563 docker_settings = re.findall(
"(DOCKER_.*=.*)", f.read())
1564 for setting
in docker_settings:
1565 key, value = setting.split(
"=")
1566 os.environ[key] = value
1567 del docker_settings, setting, key, value
1570 with docker.run(
"gcc:12.1",
1571 interactive=
True, detach=
True,
1573 volumes=[(ns3_path,
"/ns-3-dev")],
1576 def split_exec(docker_container, cmd):
1577 return docker_container._execute(cmd.split(), workdir=
"/ns-3-dev")
1579 container._execute = container.execute
1580 container.execute = partial(split_exec, container)
1583 container.execute(
"apt-get update")
1584 container.execute(
"apt-get install -y python3 ninja-build cmake g++ lld")
1587 container.execute(
"./ns3 configure -G Ninja")
1590 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1591 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1592 self.assertIn(
"-fuse-ld=lld", f.read())
1596 container.execute(
"./ns3 build core")
1597 except DockerException:
1598 self.assertTrue(
False,
"Build with lld failed")
1601 if not os.path.exists(
"./mold-1.4.2-x86_64-linux.tar.gz"):
1603 "wget https://github.com/rui314/mold/releases/download/v1.4.2/mold-1.4.2-x86_64-linux.tar.gz")
1604 container.execute(
"tar xzfC mold-1.4.2-x86_64-linux.tar.gz /usr/local --strip-components=1")
1608 container.execute(
"./ns3 configure -G Ninja")
1611 self.assertTrue(os.path.exists(os.path.join(ns3_path,
"cmake-cache",
"build.ninja")))
1612 with open(os.path.join(ns3_path,
"cmake-cache",
"build.ninja"),
"r")
as f:
1613 self.assertIn(
"-fuse-ld=mold", f.read())
1617 container.execute(
"./ns3 build core")
1618 except DockerException:
1619 self.assertTrue(
False,
"Build with mold failed")
1622 os.remove(
"./mold-1.4.2-x86_64-linux.tar.gz")
1630 Tests ns3 regarding building the project
1634 cleaned_once = False
1638 Reuse cleaning/release configuration from NS3BaseTestCase
if flag
is cleaned
1641 if not NS3BuildBaseTestCase.cleaned_once:
1642 NS3BuildBaseTestCase.cleaned_once =
True
1643 NS3BaseTestCase.cleaned_once =
False
1650 Try building the core library
1653 return_code, stdout, stderr = run_ns3("build core")
1654 self.assertEqual(return_code, 0)
1655 self.assertIn(
"Built target libcore", stdout)
1659 Try building core-test library without tests enabled
1663 return_code, stdout, stderr =
run_ns3(
"build core-test")
1664 self.assertEqual(return_code, 1)
1665 self.assertIn(
"Target to build does not exist: core-test", stdout)
1669 Try building the project:
1672 return_code, stdout, stderr = run_ns3("build")
1673 self.assertEqual(return_code, 0)
1674 self.assertIn(
"Built target", stdout)
1676 self.assertTrue(os.path.exists(program), program)
1677 self.assertIn(cmake_build_project_command, stdout)
1681 Try hiding task lines
1684 return_code, stdout, stderr = run_ns3("--quiet build")
1685 self.assertEqual(return_code, 0)
1686 self.assertIn(cmake_build_project_command, stdout)
1690 Try removing an essential file to break the build
1694 attribute_cc_path = os.sep.join([ns3_path,
"src",
"core",
"model",
"attribute.cc"])
1695 attribute_cc_bak_path = attribute_cc_path +
".bak"
1696 shutil.move(attribute_cc_path, attribute_cc_bak_path)
1699 return_code, stdout, stderr =
run_ns3(
"build")
1700 self.assertNotEqual(return_code, 0)
1703 shutil.move(attribute_cc_bak_path, attribute_cc_path)
1706 return_code, stdout, stderr =
run_ns3(
"build")
1707 self.assertEqual(return_code, 0)
1710 NS3BuildBaseTestCase.cleaned_once =
False
1714 Test if changing the version file affects the library names
1720 version_file = os.sep.join([ns3_path,
"VERSION"])
1721 with open(version_file,
"w")
as f:
1725 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\"")
1729 return_code, stdout, stderr =
run_ns3(
"build")
1730 self.assertEqual(return_code, 0)
1731 self.assertIn(
"Built target", stdout)
1737 for program
in new_programs:
1738 self.assertTrue(os.path.exists(program))
1746 self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
1747 for library
in new_libraries:
1748 self.assertNotIn(
"libns3-dev", library)
1749 self.assertIn(
"libns3-00", library)
1750 self.assertTrue(os.path.exists(library))
1753 with open(version_file,
"w")
as f:
1757 NS3BuildBaseTestCase.cleaned_once =
False
1761 Try setting a different output directory and if everything
is
1762 in the right place
and still working correctly
1767 return_code, stdout, stderr =
run_ns3(
"build")
1768 self.assertEqual(return_code, 0)
1783 absolute_path = os.sep.join([ns3_path,
"build",
"release"])
1784 relative_path = os.sep.join([
"build",
"release"])
1785 for different_out_dir
in [absolute_path, relative_path]:
1786 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=%s" % different_out_dir)
1788 self.assertIn(
"Build directory : %s" % absolute_path.replace(os.sep,
'/'), stdout)
1796 for program
in new_programs:
1797 self.assertTrue(os.path.exists(program))
1802 self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
1803 for library
in new_libraries:
1804 self.assertTrue(os.path.exists(library))
1807 shutil.rmtree(absolute_path)
1810 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --out=''")
1812 self.assertIn(
"Build directory : %s" % usual_outdir.replace(os.sep,
'/'), stdout)
1820 for program
in new_programs:
1821 self.assertTrue(os.path.exists(program))
1826 for library
in libraries:
1827 self.assertTrue(os.path.exists(library))
1831 Tries setting a ns3 version, then installing it.
1832 After that, tries searching for ns-3
with CMake
's find_package(ns3).
1833 Finally, tries using core library in a 3rd-party project
1838 for library
in libraries:
1842 version_file = os.sep.join([ns3_path,
"VERSION"])
1843 with open(version_file,
"w")
as f:
1847 install_prefix = os.sep.join([ns3_path,
"build",
"install"])
1848 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --prefix=%s" % install_prefix)
1860 lib64 = os.path.exists(os.sep.join([install_prefix,
"lib64"]))
1861 installed_libdir = os.sep.join([install_prefix, (
"lib64" if lib64
else "lib")])
1865 installed_libraries_list =
";".join(installed_libraries)
1866 for library
in libraries:
1867 library_name = os.path.basename(library)
1868 self.assertIn(library_name, installed_libraries_list)
1872 missing_headers =
list(set([os.path.basename(x)
for x
in headers])
1873 - (set([os.path.basename(x)
for x
in installed_headers]))
1875 self.assertEqual(len(missing_headers), 0)
1878 test_main_file = os.sep.join([install_prefix,
"main.cpp"])
1879 with open(test_main_file,
"w")
as f:
1882 using namespace ns3;
1885 Simulator::Stop (Seconds (1.0));
1887 Simulator::Destroy ();
1895 for version
in [
"",
"3.01",
"3.00"]:
1896 ns3_import_methods = []
1899 cmake_find_package_import =
"""
1900 list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3)
1901 find_package(ns3 {version} COMPONENTS libcore)
1902 target_link_libraries(test PRIVATE ns3::libcore)
1903 """.format(lib=("lib64" if lib64 else "lib"), version=version)
1904 ns3_import_methods.append(cmake_find_package_import)
1907 pkgconfig_import =
"""
1908 list(APPEND CMAKE_PREFIX_PATH ./)
1909 include(FindPkgConfig)
1910 pkg_check_modules(ns3 REQUIRED IMPORTED_TARGET ns3-core{version})
1911 target_link_libraries(test PUBLIC PkgConfig::ns3)
1912 """.format(lib=("lib64" if lib64 else "lib"),
1913 version="=" + version
if version
else ""
1915 if shutil.which(
"pkg-config"):
1916 ns3_import_methods.append(pkgconfig_import)
1919 for import_method
in ns3_import_methods:
1920 test_cmake_project =
"""
1921 cmake_minimum_required(VERSION 3.10..3.10)
1923 set(CMAKE_CXX_STANDARD 17)
1924 set(CMAKE_CXX_STANDARD_REQUIRED ON)
1925 add_executable(test main.cpp)
1928 test_cmake_project_file = os.sep.join([install_prefix, "CMakeLists.txt"])
1929 with open(test_cmake_project_file,
"w")
as f:
1930 f.write(test_cmake_project)
1933 cmake = shutil.which(
"cmake")
1936 "-DCMAKE_BUILD_TYPE=debug -G\"{generator}\" .".format(generator=platform_makefiles),
1940 if version ==
"3.00":
1941 self.assertEqual(return_code, 1)
1942 if import_method == cmake_find_package_import:
1943 self.assertIn(
'Could not find a configuration file for package "ns3" that is compatible',
1944 stderr.replace(
"\n",
""))
1945 elif import_method == pkgconfig_import:
1946 self.assertIn(
'A required package was not found',
1947 stderr.replace(
"\n",
""))
1949 raise Exception(
"Unknown import type")
1951 self.assertEqual(return_code, 0)
1952 self.assertIn(
"Build files", stdout)
1955 return_code, stdout, stderr =
run_program(
"cmake",
"--build .", cwd=install_prefix)
1957 if version ==
"3.00":
1958 self.assertEqual(return_code, 2)
1959 self.assertGreater(len(stderr), 0)
1961 self.assertEqual(return_code, 0)
1962 self.assertIn(
"Built target", stdout)
1966 test_program = os.path.join(install_prefix,
"test.exe")
1967 env_sep =
";" if ";" in os.environ[
"PATH"]
else ":"
1968 env = {
"PATH": env_sep.join([os.environ[
"PATH"], os.path.join(install_prefix,
"lib")])}
1970 test_program =
"./test"
1972 return_code, stdout, stderr =
run_program(test_program,
"", cwd=install_prefix, env=env)
1973 self.assertEqual(return_code, 0)
1976 return_code, stdout, stderr =
run_ns3(
"uninstall")
1977 self.assertIn(
"Built target uninstall", stdout)
1980 os.remove(version_file)
1981 with open(version_file,
"w")
as f:
1985 NS3BuildBaseTestCase.cleaned_once =
False
1989 Tries to build scratch-simulator and subdir/scratch-simulator-subdir
1993 targets = {
"scratch/scratch-simulator":
"scratch-simulator",
1994 "scratch/scratch-simulator.cc":
"scratch-simulator",
1995 "scratch-simulator":
"scratch-simulator",
1996 "scratch/subdir/scratch-subdir":
"subdir_scratch-subdir",
1997 "subdir/scratch-subdir":
"subdir_scratch-subdir",
1998 "scratch-subdir":
"subdir_scratch-subdir",
2000 for (target_to_run, target_cmake)
in targets.items():
2002 build_line =
"target scratch_%s" % target_cmake
2003 return_code, stdout, stderr =
run_ns3(
"build %s" % target_to_run)
2004 self.assertEqual(return_code, 0)
2005 self.assertIn(build_line, stdout)
2008 return_code, stdout, stderr =
run_ns3(
"run %s --verbose" % target_to_run)
2009 self.assertEqual(return_code, 0)
2010 self.assertIn(build_line, stdout)
2011 stdout = stdout.replace(
"scratch_%s" % target_cmake,
"")
2012 self.assertIn(target_to_run.split(
"/")[-1].replace(
".cc",
""), stdout)
2014 NS3BuildBaseTestCase.cleaned_once =
False
2018 Test if ns3 can alert correctly
in case a shortcut collision happens
2023 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
2024 self.assertEqual(return_code, 0)
2027 shutil.copy(
"./examples/tutorial/second.cc",
"./scratch/second.cc")
2030 return_code, stdout, stderr =
run_ns3(
"configure -G \"{generator}\" --enable-examples")
2031 self.assertEqual(return_code, 0)
2034 return_code, stdout, stderr =
run_ns3(
"build second")
2035 self.assertEqual(return_code, 1)
2037 'Build target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2038 stdout.replace(os.sep,
'/')
2042 return_code, stdout, stderr =
run_ns3(
"build scratch/second")
2043 self.assertEqual(return_code, 0)
2047 return_code, stdout, stderr =
run_ns3(
"build tutorial/second")
2048 self.assertEqual(return_code, 0)
2052 return_code, stdout, stderr =
run_ns3(
"run second")
2053 self.assertEqual(return_code, 1)
2055 'Run target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
2056 stdout.replace(os.sep,
'/')
2060 return_code, stdout, stderr =
run_ns3(
"run scratch/second")
2061 self.assertEqual(return_code, 0)
2064 return_code, stdout, stderr =
run_ns3(
"run tutorial/second")
2065 self.assertEqual(return_code, 0)
2068 os.remove(
"./scratch/second.cc")
2070 NS3BuildBaseTestCase.cleaned_once =
False
2074 Test if we can build a static ns-3 library
and link it to static programs
2079 return_code, stdout, stderr =
run_ns3(
2080 "configure -G \"{generator}\" --enable-examples --disable-gtk --enable-static")
2085 self.assertEqual(return_code, 1)
2086 self.assertIn(
"Static builds are unsupported on Windows", stderr)
2089 self.assertEqual(return_code, 0)
2092 return_code, stdout, stderr =
run_ns3(
'build sample-simulator')
2093 self.assertEqual(return_code, 0)
2094 self.assertIn(
"Built target", stdout)
2097 NS3BuildBaseTestCase.cleaned_once =
False
2101 Test if we can use python bindings
2106 except ModuleNotFoundError:
2107 self.skipTest(
"Cppyy was not found")
2110 return_code, stdout, stderr =
run_ns3(
2111 "configure -G \"{generator}\" --enable-python-bindings")
2114 self.assertEqual(return_code, 0)
2117 return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
2118 self.assertEqual(return_code, 0)
2121 return_code, stdout, stderr =
run_program(
"test.py",
"-p mixed-wired-wireless", python=
True)
2122 self.assertEqual(return_code, 0)
2125 return_code, stdout, stderr =
run_program(
"test.py",
"-p ./examples/wireless/mixed-wired-wireless", python=
True)
2126 self.assertEqual(return_code, 0)
2131 Tests ns3 usage in more realistic scenarios
2135 cleaned_once = False
2139 Reuse cleaning/release configuration from NS3BaseTestCase
if flag
is cleaned
2140 Here examples, tests
and documentation are also enabled.
2143 if not NS3ExpectedUseTestCase.cleaned_once:
2144 NS3ExpectedUseTestCase.cleaned_once =
True
2145 NS3BaseTestCase.cleaned_once =
False
2149 return_code, stdout, stderr =
run_ns3(
2150 "configure -d release -G \"{generator}\" --enable-examples --enable-tests")
2154 self.assertTrue(os.path.exists(ns3_lock_filename))
2160 self.assertTrue(os.path.exists(ns3_lock_filename))
2167 Try to build the project
2170 return_code, stdout, stderr = run_ns3("build")
2171 self.assertEqual(return_code, 0)
2172 self.assertIn(
"Built target", stdout)
2174 self.assertTrue(os.path.exists(program))
2177 self.assertIn(module.replace(
"ns3-",
""),
";".join(libraries))
2178 self.assertIn(cmake_build_project_command, stdout)
2182 Try to build and run test-runner
2185 return_code, stdout, stderr = run_ns3('run "test-runner --list" --verbose')
2186 self.assertEqual(return_code, 0)
2187 self.assertIn(
"Built target test-runner", stdout)
2192 Try to build and run a library
2195 return_code, stdout, stderr = run_ns3("run core")
2196 self.assertEqual(return_code, 1)
2197 self.assertIn(
"Couldn't find the specified program: core", stderr)
2201 Try to build and run an unknown target
2204 return_code, stdout, stderr = run_ns3("run nonsense")
2205 self.assertEqual(return_code, 1)
2206 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2210 Try to run test-runner without building
2213 return_code, stdout, stderr = run_ns3('run "test-runner --list" --no-build --verbose')
2214 self.assertEqual(return_code, 0)
2215 self.assertNotIn(
"Built target test-runner", stdout)
2220 Test ns3 fails to run a library
2223 return_code, stdout, stderr = run_ns3("run core --no-build")
2224 self.assertEqual(return_code, 1)
2225 self.assertIn(
"Couldn't find the specified program: core", stderr)
2229 Test ns3 fails to run an unknown program
2232 return_code, stdout, stderr = run_ns3("run nonsense --no-build")
2233 self.assertEqual(return_code, 1)
2234 self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
2238 Test if scratch simulator
is executed through gdb
and lldb
2241 if shutil.which(
"gdb")
is None:
2242 self.skipTest(
"Missing gdb")
2244 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --gdb --verbose --no-build", env={
"gdb_eval":
"1"})
2245 self.assertEqual(return_code, 0)
2246 self.assertIn(
"scratch-simulator", stdout)
2248 self.assertIn(
"GNU gdb", stdout)
2250 self.assertIn(
"No debugging symbols found", stdout)
2254 Test if scratch simulator
is executed through valgrind
2257 if shutil.which(
"valgrind")
is None:
2258 self.skipTest(
"Missing valgrind")
2260 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --valgrind --verbose --no-build")
2261 self.assertEqual(return_code, 0)
2262 self.assertIn(
"scratch-simulator", stderr)
2263 self.assertIn(
"Memcheck", stderr)
2267 Test the doxygen target that does trigger a full build
2270 if shutil.which(
"doxygen")
is None:
2271 self.skipTest(
"Missing doxygen")
2273 if shutil.which(
"bash")
is None:
2274 self.skipTest(
"Missing bash")
2276 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2278 doxygen_files = [
"introspected-command-line.h",
"introspected-doxygen.h"]
2279 for filename
in doxygen_files:
2280 file_path = os.sep.join([doc_folder, filename])
2281 if os.path.exists(file_path):
2282 os.remove(file_path)
2289 return_code, stdout, stderr =
run_ns3(
"docs doxygen")
2290 self.assertEqual(return_code, 0)
2292 self.assertIn(
"Built target doxygen", stdout)
2296 Test the doxygen target that doesn't trigger a full build
2299 if shutil.which(
"doxygen")
is None:
2300 self.skipTest(
"Missing doxygen")
2308 return_code, stdout, stderr =
run_ns3(
"docs doxygen-no-build")
2309 self.assertEqual(return_code, 0)
2311 self.assertIn(
"Built target doxygen-no-build", stdout)
2315 Test every individual target for Sphinx-based documentation
2318 if shutil.which(
"sphinx-build")
is None:
2319 self.skipTest(
"Missing sphinx")
2321 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2324 for target
in [
"contributing",
"manual",
"models",
"tutorial"]:
2326 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2327 doc_temp_folder = os.sep.join([doc_folder, target,
"source-temp"])
2328 if os.path.exists(doc_build_folder):
2329 shutil.rmtree(doc_build_folder)
2330 if os.path.exists(doc_temp_folder):
2331 shutil.rmtree(doc_temp_folder)
2334 return_code, stdout, stderr =
run_ns3(
"docs %s" % target)
2335 self.assertEqual(return_code, 0, target)
2337 self.assertIn(
"Built target sphinx_%s" % target, stdout)
2340 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2341 self.assertTrue(os.path.exists(doc_build_folder))
2344 for build_type
in [
"latex",
"html",
"singlehtml"]:
2345 self.assertTrue(os.path.exists(os.sep.join([doc_build_folder, build_type])))
2349 Test the documentation target that builds
2350 both doxygen and sphinx based documentation
2353 if shutil.which(
"doxygen")
is None:
2354 self.skipTest(
"Missing doxygen")
2355 if shutil.which(
"sphinx-build")
is None:
2356 self.skipTest(
"Missing sphinx")
2358 doc_folder = os.path.abspath(os.sep.join([
".",
"doc"]))
2367 for target
in [
"manual",
"models",
"tutorial"]:
2368 doc_build_folder = os.sep.join([doc_folder, target,
"build"])
2369 if os.path.exists(doc_build_folder):
2370 shutil.rmtree(doc_build_folder)
2372 return_code, stdout, stderr =
run_ns3(
"docs all")
2373 self.assertEqual(return_code, 0)
2375 self.assertIn(
"Built target sphinx", stdout)
2377 self.assertIn(
"Built target doxygen", stdout)
2381 Try to set ownership of scratch-simulator from current user to root,
2382 and change execution permissions
2387 sudo_password = os.getenv(
"SUDO_PASSWORD",
None)
2390 if sudo_password
is None:
2391 self.skipTest(
"SUDO_PASSWORD environment variable was not specified")
2394 self.assertFalse(enable_sudo
is True)
2397 return_code, stdout, stderr =
run_ns3(
'run scratch-simulator')
2398 self.assertEqual(return_code, 0)
2399 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2401 scratch_simulator_path =
list(filter(
lambda x: x
if "scratch-simulator" in x
else None,
2405 prev_fstat = os.stat(scratch_simulator_path)
2408 return_code, stdout, stderr =
run_ns3(
'run scratch-simulator --enable-sudo',
2409 env={
"SUDO_PASSWORD": sudo_password})
2410 self.assertEqual(return_code, 0)
2411 self.assertIn(
"Built target scratch_scratch-simulator", stdout)
2413 fstat = os.stat(scratch_simulator_path)
2418 likely_fuse_mount = ((prev_fstat.st_mode & stat.S_ISUID) == (fstat.st_mode & stat.S_ISUID))
and \
2419 prev_fstat.st_uid == 0
2421 if win32
or likely_fuse_mount:
2422 self.skipTest(
"Windows or likely a FUSE mount")
2425 self.assertEqual(fstat.st_uid, 0)
2426 self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID)
2429 return_code, stdout, stderr =
run_ns3(
'configure --enable-sudo')
2430 self.assertEqual(return_code, 0)
2434 self.assertTrue(enable_sudo)
2438 if os.path.exists(executable):
2439 os.remove(executable)
2442 return_code, stdout, stderr =
run_ns3(
'build', env={
"SUDO_PASSWORD": sudo_password})
2443 self.assertEqual(return_code, 0)
2446 self.assertIn(
"chown root", stdout)
2447 self.assertIn(
"chmod u+s", stdout)
2449 self.assertIn(os.path.basename(executable), stdout)
2452 fstat = os.stat(scratch_simulator_path)
2453 self.assertEqual(fstat.st_uid, 0)
2454 self.assertEqual(fstat.st_mode & stat.S_ISUID, stat.S_ISUID)
2458 Check if command template
is working
2463 return_code0, stdout0, stderr0 =
run_ns3(
'run sample-simulator --command-template')
2464 self.assertEqual(return_code0, 2)
2465 self.assertIn(
"argument --command-template: expected one argument", stderr0)
2467 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template=" "')
2468 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --command-template " "')
2469 return_code3, stdout3, stderr3 =
run_ns3(
'run sample-simulator --command-template "echo "')
2470 self.assertEqual((return_code1, return_code2, return_code3), (1, 1, 1))
2471 self.assertIn(
"not all arguments converted during string formatting", stderr1)
2472 self.assertEqual(stderr1, stderr2)
2473 self.assertEqual(stderr2, stderr3)
2476 return_code4, stdout4, _ =
run_ns3(
'run sample-simulator --command-template "%s --PrintVersion" --verbose')
2477 return_code5, stdout5, _ =
run_ns3(
'run sample-simulator --command-template="%s --PrintVersion" --verbose')
2478 self.assertEqual((return_code4, return_code5), (0, 0))
2480 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout4)
2481 self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout5)
2485 Check if all flavors of different argument passing to
2486 executable targets are working
2491 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --verbose')
2492 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template="%s --help" --verbose')
2493 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --verbose -- --help')
2495 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2496 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout0)
2497 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout1)
2498 self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout2)
2501 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --help" --no-build')
2502 return_code1, stdout1, stderr1 =
run_ns3(
'run sample-simulator --command-template="%s --help" --no-build')
2503 return_code2, stdout2, stderr2 =
run_ns3(
'run sample-simulator --no-build -- --help')
2504 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2505 self.assertEqual(stdout0, stdout1)
2506 self.assertEqual(stdout1, stdout2)
2507 self.assertEqual(stderr0, stderr1)
2508 self.assertEqual(stderr1, stderr2)
2511 return_code0, stdout0, stderr0 =
run_ns3(
'run "sample-simulator --PrintGlobals" --verbose')
2512 return_code1, stdout1, stderr1 =
run_ns3(
'run "sample-simulator --PrintGroups" --verbose')
2513 return_code2, stdout2, stderr2 =
run_ns3(
'run "sample-simulator --PrintTypeIds" --verbose')
2515 self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
2516 self.assertIn(
"sample-simulator{ext} --PrintGlobals".format(ext=ext), stdout0)
2517 self.assertIn(
"sample-simulator{ext} --PrintGroups".format(ext=ext), stdout1)
2518 self.assertIn(
"sample-simulator{ext} --PrintTypeIds".format(ext=ext), stdout2)
2521 cmd =
'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" --verbose -- --PrintTypeIds'
2522 return_code, stdout, stderr =
run_ns3(cmd)
2523 self.assertEqual(return_code, 0)
2528 self.assertIn(
"sample-simulator{ext} --PrintGroups --PrintGlobals --PrintTypeIds".format(ext=ext), stdout)
2531 cmd0 =
'run sample-simulator --command-template="%s " --PrintTypeIds'
2532 cmd1 =
'run sample-simulator --PrintTypeIds'
2534 return_code0, stdout0, stderr0 =
run_ns3(cmd0)
2535 return_code1, stdout1, stderr1 =
run_ns3(cmd1)
2536 self.assertEqual((return_code0, return_code1), (1, 1))
2537 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr0)
2538 self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr1)
2542 Test if scratch simulator
is executed through lldb
2545 if shutil.which(
"lldb")
is None:
2546 self.skipTest(
"Missing lldb")
2548 return_code, stdout, stderr =
run_ns3(
"run scratch-simulator --lldb --verbose --no-build")
2549 self.assertEqual(return_code, 0)
2550 self.assertIn(
"scratch-simulator", stdout)
2551 self.assertIn(
"(lldb) target create", stdout)
2556 ns-3 tests to control the quality of the repository over time,
2557 by checking the state of URLs listed and more
2562 Test if all urls
in source files are alive
2571 self.skipTest(
"Django URL validators are not available")
2578 self.skipTest(
"Requests library is not available")
2580 regex = re.compile(
r'((http|https)://[^\ \n\)\"\'\}><\]\;\`\\]*)')
2583 whitelisted_urls = {
"https://gitlab.com/your-user-name/ns-3-dev",
2584 "https://www.nsnam.org/release/ns-allinone-3.31.rc1.tar.bz2",
2585 "https://www.nsnam.org/release/ns-allinone-3.X.rcX.tar.bz2",
2586 "https://www.nsnam.org/releases/ns-3-x",
2587 "https://www.nsnam.org/releases/ns-allinone-3.(x-1",
2588 "https://www.nsnam.org/releases/ns-allinone-3.x.tar.bz2",
2590 "https://cmake.org/cmake/help/latest/manual/cmake-",
2591 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_",
2593 "http://www.lysator.liu.se/~alla/dia/",
2595 "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_Digital_Terrestrial_Television_Broadcasting_(DTTB",
2596 "http://en.wikipedia.org/wiki/Namespace_(computer_science",
2597 "http://en.wikipedia.org/wiki/Bonobo_(component_model",
2598 "http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85",
2600 "http://www.research.att.com/info/kpv/",
2601 "http://www.research.att.com/~gsf/",
2605 files_and_urls = set()
2607 for topdir
in [
"bindings",
"doc",
"examples",
"src",
"utils"]:
2608 for root, dirs, files
in os.walk(topdir):
2610 if "build" in root
or "_static" in root
or "source-temp" in root
or 'html' in root:
2614 if file.endswith(
".svg"):
2616 filepath = os.path.join(root, file)
2619 with open(filepath,
"r")
as f:
2620 matches = regex.findall(f.read())
2625 urls =
list(map(
lambda x: x[0][:-1]
if x[0][-1]
in ".," else x[0], matches))
2626 except UnicodeDecodeError:
2627 skipped_files.append(filepath)
2631 for url
in set(urls) - unique_urls - whitelisted_urls:
2632 unique_urls.add(url)
2633 files_and_urls.add((filepath, url))
2636 from django.core.validators
import URLValidator
2637 from django.core.exceptions
import ValidationError
2638 validate_url = URLValidator()
2642 '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'
2645 def test_file_url(args):
2646 test_filepath, test_url = args
2647 dead_link_msg =
None
2651 validate_url(test_url)
2652 except ValidationError:
2653 dead_link_msg =
"%s: URL %s, invalid URL" % (test_filepath, test_url)
2656 if dead_link_msg
is None:
2663 response = requests.get(test_url, verify=
False, headers=headers)
2666 if response.status_code
in [200, 301]:
2667 dead_link_msg =
None
2672 if response.status_code
in [302, 308, 500, 503]:
2673 if response.reason.lower()
in [
'found',
2674 'moved temporarily',
2675 'permanent redirect',
2677 'service temporarily unavailable'
2679 dead_link_msg =
None
2683 dead_link_msg =
"%s: URL %s: returned code %d" % (test_filepath, test_url, response.status_code)
2685 except requests.exceptions.InvalidURL:
2686 dead_link_msg =
"%s: URL %s: invalid URL" % (test_filepath, test_url)
2687 except requests.exceptions.SSLError:
2688 dead_link_msg =
"%s: URL %s: SSL error" % (test_filepath, test_url)
2689 except requests.exceptions.TooManyRedirects:
2690 dead_link_msg =
"%s: URL %s: too many redirects" % (test_filepath, test_url)
2691 except Exception
as e:
2693 error_msg = e.args[0].reason.__str__()
2694 except AttributeError:
2695 error_msg = e.args[0]
2696 dead_link_msg =
"%s: URL %s: failed with exception: %s" % (test_filepath, test_url, error_msg)
2697 return dead_link_msg
2700 from concurrent.futures
import ThreadPoolExecutor
2701 with ThreadPoolExecutor(max_workers=20)
as executor:
2702 dead_links =
list(executor.map(test_file_url,
list(files_and_urls)))
2705 dead_links =
list(sorted(filter(
lambda x: x
is not None, dead_links)))
2706 self.assertEqual(len(dead_links), 0, msg=
"\n".join([
"Dead links found:", *dead_links]))
2710 Test if all tests can be executed without hitting major memory bugs
2713 return_code, stdout, stderr = run_ns3(
2714 "configure --enable-tests --enable-examples --enable-sanitizers -d optimized")
2715 self.assertEqual(return_code, 0)
2717 test_return_code, stdout, stderr =
run_program(
"test.py",
"", python=
True)
2719 return_code, stdout, stderr =
run_ns3(
"clean")
2720 self.assertEqual(return_code, 0)
2721 self.assertEqual(test_return_code, 0)
2725 Check if images
in the docs are above a brightness threshold.
2726 This should prevent screenshots
with dark UI themes.
2729 if shutil.which(
"convert")
is None:
2730 self.skipTest(
"Imagemagick was not found")
2732 from pathlib
import Path
2735 image_extensions = [
"png",
"jpg"]
2737 for extension
in image_extensions:
2738 images +=
list(Path(
"./doc").glob(
"**/figures/*.{ext}".format(ext=extension)))
2739 images +=
list(Path(
"./doc").glob(
"**/figures/**/*.{ext}".format(ext=extension)))
2742 imagemagick_get_image_brightness = \
2743 'convert {image} -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]" info:'
2747 brightness_threshold = 50
2748 for image
in images:
2749 brightness = subprocess.check_output(imagemagick_get_image_brightness.format(image=image).split())
2750 brightness = float(brightness.decode().strip(
"'\""))
2751 self.assertGreater(brightness, brightness_threshold,
2752 "Image darker than threshold (%d < %d): %s" % (brightness, brightness_threshold, image)
2762 test_completeness = {
2763 "style": [NS3UnusedSourcesTestCase,
2766 "build": [NS3CommonSettingsTestCase,
2767 NS3ConfigureBuildProfileTestCase,
2768 NS3ConfigureTestCase,
2769 NS3BuildBaseTestCase,
2770 NS3ExpectedUseTestCase,
2772 "complete": [NS3UnusedSourcesTestCase,
2774 NS3CommonSettingsTestCase,
2775 NS3ConfigureBuildProfileTestCase,
2776 NS3ConfigureTestCase,
2777 NS3BuildBaseTestCase,
2778 NS3ExpectedUseTestCase,
2779 NS3QualityControlTestCase,
2781 "extras": [NS3DependenciesTestCase,
2787 parser = argparse.ArgumentParser(
"Test suite for the ns-3 buildsystem")
2788 parser.add_argument(
"-c",
"--completeness",
2789 choices=test_completeness.keys(),
2791 parser.add_argument(
"-tn",
"--test-name",
2795 parser.add_argument(
"-rtn",
"--resume-from-test-name",
2799 parser.add_argument(
"-q",
"--quiet",
2800 action=
"store_true",
2802 args = parser.parse_args(sys.argv[1:])
2804 loader = unittest.TestLoader()
2805 suite = unittest.TestSuite()
2808 for testCase
in test_completeness[args.completeness]:
2809 suite.addTests(loader.loadTestsFromTestCase(testCase))
2814 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
2816 tests_to_run = set(map(
lambda x: x
if args.test_name
in x
else None, tests.keys()))
2817 tests_to_remove = set(tests) - set(tests_to_run)
2818 for test_to_remove
in tests_to_remove:
2819 suite._tests.remove(tests[test_to_remove])
2822 if args.resume_from_test_name:
2824 tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
2825 keys =
list(tests.keys())
2827 while args.resume_from_test_name
not in keys[0]
and len(tests) > 0:
2828 suite._tests.remove(tests[keys[0]])
2832 ns3rc_script_bak = ns3rc_script +
".bak"
2833 if os.path.exists(ns3rc_script)
and not os.path.exists(ns3rc_script_bak):
2834 shutil.move(ns3rc_script, ns3rc_script_bak)
2837 runner = unittest.TextTestRunner(failfast=
True, verbosity=1
if args.quiet
else 2)
2841 if os.path.exists(ns3rc_script_bak):
2842 shutil.move(ns3rc_script_bak, ns3rc_script)
2845if __name__ ==
'__main__':
Generic test case with basic function inherited by more complex tests.
def config_ok(self, return_code, stdout)
Check if configuration for release mode worked normally.
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
def setUp(self)
Clean configuration/build artifacts before testing configuration and build settings After configuring...
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
Tests ns3 regarding building the project.
def test_06_TestVersionFile(self)
Test if changing the version file affects the library names.
def test_10_AmbiguityCheck(self)
Test if ns3 can alert correctly in case a shortcut collision happens.
def test_01_BuildExistingTargets(self)
Try building the core library.
def test_12_CppyyBindings(self)
Test if we can use python bindings.
def test_08_InstallationAndUninstallation(self)
Tries setting a ns3 version, then installing it.
def test_11_StaticBuilds(self)
Test if we can build a static ns-3 library and link it to static programs.
def setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned.
def test_02_BuildNonExistingTargets(self)
Try building core-test library without tests enabled.
def test_04_BuildProjectNoTaskLines(self)
Try hiding task lines.
def test_03_BuildProject(self)
Try building the project:
def test_09_Scratches(self)
Tries to build scratch-simulator and subdir/scratch-simulator-subdir.
def test_05_BreakBuild(self)
Try removing an essential file to break the build.
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
def test_07_OutputDirectory(self)
Try setting a different output directory and if everything is in the right place and still working co...
ns3_libraries
ns3_libraries holds a list of built module libraries # noqa
ns3 tests related to generic options
def test_05_CheckVersion(self)
Test only passing 'show version' argument to ns3.
def setUp(self)
Clean configuration/build artifacts before common commands.
def test_01_NoOption(self)
Test not passing any arguments to.
def test_02_NoTaskLines(self)
Test only passing –quiet argument to ns3.
def test_03_CheckConfig(self)
Test only passing 'show config' argument to ns3.
def test_04_CheckProfile(self)
Test only passing 'show profile' argument to ns3.
ns-3 tests related to dependencies
def test_01_CheckIfIncludedHeadersMatchLinkedModules(self)
Checks if headers from different modules (src/A, contrib/B) that are included by the current module (...
Tests ns3 usage in more realistic scenarios.
def test_10_DoxygenWithBuild(self)
Test the doxygen target that does trigger a full build.
def test_02_BuildAndRunExistingExecutableTarget(self)
Try to build and run test-runner.
def test_08_RunNoBuildGdb(self)
Test if scratch simulator is executed through gdb and lldb.
def test_05_RunNoBuildExistingExecutableTarget(self)
Try to run test-runner without building.
def test_06_RunNoBuildExistingLibraryTarget(self)
Test ns3 fails to run a library.
def test_03_BuildAndRunExistingLibraryTarget(self)
Try to build and run a library.
def test_01_BuildProject(self)
Try to build the project.
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
def test_14_EnableSudo(self)
Try to set ownership of scratch-simulator from current user to root, and change execution permissions...
def test_16_ForwardArgumentsToRunTargets(self)
Check if all flavors of different argument passing to executable targets are working.
def test_17_RunNoBuildLldb(self)
Test if scratch simulator is executed through lldb.
def test_15_CommandTemplate(self)
Check if command template is working.
def test_04_BuildAndRunNonExistingTarget(self)
Try to build and run an unknown target.
def test_07_RunNoBuildNonExistingExecutableTarget(self)
Test ns3 fails to run an unknown program.
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
def test_09_RunNoBuildValgrind(self)
Test if scratch simulator is executed through valgrind.
def test_13_Documentation(self)
Test the documentation target that builds both doxygen and sphinx based documentation.
def setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned Here examples,...
def test_11_DoxygenWithoutBuild(self)
Test the doxygen target that doesn't trigger a full build.
def test_12_SphinxDocumentation(self)
Test every individual target for Sphinx-based documentation.
ns-3 tests to control the quality of the repository over time, by checking the state of URLs listed a...
def test_03_CheckImageBrightness(self)
Check if images in the docs are above a brightness threshold.
def test_02_MemoryCheckWithSanitizers(self)
Test if all tests can be executed without hitting major memory bugs.
def test_01_CheckForDeadLinksInSources(self)
Test if all urls in source files are alive.
ns-3 tests to check if the source code, whitespaces and CMake formatting are according to the coding ...
def test_01_CheckCMakeFormat(self)
Check if there is any difference between tracked file after applying cmake-format.
None setUp(self)
Import GitRepo and load the original diff state of the repository before the tests.
ns-3 tests related to checking if source files were left behind, not being used by CMake
dictionary directory_and_files
dictionary containing directories with .cc source files # noqa
def test_01_UnusedExampleSources(self)
Test if all example source files are being used in their respective CMakeLists.txt.
def setUp(self)
Scan all C++ source files and add them to a list based on their path.
def test_02_UnusedModuleSources(self)
Test if all module source files are being used in their respective CMakeLists.txt.
def test_03_UnusedUtilsSources(self)
Test if all utils source files are being used in their respective CMakeLists.txt.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
def run_ns3(args, env=None, generator=platform_makefiles)
Runs the ns3 wrapper script with arguments.
def get_programs_list()
Extracts the programs list from .lock-ns3.
def get_libraries_list(lib_outdir=usual_lib_outdir)
Gets a list of built libraries.
def get_test_enabled()
Check if tests are enabled in the .lock-ns3.
def read_lock_entry(entry)
Read interesting entries from the .lock-ns3 file.
cmake_build_target_command
def get_headers_list(outdir=usual_outdir)
Gets a list of header files.
def run_program(program, args, python=False, cwd=ns3_path, env=None)
Runs a program with the given arguments and returns a tuple containing (error code,...
def get_enabled_modules()