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

1# 

2# Copyright (c) Microsoft Corporation. 

3# Licensed under the MIT License. 

4# 

5"""Unit tests for composite environment.""" 

6 

7import pytest 

8 

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 

13 

14# pylint: disable=redefined-outer-name 

15 

16 

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 ) 

80 

81 

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. 

86 

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 } 

115 

116 

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 ) 

126 

127 with composite_env as env_context: 

128 assert env_context.setup(tunable_groups) 

129 

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 } 

155 

156 

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 ) 

236 

237 

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. 

242 

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 } 

265 

266 

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 ) 

279 

280 with nested_composite_env as env_context: 

281 assert env_context.setup(tunable_groups) 

282 

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 } 

293 

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 }