Coverage for mlos_bench/mlos_bench/tests/environments/composite_env_test.py: 100%
35 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-21 01:50 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-21 01:50 +0000
1#
2# Copyright (c) Microsoft Corporation.
3# Licensed under the MIT License.
4#
5"""Unit tests for composite environment."""
7import pytest
9from mlos_bench.environments.composite_env import CompositeEnv
10from mlos_bench.services.config_persistence import ConfigPersistenceService
11from mlos_bench.tests import BUILT_IN_ENV_VAR_DEFAULTS
12from mlos_bench.tunables.tunable_groups import TunableGroups
14# pylint: disable=redefined-outer-name
17@pytest.fixture
18def composite_env(tunable_groups: TunableGroups) -> CompositeEnv:
19 """Test fixture for CompositeEnv."""
20 return CompositeEnv(
21 name="Composite Test Environment",
22 config={
23 "tunable_params": ["provision", "boot"],
24 "const_args": {
25 "vm_server_name": "Mock Server VM",
26 "vm_client_name": "Mock Client VM",
27 "someConst": "root",
28 "global_param": "default",
29 },
30 "children": [
31 {
32 "name": "Mock Client Environment 1",
33 "class": "mlos_bench.environments.mock_env.MockEnv",
34 "config": {
35 "tunable_params": ["provision"],
36 "const_args": {
37 "vmName": "$vm_client_name",
38 "EnvId": 1,
39 },
40 "required_args": ["vmName", "someConst", "global_param"],
41 "mock_env_range": [60, 120],
42 "mock_env_metrics": ["score"],
43 },
44 },
45 {
46 "name": "Mock Server Environment 2",
47 "class": "mlos_bench.environments.mock_env.MockEnv",
48 "config": {
49 "tunable_params": ["boot"],
50 "const_args": {
51 "vmName": "$vm_server_name",
52 "EnvId": 2,
53 "global_param": "local",
54 },
55 "required_args": ["vmName"],
56 "mock_env_range": [60, 120],
57 "mock_env_metrics": ["score"],
58 },
59 },
60 {
61 "name": "Mock Control Environment 3",
62 "class": "mlos_bench.environments.mock_env.MockEnv",
63 "config": {
64 "tunable_params": ["boot"],
65 "const_args": {
66 "vmName": "Mock Control VM",
67 "EnvId": 3,
68 },
69 "required_args": ["vmName", "vm_server_name", "vm_client_name"],
70 "mock_env_range": [60, 120],
71 "mock_env_metrics": ["score"],
72 },
73 },
74 ],
75 },
76 tunables=tunable_groups,
77 service=ConfigPersistenceService({}),
78 global_config={"global_param": "global_value"},
79 )
82def test_composite_env_params(composite_env: CompositeEnv) -> None:
83 """
84 Check that the const_args from the parent environment get propagated to the
85 children.
87 NOTE: The current logic is that variables flow down via required_args and const_args, parent
88 """
89 assert composite_env.children[0].parameters == {
90 "vmName": "Mock Client VM", # const_args from the parent thru variable substitution
91 "EnvId": 1, # const_args from the child
92 "vmSize": "Standard_B4ms", # tunable_params from the parent
93 "someConst": "root", # pulled in from parent via required_args
94 "global_param": "global_value", # pulled in from the global_config
95 **BUILT_IN_ENV_VAR_DEFAULTS,
96 }
97 assert composite_env.children[1].parameters == {
98 "vmName": "Mock Server VM", # const_args from the parent
99 "EnvId": 2, # const_args from the child
100 "idle": "halt", # tunable_params from the parent
101 # "someConst": "root" # not required, so not passed from the parent
102 "global_param": "global_value", # pulled in from the global_config
103 **BUILT_IN_ENV_VAR_DEFAULTS,
104 }
105 assert composite_env.children[2].parameters == {
106 "vmName": "Mock Control VM", # const_args from the parent
107 "EnvId": 3, # const_args from the child
108 "idle": "halt", # tunable_params from the parent
109 # "someConst": "root" # not required, so not passed from the parent
110 "vm_client_name": "Mock Client VM",
111 "vm_server_name": "Mock Server VM",
112 # "global_param": "global_value" # not required, so not picked from the global_config
113 **BUILT_IN_ENV_VAR_DEFAULTS,
114 }
117def test_composite_env_setup(composite_env: CompositeEnv, tunable_groups: TunableGroups) -> None:
118 """Check that the child environments update their tunable parameters."""
119 tunable_groups.assign(
120 {
121 "vmSize": "Standard_B2s",
122 "idle": "mwait",
123 "kernel_sched_migration_cost_ns": 100000,
124 }
125 )
127 with composite_env as env_context:
128 assert env_context.setup(tunable_groups)
130 assert composite_env.children[0].parameters == {
131 "vmName": "Mock Client VM", # const_args from the parent
132 "EnvId": 1, # const_args from the child
133 "vmSize": "Standard_B2s", # tunable_params from the parent
134 "someConst": "root", # pulled in from parent via required_args
135 "global_param": "global_value", # pulled in from the global_config
136 **BUILT_IN_ENV_VAR_DEFAULTS,
137 }
138 assert composite_env.children[1].parameters == {
139 "vmName": "Mock Server VM", # const_args from the parent
140 "EnvId": 2, # const_args from the child
141 "idle": "mwait", # tunable_params from the parent
142 # "someConst": "root" # not required, so not passed from the parent
143 "global_param": "global_value", # pulled in from the global_config
144 **BUILT_IN_ENV_VAR_DEFAULTS,
145 }
146 assert composite_env.children[2].parameters == {
147 "vmName": "Mock Control VM", # const_args from the parent
148 "EnvId": 3, # const_args from the child
149 "idle": "mwait", # tunable_params from the parent
150 "vm_client_name": "Mock Client VM",
151 "vm_server_name": "Mock Server VM",
152 # "global_param": "global_value" # not required, so not picked from the global_config
153 **BUILT_IN_ENV_VAR_DEFAULTS,
154 }
157@pytest.fixture
158def nested_composite_env(tunable_groups: TunableGroups) -> CompositeEnv:
159 """Test fixture for CompositeEnv."""
160 return CompositeEnv(
161 name="Composite Test Environment",
162 config={
163 "tunable_params": ["provision", "boot"],
164 "const_args": {
165 "vm_server_name": "Mock Server VM",
166 "vm_client_name": "Mock Client VM",
167 "someConst": "root",
168 },
169 "children": [
170 {
171 "name": "Nested Composite Client Environment 1",
172 "class": "mlos_bench.environments.composite_env.CompositeEnv",
173 "config": {
174 "tunable_params": ["provision"],
175 "const_args": {
176 "vmName": "$vm_client_name",
177 "EnvId": 1,
178 },
179 "required_args": ["vmName", "EnvId", "someConst", "vm_server_name"],
180 "children": [
181 {
182 "name": "Mock Client Environment 1",
183 "class": "mlos_bench.environments.mock_env.MockEnv",
184 "config": {
185 "tunable_params": ["provision"],
186 # TODO: Might be nice to include a "^" or "*" option
187 # here to indicate that all required_args from
188 # the parent should be included here too in
189 # order to reduce duplication.
190 "required_args": [
191 "vmName",
192 "EnvId",
193 "someConst",
194 "vm_server_name",
195 "global_param",
196 ],
197 "mock_env_range": [60, 120],
198 "mock_env_metrics": ["score"],
199 },
200 },
201 # ...
202 ],
203 },
204 },
205 {
206 "name": "Nested Composite Server Environment 2",
207 "class": "mlos_bench.environments.composite_env.CompositeEnv",
208 "config": {
209 "tunable_params": ["boot"],
210 "const_args": {
211 "vmName": "$vm_server_name",
212 "EnvId": 2,
213 },
214 "required_args": ["vmName", "EnvId", "vm_client_name"],
215 "children": [
216 {
217 "name": "Mock Server Environment 2",
218 "class": "mlos_bench.environments.mock_env.MockEnv",
219 "config": {
220 "tunable_params": ["boot"],
221 "required_args": ["vmName", "EnvId", "vm_client_name"],
222 "mock_env_range": [60, 120],
223 "mock_env_metrics": ["score"],
224 },
225 },
226 # ...
227 ],
228 },
229 },
230 ],
231 },
232 tunables=tunable_groups,
233 service=ConfigPersistenceService({}),
234 global_config={"global_param": "global_value"},
235 )
238def test_nested_composite_env_params(nested_composite_env: CompositeEnv) -> None:
239 """
240 Check that the const_args from the parent environment get propagated to the
241 children.
243 NOTE: The current logic is that variables flow down via required_args and const_args, parent
244 """
245 assert isinstance(nested_composite_env.children[0], CompositeEnv)
246 assert nested_composite_env.children[0].children[0].parameters == {
247 "vmName": "Mock Client VM", # const_args from the parent thru variable substitution
248 "EnvId": 1, # const_args from the child
249 "vmSize": "Standard_B4ms", # tunable_params from the parent
250 "someConst": "root", # pulled in from parent via required_args
251 "vm_server_name": "Mock Server VM",
252 "global_param": "global_value", # pulled in from the global_config
253 **BUILT_IN_ENV_VAR_DEFAULTS,
254 }
255 assert isinstance(nested_composite_env.children[1], CompositeEnv)
256 assert nested_composite_env.children[1].children[0].parameters == {
257 "vmName": "Mock Server VM", # const_args from the parent
258 "EnvId": 2, # const_args from the child
259 "idle": "halt", # tunable_params from the parent
260 # "someConst": "root" # not required, so not passed from the parent
261 "vm_client_name": "Mock Client VM",
262 # "global_param": "global_value" # not required, so not picked from the global_config
263 **BUILT_IN_ENV_VAR_DEFAULTS,
264 }
267def test_nested_composite_env_setup(
268 nested_composite_env: CompositeEnv,
269 tunable_groups: TunableGroups,
270) -> None:
271 """Check that the child environments update their tunable parameters."""
272 tunable_groups.assign(
273 {
274 "vmSize": "Standard_B2s",
275 "idle": "mwait",
276 "kernel_sched_migration_cost_ns": 100000,
277 }
278 )
280 with nested_composite_env as env_context:
281 assert env_context.setup(tunable_groups)
283 assert isinstance(nested_composite_env.children[0], CompositeEnv)
284 assert nested_composite_env.children[0].children[0].parameters == {
285 "vmName": "Mock Client VM", # const_args from the parent
286 "EnvId": 1, # const_args from the child
287 "vmSize": "Standard_B2s", # tunable_params from the parent
288 "someConst": "root", # pulled in from parent via required_args
289 "vm_server_name": "Mock Server VM",
290 "global_param": "global_value", # pulled in from the global_config
291 **BUILT_IN_ENV_VAR_DEFAULTS,
292 }
294 assert isinstance(nested_composite_env.children[1], CompositeEnv)
295 assert nested_composite_env.children[1].children[0].parameters == {
296 "vmName": "Mock Server VM", # const_args from the parent
297 "EnvId": 2, # const_args from the child
298 "idle": "mwait", # tunable_params from the parent
299 # "someConst": "root" # not required, so not passed from the parent
300 "vm_client_name": "Mock Client VM",
301 **BUILT_IN_ENV_VAR_DEFAULTS,
302 }