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