def test_credentials(cred_json, conf_json): """ Tests if credentials in "cred.json" are valid. """ perform_once(__name__ + '.test_credentials') from http.client import HTTPSConnection from json import loads # Checks Client ID and secret ID presence client_id = cred_json['client_id'] client_secret = cred_json['client_secret'] assert client_id assert client_secret # Check OAuth credential validity def get_oauth_token(): """Get OAuth token""" connection = HTTPSConnection(conf_json['licensing']['url'].split( '//', 1)[1]) connection.request( "POST", "/o/token/", "client_id=%s&client_secret=%s&grant_type=client_credentials" % (client_id, client_secret), { 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' }) return connection.getresponse() for i in range(3): response = get_oauth_token() status = response.status if status == 401 or status < 300: break if not (200 <= response.status < 300): pytest.fail(response.read().decode()) assert loads(response.read()).get('access_token')
def test_abi_compliance(tmpdir, accelize_drm): """ Test the ABI/API compliance of the lib_name. """ perform_once(__name__ + '.test_abi_compliance') if not accelize_drm.pytest_build_environment: pytest.skip('This test is only performed on build environment.') elif not accelize_drm.pytest_build_type == 'debug': pytest.xfail('This test need libraries compiled in debug mode.') # Initialize test from concurrent.futures import ThreadPoolExecutor, as_completed build_futures = [] dump_futures = [] latest_futures = [] tools_futures = [] latest_dumps = {} reports = {} with ThreadPoolExecutor() as executor: def dumps_library(lib_version, lib_path, futures): """ Dumps a version asynchronously. Args: lib_version (str): version. lib_path (str): Library directory. futures (list): Future list. """ include = os.path.join(lib_path, 'include') for lib_name in LIB_NAMES: futures.append( executor.submit( dump_abi, str( tmpdir.join('%s_%s.abidump' % (lib_name, lib_version))), os.path.join(lib_path, '%s.so' % lib_name), include, lib_version, lib_name)) # Get references versions abi_version = accelize_drm.get_api_version().major versions = executor.submit(get_reference_versions, tmpdir, abi_version) # Build reference versions versions = versions.result() if not versions: pytest.skip('No previous versions with ABI version %s' % abi_version) print('CHECKING ABI/API AGAINST VERSIONS:', ', '.join(versions)) for version, path in versions.items(): build_futures.append(executor.submit(make_tag, version, path)) # Waits for tools build completion for future in as_completed(tools_futures): future.result() # Dump latest version ABI and API dumps_library('latest', '.', latest_futures) # Dumps reference versions ABI and API for future in as_completed(build_futures): version, path = future.result() dumps_library(version, path, dump_futures) # Waits for latest version dump completion for future in as_completed(latest_futures): _, dump_file, name = future.result() latest_dumps[name] = dump_file # Compare latest ABI / API dumps with reference versions for future in as_completed(dump_futures): version, dump_file, name = future.result() reports[' '.join((name, version))] = executor.submit( checks_abi_compliance, old_dump=dump_file, new_dump=latest_dumps[name], name=name, report_path=str(tmpdir.join('%s%s.html' % (name, version)))) # Analyses reports abi_broken = False for title, future in reports.items(): report = future.result() if ('Total binary compatibility problems: 0' not in report or 'Total source compatibility problems: 0,' not in report): abi_broken = True print('Comparison against %s:\n%s\n' % (title, report)) assert not abi_broken
def test_systemd(conf_json, cred_json, tmpdir): """Test Accelize DRM systemd service""" perform_once(__name__ + '.test_systemd') from os import environ from socket import socket, AF_UNIX, SOCK_DGRAM from threading import Thread from time import sleep, time import accelize_drm._systemd as systemd from accelize_drm._systemd import AccelizeDrmService # Set FPGA slot fpga_slot_id = 1 # Set configuration files conf_env_var = 'ACCELIZE_DRM_CONF_%s' % fpga_slot_id cred_env_var = 'ACCELIZE_DRM_CRED_%s' % fpga_slot_id conf_file_path = conf_json.path cred_file_path = cred_json.path environ[conf_env_var] = conf_file_path environ[cred_env_var] = cred_file_path default_conf_file_path = AccelizeDrmService.DEFAULT_CONF_FILE_PATH default_cred_file_path = AccelizeDrmService.DEFAULT_CRED_FILE_PATH # Set FPGA driver to use in configuration driver_env_var = 'ACCELIZE_DRM_DRIVER_%s' % fpga_slot_id fpga_driver_name = 'driver_name' environ[driver_env_var] = fpga_driver_name # Mock systemd notify socket socket_file = tmpdir.join('sd_notify') socket_address = environ['NOTIFY_SOCKET'] = str(socket_file) socket_received = [] socket_stop = False class SdNotifySocketThread(Thread): """A thread running a UDP socket server""" def run(self): """Create a connection""" with socket(AF_UNIX, SOCK_DGRAM) as sock: sock.bind(socket_address) sock.setblocking(False) t0 = time() while True: # Stop loop if socket_stop: break # Timeout to stop test if something is wrong elif time() - t0 > 20: raise TimeoutError() # Wait until error try: socket_received.append(sock.recv(4096)) except OSError: continue # Mock driver and DRM library class Driver: """Mocked accelize_drm.fpga_drivers Driver""" def __init__(self, **kwargs): assert kwargs['fpga_slot_id'] == int(fpga_slot_id), \ "Driver: Slot ID" assert 'drm_ctrl_base_addr' in kwargs, "Driver: Base address" read_register_callback = None write_register_callback = None def _get_driver(name): """Mocked accelize_drm.fpga_drivers.get_driver""" assert name == fpga_driver_name, 'Get driver: Driver name' return Driver class DrmManager: """Mocked accelize_drm.fpga_drivers Driver""" def __init__(self, **kwargs): assert kwargs['conf_file_path'] == conf_file_path, \ 'DRM manager: conf.json' assert kwargs['cred_file_path'] == cred_file_path, \ 'DRM manager: cred.json' assert 'read_register' in kwargs, 'DRM manager: read_register' assert 'write_register' in kwargs, 'DRM manager: write_register' @staticmethod def activate(): """Do nothing""" @staticmethod def deactivate(): """Do nothing""" @staticmethod def set(*_, **__): """Do nothing""" systemd_get_driver = systemd._get_driver systemd._get_driver = _get_driver systemd_drm_manager = systemd._DrmManager systemd._DrmManager = DrmManager # Tests try: sd_notify_thread = SdNotifySocketThread() try: sd_notify_thread.start() # Test: Start and stop service with AccelizeDrmService() as service: # Checks some parameters assert service._sd_notify_address == socket_address assert list(service._fpga_slots) == [fpga_slot_id] assert service._fpga_slots[fpga_slot_id][ 'conf_file_path'] == conf_json.path assert service._fpga_slots[fpga_slot_id][ 'cred_file_path'] == cred_json.path assert service._fpga_slots[fpga_slot_id][ 'fpga_driver_name'] == fpga_driver_name # Test: systemd notification sleep(0.1) assert socket_received[0].startswith(b'READY=1\nSTATUS=') assert socket_received[-1].startswith(b"STOPPING=1") # Test: Bad path and error handling environ[conf_env_var] = str(tmpdir.join('not_exists')) with pytest.raises(KeyboardInterrupt): AccelizeDrmService() sleep(0.1) assert socket_received[-1].startswith(b"STATUS=Error") finally: socket_stop = True sd_notify_thread.join() del environ['NOTIFY_SOCKET'] environ[conf_env_var] = conf_json.path socket_file.remove() # Test: Socket address starting by @ fake_address = tmpdir.join('sd_notify_not_exists') environ['NOTIFY_SOCKET'] = '@%s' % fake_address try: assert AccelizeDrmService._get_sd_notify_socket() == \ '\0%s' % fake_address finally: del environ['NOTIFY_SOCKET'] # Test: Broken socket should not break service AccelizeDrmService() # Test: Default values for key in (conf_env_var, cred_env_var, driver_env_var): del environ[key] fpga_slot_id = AccelizeDrmService.DEFAULT_FPGA_SLOT_ID fpga_driver_name = AccelizeDrmService.DEFAULT_FPGA_DRIVER_NAME AccelizeDrmService.DEFAULT_CONF_FILE_PATH = conf_file_path AccelizeDrmService.DEFAULT_CRED_FILE_PATH = cred_file_path with AccelizeDrmService() as service: # Checks some parameters assert list(service._fpga_slots) == [fpga_slot_id] assert service._fpga_slots[fpga_slot_id] == {} except KeyboardInterrupt: pytest.fail('Service stopped by "KeyboardInterrupt"') finally: systemd._get_driver = systemd_get_driver systemd._DrmManager = systemd_drm_manager AccelizeDrmService.DEFAULT_CONF_FILE_PATH = default_conf_file_path AccelizeDrmService.DEFAULT_CRED_FILE_PATH = default_cred_file_path
def test_abi_compliance(tmpdir, accelize_drm): """ Test the ABI/API compliance of the lib_name. """ if not accelize_drm.pytest_build_environment: pytest.skip('This test is only performed on build environment.') elif not accelize_drm.pytest_build_type == 'debug': pytest.xfail('This test needs libraries compiled in debug mode.') elif not check_dump_abi(): pytest.xfail( 'This test cannot be performed because ABI-Dumper app is not usable.' ) perform_once(__name__ + '.test_abi_compliance') # Initialize test from concurrent.futures import ThreadPoolExecutor, as_completed build_tag_futures = [] dump_tag_futures = [] dump_current_futures = [] current_dumps = {} reports = {} with ThreadPoolExecutor() as executor: def dumps_library(lib_version, lib_path, futures): """ Dumps a version asynchronously. Args: lib_version (str): version. lib_path (str): Library directory. futures (list): Future list. """ include = join(lib_path, 'include') for lib_name in LIB_NAMES: futures.append( executor.submit( dump_abi, str( tmpdir.join('%s_%s.abidump' % (lib_name, lib_version))), join(lib_path, '%s.so' % lib_name), include, lib_version, lib_name)) # Get reference versions abi_version = accelize_drm.get_api_version().major versions = executor.submit(get_reference_versions, tmpdir, abi_version) # Build reference versions versions = versions.result() if not versions: pytest.skip('No previous versions with ABI version %s' % abi_version) print('CHECKING ABI/API AGAINST VERSIONS:', ', '.join(versions)) # Close each tag with the same major version for version, path in versions.items(): build_tag_futures.append( executor.submit(build_tag_version, version, path)) # Dump current version ABI and API dumps_library('current', '.', dump_current_futures) # Dumps reference versions ABI and API for future in as_completed(build_tag_futures): version, path = future.result() dumps_library(version, path, dump_tag_futures) # Waits for current version dump completion for future in as_completed(dump_current_futures): _, dump_file, name = future.result() current_dumps[name] = dump_file # Compare current ABI / API dumps with reference versions for future in as_completed(dump_tag_futures): version, dump_file, name = future.result() report_file = join(accelize_drm.pytest_artifacts_dir, '%s%s.html' % (name, version)) reports[' '.join( (name, version))] = (report_file, executor.submit(checks_abi_compliance, old_dump=dump_file, new_dump=current_dumps[name], name=name, report_path=report_file)) # Analyses reports abi_broken = False for title, (report_file, future) in reports.items(): stdout = future.result() if ('Total binary compatibility problems: 0' not in stdout or 'Total source compatibility problems: 0,' not in stdout): print('Comparison against %s shows issues:\n%s\n' % (title, stdout)) abi_broken = True else: print('Comparison against %s shows no issue:\n%s\n' % (title, stdout)) assert not abi_broken
def test_changelog_and_version(accelize_drm): """ Checks if Version match with Git tag and if changelog is up to date. """ perform_once(__name__ + '.test_changelog_and_version') from os.path import join from subprocess import run, PIPE from re import fullmatch if not accelize_drm.pytest_build_environment: pytest.skip("Can only be checked in build environment") # Ensure tags are pulled try: run(['git', 'fetch', '--tags', '--force'], stderr=PIPE, stdout=PIPE, universal_newlines=True) except FileNotFoundError: fail = (pytest.fail if accelize_drm.pytest_build_type == 'debug' else pytest.xfail) fail('Git is required for this test.') # Get head tag if any result = run( ['git', 'describe', '--abbrev=0', '--exact-match', '--tags', 'HEAD'], stderr=PIPE, stdout=PIPE, universal_newlines=True) if result.returncode: pytest.skip("Can only be checked on tagged git head") tag = result.stdout.strip() version = tag.lstrip('v') # Checks tag format using library version lib_ver = accelize_drm.get_api_version() assert tag == 'v%s' % (lib_ver.version.split('+')[0]) # Check tag format match semantic versioning if not fullmatch( r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)' r'(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)' r'(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?' r'(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$', version): pytest.fail('"%s" does not match semantic versioning format.' % version) # Check if changelog is up-to-date (Not for prereleases) if not lib_ver.prerelease: changelog_path = join(accelize_drm.pytest_build_source_dir, 'CHANGELOG') with open(changelog_path, 'rt') as changelog: last_change = changelog.readline().strip() assert fullmatch( r"\* [a-zA-Z]{3} [a-zA-Z]{3} [0-9]{2} [0-9]{4} Accelize " + tag, last_change) # Check prerelease format: # Alpha: "1.0.0-alpha.1" # Beta: "1.0.0-beta.1" # Release candidate: "1.0.0-rc.1" else: assert fullmatch(r"(alpha|beta|rc)\.[0-9]+", lib_ver.prerelease)