diff --git a/cron/client.py b/cron/client.py index 3a40904e0..fa0d24d6d 100644 --- a/cron/client.py +++ b/cron/client.py @@ -10,7 +10,6 @@ import subprocess import json import argparse -from pathlib import Path from lib.job.base import Job from lib.global_config import GlobalConfig @@ -75,7 +74,7 @@ def do_cleanup(cur_temp, cooldown_time_after_job): try: parser = argparse.ArgumentParser() parser.add_argument('--testing', action='store_true', help='End after processing one run for testing') - parser.add_argument('--config-override', type=str, help='Override the configuration file with the passed in yml file. Must be located in the same directory as the regular configuration file. Pass in only the name.') + parser.add_argument('--config-override', type=str, help='Override the configuration file with the passed in yml file. Supply full path.') args = parser.parse_args() @@ -84,11 +83,7 @@ def do_cleanup(cur_temp, cooldown_time_after_job): parser.print_help() error_helpers.log_error('Config override file must be a yml file') sys.exit(1) - if not Path(f"{CURRENT_DIR}/../{args.config_override}").is_file(): - parser.print_help() - error_helpers.log_error(f"Could not find config override file on local system. Please double check: {CURRENT_DIR}/../{args.config_override}") - sys.exit(1) - GlobalConfig(config_name=args.config_override) # will create a singleton and subsequent calls will retrieve object with altered default config file + GlobalConfig(config_location=args.config_override) # will create a singleton and subsequent calls will retrieve object with altered default config file config_main = GlobalConfig().config @@ -103,7 +98,8 @@ def do_cleanup(cur_temp, cooldown_time_after_job): job = Job.get_job('run') if job and job.check_job_running(): error_helpers.log_error('Job is still running. This is usually an error case! Continuing for now ...', machine=config_main['machine']['description']) - time.sleep(client_main['sleep_time_no_job']) + if not args.testing: + time.sleep(client_main['sleep_time_no_job']) continue if not args.testing: @@ -120,7 +116,8 @@ def do_cleanup(cur_temp, cooldown_time_after_job): set_status('cooldown', current_temperature, last_cooldown_time) cooldown_time += 60 temperature_errors += 1 - time.sleep(60) + if not args.testing: + time.sleep(60) continue if current_temperature <= (config_main['machine']['base_temperature_value'] - 5): @@ -161,7 +158,8 @@ def do_cleanup(cur_temp, cooldown_time_after_job): # the process will now go to sleep for 'time_between_control_workload_validations'' # This is as long as the next validation is needed and thus it will loop # endlessly in validation until manually handled, which is what we want. - time.sleep(client_main['time_between_control_workload_validations']) + if not args.testing: + time.sleep(client_main['time_between_control_workload_validations']) finally: do_cleanup(current_temperature, last_cooldown_time) @@ -174,10 +172,12 @@ def do_cleanup(cur_temp, cooldown_time_after_job): set_status('job_error', current_temperature, last_cooldown_time, data=str(exc), run_id=job._run_id) if exc.status == Status.WARN: # Warnings is something like CPU% too high. Here short sleep error_helpers.log_error('Job processing in cluster failed (client.py)', exception=exc, status=exc.status, run_id=job._run_id, name=job._name, url=job._url, machine=config_main['machine']['description'], sleep_duration=600) - time.sleep(600) + if not args.testing: + time.sleep(600) else: # Hard fails won't resolve on it's own. We sleep until next cluster validation error_helpers.log_error('Job processing in cluster failed (client.py)', exception=exc, status=exc.status, run_id=job._run_id, name=job._name, url=job._url, machine=config_main['machine']['description'], sleep_duration=client_main['time_between_control_workload_validations']) - time.sleep(client_main['time_between_control_workload_validations']) + if not args.testing: + time.sleep(client_main['time_between_control_workload_validations']) except subprocess.CalledProcessError as exc: set_status('job_error', current_temperature, last_cooldown_time, data=str(exc), run_id=job._run_id) @@ -194,7 +194,8 @@ def do_cleanup(cur_temp, cooldown_time_after_job): set_status('job_no', current_temperature, last_cooldown_time) if client_main['shutdown_on_job_no'] is True: subprocess.check_output(['sudo', 'systemctl', 'suspend']) - time.sleep(client_main['sleep_time_no_job']) + if not args.testing: + time.sleep(client_main['sleep_time_no_job']) if args.testing: print('Successfully ended testing run of client.py') break diff --git a/cron/jobs.py b/cron/jobs.py index f75e93e08..094aeabf3 100644 --- a/cron/jobs.py +++ b/cron/jobs.py @@ -8,7 +8,6 @@ import os from datetime import datetime import argparse -from pathlib import Path CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -33,7 +32,7 @@ try: parser = argparse.ArgumentParser() parser.add_argument('type', help='Select the operation mode.', choices=['email', 'run']) - parser.add_argument('--config-override', type=str, help='Override the configuration file with the passed in yml file. Must be located in the same directory as the regular configuration file. Pass in only the name.') + parser.add_argument('--config-override', type=str, help='Override the configuration file with the passed in yml file. Supply full path.') parser.add_argument('--skip-system-checks', action='store_true', default=False, help='Skip system checks') parser.add_argument('--full-docker-prune', action='store_true', default=False, help='Prune all images and build caches on the system') parser.add_argument('--docker-prune', action='store_true', help='Prune all unassociated build caches, networks volumes and stopped containers on the system') @@ -48,12 +47,7 @@ parser.print_help() error_helpers.log_error('Config override file must be a yml file') sys.exit(1) - if not Path(f"{CURRENT_DIR}/../{args.config_override}").is_file(): - parser.print_help() - error_helpers.log_error(f"Could not find config override file on local system.\ - Please double check: {CURRENT_DIR}/../{args.config_override}") - sys.exit(1) - GlobalConfig(config_name=args.config_override) + GlobalConfig(config_location=args.config_override) job_main = Job.get_job(args.type) if not job_main: diff --git a/lib/global_config.py b/lib/global_config.py index 3ccc9ef20..081b90f01 100644 --- a/lib/global_config.py +++ b/lib/global_config.py @@ -1,26 +1,55 @@ import os import yaml +class FrozenDict(dict): + def __setattr__(self, key, value): + raise TypeError("GlobalConfig is immutable once loaded! (__setattr__)") + + def __setitem__(self, key, value): + raise TypeError("GlobalConfig is immutable once loaded! (__setitem__)") + + def __delitem__(self, key): + raise TypeError("GlobalConfig is immutable once loaded! (__delitem__)") + + def update(self, *args, **kwargs): + raise TypeError("GlobalConfig is immutable once loaded! (update)") + + def setdefault(self, *args, **kwargs): + raise TypeError("GlobalConfig is immutable once loaded! (setdefault)") + +# Function to recursively freeze nested dictionaries +def freeze_dict(d): + if isinstance(d, dict): + # Convert nested dicts to FrozenDict + return FrozenDict({k: freeze_dict(v) for k, v in d.items()}) + if isinstance(d, list): + # Convert lists to tuples (to make them immutable) + return tuple(freeze_dict(item) for item in d) + if not hasattr(d, '__class__') and isinstance(d, object): # hasattr __class__ separates actual defined classes from builtins like str + raise RuntimeError(f"GlobalConfig received object of type {type(d)} in it's config initalization. This is not expected and leads to issues as it cannot be made immutable!") + + # Return the object itself if not a dict or list + return d + class GlobalConfig: # for unknown reasons pylint needs this argument set, although we don't use it. Only in __init__ # pylint: disable=unused-argument - def __new__(cls, config_name='config.yml'): + def __new__(cls, config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../config.yml"): if not hasattr(cls, 'instance'): cls.instance = super(GlobalConfig, cls).__new__(cls) return cls.instance - def __init__(self, config_name='config.yml'): + def __init__(self, config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../config.yml"): if not hasattr(self, 'config'): - path = os.path.dirname(os.path.realpath(__file__)) - with open(f"{path}/../{config_name}", encoding='utf8') as config_file: - self.config = yaml.load(config_file, yaml.FullLoader) + with open(config_location, encoding='utf8') as config_file: + self.config = freeze_dict(yaml.load(config_file, yaml.FullLoader)) + ## add an override function that will always set the config to a new value - def override_config(self, config_name='config.yml'): - path = os.path.dirname(os.path.realpath(__file__)) - with open(f"{path}/../{config_name}", encoding='utf8') as config_file: - self.config = yaml.load(config_file, yaml.FullLoader) + def override_config(self, config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../config.yml"): + with open(config_location, encoding='utf8') as config_file: + self.config = freeze_dict(yaml.load(config_file, yaml.FullLoader)) if __name__ == '__main__': diff --git a/runner.py b/runner.py index 0ee49e89e..2786510db 100755 --- a/runner.py +++ b/runner.py @@ -507,18 +507,24 @@ def import_metric_providers(self): module_path = f"metric_providers.{module_path}" conf = metric_providers[metric_provider] or {} - if rootless and '.cgroup.' in module_path: - conf['rootless'] = True + print(f"Importing {class_name} from {module_path}") + module = importlib.import_module(module_path) - if self._skip_system_checks: - conf['skip_check'] = True + if rootless and '.cgroup.' in module_path and self._skip_system_checks: + metric_provider_obj = getattr(module, class_name)(**conf, rootless=True, skip_check=True) + print(f"Configuration is {conf}; rootless=true, skip_check=True") + elif rootless and '.cgroup.' in module_path: + metric_provider_obj = getattr(module, class_name)(**conf, rootless=True) + print(f"Configuration is {conf}; rootless=true") + elif self._skip_system_checks: + metric_provider_obj = getattr(module, class_name)(**conf, skip_check=True) + print(f"Configuration is {conf}; skip_check=true") + else: + metric_provider_obj = getattr(module, class_name)(**conf) + print(f"Configuration is {conf}") - print(f"Importing {class_name} from {module_path}") - print(f"Configuration is {conf}") - module = importlib.import_module(module_path) - metric_provider_obj = getattr(module, class_name)(**conf) self.__metric_providers.append(metric_provider_obj) @@ -1641,7 +1647,7 @@ def run(self): parser.add_argument('--branch', type=str, help='Optionally specify the git branch when targeting a git repository') parser.add_argument('--name', type=str, help='A name which will be stored to the database to discern this run from others') parser.add_argument('--filename', type=str, default='usage_scenario.yml', help='An optional alternative filename if you do not want to use "usage_scenario.yml"') - parser.add_argument('--config-override', type=str, help='Override the configuration file with the passed in yml file. Must be located in the same directory as the regular configuration file. Pass in only the name.') + parser.add_argument('--config-override', type=str, help='Override the configuration file with the passed in yml file. Supply full path.') parser.add_argument('--file-cleanup', action='store_true', help='Delete all temporary files that the runner produced') parser.add_argument('--debug', action='store_true', help='Activate steppable debug mode') parser.add_argument('--allow-unsafe', action='store_true', help='Activate unsafe volume bindings, ports and complex environment vars') @@ -1699,11 +1705,7 @@ def run(self): parser.print_help() error_helpers.log_error('Config override file must be a yml file') sys.exit(1) - if not Path(f"{CURRENT_DIR}/{args.config_override}").is_file(): - parser.print_help() - error_helpers.log_error(f"Could not find config override file on local system. Please double check: {CURRENT_DIR}/{args.config_override}") - sys.exit(1) - GlobalConfig(config_name=args.config_override) + GlobalConfig(config_location=args.config_override) runner = Runner(name=args.name, uri=args.uri, uri_type=run_type, filename=args.filename, branch=args.branch, debug_mode=args.debug, allow_unsafe=args.allow_unsafe, diff --git a/tests/api/test_api.py b/tests/api/test_api.py index e0dccdcaa..c310b5cf0 100644 --- a/tests/api/test_api.py +++ b/tests/api/test_api.py @@ -12,7 +12,7 @@ from lib.global_config import GlobalConfig from tests import test_functions as Tests -config = GlobalConfig(config_name='test-config.yml').config +config = GlobalConfig(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml").config API_URL = config['cluster']['api_url'] from api.main import Software diff --git a/tests/conftest.py b/tests/conftest.py index 667c60390..13132d2a4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,12 @@ import pytest +import os from tests import test_functions as Tests ## VERY IMPORTANT to override the config file here ## otherwise it will automatically connect to non-test DB and delete all your real data from lib.global_config import GlobalConfig -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") def pytest_collection_modifyitems(items): for item in items: diff --git a/tests/cron/test_client.py b/tests/cron/test_client.py index 0c69eefaa..c1d0b925d 100644 --- a/tests/cron/test_client.py +++ b/tests/cron/test_client.py @@ -8,7 +8,7 @@ from lib.job.base import Job from tests import test_functions as Tests -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml") config = GlobalConfig().config def test_simple_cluster_run(): @@ -21,7 +21,7 @@ def test_simple_cluster_run(): Job.insert('run', user_id=1, name=name, url=url, email=None, branch=branch, filename=filename, machine_id=machine_id) ps = subprocess.run( - ['python3', '../cron/client.py', '--testing', '--config-override', 'test-config.yml'], + ['python3', '../cron/client.py', '--testing', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, diff --git a/tests/cron/test_jobs.py b/tests/cron/test_jobs.py index f3f57a0b9..d1c8d174a 100644 --- a/tests/cron/test_jobs.py +++ b/tests/cron/test_jobs.py @@ -13,7 +13,7 @@ from lib.user import User from tests import test_functions as Tests -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml") config = GlobalConfig().config # This should be done once per module @@ -38,7 +38,7 @@ def get_job(job_id): def test_no_run_job(): ps = subprocess.run( - ['python3', '../cron/jobs.py', 'run', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'run', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -50,7 +50,7 @@ def test_no_run_job(): def test_no_email_job(): ps = subprocess.run( - ['python3', '../cron/jobs.py', 'email', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'email', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -81,7 +81,7 @@ def test_simple_run_job_no_quota(): Job.insert('run', user_id=1, name=name, url=url, email=None, branch=branch, filename=filename, machine_id=machine_id) ps = subprocess.run( - ['python3', '../cron/jobs.py', 'run', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'run', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -108,7 +108,7 @@ def test_simple_run_job_quota_gets_deducted(): user.update() ps = subprocess.run( - ['python3', '../cron/jobs.py', 'run', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'run', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -156,7 +156,7 @@ def test_measurement_quota_exhausted(): user.deduct_measurement_quota(machine_id=machine_id, amount=2678400) ps = subprocess.run( - ['python3', '../cron/jobs.py', 'run', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'run', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -178,7 +178,7 @@ def test_machine_not_allowed(): user.update() ps = subprocess.run( - ['python3', '../cron/jobs.py', 'run', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'run', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -208,7 +208,7 @@ def todo_test_simple_email_job(): # Why is this patch not working :-( with patch('email_helpers.send_email') as send_email: ps = subprocess.run( - ['python3', '../cron/jobs.py', 'email', '--config-override', 'test-config.yml'], + ['python3', '../cron/jobs.py', 'email', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml"], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, diff --git a/tests/lib/test_diff.py b/tests/lib/test_diff.py index 6872f5b62..ca4c31a1b 100644 --- a/tests/lib/test_diff.py +++ b/tests/lib/test_diff.py @@ -1,8 +1,9 @@ +import os from lib.db import DB from lib.global_config import GlobalConfig from tests import test_functions as Tests -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml") config = GlobalConfig().config diff --git a/tests/metric_providers/test_metric_providers.py b/tests/metric_providers/test_metric_providers.py index a12034098..f8ebc9b76 100644 --- a/tests/metric_providers/test_metric_providers.py +++ b/tests/metric_providers/test_metric_providers.py @@ -15,7 +15,7 @@ from tools.phase_stats import build_and_store_phase_stats -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/../test-config.yml") config = GlobalConfig().config # override per test cleanup, as the module setup requires writing to DB @@ -30,7 +30,7 @@ def cleanup_after_module(): Tests.reset_db() run_id = None -MB = 1024*1024 +MB = 1000*1000 # Note: GMT uses SI Units! # Runs once per file before any test( #pylint: disable=expression-not-assigned @@ -64,6 +64,8 @@ def mock_temporary_network_file(file_path, temp_file, actual_network_interface): file.write(modified_contents) def test_splitting_by_group(): + if utils.get_architecture() == 'macos': + return obj = NetworkIoProcfsSystemProvider(100, remove_virtual_interfaces=False) @@ -137,7 +139,7 @@ def test_network_providers(): if metric == 'network_total_procfs_system': # Some small network overhead to a 5 MB file always occurs - assert 5*MB <= val < 5.5*MB , f"network_total_procfs_system is not between 5 and 5.5 MB but {metric_provider['value']} {metric_provider['unit']}" + assert 5*MB <= val < 5.6*MB , f"network_total_procfs_system is not between 5 and 5.6 MB but {metric_provider['value']} {metric_provider['unit']}" seen_network_total_procfs_system = True assert seen_network_total_procfs_system is True @@ -175,8 +177,8 @@ def test_cpu_memory_carbon_providers(): seen_cpu_utilization = True elif metric == 'cpu_utilization_mach_system': # macOS values do not get as high due to the VM. - assert 5500 < val <= 10000 , f"cpu_utilization_mach_system is not between 90_00 and 100_00 but {metric_provider['value']} {metric_provider['unit']}" - assert 8000 < max_value <= 10500 , f"cpu_utilization_mach_system max is not between 95_00 and 105_00 but {metric_provider['value']} {metric_provider['unit']}" + assert 5000 < val <= 10000 , f"cpu_utilization_mach_system is not between 50_00 and 100_00 but {metric_provider['value']} {metric_provider['unit']}" + assert 8000 < max_value <= 10500 , f"cpu_utilization_mach_system max is not between 80_00 and 105_00 but {metric_provider['value']} {metric_provider['unit']}" seen_cpu_utilization = True diff --git a/tests/setup-test-env.py b/tests/setup-test-env.py index d165131ed..ed7bd0a3b 100644 --- a/tests/setup-test-env.py +++ b/tests/setup-test-env.py @@ -76,7 +76,7 @@ def edit_compose_file(): # for nginx and gunicorn services, add test config mapping if 'nginx' in service or 'gunicorn' in service: new_vol_list.append( - f'{current_dir}/../test-config.yml:/var/www/green-metrics-tool/config.yml') + f'{current_dir}/test-config.yml:/var/www/green-metrics-tool/config.yml') compose['services'][service]['volumes'] = new_vol_list # For postgresql, change password diff --git a/tests/smoke_test.py b/tests/smoke_test.py index a6c4c4371..09aedf62b 100644 --- a/tests/smoke_test.py +++ b/tests/smoke_test.py @@ -36,7 +36,7 @@ def cleanup_after_module(): def setup_module(module): out = io.StringIO() err = io.StringIO() - GlobalConfig(config_name='test-config.yml').config + GlobalConfig(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml").config with redirect_stdout(out), redirect_stderr(err): folder = 'tests/data/stress-application/' filename = 'usage_scenario.yml' @@ -79,7 +79,7 @@ def test_db_rows_are_written_and_presented(): data = DB().fetch_all(query, (run_id,)) assert(data is not None and data != []) - config = GlobalConfig(config_name='test-config.yml').config + config = GlobalConfig(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml").config metric_providers = utils.get_metric_providers_names(config) # The network connection proxy provider writes to a different table so we need to remove it here diff --git a/tests/test-config-duplicate-psu-providers.yml b/tests/test-config-duplicate-psu-providers.yml new file mode 100644 index 000000000..a74f7c8c7 --- /dev/null +++ b/tests/test-config-duplicate-psu-providers.yml @@ -0,0 +1,107 @@ +postgresql: + host: test-green-coding-postgres-container + user: postgres + dbname: test-green-coding + password: testpw + port: 9573 + +redis: + host: test-green-coding-redis-container + +smtp: + server: null + sender: null + port: null + password: null + user: null + +admin: + notification_email: False + error_file: False + error_email: False + email_bcc: False + +cluster: + api_url: http://api.green-coding.internal:9142 + metrics_url: http://metrics.green-coding.internal:9142 + cors_allowed_origins: + - http://api.green-coding.internal:9142 + - http://metrics.green-coding.internal:9142 + client: + sleep_time_no_job: 300 + jobs_processing: random + time_between_control_workload_validations: 21600 + send_control_workload_status_mail: false + shutdown_on_job_no: false + control_workload: + name: Measurement control Workload + uri: https://github.com/green-coding-solutions/measurement-control-workload + filename: usage_scenario.yml + branch: main + comparison_window: 5 + threshold: 0.01 + phase: 004_[RUNTIME] + metrics: + - psu_energy_ac_mcp_machine + - psu_power_ac_mcp_machine + - cpu_power_rapl_msr_component + - cpu_energy_rapl_msr_component + +machine: + id: 1 + description: Development machine for testing + base_temperature_value: 10 + base_temperature_chip: "asd" + base_temperature_feature: "asd" + +measurement: + system_check_threshold: 3 + pre-test-sleep: 0 + idle-duration: 0 + baseline-duration: 0 + flow-process-duration: 1800 # half hour + total-duration: 3600 # one hour + post-test-sleep: 0 + phase-transition-time: 0 + boot: + wait_time_dependencies: 10 + metric-providers: + linux: + cpu.utilization.procfs.system.provider.CpuUtilizationProcfsSystemProvider: + resolution: 99 +# disk.io.procfs.system.provider.DiskIoProcfsSystemProvider: +# resolution: 99 + network.io.procfs.system.provider.NetworkIoProcfsSystemProvider: + resolution: 99 + remove_virtual_interfaces: True + disk.used.statvfs.system.provider.DiskUsedStatvfsSystemProvider: + resolution: 99 + memory.used.procfs.system.provider.MemoryUsedProcfsSystemProvider: + resolution: 99 + macos: + cpu.utilization.mach.system.provider.CpuUtilizationMachSystemProvider: + resolution: 99 + common: + psu.energy.ac.bar.machine.provider.SomeOtherProvider': + resolution: 99 + psu.energy.ac.xgboost.machine.provider.PsuEnergyAcXgboostMachineProvider: + resolution: 99 + CPUChips: 1 + HW_CPUFreq: 3200 + CPUCores: 4 + CPUThreads: 4 + TDP: 65 + HW_MemAmountGB: 16 + Hardware_Availability_Year: 2011 + +sci: + EL: 4 + RS: 1 + TE: 181000 + I: 436 + +optimization: + ignore: + - example_optimization_test + +electricity_maps_token: 'testing' diff --git a/test-config.yml b/tests/test-config.yml similarity index 100% rename from test-config.yml rename to tests/test-config.yml diff --git a/tests/test_config_opts.py b/tests/test_config_opts.py index abc5556df..7390a9242 100644 --- a/tests/test_config_opts.py +++ b/tests/test_config_opts.py @@ -12,7 +12,7 @@ from runner import Runner -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") def test_global_timeout(): diff --git a/tests/test_runner.py b/tests/test_runner.py index a67a0035d..bef66a209 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -11,32 +11,24 @@ GMT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../') -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") test_data = [ - (True, does_not_raise()), - (False, pytest.raises(ConfigurationCheckError)), + (True, f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", does_not_raise()), + (False, f"{os.path.dirname(os.path.realpath(__file__))}/test-config-duplicate-psu-providers.yml", pytest.raises(ConfigurationCheckError)), ] -@pytest.mark.parametrize("skip_system_checks,expectation", test_data) -def test_check_system(skip_system_checks, expectation): - runner = Runner(uri="not_relevant", uri_type="folder", skip_system_checks=skip_system_checks) +@pytest.mark.parametrize("skip_system_checks,config_file,expectation", test_data) +def test_check_system(skip_system_checks, config_file, expectation): - if GlobalConfig().config['measurement']['metric-providers']['common'] is None: - GlobalConfig().config['measurement']['metric-providers']['common'] = {} + GlobalConfig().override_config(config_location=config_file) + runner = Runner(uri="not_relevant", uri_type="folder", skip_system_checks=skip_system_checks) - GlobalConfig().config['measurement']['metric-providers']['common']['psu.energy.ac.foo.machine.provider.SomeProvider'] = { - 'key': 'value' - } - GlobalConfig().config['measurement']['metric-providers']['common']['psu.energy.ac.bar.machine.provider.SomeOtherProvider'] = { - 'key': 'value' - } try: with expectation: runner.check_system() finally: - del GlobalConfig().config['measurement']['metric-providers']['common']['psu.energy.ac.foo.machine.provider.SomeProvider'] - del GlobalConfig().config['measurement']['metric-providers']['common']['psu.energy.ac.bar.machine.provider.SomeOtherProvider'] + GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") # reset def test_reporters_still_running(): runner = Runner(uri=GMT_DIR, uri_type='folder', filename='tests/data/usage_scenarios/basic_stress.yml', skip_system_checks=False, dev_no_build=True, dev_no_sleeps=True, dev_no_metrics=False) diff --git a/tests/test_usage_scenario.py b/tests/test_usage_scenario.py index 1fcb962b5..c3beb78b5 100644 --- a/tests/test_usage_scenario.py +++ b/tests/test_usage_scenario.py @@ -20,7 +20,7 @@ from runner import Runner from lib.schema_checker import SchemaError -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") config = GlobalConfig().config ## Note: @@ -524,7 +524,7 @@ def test_uri_local_dir(): run_name = 'test_' + utils.randomword(12) filename = 'tests/data/stress-application/usage_scenario.yml' ps = subprocess.run( - ['python3', '../runner.py', '--name', run_name, '--uri', GMT_DIR ,'--config-override', 'test-config.yml', + ['python3', '../runner.py', '--name', run_name, '--uri', GMT_DIR ,'--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--filename', filename, '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], check=True, @@ -557,7 +557,7 @@ def test_uri_github_repo(): filename = 'usage_scenario.yml' run_name = 'test_' + utils.randomword(12) ps = subprocess.run( - ['python3', '../runner.py', '--name', run_name, '--uri', uri ,'--config-override', 'test-config.yml', + ['python3', '../runner.py', '--name', run_name, '--uri', uri ,'--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], check=True, stderr=subprocess.PIPE, @@ -594,7 +594,7 @@ def test_uri_github_repo_branch(): ps = subprocess.run( ['python3', '../runner.py', '--name', run_name, '--uri', uri , '--branch', branch , '--filename', 'basic_stress.yml', - '--config-override', 'test-config.yml', '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], + '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -624,7 +624,7 @@ def test_name_is_in_db(): subprocess.run( ['python3', '../runner.py', '--name', run_name, '--uri', GMT_DIR , '--filename', 'tests/data/stress-application/usage_scenario.yml', - '--config-override', 'test-config.yml', + '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--skip-system-checks', '--dev-no-metrics', '--dev-no-optimizations', '--dev-no-sleeps', '--dev-no-build'], check=True, stderr=subprocess.PIPE, @@ -640,7 +640,7 @@ def test_name_is_in_db(): def test_different_filename(): run_name = 'test_' + utils.randomword(12) ps = subprocess.run( - ['python3', '../runner.py', '--name', run_name, '--uri', GMT_DIR , '--filename', 'tests/data/usage_scenarios/basic_stress.yml', '--config-override', 'test-config.yml', + ['python3', '../runner.py', '--name', run_name, '--uri', GMT_DIR , '--filename', 'tests/data/usage_scenarios/basic_stress.yml', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--skip-system-checks', '--dev-no-metrics', '--dev-no-optimizations', '--dev-no-sleeps', '--dev-no-build'], check=True, stderr=subprocess.PIPE, @@ -685,7 +685,7 @@ def test_no_file_cleanup(): def test_file_cleanup(): subprocess.run( ['python3', '../runner.py', '--uri', GMT_DIR , '--filename', 'tests/data/usage_scenarios/basic_stress.yml', - '--file-cleanup', '--config-override', 'test-config.yml', '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], + '--file-cleanup', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], check=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -707,7 +707,7 @@ def test_debug(monkeypatch): ps = subprocess.run( ['python3', '../runner.py', '--uri', GMT_DIR , '--filename', 'tests/data/usage_scenarios/basic_stress.yml', '--debug', - '--config-override', 'test-config.yml', '--skip-system-checks', + '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--skip-system-checks', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], check=True, stderr=subprocess.PIPE, @@ -890,7 +890,7 @@ def wip_test_verbose_provider_boot(): run_name = 'test_' + utils.randomword(12) ps = subprocess.run( ['python3', '../runner.py', '--name', run_name, '--uri', GMT_DIR , - '--verbose-provider-boot', '--config-override', 'test-config.yml', + '--verbose-provider-boot', '--config-override', f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml", '--filename', 'tests/data/stress-application/usage_scenario.yml', '--dev-no-sleeps', '--dev-no-build', '--dev-no-metrics', '--dev-no-optimizations'], check=True, diff --git a/tests/test_volume_loading.py b/tests/test_volume_loading.py index fe001c3d9..ed04b025f 100644 --- a/tests/test_volume_loading.py +++ b/tests/test_volume_loading.py @@ -12,7 +12,7 @@ from lib.global_config import GlobalConfig from runner import Runner -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") def test_volume_load_no_escape(): runner = Runner(uri=GMT_DIR, uri_type='folder', filename='tests/data/usage_scenarios/volume_load_etc_hosts.yml', skip_system_checks=True, dev_no_metrics=True, dev_no_sleeps=True, dev_no_build=False) diff --git a/tests/test_yml_parsing.py b/tests/test_yml_parsing.py index 8d0a24698..20b20db30 100644 --- a/tests/test_yml_parsing.py +++ b/tests/test_yml_parsing.py @@ -7,7 +7,7 @@ from lib.global_config import GlobalConfig from runner import Runner -GlobalConfig().override_config(config_name='test-config.yml') +GlobalConfig().override_config(config_location=f"{os.path.dirname(os.path.realpath(__file__))}/test-config.yml") class TestYML(unittest.TestCase):