Coverage for mlos_bench/mlos_bench/tests/tunables/tunables_assign_test.py: 100%
85 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-07 01:52 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-07 01:52 +0000
1#
2# Copyright (c) Microsoft Corporation.
3# Licensed under the MIT License.
4#
5"""Unit tests for assigning values to the individual parameters within tunable
6groups.
7"""
9import json5 as json
10import pytest
12from mlos_bench.tunables.tunable import Tunable
13from mlos_bench.tunables.tunable_groups import TunableGroups
16def test_tunables_assign_unknown_param(tunable_groups: TunableGroups) -> None:
17 """Make sure that bulk assignment fails for parameters that don't exist in the
18 TunableGroups object.
19 """
20 with pytest.raises(KeyError):
21 tunable_groups.assign(
22 {
23 "vmSize": "Standard_B2ms",
24 "idle": "mwait",
25 "UnknownParam_1": 1,
26 "UnknownParam_2": "invalid-value",
27 }
28 )
31def test_tunables_assign_categorical(tunable_categorical: Tunable) -> None:
32 """Regular assignment for categorical tunable."""
33 # Must be one of: {"Standard_B2s", "Standard_B2ms", "Standard_B4ms"}
34 tunable_categorical.value = "Standard_B4ms"
35 assert not tunable_categorical.is_special
38def test_tunables_assign_invalid_categorical(tunable_groups: TunableGroups) -> None:
39 """Check parameter validation for categorical tunables."""
40 with pytest.raises(ValueError):
41 tunable_groups.assign({"vmSize": "InvalidSize"})
44def test_tunables_assign_invalid_range(tunable_groups: TunableGroups) -> None:
45 """Check parameter out-of-range validation for numerical tunables."""
46 with pytest.raises(ValueError):
47 tunable_groups.assign({"kernel_sched_migration_cost_ns": -2})
50def test_tunables_assign_coerce_str(tunable_groups: TunableGroups) -> None:
51 """Check the conversion from strings when assigning to an integer parameter."""
52 tunable_groups.assign({"kernel_sched_migration_cost_ns": "10000"})
55def test_tunables_assign_coerce_str_range_check(tunable_groups: TunableGroups) -> None:
56 """Check the range when assigning to an integer tunable."""
57 with pytest.raises(ValueError):
58 tunable_groups.assign({"kernel_sched_migration_cost_ns": "5500000"})
61def test_tunables_assign_coerce_str_invalid(tunable_groups: TunableGroups) -> None:
62 """Make sure we fail when assigning an invalid string to an integer tunable."""
63 with pytest.raises(ValueError):
64 tunable_groups.assign({"kernel_sched_migration_cost_ns": "1.1"})
67def test_tunable_assign_str_to_numerical(tunable_int: Tunable) -> None:
68 """Check str to int coercion."""
69 with pytest.raises(ValueError):
70 tunable_int.numerical_value = "foo" # type: ignore[assignment]
73def test_tunable_assign_int_to_numerical_value(tunable_int: Tunable) -> None:
74 """Check numerical value assignment."""
75 tunable_int.numerical_value = 10.0
76 assert tunable_int.numerical_value == 10
77 assert not tunable_int.is_special
80def test_tunable_assign_float_to_numerical_value(tunable_float: Tunable) -> None:
81 """Check numerical value assignment."""
82 tunable_float.numerical_value = 0.1
83 assert tunable_float.numerical_value == 0.1
84 assert not tunable_float.is_special
87def test_tunable_assign_str_to_int(tunable_int: Tunable) -> None:
88 """Check str to int coercion."""
89 tunable_int.value = "10"
90 assert tunable_int.value == 10 # type: ignore[comparison-overlap]
91 assert not tunable_int.is_special
94def test_tunable_assign_str_to_float(tunable_float: Tunable) -> None:
95 """Check str to float coercion."""
96 tunable_float.value = "0.5"
97 assert tunable_float.value == 0.5 # type: ignore[comparison-overlap]
98 assert not tunable_float.is_special
101def test_tunable_assign_float_to_int(tunable_int: Tunable) -> None:
102 """Check float to int coercion."""
103 tunable_int.value = 10.0
104 assert tunable_int.value == 10
105 assert not tunable_int.is_special
108def test_tunable_assign_float_to_int_fail(tunable_int: Tunable) -> None:
109 """Check the invalid float to int coercion."""
110 with pytest.raises(ValueError):
111 tunable_int.value = 10.1
114def test_tunable_assign_null_to_categorical() -> None:
115 """Checks that we can use null/None in categorical tunables."""
116 json_config = """
117 {
118 "name": "categorical_test",
119 "type": "categorical",
120 "values": ["foo", null],
121 "default": "foo"
122 }
123 """
124 config = json.loads(json_config)
125 categorical_tunable = Tunable(name="categorical_test", config=config)
126 assert categorical_tunable
127 assert categorical_tunable.category == "foo"
128 categorical_tunable.value = None
129 assert categorical_tunable.value is None
130 assert categorical_tunable.value != "None"
131 assert categorical_tunable.category is None
134def test_tunable_assign_null_to_int(tunable_int: Tunable) -> None:
135 """Checks that we can't use null/None in integer tunables."""
136 with pytest.raises((TypeError, AssertionError)):
137 tunable_int.value = None
138 with pytest.raises((TypeError, AssertionError)):
139 tunable_int.numerical_value = None # type: ignore[assignment]
142def test_tunable_assign_null_to_float(tunable_float: Tunable) -> None:
143 """Checks that we can't use null/None in float tunables."""
144 with pytest.raises((TypeError, AssertionError)):
145 tunable_float.value = None
146 with pytest.raises((TypeError, AssertionError)):
147 tunable_float.numerical_value = None # type: ignore[assignment]
150def test_tunable_assign_special(tunable_int: Tunable) -> None:
151 """Check the assignment of a special value outside of the range (but declared
152 `special`).
153 """
154 tunable_int.numerical_value = -1
155 assert tunable_int.numerical_value == -1
156 assert tunable_int.is_special
159def test_tunable_assign_special_fail(tunable_int: Tunable) -> None:
160 """Assign a value that is neither special nor in range and fail."""
161 with pytest.raises(ValueError):
162 tunable_int.numerical_value = -2
165def test_tunable_assign_special_with_coercion(tunable_int: Tunable) -> None:
166 """
167 Check the assignment of a special value outside of the range (but declared
168 `special`).
170 Check coercion from float to int.
171 """
172 tunable_int.numerical_value = -1.0
173 assert tunable_int.numerical_value == -1
174 assert tunable_int.is_special
177def test_tunable_assign_special_with_coercion_str(tunable_int: Tunable) -> None:
178 """
179 Check the assignment of a special value outside of the range (but declared
180 `special`).
182 Check coercion from string to int.
183 """
184 tunable_int.value = "-1"
185 assert tunable_int.numerical_value == -1
186 assert tunable_int.is_special