@@ -332,12 +332,30 @@ async def test_get_many_all_successful(
332332 self , async_client : AsyncClient , mock_async_client : AsyncMock
333333 ) -> None :
334334 """Test bulk retrieval where all meetings are retrieved successfully."""
335- # Mock meeting list response for details method
336- mock_meetings_list = [
337- {"Id" : 100 , "Type" : "L10" , "Key" : "L10-100" , "Name" : "Weekly Standup" },
338- {"Id" : 101 , "Type" : "L10" , "Key" : "L10-101" , "Name" : "Sprint Planning" },
339- {"Id" : 102 , "Type" : "L10" , "Key" : "L10-102" , "Name" : "Retrospective" },
340- ]
335+ # Mock direct L10/{id} responses and sub-resource responses
336+ direct_responses = {
337+ 100 : {
338+ "Id" : 100 ,
339+ "Basics" : {"Name" : "Weekly Standup" },
340+ "CreateTime" : None ,
341+ "StartDateUtc" : None ,
342+ "OrganizationId" : None ,
343+ },
344+ 101 : {
345+ "Id" : 101 ,
346+ "Basics" : {"Name" : "Sprint Planning" },
347+ "CreateTime" : None ,
348+ "StartDateUtc" : None ,
349+ "OrganizationId" : None ,
350+ },
351+ 102 : {
352+ "Id" : 102 ,
353+ "Basics" : {"Name" : "Retrospective" },
354+ "CreateTime" : None ,
355+ "StartDateUtc" : None ,
356+ "OrganizationId" : None ,
357+ },
358+ }
341359
342360 # Mock attendees responses
343361 attendees_responses = {
@@ -373,17 +391,17 @@ async def test_get_many_all_successful(
373391 def get_side_effect (url , ** _kwargs ):
374392 mock_response = MagicMock ()
375393
376- if url .endswith ("/list" ):
377- mock_response .json .return_value = mock_meetings_list
378- elif "/attendees" in url :
379- # Extract meeting ID from URL
394+ if "/attendees" in url :
380395 meeting_id = int (url .split ("/" )[1 ])
381396 mock_response .json .return_value = attendees_responses .get (
382397 meeting_id , []
383398 )
384- else :
385- # For issues, todos, metrics
399+ elif "/issues" in url or "/todos" in url or "/measurables" in url :
386400 mock_response .json .return_value = []
401+ else :
402+ # Direct L10/{id} endpoint
403+ meeting_id = int (url .split ("/" )[1 ])
404+ mock_response .json .return_value = direct_responses .get (meeting_id , {})
387405
388406 mock_response .raise_for_status = MagicMock ()
389407 return mock_response
@@ -409,25 +427,37 @@ def get_side_effect(url, **_kwargs):
409427 assert len (result .successful [2 ].attendees ) == 1
410428
411429 # Verify API calls - 5 calls per meeting
412- # (list , attendees, issues, todos, metrics)
430+ # (direct , attendees, issues, todos, metrics)
413431 assert mock_async_client .get .call_count == 15
414432
415433 @pytest .mark .asyncio
416434 async def test_get_many_partial_failure (
417435 self , async_client : AsyncClient , mock_async_client : AsyncMock
418436 ) -> None :
419437 """Test bulk retrieval where some meetings fail."""
420- # Mock meeting list response - contains meeting 200 but not 999 or 500
421- mock_meetings_list = [
422- {"Id" : 200 , "Type" : "L10" , "Key" : "L10-200" , "Name" : "Success Meeting" },
423- ]
438+ from httpx import HTTPStatusError , Request , Response
424439
425440 # Create side effect function that returns appropriate response based on URL
426441 def get_side_effect (url , ** _kwargs ):
427442 mock_response = MagicMock ()
428443
429- if url .endswith ("/list" ):
430- mock_response .json .return_value = mock_meetings_list
444+ # Direct endpoint for meeting 200
445+ if url == "L10/200" :
446+ mock_response .json .return_value = {
447+ "Id" : 200 ,
448+ "Basics" : {"Name" : "Success Meeting" },
449+ "CreateTime" : None ,
450+ "StartDateUtc" : None ,
451+ "OrganizationId" : None ,
452+ }
453+ mock_response .raise_for_status = MagicMock ()
454+ elif url in ("L10/999" , "L10/500" ):
455+ # Simulate 404 for non-existent meetings
456+ mock_response .raise_for_status .side_effect = HTTPStatusError (
457+ "Not Found" ,
458+ request = Request ("GET" , url ),
459+ response = Response (404 ),
460+ )
431461 elif "/200/attendees" in url :
432462 mock_response .json .return_value = [
433463 {
@@ -436,11 +466,11 @@ def get_side_effect(url, **_kwargs):
436466 "ImageUrl" : "https://example.com/img1.jpg" ,
437467 }
438468 ]
469+ mock_response .raise_for_status = MagicMock ()
439470 else :
440- # For issues, todos, metrics
441471 mock_response .json .return_value = []
472+ mock_response .raise_for_status = MagicMock ()
442473
443- mock_response .raise_for_status = MagicMock ()
444474 return mock_response
445475
446476 mock_async_client .get .side_effect = get_side_effect
@@ -458,11 +488,9 @@ def get_side_effect(url, **_kwargs):
458488 # Check failed items
459489 assert result .failed [0 ].index == 1
460490 assert result .failed [0 ].input_data ["meeting_id" ] == 999
461- assert "not found" in result .failed [0 ].error .lower ()
462491
463492 assert result .failed [1 ].index == 2
464493 assert result .failed [1 ].input_data ["meeting_id" ] == 500
465- assert "not found" in result .failed [1 ].error .lower ()
466494
467495 @pytest .mark .asyncio
468496 async def test_get_many_empty_list (
@@ -507,29 +535,26 @@ async def delayed_get(*args, **_kwargs):
507535 # Extract the URL from args (first positional argument)
508536 url = args [0 ] if args else ""
509537
510- if url .endswith ("/list" ):
511- # Return list of all meetings
512- mock_response .json .return_value = [
513- {
514- "Id" : i + 400 ,
515- "Type" : "L10" ,
516- "Key" : f"L10-{ i + 400 } " ,
517- "Name" : f"Meeting { i } " ,
518- }
519- for i in range (5 )
520- ]
521- elif "/attendees" in url :
522- # Return attendees for any meeting
538+ if "/attendees" in url :
523539 mock_response .json .return_value = [
524540 {
525541 "Id" : 456 ,
526542 "Name" : "John Doe" ,
527543 "ImageUrl" : "https://example.com/img.jpg" ,
528544 }
529545 ]
530- else :
531- # For issues, todos, metrics
546+ elif "/issues" in url or "/todos" in url or "/measurables" in url :
532547 mock_response .json .return_value = []
548+ else :
549+ # Direct L10/{id} endpoint
550+ meeting_id = int (url .split ("/" )[1 ])
551+ mock_response .json .return_value = {
552+ "Id" : meeting_id ,
553+ "Basics" : {"Name" : f"Meeting { meeting_id - 400 } " },
554+ "CreateTime" : None ,
555+ "StartDateUtc" : None ,
556+ "OrganizationId" : None ,
557+ }
533558
534559 mock_response .raise_for_status = MagicMock ()
535560 return mock_response
@@ -551,7 +576,7 @@ async def delayed_get(*args, **_kwargs):
551576
552577 # Verify concurrent execution
553578 # With max_concurrent=3 and 5 meetings:
554- # Each meeting makes 5 API calls (list , attendees, issues, todos, metrics)
579+ # Each meeting makes 5 API calls (direct , attendees, issues, todos, metrics)
555580 # Each call has 0.1s delay, so each meeting takes ~0.5s
556581 # With concurrency of 3, we should see significant speedup vs sequential
557582 # Sequential would take 5 * 0.5 = 2.5s
0 commit comments