|
1 | 1 | """Additional tests for async user operations to improve coverage.""" |
2 | 2 |
|
| 3 | +import asyncio |
3 | 4 | from unittest.mock import AsyncMock, MagicMock |
4 | 5 |
|
5 | 6 | import pytest |
@@ -209,3 +210,64 @@ async def test_list_users( |
209 | 210 | mock_async_client.get.assert_called_once_with( |
210 | 211 | "search/all", params={"term": "%"} |
211 | 212 | ) |
| 213 | + |
| 214 | + @pytest.mark.asyncio |
| 215 | + async def test_details_include_all_fetches_subresources_concurrently( |
| 216 | + self, |
| 217 | + async_client: AsyncClient, |
| 218 | + mock_async_client: AsyncMock, |
| 219 | + ) -> None: |
| 220 | + """When both flags are set, direct reports and positions run concurrently.""" |
| 221 | + user_data = { |
| 222 | + "Id": 123, |
| 223 | + "Name": "John Doe", |
| 224 | + "Description": "CEO", |
| 225 | + "Email": "john@example.com", |
| 226 | + "OrganizationId": 1, |
| 227 | + "ImageUrl": "https://example.com/avatar.jpg", |
| 228 | + } |
| 229 | + reports_data = [ |
| 230 | + { |
| 231 | + "Id": 456, |
| 232 | + "Name": "Jane Smith", |
| 233 | + "Description": "VP Sales", |
| 234 | + "Email": "jane@example.com", |
| 235 | + "OrganizationId": 1, |
| 236 | + "ImageUrl": "https://example.com/jane.jpg", |
| 237 | + } |
| 238 | + ] |
| 239 | + positions_data = [{"Group": {"Position": {"Id": 1, "Name": "CEO"}}}] |
| 240 | + |
| 241 | + in_flight = 0 |
| 242 | + max_in_flight = 0 |
| 243 | + |
| 244 | + async def get_side_effect(url: str) -> MagicMock: |
| 245 | + nonlocal in_flight, max_in_flight |
| 246 | + in_flight += 1 |
| 247 | + max_in_flight = max(max_in_flight, in_flight) |
| 248 | + await asyncio.sleep(0.02) |
| 249 | + in_flight -= 1 |
| 250 | + |
| 251 | + resp = MagicMock() |
| 252 | + resp.raise_for_status = MagicMock() |
| 253 | + if url == "users/123": |
| 254 | + resp.json.return_value = user_data |
| 255 | + elif url == "users/123/directreports": |
| 256 | + resp.json.return_value = reports_data |
| 257 | + elif url == "users/123/seats": |
| 258 | + resp.json.return_value = positions_data |
| 259 | + else: |
| 260 | + raise ValueError(f"Unexpected URL: {url}") |
| 261 | + return resp |
| 262 | + |
| 263 | + mock_async_client.get.side_effect = get_side_effect |
| 264 | + |
| 265 | + result = await async_client.user.details(user_id=123, include_all=True) |
| 266 | + |
| 267 | + assert isinstance(result, UserDetails) |
| 268 | + assert result.direct_reports is not None |
| 269 | + assert result.positions is not None |
| 270 | + assert len(result.direct_reports) == 1 |
| 271 | + assert len(result.positions) == 1 |
| 272 | + # User details first (sequential), then the two sub-resources overlap. |
| 273 | + assert max_in_flight >= 2 |
0 commit comments