Add comprehensive tests for 11 modules with AAA pattern comments#2408
Add comprehensive tests for 11 modules with AAA pattern comments#2408
Conversation
…onstants, logging, config_utils, metric_config, metric_result, search_parameter, search_point, search_sample, data registry, and telemetry utils Agent-Logs-Url: https://github.com/microsoft/Olive/sessions/656d3838-fc06-4d40-8a11-b75da7f23724 Co-authored-by: xiaoyu-work <85524621+xiaoyu-work@users.noreply.github.com>
Agent-Logs-Url: https://github.com/microsoft/Olive/sessions/656d3838-fc06-4d40-8a11-b75da7f23724 Co-authored-by: xiaoyu-work <85524621+xiaoyu-work@users.noreply.github.com>
…ethods Agent-Logs-Url: https://github.com/microsoft/Olive/sessions/6dac7c0c-a4f5-4649-9a9a-1d9237f27a3d Co-authored-by: xiaoyu-work <85524621+xiaoyu-work@users.noreply.github.com>
…xists Agent-Logs-Url: https://github.com/microsoft/Olive/sessions/3dc88a98-09ac-43c9-86b5-b2eddc3e34ae Co-authored-by: xiaoyu-work <85524621+xiaoyu-work@users.noreply.github.com>
Agent-Logs-Url: https://github.com/microsoft/Olive/sessions/4d88a644-eb92-4192-8494-b25f650bc10d Co-authored-by: xiaoyu-work <85524621+xiaoyu-work@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds new unit tests across several Olive modules, aiming to improve coverage and adopt a consistent AAA-style structure in test methods.
Changes:
- Added new pytest suites for logging, exceptions, constants, telemetry utilities, search primitives, evaluator metric types, data registry, and config utilities.
- Introduced parameterized tests for validation and mapping behaviors (for example metric goals, logger levels, precision to bits).
- Added telemetry and search serialization roundtrip tests (
to_jsonandfrom_json).
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test_logging.py | Adds coverage for logger creation, verbosity setters, env-based configuration, and file logging. |
| test/test_exception.py | Adds basic tests for Olive exception hierarchy and expected exception tuples. |
| test/test_constants.py | Adds tests for constants and enum behaviors, including mapping helpers. |
| test/telemetry/test_telemetry_utils.py | Adds tests for telemetry path resolution, exception formatting, and base64 cache line encode/decode. |
| test/telemetry/init.py | Adds package init for telemetry tests. |
| test/search/test_search_sample.py | Adds tests for SearchSample config extraction, JSON roundtrip, and repr. |
| test/search/test_search_point.py | Adds tests for SearchPoint construction, equality, validity checks, and JSON roundtrip. |
| test/search/test_search_parameter.py | Adds tests for search parameter classes and JSON factory logic. |
| test/evaluator/test_metric_result.py | Adds tests for metric result containers and flattening helpers. |
| test/evaluator/test_metric_config.py | Adds tests for metric config defaults and MetricGoal validation logic. |
| test/data_container/test_registry.py | Adds tests for data component registration and retrieval behavior. |
| test/common/test_config_utils.py | Adds broad coverage for config serialization, loading, validation, and dynamic config class creation. |
| assert result == expected | ||
|
|
||
|
|
||
| class TestPrecision: | ||
| def test_precision_all_members(self): | ||
| # setup | ||
| expected_count = 14 | ||
|
|
||
| # execute | ||
| result = len(Precision) | ||
|
|
||
| # assert | ||
| assert result == expected_count | ||
|
|
||
|
|
||
| class TestQuantAlgorithm: | ||
| def test_quant_algorithm_case_insensitive(self): |
There was a problem hiding this comment.
The PR description says to remove enum/constant value tests that only assert Enum.MEMBER == "literal" without exercising behavior, but this file still includes several of those (for example test_framework_values, test_framework_str, and similar value/str tests below). Please remove these nonsensical value-only assertions and keep the behavior-focused tests (case-insensitive parsing, __members__ completeness, and precision_bits_from_precision mapping).
| values = OrderedDict( | ||
| { | ||
| "pass1": OrderedDict( | ||
| { | ||
| "param1": SpecialParamValue.INVALID, | ||
| } | ||
| ) | ||
| } | ||
| ) | ||
| point = SearchPoint(index=0, values=values) | ||
|
|
There was a problem hiding this comment.
SearchPoint.values is defined/produced as dict[str, tuple[int, Any]] (for example via SearchSpace.get_sample_point_values), but this test builds values as nested OrderedDict without the (index, value) tuples. That means the test is not validating behavior under the real data structure and can mask issues in SearchPoint.is_valid(). Please construct values using the same tuple shape as production code (and then assert validity accordingly).
| # execute | ||
| with patch.dict("os.environ", {}, clear=True): | ||
| set_verbosity_from_env() | ||
|
|
||
| # assert (no exception raised) | ||
|
|
There was a problem hiding this comment.
This test currently has no assertions, so it will not catch regressions in the default behavior of set_verbosity_from_env() (which should set the logger level based on the default "INFO"). Please assert the expected resulting logger level (and restore the prior level afterward to avoid cross-test pollution).
| # execute | |
| with patch.dict("os.environ", {}, clear=True): | |
| set_verbosity_from_env() | |
| # assert (no exception raised) | |
| # setup | |
| previous_level = get_olive_logger().level | |
| try: | |
| # execute | |
| with patch.dict("os.environ", {}, clear=True): | |
| set_verbosity_from_env() | |
| # assert | |
| assert get_olive_logger().level == logging.INFO | |
| finally: | |
| # cleanup | |
| set_verbosity(previous_level) |
| class TestSetVerbosity: | ||
| def test_set_verbosity_info(self): | ||
| # execute | ||
| set_verbosity_info() | ||
|
|
||
| # assert | ||
| assert get_olive_logger().level == logging.INFO | ||
|
|
||
| def test_set_verbosity_warning(self): | ||
| # execute | ||
| set_verbosity_warning() | ||
|
|
||
| # assert | ||
| assert get_olive_logger().level == logging.WARNING | ||
|
|
||
| def test_set_verbosity_debug(self): | ||
| # execute | ||
| set_verbosity_debug() | ||
|
|
||
| # assert | ||
| assert get_olive_logger().level == logging.DEBUG | ||
|
|
||
| def test_set_verbosity_error(self): | ||
| # execute | ||
| set_verbosity_error() | ||
|
|
||
| # assert | ||
| assert get_olive_logger().level == logging.ERROR | ||
|
|
||
| def test_set_verbosity_critical(self): | ||
| # execute | ||
| set_verbosity_critical() | ||
|
|
||
| # assert | ||
| assert get_olive_logger().level == logging.CRITICAL | ||
|
|
||
| def test_set_verbosity_custom_level(self): | ||
| # execute | ||
| set_verbosity(logging.WARNING) | ||
|
|
||
| # assert | ||
| assert get_olive_logger().level == logging.WARNING |
There was a problem hiding this comment.
These tests mutate the global olive logger level and do not restore it, which can make other tests order-dependent. Please capture the original logger level (and ideally handlers) and restore them in a fixture or teardown so this module does not leak global logging state.
test/test_logging.py
Outdated
|
|
||
| # execute | ||
| enable_filelog(1, str(tmp_path), workflow_id) | ||
|
|
||
| # assert | ||
| logger = get_olive_logger() | ||
| log_file_path = tmp_path / f"{workflow_id}.log" | ||
| file_handlers = [h for h in logger.handlers if isinstance(h, logging.FileHandler)] | ||
| assert len(file_handlers) > 0 | ||
|
|
||
| # cleanup | ||
| for h in file_handlers: | ||
| if Path(h.baseFilename) == log_file_path.resolve(): | ||
| logger.removeHandler(h) | ||
| h.close() |
There was a problem hiding this comment.
test_enable_filelog_creates_handler only asserts that some FileHandler exists on the global logger. This can become a false positive if any prior test added a file handler. Please assert that a handler was added for the expected workflow_id path (and consider verifying the file is created), and restore the logger handler list to its prior state to prevent leaks.
| # execute | |
| enable_filelog(1, str(tmp_path), workflow_id) | |
| # assert | |
| logger = get_olive_logger() | |
| log_file_path = tmp_path / f"{workflow_id}.log" | |
| file_handlers = [h for h in logger.handlers if isinstance(h, logging.FileHandler)] | |
| assert len(file_handlers) > 0 | |
| # cleanup | |
| for h in file_handlers: | |
| if Path(h.baseFilename) == log_file_path.resolve(): | |
| logger.removeHandler(h) | |
| h.close() | |
| logger = get_olive_logger() | |
| original_handlers = list(logger.handlers) | |
| original_handler_ids = {id(handler) for handler in original_handlers} | |
| log_file_path = (tmp_path / f"{workflow_id}.log").resolve() | |
| try: | |
| # execute | |
| enable_filelog(1, str(tmp_path), workflow_id) | |
| # assert | |
| new_handlers = [handler for handler in logger.handlers if id(handler) not in original_handler_ids] | |
| matching_handlers = [ | |
| handler | |
| for handler in new_handlers | |
| if isinstance(handler, logging.FileHandler) and Path(handler.baseFilename).resolve() == log_file_path | |
| ] | |
| assert matching_handlers, f"Expected a FileHandler for {log_file_path}, but none was added." | |
| assert log_file_path.exists() | |
| finally: | |
| # cleanup | |
| for handler in [handler for handler in logger.handlers if id(handler) not in original_handler_ids]: | |
| logger.removeHandler(handler) | |
| handler.close() |
test/evaluator/test_metric_config.py
Outdated
| def test_unknown_metric_type(self): | ||
| # execute | ||
| cls = get_user_config_class("latency") | ||
| instance = cls() | ||
|
|
||
| # assert | ||
| assert hasattr(instance, "user_script") |
There was a problem hiding this comment.
The test name test_unknown_metric_type is misleading because it calls get_user_config_class("latency"), which is a known metric type. Please rename the test to reflect what is actually being validated (for example, that non-"custom" metric types still include the common user-config fields).
…prove assertions, rename test Agent-Logs-Url: https://github.com/microsoft/Olive/sessions/6e93cade-0aec-4b0e-b700-2063624d8f7d Co-authored-by: xiaoyu-work <85524621+xiaoyu-work@users.noreply.github.com>
# setupcomments from test methods where no setup code existstest_constants.pyexception/tracebackbefore try block intest/telemetry/test_telemetry_utils.pytest/test_constants.pyreview comment is stale (value-only tests already removed in prior commit)test/search/test_search_point.pyreview comment: test correctly matchesis_valid()implementation which uses plain OrderedDict recursion, not tuple-wrapped valuestest/test_logging.py: add_restore_logger_levelautouse fixture to prevent global state leakstest/test_logging.py: add assertion fortest_set_verbosity_from_env_default(assert level == INFO)test/test_logging.py: improvetest_enable_filelog_creates_handlerto verify handler matches expected file path and cleanup in finally blocktest/evaluator/test_metric_config.py: renametest_unknown_metric_typetotest_non_custom_metric_type_includes_common_fields