@@ -87,7 +87,7 @@ class TestWorkerProcessGroup:
87
87
"requests" : None ,
88
88
"cycle_requests" : ["request1" , "request2" , "request3" ],
89
89
"strategy" : SynchronousStrategy (),
90
- "constraints" : {"max_requests " : MaxNumberConstraint (max_num = 10 )},
90
+ "constraints" : {"max_num " : MaxNumberConstraint (max_num = 10 )},
91
91
},
92
92
{
93
93
"requests" : None ,
@@ -185,33 +185,137 @@ def test_initialization(self, valid_instances):
185
185
assert instance ._state is None
186
186
assert instance .messaging is None
187
187
188
+ @pytest .mark .sanity
189
+ @pytest .mark .parametrize (
190
+ ("requests" , "cycle_requests" , "expected_error" ),
191
+ [
192
+ (None , None , ValueError ),
193
+ ([], iter ([]), ValueError ), # cycle_requests as Iterator
194
+ (None , iter (["req1" ]), ValueError ), # cycle_requests as Iterator
195
+ ],
196
+ ids = ["no_requests" , "cycle_as_iterator_empty" , "cycle_as_iterator_data" ],
197
+ )
198
+ def test_invalid_initialization_values (
199
+ self , requests , cycle_requests , expected_error
200
+ ):
201
+ """Test WorkerProcessGroup with invalid initialization values."""
202
+ with pytest .raises (expected_error ):
203
+ WorkerProcessGroup (
204
+ requests = requests ,
205
+ cycle_requests = cycle_requests ,
206
+ backend = MockBackend (),
207
+ strategy = SynchronousStrategy (),
208
+ constraints = {},
209
+ )
210
+
211
+ @pytest .mark .sanity
212
+ def test_invalid_initialization_missing (self ):
213
+ """Test WorkerProcessGroup initialization without required fields."""
214
+ with pytest .raises (TypeError ):
215
+ WorkerProcessGroup ()
216
+
188
217
@pytest .mark .smoke
189
- # @async_timeout(5 )
218
+ @async_timeout (10 )
190
219
@pytest .mark .asyncio
191
220
async def test_lifecycle (self , valid_instances : tuple [WorkerProcessGroup , dict ]):
192
221
"""Test the lifecycle methods of WorkerProcessGroup."""
193
- instance , _ = valid_instances
222
+ instance , constructor_args = valid_instances
194
223
195
224
# Test create processes
196
225
await instance .create_processes ()
197
- # TODO: check valid process creation
226
+
227
+ # Check valid process creation
228
+ assert instance .mp_context is not None
229
+ assert instance .mp_manager is not None
230
+ assert instance .processes is not None
231
+ assert len (instance .processes ) > 0
232
+ assert all (proc .is_alive () for proc in instance .processes )
233
+ assert instance .startup_barrier is not None
234
+ assert instance .shutdown_event is not None
235
+ assert instance .error_event is not None
236
+ assert instance .requests_completed_event is not None
237
+ assert instance .messaging is not None
198
238
199
239
# Test start
200
240
start_time = time .time () + 0.1
201
241
await instance .start (start_time = start_time )
202
- # TODO: check valid start behavior
242
+
243
+ # Check valid start behavior
244
+ assert instance .messaging is not None
245
+ assert instance ._state is not None
246
+ assert instance ._state ._start_time == start_time
247
+ assert instance ._state ._state .num_processes == len (instance .processes )
248
+ assert not instance .error_event .is_set ()
203
249
204
250
# Test iter updates
205
- updates = {}
206
- async for resp , req , info , state in instance .request_updates ():
207
- pass
208
- # TODO: validate correct updates based on requests, cycle_requests, and constraints
251
+ updates_list = []
252
+ responses_count = 0
253
+
254
+ async for (
255
+ response ,
256
+ request ,
257
+ request_info ,
258
+ scheduler_state ,
259
+ ) in instance .request_updates ():
260
+ updates_list .append ((response , request , request_info , scheduler_state ))
261
+ if response is not None :
262
+ responses_count += 1
263
+
264
+ # Validate request info structure
265
+ assert hasattr (request_info , "request_id" )
266
+ assert hasattr (request_info , "status" )
267
+ valid_statuses = [
268
+ "queued" ,
269
+ "in_progress" ,
270
+ "completed" ,
271
+ "errored" ,
272
+ "cancelled" ,
273
+ ]
274
+ assert request_info .status in valid_statuses
275
+
276
+ # Validate state structure
277
+ assert hasattr (scheduler_state , "created_requests" )
278
+ assert hasattr (scheduler_state , "processed_requests" )
279
+ assert hasattr (scheduler_state , "successful_requests" )
280
+ assert scheduler_state .created_requests >= 0
281
+ assert scheduler_state .processed_requests >= 0
282
+ assert scheduler_state .successful_requests >= 0
283
+
284
+ # Validate correctness of all updates
285
+ if constructor_args .get ("requests" ) is not None :
286
+ assert len (updates_list ) == 2 * len (constructor_args ["requests" ]), (
287
+ "Should have received updates for all requests"
288
+ )
289
+ if constructor_args .get ("constraints" , {}).get ("max_num" ) is not None :
290
+ assert (
291
+ len (updates_list )
292
+ == 2 * constructor_args ["constraints" ]["max_num" ].max_num
293
+ ), "Should not have received more updates than max_num constraint"
294
+
295
+ assert len (updates_list ) > 0 , "Should have received at least one update"
296
+
297
+ # Constraints should be satisfied
298
+ for constraint_name , _ in constructor_args ["constraints" ].items ():
299
+ constraint_check = (
300
+ "max" in constraint_name .lower ()
301
+ or "duration" in constraint_name .lower ()
302
+ )
303
+ if constraint_check :
304
+ assert scheduler_state .end_processing_time is not None , (
305
+ f"Should have stopped processing due to { constraint_name } "
306
+ )
209
307
210
308
# Test shutdown
211
- await instance .shutdown ()
212
- print (
213
- f"\n Requests summary: created={ state .created_requests } , queued={ state .queued_requests } , processing={ state .processing_requests } , processed={ state .processed_requests } , successful={ state .successful_requests } , cancelled={ state .cancelled_requests } , errored={ state .errored_requests } "
309
+ exceptions = await instance .shutdown ()
310
+
311
+ # Check valid shutdown behavior
312
+ assert isinstance (exceptions , list ), "Shutdown should return list of exceptions"
313
+ assert instance .messaging is None , "Messaging should be cleared after shutdown"
314
+ assert instance ._state is None , "State should be cleared after shutdown"
315
+ assert instance .processes is None , "Processes should be cleared after shutdown"
316
+ assert instance .mp_manager is None , (
317
+ "MP manager should be cleared after shutdown"
318
+ )
319
+ assert instance .mp_context is None , (
320
+ "MP context should be cleared after shutdown"
214
321
)
215
- print (resp )
216
- print (info )
217
- # TODO: check valid shutdown behavior
0 commit comments