13 from uuid
import uuid4
14 from os
import urandom
15 from functools
import wraps
16 from multiprocessing
import pool, cpu_count
17 from http.server
import SimpleHTTPRequestHandler, HTTPServer
19 from fake_http_server.fake_test_server
import FakeTestServerBackground
20 from sota_tools.treehub_server
import create_repo
23 logger = logging.getLogger(__name__)
28 def __init__(self, aktualizr_primary_exe, aktualizr_info_exe, id,
29 uptane_server, wait_port=9040, wait_timeout=60, log_level=1,
30 primary_port=None, secondaries=None, secondary_wait_sec=600, output_logs=True,
31 run_mode='once', director=None, image_repo=None,
32 sysroot=None, treehub=None, ostree_mock_path=None, **kwargs):
43 with open(path.join(self.
_storage_dir.name,
'secondary_config.json'),
'w+')
as secondary_config_file:
44 secondary_cfg = json.loads(Aktualizr.SECONDARY_CONFIG_TEMPLATE.
45 format(port=primary_port
if primary_port
else wait_port,
46 timeout=wait_timeout))
47 json.dump(secondary_cfg, secondary_config_file)
51 with open(path.join(self.
_storage_dir.name,
'config.toml'),
'w+')
as config_file:
52 config_file.write(Aktualizr.CONFIG_TEMPLATE.format(server_url=uptane_server.base_url,
54 serial=id[1], hw_ID=id[0],
60 director=director.base_url
if director
else '',
61 image_repo=image_repo.base_url
if image_repo
else '',
62 pacman_type=
'ostree' if treehub
and sysroot
else 'none',
63 ostree_sysroot=sysroot.path
if sysroot
else '',
64 treehub_server=treehub.base_url
if treehub
else '',
69 if secondaries
is not None:
75 if sysroot
and ostree_mock_path:
76 self.
_run_env[
'LD_PRELOAD'] = os.path.abspath(ostree_mock_path)
77 self.
_run_env[
'OSTREE_DEPLOYMENT_VERSION_FILE'] = sysroot.version_file
81 server = "{server_url}"
84 base_path = "{import_path}"
85 tls_cacert_path = "ca.pem"
86 tls_pkey_path = "pkey.pem"
87 tls_clientcert_path = "client.pem"
90 primary_ecu_serial = "{serial}"
91 primary_ecu_hardware_id = "{hw_ID}"
94 path = "{storage_dir}"
96 sqldb_path = "{db_path}"
99 type = "{pacman_type}"
100 images_path = "{storage_dir}/images"
101 sysroot = "{ostree_sysroot}"
102 ostree_server = "{treehub_server}"
107 secondary_config_file = "{secondary_cfg_file}"
108 secondary_preinstall_wait_sec = {secondary_wait_sec}
109 director_server = "{director}"
110 repo_server = "{image_repo}"
113 reboot_sentinel_dir = "{sentinel_dir}"
114 reboot_sentinel_name = "{sentinel_name}"
118 loglevel = {log_level}
122 SECONDARY_CONFIG_TEMPLATE =
'''
125 "secondaries_wait_port": {port},
126 "secondaries_wait_timeout": {timeout},
132 def set_mode(self, mode):
135 def add_secondary(self, secondary):
137 sec_cfg = json.load(config_file)
138 sec_cfg[
"IP"][
"secondaries"].append({
"addr":
"127.0.0.1:{}".format(secondary.port)})
140 json.dump(sec_cfg, config_file)
142 def remove_secondary(self, secondary):
144 sec_cfg = json.load(config_file)
145 sec_cfg[
"IP"][
"secondaries"].remove({
"addr":
"127.0.0.1:{}".format(secondary.port)})
147 json.dump(sec_cfg, config_file)
148 config_file.truncate()
150 def update_wait_timeout(self, timeout):
152 sec_cfg = json.load(config_file)
153 sec_cfg[
"IP"][
"secondaries_wait_timeout"] = timeout
155 json.dump(sec_cfg, config_file)
157 def run(self, run_mode):
163 def get_info(self, retry=30):
165 for ii
in range(0, retry):
167 timeout=60, stdout=subprocess.PIPE, env=self.
_run_env)
168 if info_exe_res.returncode == 0
and \
169 str(info_exe_res.stdout).find(
'Provisioned on server: yes') != -1
and \
170 str(info_exe_res.stdout).find(
'Current Primary ECU running version:') != -1:
173 if info_exe_res
and info_exe_res.returncode == 0:
174 return str(info_exe_res.stdout)
176 logger.error(
'Failed to get an aktualizr\'s status info, stdout: {}, stderr: {}'.
177 format(str(info_exe_res.stdout), str(info_exe_res.stderr)))
182 def is_ecu_registered(self, ecu_id):
184 if not ((device_status.find(ecu_id[0]) != -1)
and (device_status.find(ecu_id[1]) != -1)):
186 not_registered_field =
"Removed or unregistered ECUs (deprecated):"
187 not_reg_start = device_status.find(not_registered_field)
188 return not_reg_start == -1
or (device_status.find(ecu_id[1], not_reg_start) == -1)
190 def get_current_image_info(self, ecu_id):
191 if self.
id == ecu_id:
196 def get_current_pending_image_info(self, ecu_id):
203 def _get_current_image_info(self, ecu_id, secondary_image_hash_field='installed image hash:
'):
206 ecu_serial = ecu_id[1]
207 ecu_info_position = aktualizr_status.find(ecu_serial)
208 if ecu_info_position == -1:
211 start = aktualizr_status.find(secondary_image_hash_field, ecu_info_position)
212 end = aktualizr_status.find(
'\\n', start)
213 hash_val = aktualizr_status[start + len(secondary_image_hash_field):end]
223 def get_current_primary_image_info(self):
224 primary_hash_field =
'Current Primary ECU running version: '
227 start = aktualizr_status.find(primary_hash_field)
228 end = aktualizr_status.find(
'\\n', start)
229 return aktualizr_status[start + len(primary_hash_field):end]
231 logger.error(
"Failed to get aktualizr info/status")
236 def get_primary_pending_version(self):
237 primary_hash_field =
'Pending Primary ECU version: '
239 start = aktualizr_status.find(primary_hash_field)
240 end = aktualizr_status.find(
'\\n', start)
241 return aktualizr_status[start + len(primary_hash_field):end]
246 stderr=
None if self.
_output_logs else subprocess.STDOUT,
249 logger.debug(
"Aktualizr has been started")
252 def __exit__(self, exc_type, exc_val, exc_tb):
255 logger.debug(
"Aktualizr has been stopped")
257 def terminate(self, sig=signal.SIGTERM):
261 return self.
_process.stdout.read().decode(errors=
'replace')
263 def wait_for_completion(self, timeout=120):
266 def wait_for_provision(self, timeout=60):
267 deadline = time.time() + timeout
268 while timeout == 0
or time.time() < deadline:
270 if info
is not None and 'Provisioned on server: yes' in info:
275 def emulate_reboot(self):
283 def copy_keys(dest_path):
285 shutil.copy(KeyStore.ca(), dest_path)
286 shutil.copy(KeyStore.pkey(), dest_path)
287 shutil.copy(KeyStore.cert(), dest_path)
291 return path.join(KeyStore.base_dir,
'tests/test_data/prov_testupdate/ca.pem')
295 return path.join(KeyStore.base_dir,
'tests/test_data/prov_testupdate/pkey.pem')
299 return path.join(KeyStore.base_dir,
'tests/test_data/prov_testupdate/client.pem')
304 def __init__(self, id, aktualizr_secondary_exe='src/aktualizr_secondary/aktualizr-secondary', port=None, primary_port=None,
305 sysroot=None, treehub=None, output_logs=True, force_reboot=False,
306 ostree_mock_path=None, **kwargs):
322 with open(path.join(self.
storage_dir.name,
'config.toml'),
'w+')
as config_file:
323 config_file.write(IPSecondary.CONFIG_TEMPLATE.format(serial=id[1], hw_ID=id[0],
324 force_reboot=1
if force_reboot
else 0,
325 reboot_command=reboot_command,
328 db_path=path.join(self.
storage_dir.name,
'db.sql'),
329 pacman_type=
'ostree' if treehub
and sysroot
else 'none',
330 ostree_sysroot=sysroot.path
if sysroot
else '',
331 treehub_server=treehub.base_url
if treehub
else '',
338 if sysroot
and ostree_mock_path:
339 self.
_run_env[
'LD_PRELOAD'] = os.path.abspath(ostree_mock_path)
340 self.
_run_env[
'OSTREE_DEPLOYMENT_VERSION_FILE'] = sysroot.version_file
343 CONFIG_TEMPLATE =
'''
345 ecu_serial = "{serial}"
346 ecu_hardware_id = "{hw_ID}"
347 force_install_completion = {force_reboot}
351 primary_ip = "127.0.0.1"
352 primary_port = {primary_port}
356 path = "{storage_dir}"
357 sqldb_path = "{db_path}"
360 type = "{pacman_type}"
361 sysroot = "{ostree_sysroot}"
362 ostree_server = "{treehub_server}"
366 reboot_sentinel_dir = "{sentinel_dir}"
367 reboot_sentinel_name = "{sentinel_name}"
368 reboot_command = "{reboot_command}"
371 def is_running(self):
372 return True if self.
_process.poll()
is None else False
376 tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
378 port = tcp.getsockname()[1]
385 stderr=
None if self.
_output_logs else subprocess.STDOUT,
388 logger.debug(
"IP Secondary {} has been started: {}".format(self.
id, self.
port))
391 def __exit__(self, exc_type, exc_val, exc_tb):
394 logger.debug(
"IP Secondary {} has been stopped".format(self.
id))
396 def wait_for_completion(self, timeout=120):
399 def emulate_reboot(self):
404 def __init__(self, doc_root, ifc, port, client_handler_map={}):
405 super(UptaneRepo, self).__init__(server_address=(ifc, port), RequestHandlerClass=self.
Handler)
407 self.
base_url =
'http://{}:{}'.format(self.server_address[0], self.server_address[1])
412 lambda request: (self.
Handler.handler_map.get(
'POST', {})).get(request.path,
413 self.
Handler.default_handler)(request)
416 lambda request: (self.
Handler.handler_map.get(
'PUT', {})).get(request.path,
417 self.
Handler.default_handler)(request)
420 lambda request: (self.
Handler.handler_map.get(
'GET', {})).get(request.path,
421 self.
Handler.default_get)(request)
423 for method, method_handlers
in client_handler_map.items():
424 for url, handler
in method_handlers.items():
425 if self.
Handler.handler_map.get(method,
None)
is None:
426 self.
Handler.handler_map[method] = {}
427 self.
Handler.handler_map[method][url] = handler
430 def __init__(self, request, client_address, server):
435 def default_handler(self):
436 self.send_response(200)
439 def default_get(self):
441 self.send_response(404)
444 self.send_response(200)
446 with open(self.
file_path,
'rb')
as source:
447 self.copyfile(source, self.wfile)
453 return os.path.join(self.
doc_root, self.path[1:])
456 self._server_thread = threading.Thread(target=self.serve_forever)
457 self._server_thread.start()
463 if self._server_thread:
464 self._server_thread.join(timeout=60)
465 self._server_thread =
None
470 def __exit__(self, exc_type, exc_val, exc_tb):
477 - serves signed metadata about images
478 - receives device manifest which includes installation report if any installation has happened
481 director_subdir =
"repo/director"
483 def __init__(self, uptane_repo_root, ifc, port, client_handler_map={}):
484 super(DirectorRepo, self).__init__(os.path.join(uptane_repo_root, self.
director_subdir), ifc=ifc, port=port,
485 client_handler_map=client_handler_map)
493 def handle_manifest(self):
494 self.send_response(200)
498 data_size = int(self.headers[
'Content-Length'])
499 data_string = self.rfile.read(data_size)
500 json_data = json.loads(data_string)
501 except Exception
as exc:
505 install_report = json_data[
'signed'].get(
'installation_report',
"")
507 self.server.set_install_event(json_data)
509 handler_map = {
'PUT': {
'/manifest': handle_manifest}}
511 def set_install_event(self, manifest):
512 with self._installed_condition:
513 self._manifest = manifest
514 self._last_install_res = manifest[
'signed'][
'installation_report'][
'report'][
'result'][
'success']
515 self._installed_condition.notifyAll()
517 def wait_for_install(self, timeout=180):
518 with self._installed_condition:
519 self._installed_condition.wait(timeout=timeout)
520 return self._last_install_res
522 def get_install_result(self):
523 with self._installed_condition:
524 return self._last_install_res
526 def get_manifest(self):
527 with self._installed_condition:
528 return self._manifest
530 def get_ecu_manifest(self, ecu_serial):
531 return self.get_manifest()[
'signed'][
'ecu_version_manifests'][ecu_serial]
533 def get_ecu_manifest_filepath(self, ecu_serial):
534 return self.get_ecu_manifest(ecu_serial)[
'signed'][
'installed_image'][
'filepath']
539 This server serves signed metadata about images
540 as well as images by default (it's possible to serve images from another server by using the 'custom URI' feature)
543 image_subdir =
"repo/repo"
545 def __init__(self, uptane_repo_root, ifc, port, client_handler_map={}):
546 super(ImageRepo, self).__init__(os.path.join(uptane_repo_root, self.
image_subdir), ifc=ifc, port=port,
547 client_handler_map=client_handler_map)
552 This server serves images
554 image_subdir =
"repo/repo"
556 def __init__(self, root, ifc, port, client_handler_map={}):
557 super(CustomRepo, self).__init__(os.path.join(root, self.
image_subdir),
558 ifc=ifc, port=port, client_handler_map=client_handler_map)
563 This server serves requests from an OSTree client, i.e. emulates/mocks the treehub server
565 def __init__(self, ifc, port, client_handler_map={}):
566 self.
root = tempfile.mkdtemp()
567 super(Treehub, self).__init__(self.
root, ifc=ifc, port=port, client_handler_map=client_handler_map)
571 return super(Treehub, self).__enter__()
573 def __exit__(self, exc_type, exc_val, exc_tb):
574 super(Treehub, self).__exit__(exc_type, exc_val, exc_tb)
575 shutil.rmtree(self.
root, ignore_errors=
True)
578 def default_get(self):
580 self.send_response(404)
588 def __init__(self, number_of_failures=1, bytes_to_send_before_interruption=10, url=''):
594 def __call__(self, request_handler):
596 request_handler.send_response(200)
597 file_size = os.path.getsize(request_handler.file_path)
598 request_handler.send_header(
'Content-Length', file_size)
599 request_handler.end_headers()
601 with open(request_handler.file_path,
'rb')
as source:
603 request_handler.wfile.write(data)
607 request_handler.default_get()
609 def map(self, url=''):
615 dummy_filez = (b
'\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06' +
616 b
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xa4\x00\x00\x00\x00' +
617 b
'\x00\x19\x33\x34\x32\x36\x31\xe5\x02\x00')
619 def __init__(self, number_of_failures=1, url='', fake_filez=False):
625 def __call__(self, request_handler):
627 request_handler.send_response(200)
628 request_handler.end_headers()
632 request_handler.wfile.write(b
'malformed image')
636 request_handler.default_get()
644 def __init__(self, number_of_failures=1, url=''):
649 def __call__(self, request_handler):
651 request_handler.send_response(200)
652 file_size = os.path.getsize(request_handler.file_path)
653 request_handler.end_headers()
655 with open(request_handler.file_path,
'rb')
as source:
657 data = source.read(1)
660 request_handler.wfile.write(data)
661 request_handler.wfile.flush()
667 request_handler.default_get()
674 def __init__(self, number_of_redirects=1, url=''):
679 def __call__(self, request_handler):
681 request_handler.send_response(301)
682 request_handler.send_header(
'Location', request_handler.server.base_url + request_handler.path)
683 request_handler.end_headers()
686 request_handler.default_get()
693 def __init__(self, number_of_failures=1):
697 def __call__(self, request_handler):
699 request_handler.send_response(200)
700 request_handler.end_headers()
701 request_handler.wfile.write(b
'{"non-uptane-json": "some-value"}')
705 request_handler.default_get()
712 def __init__(self, repo_manager_exe, server_port=0, director_port=0, image_repo_port=0, custom_repo_port=0):
724 def create_generic_server(self, **kwargs):
727 def create_director_repo(self, handler_map={}):
730 def create_image_repo(self, handler_map={}):
733 def create_custom_repo(self, handler_map={}):
741 def target_dir(self):
745 def target_file(self):
746 return path.join(self.
image_dir,
'targets.json')
748 def add_image(self, id, image_filename, target_name=None, image_size=1024, custom_url=''):
750 targetname = target_name
if target_name
else image_filename
752 with open(path.join(self.
image_dir, image_filename),
'wb')
as image_file:
753 image_file.write(urandom(image_size))
756 '--command',
'image',
'--filename', image_filename,
'--targetname', targetname,
'--hwid', id[0]]
759 image_creation_cmdline.append(
'--url')
760 image_creation_cmdline.append(custom_url)
762 subprocess.run(image_creation_cmdline, cwd=self.
image_dir, check=
True)
766 '--command',
'addtarget',
'--targetname', targetname,
767 '--hwid', id[0],
'--serial', id[1]], check=
True)
773 targets = json.load(target_file)
774 target_hash = targets[
"signed"][
"targets"][targetname][
"hashes"][
"sha256"]
778 def add_ostree_target(self, id, rev_hash, target_name=None, expires_within_sec=(60 * 5)):
780 target_name = rev_hash
if target_name
is None else "{}-{}".format(target_name, rev_hash)
782 '--command',
'image',
784 '--targetname', target_name,
785 '--targetsha256', rev_hash,
786 '--targetlength',
'0',
787 '--targetformat',
'OSTREE',
789 subprocess.run(image_creation_cmdline, check=
True)
791 expiration_time = time.time() + expires_within_sec
792 expiration_time_str = time.strftime(
"%Y-%m-%dT%H:%M:%SZ", time.gmtime(expiration_time))
795 '--command',
'addtarget',
797 '--targetname', target_name,
800 '--expires', expiration_time_str],
811 def __exit__(self, exc_type, exc_val, exc_tb):
812 shutil.rmtree(self.
root_dir, ignore_errors=
True)
814 def _generate_repo(self):
816 '--command',
'generate',
'--keytype',
'ED25519'], check=
True)
819 def with_aktualizr(start=True, output_logs=False, id=(
'primary-hw-ID-001', str(uuid4())), wait_timeout=60,
820 secondary_wait_sec=600, log_level=1, aktualizr_primary_exe=
'src/aktualizr_primary/aktualizr',
821 aktualizr_info_exe=
'src/aktualizr_info/aktualizr-info',
825 def wrapper(*args, ostree_mock_path=None, **kwargs):
826 aktualizr =
Aktualizr(aktualizr_primary_exe=aktualizr_primary_exe,
827 aktualizr_info_exe=aktualizr_info_exe, id=id,
828 wait_timeout=wait_timeout,
829 secondary_wait_sec=secondary_wait_sec,
830 log_level=log_level, output_logs=output_logs,
831 run_mode=run_mode, ostree_mock_path=ostree_mock_path, **kwargs)
834 result = test(*args, **kwargs, aktualizr=aktualizr)
836 result = test(*args, **kwargs, aktualizr=aktualizr)
844 def with_uptane_backend(start_generic_server=True, repo_manager_exe='src/uptane_generator/uptane-generator'):
847 def wrapper(*args, **kwargs):
848 repo_manager_exe_abs_path = path.abspath(repo_manager_exe)
850 if start_generic_server:
851 with repo.create_generic_server()
as uptane_server:
852 result = test(*args, **kwargs, uptane_repo=repo, uptane_server=uptane_server)
854 result = test(*args, **kwargs, uptane_repo=repo)
860 def with_director(start=True, handlers=[]):
863 def wrapper(*args, uptane_repo, **kwargs):
864 def func(handler_map={}):
865 director = uptane_repo.create_director_repo(handler_map=handler_map)
868 result = test(*args, **kwargs, uptane_repo=uptane_repo, director=director)
870 result = test(*args, **kwargs, uptane_repo=uptane_repo, director=director)
873 if handlers
and len(handlers) > 0:
874 for handler
in handlers:
875 result = func(handler.map(kwargs.get(
'test_path',
'')))
885 def with_imagerepo(start=True, handlers=[]):
888 def wrapper(*args, uptane_repo, **kwargs):
889 def func(handler_map={}):
890 image_repo = uptane_repo.create_image_repo(handler_map=handler_map)
893 result = test(*args, **kwargs, uptane_repo=uptane_repo, image_repo=image_repo)
895 result = test(*args, **kwargs, uptane_repo=uptane_repo, image_repo=image_repo)
898 if handlers
and len(handlers) > 0:
899 for handler
in handlers:
900 result = func(handler.map(kwargs.get(
'test_path',
'')))
910 def with_secondary(start=True, output_logs=False, id=(
'secondary-hw-ID-001',
None),
911 force_reboot=
False, arg_name=
'secondary',
912 aktualizr_secondary_exe=
'src/aktualizr_secondary/aktualizr-secondary'):
915 def wrapper(*args, **kwargs):
918 id1 = (id1[0], str(uuid4()))
919 secondary =
IPSecondary(aktualizr_secondary_exe=aktualizr_secondary_exe, output_logs=output_logs, id=id1, force_reboot=force_reboot, **kwargs)
920 sl = kwargs.get(
"secondaries", []) + [secondary]
921 kwargs.update({arg_name: secondary,
"secondaries": sl})
922 if "primary_port" not in kwargs:
923 kwargs[
"primary_port"] = secondary.primary_port
926 result = test(*args, **kwargs)
928 result = test(*args, **kwargs)
934 def with_path(paths):
937 def wrapper(*args, **kwargs):
938 for test_path
in paths:
939 result = test(*args, **kwargs, test_path=test_path)
948 def __init__(self, aktualizr, uptane_repo, images_to_install=[]):
951 for image
in images_to_install:
954 'filename': image[1],
955 'hash': uptane_repo.add_image(image[0], image[1], custom_url=image[2]
if len(image) > 2
else '')
958 def are_images_installed(self):
961 if not (image[
'hash'] == self.
aktualizr.get_current_image_info(image[
'ecu_id'])):
968 def with_install_manager(default_images=True):
971 def wrapper(*args, aktualizr, uptane_repo, secondary=None, images_to_install=[], **kwargs):
972 if default_images
and (
not images_to_install
or len(images_to_install) == 0):
973 images_to_install = [(aktualizr.id,
'primary-image.img')]
975 images_to_install.append((secondary.id,
'secondary-image.img'))
976 install_mngr =
InstallManager(aktualizr, uptane_repo, images_to_install)
977 result = test(*args, **kwargs, aktualizr=aktualizr, secondary=secondary,
978 uptane_repo=uptane_repo, install_mngr=install_mngr)
984 def with_images(images_to_install):
987 def wrapper(*args, **kwargs):
988 return test(*args, **kwargs, images_to_install=images_to_install)
993 def with_customrepo(start=True, handlers=[]):
996 def wrapper(*args, uptane_repo, **kwargs):
997 def func(handler_map={}):
998 custom_repo = uptane_repo.create_custom_repo(handler_map=handler_map)
1001 result = test(*args, **kwargs, uptane_repo=uptane_repo, custom_repo=custom_repo)
1003 result = test(*args, **kwargs, uptane_repo=uptane_repo, custom_repo=custom_repo)
1006 if handlers
and len(handlers) > 0:
1007 for handler
in handlers:
1008 result = func(handler.map(kwargs.get(
'test_path',
'')))
1019 repo_path =
'ostree_repo'
1021 def __enter__(self):
1022 self.
_root = tempfile.mkdtemp()
1026 subprocess.run([
'cp',
'-r', self.
repo_path, self.
_root], check=
True)
1030 version_file.writelines([
'{}\n'.format(initial_revision),
1032 '{}\n'.format(initial_revision),
1033 '{}\n'.format(
'0')])
1037 def __exit__(self, exc_type, exc_val, exc_tb):
1038 shutil.rmtree(self.
_root, ignore_errors=
True)
1040 def get_revision(self):
1041 rev_cmd_res = subprocess.run([
'ostree',
'rev-parse',
'--repo', self.
path +
'/ostree/repo',
'generate-remote:generated'],
1042 timeout=60, check=
True, stdout=subprocess.PIPE)
1044 return rev_cmd_res.stdout.decode(
'ascii').rstrip(
'\n')
1046 def update_revision(self, rev):
1048 version_file.writelines([
'{}\n'.format(rev),
1051 '{}\n'.format(
'1')])
1054 def with_sysroot(ostree_mock_path='tests/libostree_mock.so'):
1055 def decorator(test):
1057 def wrapper(*args, **kwargs):
1059 return test(*args, **kwargs, sysroot=sysroot, ostree_mock_path=ostree_mock_path)
1064 def with_treehub(handlers=[], port=0):
1065 def decorator(test):
1067 def wrapper(*args, **kwargs):
1068 def func(handler_map={}):
1069 with Treehub(
'localhost', port=port, client_handler_map=handler_map)
as treehub:
1070 return test(*args, **kwargs, treehub=treehub)
1072 if handlers
and len(handlers) > 0:
1073 for handler
in handlers:
1074 result = func(handler.map(kwargs.get(
'test_path',
'')))
1085 def Process(self, *args, **kwds):
1086 proc = super(NonDaemonPool, self).
Process(*args, **kwds)
1088 class NonDaemonProcess(proc.__class__):
1089 """Monkey-patch process to ensure it is never daemonized"""
1096 def daemon(self, val):
1099 proc.__class__ = NonDaemonProcess
1105 def __init__(self, tests):
1109 def __enter__(self):
1112 def __exit__(self, exc_type, exc_value, traceback):
1117 def test_runner(test):
1118 logger.info(
'>>> Running {}...'.format(test.__name__))
1119 test_run_result = test()
1120 logger.info(
'>>> {}: {}\n'.format(
'OK' if test_run_result
else 'FAILED', test.__name__))
1121 return test_run_result
1126 for result
in results:
1127 total_result = total_result
and result