1+ from contextlib import ExitStack
12from unittest .mock import AsyncMock , patch
23
34import pytest
45
56from transformerlab .services .compute_provider import storage_usage_service as svc
67
78
9+ async def fake_du (path ):
10+ return 10 if path .endswith ("models" ) else 5
11+
12+
13+ def _enter_dir_patches (stack : ExitStack ) -> None :
14+ """Enter the common directory + storage.du patches on an ExitStack."""
15+ stack .enter_context (patch .object (svc .storage , "du" , side_effect = fake_du ))
16+ stack .enter_context (patch .object (svc , "set_organization_id" ))
17+ stack .enter_context (patch .object (svc , "get_workspace_dir" , return_value = "/ws" ))
18+ stack .enter_context (patch .object (svc , "get_models_dir" , return_value = "/ws/models" ))
19+ stack .enter_context (patch .object (svc , "get_datasets_dir" , return_value = "/ws/datasets" ))
20+ stack .enter_context (patch .object (svc , "get_experiments_dir" , return_value = "/ws/experiments" ))
21+ stack .enter_context (patch .object (svc , "get_local_provider_org_dir" , return_value = "/lp/team1" ))
22+
23+
824@pytest .mark .asyncio
9- async def test_compute_org_storage_sums_categories ():
10- async def fake_du (path ):
11- return 10 if path .endswith ("models" ) else 5
12-
13- with (
14- patch .object (svc .storage , "du" , side_effect = fake_du ),
15- patch .object (svc , "set_organization_id" ),
16- patch .object (svc , "get_workspace_dir" , return_value = "/ws" ),
17- patch .object (svc , "get_models_dir" , return_value = "/ws/models" ),
18- patch .object (svc , "get_datasets_dir" , return_value = "/ws/datasets" ),
19- patch .object (svc , "get_experiments_dir" , return_value = "/ws/experiments" ),
20- patch .object (svc , "get_local_provider_org_dir" , return_value = "/lp/team1" ),
21- patch .object (svc , "_compute_per_user_bytes" , new = AsyncMock (return_value = {"u1" : 3 })),
22- ):
25+ async def test_compute_org_storage_sums_categories_with_per_user_enabled ():
26+ # Per-user attribution is off by default, so enable it for this path.
27+ with ExitStack () as stack :
28+ _enter_dir_patches (stack )
29+ stack .enter_context (patch .object (svc , "_per_user_enabled" , return_value = True ))
30+ stack .enter_context (patch .object (svc , "_compute_per_user_bytes" , new = AsyncMock (return_value = {"u1" : 3 })))
2331 result = await svc .compute_org_storage ("team1" )
2432
2533 assert result ["total_bytes" ] > 0
@@ -28,6 +36,22 @@ async def fake_du(path):
2836 assert result ["per_user" ] == {"u1" : 3 }
2937
3038
39+ @pytest .mark .asyncio
40+ async def test_compute_org_storage_skips_per_user_when_disabled ():
41+ # Default (flag unset): per-user attribution is skipped and the map is empty,
42+ # but the totals/breakdown are still computed.
43+ per_user_mock = AsyncMock (return_value = {"u1" : 3 })
44+ with ExitStack () as stack :
45+ _enter_dir_patches (stack )
46+ stack .enter_context (patch .object (svc , "_per_user_enabled" , return_value = False ))
47+ stack .enter_context (patch .object (svc , "_compute_per_user_bytes" , new = per_user_mock ))
48+ result = await svc .compute_org_storage ("team1" )
49+
50+ assert result ["total_bytes" ] > 0
51+ assert result ["per_user" ] == {}
52+ per_user_mock .assert_not_called ()
53+
54+
3155def test_gb_helper_formats_bytes ():
3256 assert svc .gb (1_073_741_824 ) == 1.0
3357 assert svc .gb (0 ) == 0.0
0 commit comments