OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
encapsulated_test_case.py
Go to the documentation of this file.
1 # Routine to encapsulate a test case, so that all memory initialisations are done
2 # in an forked process
3 #
4 # Copyright (c) 2023, Chris Rogers, STFC Rutherford Appleton Laboratory, Didcot, UK
5 #
6 # This file is part of OPAL.
7 #
8 # OPAL is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with OPAL. If not, see <https://www.gnu.org/licenses/>.
15 #
16 
17 import unittest
18 import sys
19 import os
20 
21 class EncapsulatedTestCase(unittest.TestCase):
22  """
23  Because OPAL is sloppy with memory, we run many tests in a forked process.
24  This is done by using EncapsulatedTestCase instead of the regular unittest
25  TestCase.
26 
27  TestCases should inherit from this class. By default make install will put
28  the class in pyopal.objects. Individual test methods should have a name like
29  "encapsulated_test_<name>" to indicate that the method needs to be run in a
30  forked process. EncapsulatedTestCase will search for these tests at run time
31  and execute them.
32  """
34  """
35  Search through the methods and look for functions with name
36  "encapsulated_test_<name>". If one is found, it will be executed in a
37  forked process.
38 
39  This method replaces all of the encapsulated_test_<name> methods, so if
40  multiple iterations fail it still gets counted as a single failure.
41  """
42  for name, test_method in vars(self.__class__).items():
43  if name[:18] != "encapsulated_test_":
44  continue
45  if not callable(test_method):
46  continue
47  a_pid = os.fork()
48  if a_pid == 0: # the child process
49  try:
50  test_method(self)
51  except:
52  print("Encapsulated test failed with:")
53  sys.excepthook(*sys.exc_info())
54  os._exit(1)
55  os._exit(0)
56  else:
57  return_value = os.waitpid(a_pid, 0)[1]
58  classname = self.__class__.__name__
59  self.assertEqual(return_value, 0,
60  msg=f"Failed test {classname}.{name}")