diff --git a/pyproject.toml b/pyproject.toml index 91a2c7698..c0126861c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ dev = [ "pytest-cov", "pytest-asyncio", "pytest-httpx>=0.35.0", + "pytest-timeout", "responses", "ruff", "semver", @@ -72,7 +73,7 @@ dev = [ "jwcrypto", "deepdiff", "tiled[minimal-server]>=0.2.4", # For system-test of dls.py - "respx" + "respx", ] [project.scripts] @@ -103,6 +104,7 @@ filterwarnings = ["error", "ignore::DeprecationWarning"] # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" asyncio_mode = "auto" +timeout = 3 [tool.coverage.run] patch = ["subprocess"] @@ -178,6 +180,7 @@ commands = [ "term", "--cov-report", "xml:cov.xml", + "--timeout=60", { replace = "posargs", default = [ ], extend = true }, ], diff --git a/test-output b/test-output new file mode 100644 index 000000000..daad3afa6 --- /dev/null +++ b/test-output @@ -0,0 +1,859 @@ +============================= test session starts ============================== +platform linux -- Python 3.11.9, pytest-9.0.2, pluggy-1.6.0 -- /home/zoheb/workspace/blueapi/.venv/bin/python +cachedir: .pytest_cache +rootdir: /home/zoheb/workspace/blueapi +configfile: pyproject.toml +plugins: anyio-4.12.1, cov-7.0.0, httpx-0.36.0, asyncio-1.3.0, zarr-3.1.5, respx-0.22.0 +asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function +collecting ... collected 844 items + +tests/unit_tests/cli/test_cli.py::test_cli_version PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_main_no_params PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_runs_with_umask_002[serve] PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_runs_with_umask_002[setup-scratch] PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_connection_error_caught_by_wrapper_func PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_authentication_error_caught_by_wrapper_func PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_remote_error_raised_by_wrapper_func PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_get_plans PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_get_devices PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_invalid_config_path_handling PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_options_via_env PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_invalid_config_via_env PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_submit_plan PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_submit_plan_without_stomp PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_run_plan PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result0-False-Plan succeeded\n] PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result1-False-Plan succeeded: 32\n] PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result2-False-Plan returned unserializable result of type 'CustomType'\n] PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result3-True-Plan failed: ValueError: Error with value\n] PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_run_plan_background_without_stomp PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_invalid_stomp_config_for_listener PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_cannot_run_plans_without_stomp_config PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_cannot_start_a_plan_without_an_instrument_session PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_can_pass_an_instrument_session_with_an_environment_variable PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_valid_stomp_config_for_listener PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_get_env PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_get_state PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_reset_env_client_behavior PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_env_timeout PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_env_reload_server_side_error PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[unknown_plan] PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[unauthorised_access] PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[invalid_parameters] PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[remote_control] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_error_handling[value_error] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_run_task_parsing_errors[{-Parameters are not valid JSON] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_run_task_parsing_errors[[]-Parameters must be a JSON object with string keys] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_device_output_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_plan_output_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_event_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_unknown_object_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_dict_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_generic_base_model_formatting PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_init_scratch_calls_setup_scratch PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_success PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_token_login_with_valid_token PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_with_refresh_token PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_when_cached_token_decode_fails PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_with_unauthenticated_server PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_logout_success PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_logout_invalid_token PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_logout_unknown_error PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_logout_when_no_cache PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_local_cache_cleared_on_logout_when_oidc_unavailable PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_wrapper_is_a_directory_error PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_wrapper_permission_error PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_get_python_environment PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_get_python_env_with_empty_response PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_python_env_output_formatting PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_config_schema[True-True] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_config_schema[True-False] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_config_schema[False-True] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_config_schema[False-False] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_task_parameter_type[value0-result0] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_task_parameter_type[{}-result1] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_task_parameter_type[None-None] PASSED [ 7%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_installs_path PASSED [ 7%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_file PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_nonexistant_path PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_non_zero_exit_code[1] PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_non_zero_exit_code[2] PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_non_zero_exit_code[65536] PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_not_cloned_and_validated_if_found_locally PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_cloned_if_not_found_locally PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_cloned_with_correct_umask PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_discovery_errors_if_file_found_with_repo_name PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_cloned_repo_changes_to_new_branch PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_existing_repo_changes_to_existing_branch PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_existing_repo_changes_to_new_branch PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_nonexistant_root PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_non_directory_root PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_non_sgid_root PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_passes_without_required_gid PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_wrong_gid PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_blueapi_included PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_succeeds_on_required_gid SKIPPED to be broken in GH actions at the moment. We should +rewrite these tests to use mocks. + +See +https://github.com/DiamondLightSource/blueapi/issues/770) [ 10%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_iterates_repos PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_continues_after_failure PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_get_python_env_returns_correct_packages PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_fetch_python_env_with_identical_packages PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_fetch_installed_packages_details_returns_correct_packages PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_get_python_env_filters_by_name_and_source PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_get_project_name_from_pyproject_returns_name PASSED [ 11%] +tests/unit_tests/cli/test_scratch.py::test_get_project_name_from_pyproject_returns_empty_if_no_pyproject PASSED [ 11%] +tests/unit_tests/cli/test_scratch.py::test_get_project_name_from_pyproject_returns_empty_if_no_name_key PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_client_from_config PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_plans PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_plan PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_nonexistant_plan PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_devices PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_device PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_nonexistent_device PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_get_child_device PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_state_property PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_get_state PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_active_task_property PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_get_active_task PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_calls_both_creating_and_starting_endpoints PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_fails_if_task_creation_fails PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_fails_if_task_id_is_wrong PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_fails_if_task_start_fails PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_environment_property PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_get_environment PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_no_timeout PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_with_timeout PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_ignores_current_environment PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_failure PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_abort PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_stop PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_pause PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_resume PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_cannot_run_task_without_message_bus PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_sets_up_control PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_fails_on_failing_event PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_calls_event_callback[test_event0] PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_calls_event_callback[test_event1] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_calls_event_callback[test_event2] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_ignores_non_matching_events[test_event0] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_ignores_non_matching_events[test_event1] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_ignores_non_matching_events[test_event2] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_oidc_config_property PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_oidc_config PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_plans_span_ok PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_plan_span_ok PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_devices_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_device_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_state_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_active_task_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_environment_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_reload_environment_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_abort_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_stop_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_pause_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_resume_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_cannot_run_task_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_instrument_session_required PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_setting_instrument_session PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_fluent_instrument_session_setter PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_plan_cache_ignores_underscores PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_plan_cache_repr PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_cache_ignores_underscores PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_devices_are_cached PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_cache_repr PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_repr PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_ignores_underscores PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_help_text PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_fallback_help_text PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_properties PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_empty_fallback_help_text PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[required_as_positional] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[required_as_keyword] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[all_as_mixed_args_kwargs] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[all_as_positional] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[all_as_keyword] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[missing_required] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[duplicate_required] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[duplicate_optional] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[too_many_args] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[unknown_arg] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_adding_removing_callback PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callbacks[test_event0] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callbacks[test_event1] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callbacks[test_event2] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callback_failures PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_login_existing_login PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_new_login PASSED [ 21%] +tests/unit_tests/client/test_client.py::test_client_login_no_oidc PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_context_manager_connects_and_disconnects PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_subscribes_to_all_events PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_unsubscribes_on_context_exit[0] PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_unsubscribes_on_context_exit[1] PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_unsubscribes_on_context_exit[2] PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_raises_streaming_error_on_subscribe_failure PASSED [ 21%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[404-KeyError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[401-BlueskyRemoteControlError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[450-BlueskyRemoteControlError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[500-BlueskyRemoteControlError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[200-None-None] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[401-None-expected_exception1] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[403-None-expected_exception2] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[404-None-expected_exception3] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[422-{\n "detail": [{\n "loc": ["body", "params", "foo"],\n "type": "missing",\n "msg": "missing value for foo",\n "input": {}\n }]\n }-expected_exception4] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[450-non-standard-expected_exception5] PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[500-internal_error-expected_exception6] PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_auth_request_functionality PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_refresh_if_signature_expired PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_field PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_missing_string PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_extra_string PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_other_string PASSED [ 23%] +tests/unit_tests/core/test_context.py::test_add_plan[has_no_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_plan[has_one_param] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_plan[has_some_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_generated_schema PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_generated_schema_with_generic_bounds PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_invalid_plan[has_typeless_param] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_invalid_plan[has_typed_and_typeless_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_invalid_plan[has_typeless_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_plan_from_module PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_only_plans_from_source_module_detected PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_only_plans_from_all_in_module_detected PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_named_device PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_nameless_device PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_nameless_device_without_override PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_override_device_name PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_devices_from_module PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_failing_deivces_from_module PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_extra_kwargs_in_with_dodal_module_passed_to_make_all_devices PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_with_dodal_module_returns_connection_exceptions PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[sim] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[sim_det] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[sim.user_setpoint] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[addr3] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[addr4] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_nonexistent_device PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_nonexistent_device_child PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_lookup_non_device PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_non_plan PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_non_device PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_devices_and_plans_from_modules_with_config PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_metadata_with_config PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_with_config_passes_mock_to_with_dodal_module[True] PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_with_config_passes_mock_to_with_dodal_module[False] PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_function_spec PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_basic_type_conversion PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_device_reference_cache PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_device_reference_cache_with_generics PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_unregister_all_devices PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_generic_reference_type_conversion PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion_union PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion_new_style_union PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion_new_style_optional PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_default_device_reference PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_generic_default_device_reference PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_concrete_type_conversion PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_concrete_method_annotation PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_device_without_protocol_annotation PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_str_default PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_nested_str_default PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_plan_models_not_auto_camelcased PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_generic_bounds_with_generic_base PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_generic_bounds_with_multiple_bases PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_generic_bounds_with_no_bases PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[int-int] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[float-float] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[str-str] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[list-list0] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[list-list1] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[dict-dict] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[CustomClass-core.test_context.CustomClass] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[T-Any] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[GenericClass-core.test_context.GenericClass] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[InnerClass-core.test_context.OuterClass.InnerClass] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_optional_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_overloaded_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_optional_overloaded_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_explicit_none_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_empty_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_single_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_build_error PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_connection_error PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_errors_are_combined PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_mock_passed_to_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_path_provider_passed_to_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_environment_source PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_non_device_manager_errors PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_without_tiled_not_makes_tiled_inserter PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_default_not_makes_tiled_inserter PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_with_tiled_makes_tiled_inserter[None] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_with_tiled_makes_tiled_inserter[foo] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_must_have_instrument_set_for_tiled[None] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_must_have_instrument_set_for_tiled[foo] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_must_have_oidc_config_for_tiled PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_token_url_set_for_tiled PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_publishes_event PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_multi_subscriber PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_can_unsubscribe PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_can_unsubscribe_all PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_correlation_id PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_logout PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_refresh_auth_token PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_no_cache PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_refresh_fails PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_invalid_cache PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_exception_in_decode PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_poll_for_token PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_poll_for_token_timeout PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_server_raises_exception_for_invalid_token PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_processes_valid_token PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_session_cache_manager_returns_writable_file_path PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_tiled_auth_raises_exception PASSED [ 36%] +tests/unit_tests/service/test_authentication.py::test_tiled_auth_sync_auth_flow PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_plans PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_plan PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_devices PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_device PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_submit_task PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_clear_task PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_begin_task PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_begin_task_no_task_id PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_tasks_by_status PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_begin_task_with_headers PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_active_task PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_worker_state PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_pause_worker PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_resume_worker PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_cancel_active_task PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_tasks PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_task_by_id[True] PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_task_by_id[False] PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_submit_task_inserts_metadata PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_remove_tiled_subscriber PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_oidc_config PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_stomp_config PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_stomp_config_makes_no_client_when_disabled PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_scratch_no_config PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_scratch_with_config PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_configure_numtracker PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_headers_are_cleared PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_numtracker_requires_instrument_metadata PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_without_numtracker_with_existing_provider_does_not_overwrite_provider PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_without_numtracker_without_existing_provider_does_not_make_one PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_with_numtracker_makes_start_document_provider PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_with_numtracker_raises_if_provider_is_defined_in_device_module PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_numtracker_create_scan_called_with_arguments_from_metadata PASSED [ 40%] +tests/unit_tests/service/test_interface.py::test_update_scan_num_side_effect_sets_data_session_directory_in_re_md PASSED [ 40%] +tests/unit_tests/service/test_interface.py::test_update_scan_num_side_effect_sets_scan_file_in_re_md PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_log_request_details PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers0-expected_headers0] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers1-expected_headers1] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers2-expected_headers2] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers3-expected_headers3] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers4-expected_headers4] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers5-expected_headers5] PASSED [ 41%] +tests/unit_tests/service/test_openapi.py::test_generate_schema PASSED [ 41%] +tests/unit_tests/service/test_openapi.py::test_schema_updated PASSED [ 41%] +tests/unit_tests/service/test_openapi.py::test_schema_version_bump_required PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_rest_config_with_cors_gets_plan PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_rest_config_with_cors PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_get_plans PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_get_plan_by_name PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_get_non_existent_plan_by_name PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_get_devices PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_get_device_by_name PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_get_non_existent_device_by_name PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_create_task PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_create_task_inserts_auth_metadata PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_create_task_validation_error PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_put_plan_begins_task PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_put_plan_fails_if_not_idle PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_tasks PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_tasks_by_status PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_tasks_by_status_invalid PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_delete_submitted_task PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_set_active_task PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_set_active_task_active_task_complete PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_set_active_task_worker_already_running PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_task PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_all_tasks PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_task_error PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_active_task PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_active_task_none PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_state PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_running_to_paused PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_paused_to_running PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_running_to_aborting PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_running_to_stopping_including_reason PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_set_state_transition_error PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_set_state_invalid_transition PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_environment_idle PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_delete_environment PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_subprocess_enabled_by_default PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_without_authentication PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_oidc_config_not_found_when_auth_is_disabled PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_oidc_config PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_python_environment PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_health_probe PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_logout PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_docs_redirect PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_logout_when_oidc_config_invalid[True] PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_logout_when_oidc_config_invalid[False] PASSED [ 46%] +tests/unit_tests/service/test_runner.py::test_initialize PASSED [ 46%] +tests/unit_tests/service/test_runner.py::test_reload PASSED [ 46%] +tests/unit_tests/service/test_runner.py::test_raises_if_used_before_started PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[None] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[ ] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[Intentional start_worker exception] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_can_reload_after_an_error PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_subprocess_enabled_by_default PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_clear_message_for_anonymous_function PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_function_not_findable_on_subprocess PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_module_not_findable_on_subprocess PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_non_callable_excepts PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_clear_message_for_wrong_return PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_int] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_str] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_list] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_dict] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_simple_model] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_nested_model] PASSED [ 49%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_unbound_generic_model] PASSED [ 49%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_explicitly_bound_generic_model] PASSED [ 49%] +tests/unit_tests/service/test_runner.py::test_run_span_ok PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_defaults[ConfigWithDefaults] PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_defaults[NestedConfigWithDefaults] PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_some_defaults PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_override_all PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_override_all_nested PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_defaultless_schema PASSED [ 50%] +tests/unit_tests/test_config.py::test_inject_values_into_defaultless_schema PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_yaml PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_yaml_nested PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_yaml_override PASSED [ 50%] +tests/unit_tests/test_config.py::test_error_thrown_if_schema_does_not_match_yaml PASSED [ 50%] +tests/unit_tests/test_config.py::test_expand_env_vars PASSED [ 50%] +tests/unit_tests/test_config.py::test_auth_from_env PASSED [ 50%] +tests/unit_tests/test_config.py::test_auth_from_env_repeated_key PASSED [ 51%] +tests/unit_tests/test_config.py::test_auth_from_env_ignore_case PASSED [ 51%] +tests/unit_tests/test_config.py::test_auth_from_env_throws_when_not_available PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed[temp_yaml_config_file0] PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed[temp_yaml_config_file1] PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed_complete[temp_yaml_config_file0] PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed_complete[temp_yaml_config_file1] PASSED [ 51%] +tests/unit_tests/test_config.py::test_raises_validation_error[temp_yaml_config_file0] PASSED [ 51%] +tests/unit_tests/test_config.py::test_oauth_config_model_post_init PASSED [ 52%] +tests/unit_tests/test_config.py::test_extra_fields_are_forbidden_for_application_config PASSED [ 52%] +tests/unit_tests/test_config.py::test_config_schema_updated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_invalid_parameters_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_no_content_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_unauthorised_access_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_unknown_plan_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_missing_stomp_deprecated PASSED [ 52%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[plan_module-plan_names0] PASSED [ 52%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[plan_docstrings-plan_names1] PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[plan_metadata-plan_names2] PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[deferred_plans-plan_names3] PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_example_device_module_is_detectable PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_count_parameter_model_example_is_accurate PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_invalid_plan_args_are_invalid PASSED [ 53%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[stomp.yaml] PASSED [ 53%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[scratch.yaml] PASSED [ 53%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[client_auth.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[client.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[numtracker.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[plan_functions.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[graylog.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[plans_and_devices.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_helm_is_valid[scratch-pv.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_helm_is_valid[scratch-k8s.yaml] PASSED [ 54%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config0] PASSED [ 54%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config1] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config2] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config3] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_init_config_map[values0] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_init_config_map[values1] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_init_container_spec_generated PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_init_container_spec_disablable PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_does_not_render_arbitrary_rabbitmq_password PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_container_gets_container_resources PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[http://0.0.0.0-80] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[http://0.0.0.0:8001-8001] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[https://0.0.0.0-443] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[https://0.0.0.0:9090/path-9090] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[https://0.0.0.0:9000-9000] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[None-8000] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_init_container_gets_container_resources_by_default PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_init_container_resources_overridable PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_worker_scratch_config_used_when_init_container_enabled PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_fluentd_ignore_true_when_graylog_enabled PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_fluentd_ignore_false_when_graylog_disabled PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_exists_conditions[True] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_exists_conditions[False] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-None-True] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-None-False] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-foo-True] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-foo-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-None-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-None-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-foo-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-foo-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-None-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-None-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-foo-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-foo-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-None-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-None-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-foo-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-foo-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-None-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-None-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-foo-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-foo-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-None-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-None-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-foo-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-foo-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-True-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-True-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-False-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-False-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-True-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-True-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-False-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-False-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-True-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-True-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-False-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-False-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-True-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-True-False] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-False-True] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-False-False] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[0] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[1] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[1000] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[1001] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[None] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-True-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-True-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-False-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-False-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-True-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-True-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-False-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-False-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-True-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-True-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-False-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-False-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-True-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-True-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-False-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-False-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-True-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-True-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-False-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-False-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-True-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-True-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-False-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-False-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-True-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-True-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-False-True] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-False-False] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-True-True] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-True-False] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-False-True] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-False-False] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[0] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[1] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[1000] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[1001] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[None] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[True-True] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[True-False] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[False-True] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[False-False] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[True-None] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[True-foo] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[False-None] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[False-foo] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-True-True] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-True-False] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-False-True] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-False-False] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-True-True] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-True-False] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-False-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-False-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-True-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-True-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-False-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-False-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-True-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-True-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-False-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-False-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-True-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-True-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-False-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-False-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-True-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-True-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-False-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-False-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-True-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-True-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-False-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-False-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-True-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-True-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-False-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-False-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-True-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-True-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-False-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-False-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-True-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-True-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-False-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-False-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-True-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-True-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-False-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-False-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-True-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-True-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-False-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-False-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-True-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-True-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-False-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-False-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-True-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-True-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-False-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-False-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-True-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-True-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-False-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-False-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-True-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-True-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-False-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-False-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[0] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[1] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[1000] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[1001] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[None] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_init_container_config_copied_from_worker_when_enabled PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[LoadBalancer-80] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[LoadBalancer-800] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[ClusterIP-80] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[ClusterIP-800] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-LoadBalancer-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-LoadBalancer-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-ClusterIP-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-ClusterIP-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-LoadBalancer-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-LoadBalancer-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-ClusterIP-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-ClusterIP-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_not_created PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0-800] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0-800] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0:800-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0:800-800] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0:800-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0:800-800] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[None-80] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[None-800] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes0-added_mounts0] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes0-added_mounts1] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes0-None] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes1-added_mounts0] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes1-added_mounts1] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes1-None] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[None-added_mounts0] PASSED [ 80%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[None-added_mounts1] PASSED [ 80%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[None-None] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.logging.StreamHandler.emit-] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.GELFTCPHandler.emit-] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 81%] +tests/unit_tests/test_log.py::test_logger_does_not_emit_to_graylog[] PASSED [ 81%] +tests/unit_tests/test_log.py::test_logger_does_not_emit_to_graylog[blueapi] PASSED [ 81%] +tests/unit_tests/test_log.py::test_logger_does_not_emit_to_graylog[blueapi.test] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.logging.StreamHandler.emit-] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.GELFTCPHandler.emit-] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.logging.StreamHandler.emit-] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.GELFTCPHandler.emit-] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 82%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit--library_logger0] PASSED [ 82%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit--library_logger1] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit--library_logger2] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi-library_logger0] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi-library_logger1] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi-library_logger2] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi.test-library_logger0] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi.test-library_logger1] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi.test-library_logger2] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit--library_logger0] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit--library_logger1] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit--library_logger2] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi-library_logger0] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi-library_logger1] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi-library_logger2] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi.test-library_logger0] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi.test-library_logger1] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi.test-library_logger2] PASSED [ 84%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_adds_filter[] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_adds_filter[blueapi] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_adds_filter[blueapi.test] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_removes_filter[] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_removes_filter[blueapi] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_removes_filter[blueapi.test] PASSED [ 85%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.logging.StreamHandler.emit-] PASSED [ 85%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 85%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 86%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.GELFTCPHandler.emit-] PASSED [ 86%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 86%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_debug PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_info PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_warning PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_error PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_critical PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_other PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345-1-{"proposal": 12345, "visit": 1, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345-111-{"proposal": 12345, "visit": 111, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cv12345-1-{"proposal": 12345, "visit": 1, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345678-1-{"proposal": 12345678, "visit": 1, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345678-111-{"proposal": 12345678, "visit": 111, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cv12345678-111-{"proposal": 12345678, "visit": 111, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[abc12345-1] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345--1_0] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345--1_1] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345\xa31] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345-1g] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345g-1] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12g345-1] PASSED [ 88%] +tests/unit_tests/utils/test_base_model.py::test_snake_case_constructor PASSED [ 88%] +tests/unit_tests/utils/test_deprecated.py::test_deprecated_annotation PASSED [ 88%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100600 (-rw-------)] PASSED [ 88%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100777 (-rwxrwxrwx)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100000 (----------)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100644 (-rw-r--r--)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100400 (-r--------)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100666 (-rw-rw-rw-)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100444 (-r--r--r--)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[040777 (drwxrwxrwx)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[040000 (d---------)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[040600 (drw-------)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102777 (-rwxrwsrwx)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102000 (------S---)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102644 (-rw-r-Sr--)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102600 (-rw---S---)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102400 (-r----S---)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102666 (-rw-rwSrw-)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102444 (-r--r-Sr--)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[042777 (drwxrwsrwx)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[042000 (d-----S---)] PASSED [ 91%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[042600 (drw---S---)] PASSED [ 91%] +tests/unit_tests/utils/test_file_permissions.py::test_get_owner_gid PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_imports_all PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_imports_everything_without_all PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_source_is_in_module PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_source_is_not_in_module PASSED [ 91%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan PASSED [ 91%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_400_error PASSED [ 92%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_500_error PASSED [ 92%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_key_error_on_incorrectly_formatted_responses PASSED [ 92%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_runtime_error_on_graphql_error PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_with_default_template_returns_correct_path_info PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_with_custom_template_returns_correct_path_info PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_fails_with_missing_instrument PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_fails_with_missing_scan_id PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_sets_data_session_directory_default_to_tmp PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_run_start_called_with_different_document_skips PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_run_stop_called_with_different_document_skips PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_nested_runs_use_info_from_last_start_doc PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_called_without_start_raises PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_run_stop_called_out_of_order_raises PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_error_if_template_missing PASSED [ 93%] +tests/unit_tests/utils/test_thread_exception.py::test_no_print_if_no_errors PASSED [ 93%] +tests/unit_tests/utils/test_thread_exception.py::test_prints_errors PASSED [ 93%] +tests/unit_tests/utils/test_thread_exception.py::test_passes_args_and_kwargs PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_stop_doesnt_hang PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_stop_is_idempotent_if_worker_not_started PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_multi_stop PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_restart PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_multi_start PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_submit_task PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_submit_multiple_tasks PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_stop_with_task_pending PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_restart_leaves_task_pending PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_submit_before_start_pending PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_clear_task PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_clear_nonexistent_task PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_does_not_allow_simultaneous_running_tasks PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_begin_task_blocks_until_current_task_set PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_begin_task_uses_plan_name_filter PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[None-None-NoneType] PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[42-42-int] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[helloWorld-helloWorld-str] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[result3-serial3-ComplexReturn] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[result4-serial4-ModelReturn] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[result5-None-Unreturnable] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_failure_recorded_in_active_task PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_task_not_run_twice PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_produces_worker_events[0] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_produces_worker_events[1] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_produces_worker_events[2] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_full_queue_raises PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_metadata_passed_to_context PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_worker_and_data_events_produce_in_order PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_get_tasks_by_status[RUNNING-expected_task_ids0] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_get_tasks_by_status[PENDING-expected_task_ids1] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_get_tasks_by_status[COMPLETE-expected_task_ids2] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_submitting_completed_task_fails PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_start_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_stop_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_submit_task_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_submit_task_with_correlation_id PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_clear_task_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_begin_task_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_injected_devices_are_found PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_injected_devices_plan_model PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_missing_injected_devices_fail_early PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_invalid_injected_devices_fail_early PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_worker_uses_plan_tag_filter_context PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_cycle_without_otel_context PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_devices_are_found PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_devices_plan_model PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_with_pydantic_dataclass PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_with_standard_dataclass PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_plan_module_with_composite_devices_can_be_loaded_before_device_module PASSED [100%] + +======================= 843 passed, 1 skipped in 20.39s ======================== diff --git a/tests/unit_tests/test_example_config.py b/tests/unit_tests/test_example_config.py index f323cbcb3..5c6c6c742 100644 --- a/tests/unit_tests/test_example_config.py +++ b/tests/unit_tests/test_example_config.py @@ -21,6 +21,7 @@ def test_example_config_is_valid(file_name: str): loader.load() +@pytest.mark.timeout(30) @pytest.mark.parametrize("file_name", os.listdir(example_helm)) def test_example_helm_is_valid(file_name: str): path = example_helm / file_name diff --git a/uv.lock b/uv.lock index 6bc309b2a..2ef3cb5a6 100644 --- a/uv.lock +++ b/uv.lock @@ -460,6 +460,7 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-httpx" }, + { name = "pytest-timeout" }, { name = "responses" }, { name = "respx" }, { name = "ruff" }, @@ -520,6 +521,7 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-httpx", specifier = ">=0.35.0" }, + { name = "pytest-timeout" }, { name = "responses" }, { name = "respx" }, { name = "ruff" }, @@ -4266,6 +4268,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e2/d2/1eb1ea9c84f0d2033eb0b49675afdc71aa4ea801b74615f00f3c33b725e3/pytest_httpx-0.36.0-py3-none-any.whl", hash = "sha256:bd4c120bb80e142df856e825ec9f17981effb84d159f9fa29ed97e2357c3a9c8", size = 20229, upload-time = "2025-12-02T16:34:56.45Z" }, ] +[[package]] +name = "pytest-timeout" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0"