proximl 0.5.17__py3-none-any.whl → 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. examples/local_storage.py +0 -2
  2. proximl/__init__.py +1 -1
  3. proximl/checkpoints.py +56 -57
  4. proximl/cli/__init__.py +6 -3
  5. proximl/cli/checkpoint.py +18 -57
  6. proximl/cli/dataset.py +17 -57
  7. proximl/cli/job/__init__.py +89 -67
  8. proximl/cli/job/create.py +51 -24
  9. proximl/cli/model.py +14 -56
  10. proximl/cli/volume.py +18 -57
  11. proximl/datasets.py +50 -55
  12. proximl/jobs.py +269 -69
  13. proximl/models.py +51 -55
  14. proximl/proximl.py +159 -114
  15. proximl/utils/__init__.py +1 -0
  16. proximl/{auth.py → utils/auth.py} +4 -3
  17. proximl/utils/transfer.py +647 -0
  18. proximl/volumes.py +48 -53
  19. {proximl-0.5.17.dist-info → proximl-1.0.1.dist-info}/METADATA +3 -3
  20. {proximl-0.5.17.dist-info → proximl-1.0.1.dist-info}/RECORD +52 -50
  21. tests/integration/test_checkpoints_integration.py +4 -3
  22. tests/integration/test_datasets_integration.py +5 -3
  23. tests/integration/test_jobs_integration.py +33 -27
  24. tests/integration/test_models_integration.py +7 -3
  25. tests/integration/test_volumes_integration.py +2 -2
  26. tests/unit/cli/test_cli_checkpoint_unit.py +312 -1
  27. tests/unit/cloudbender/test_nodes_unit.py +112 -0
  28. tests/unit/cloudbender/test_providers_unit.py +96 -0
  29. tests/unit/cloudbender/test_regions_unit.py +106 -0
  30. tests/unit/cloudbender/test_services_unit.py +141 -0
  31. tests/unit/conftest.py +23 -10
  32. tests/unit/projects/test_project_data_connectors_unit.py +39 -0
  33. tests/unit/projects/test_project_datastores_unit.py +37 -0
  34. tests/unit/projects/test_project_members_unit.py +46 -0
  35. tests/unit/projects/test_project_services_unit.py +65 -0
  36. tests/unit/projects/test_projects_unit.py +16 -0
  37. tests/unit/test_auth_unit.py +17 -2
  38. tests/unit/test_checkpoints_unit.py +256 -71
  39. tests/unit/test_datasets_unit.py +218 -68
  40. tests/unit/test_exceptions.py +133 -0
  41. tests/unit/test_gpu_types_unit.py +11 -1
  42. tests/unit/test_jobs_unit.py +1014 -95
  43. tests/unit/test_main_unit.py +20 -0
  44. tests/unit/test_models_unit.py +218 -70
  45. tests/unit/test_proximl_unit.py +627 -3
  46. tests/unit/test_volumes_unit.py +211 -70
  47. tests/unit/utils/__init__.py +1 -0
  48. tests/unit/utils/test_transfer_unit.py +4260 -0
  49. proximl/cli/connection.py +0 -61
  50. proximl/connections.py +0 -621
  51. tests/unit/test_connections_unit.py +0 -182
  52. {proximl-0.5.17.dist-info → proximl-1.0.1.dist-info}/LICENSE +0 -0
  53. {proximl-0.5.17.dist-info → proximl-1.0.1.dist-info}/WHEEL +0 -0
  54. {proximl-0.5.17.dist-info → proximl-1.0.1.dist-info}/entry_points.txt +0 -0
  55. {proximl-0.5.17.dist-info → proximl-1.0.1.dist-info}/top_level.txt +0 -0
@@ -165,3 +165,144 @@ class serviceTests:
165
165
  )
166
166
  assert service.id == "service-id-1"
167
167
  assert response.id == "service-id-1"
168
+
169
+ def test_service_status_property(self, service):
170
+ """Test service status property."""
171
+ service._status = "active"
172
+ assert service.status == "active"
173
+
174
+ def test_service_port_property(self, service):
175
+ """Test service port property."""
176
+ service._port = "443"
177
+ assert service.port == "443"
178
+
179
+ @mark.asyncio
180
+ async def test_service_wait_for_already_at_status(self, service):
181
+ """Test wait_for returns immediately if already at target status."""
182
+ service._status = "active"
183
+ result = await service.wait_for("active")
184
+ assert result is None
185
+
186
+ @mark.asyncio
187
+ async def test_service_wait_for_invalid_status(self, service):
188
+ """Test wait_for raises error for invalid status."""
189
+ with raises(SpecificationError) as exc_info:
190
+ await service.wait_for("invalid_status")
191
+ assert "Invalid wait_for status" in str(exc_info.value.message)
192
+
193
+ @mark.asyncio
194
+ async def test_service_wait_for_timeout_validation(self, service):
195
+ """Test wait_for validates timeout."""
196
+ with raises(SpecificationError) as exc_info:
197
+ await service.wait_for("active", timeout=25 * 60 * 60)
198
+ assert "timeout must be less than" in str(exc_info.value.message)
199
+
200
+ @mark.asyncio
201
+ async def test_service_wait_for_success(self, service, mock_proximl):
202
+ """Test wait_for succeeds when status matches."""
203
+ service._status = "new"
204
+ api_response_new = dict(
205
+ provider_uuid="1",
206
+ region_uuid="a",
207
+ service_id="x",
208
+ status="new",
209
+ )
210
+ api_response_active = dict(
211
+ provider_uuid="1",
212
+ region_uuid="a",
213
+ service_id="x",
214
+ status="active",
215
+ )
216
+ mock_proximl._query = AsyncMock(
217
+ side_effect=[api_response_new, api_response_active]
218
+ )
219
+ with patch("proximl.cloudbender.services.asyncio.sleep", new_callable=AsyncMock):
220
+ result = await service.wait_for("active", timeout=10)
221
+ assert result == service
222
+ assert service.status == "active"
223
+
224
+ @mark.asyncio
225
+ async def test_service_wait_for_archived_404(self, service, mock_proximl):
226
+ """Test wait_for handles 404 for archived status."""
227
+ service._status = "active"
228
+ api_error = ApiError(404, {"errorMessage": "Not found"})
229
+ mock_proximl._query = AsyncMock(side_effect=api_error)
230
+ with patch("proximl.cloudbender.services.asyncio.sleep", new_callable=AsyncMock):
231
+ await service.wait_for("archived", timeout=10)
232
+
233
+ @mark.asyncio
234
+ async def test_service_wait_for_timeout(self, service, mock_proximl):
235
+ """Test wait_for raises timeout exception."""
236
+ service._status = "new"
237
+ api_response_new = dict(
238
+ provider_uuid="1",
239
+ region_uuid="a",
240
+ service_id="x",
241
+ status="new",
242
+ )
243
+ mock_proximl._query = AsyncMock(return_value=api_response_new)
244
+ with patch("proximl.cloudbender.services.asyncio.sleep", new_callable=AsyncMock):
245
+ with raises(ProxiMLException) as exc_info:
246
+ await service.wait_for("active", timeout=0.1)
247
+ assert "Timeout waiting for" in str(exc_info.value.message)
248
+
249
+ @mark.asyncio
250
+ async def test_service_wait_for_api_error_non_404(self, service, mock_proximl):
251
+ """Test wait_for raises ApiError when not 404 for archived (line 181)."""
252
+ service._status = "active"
253
+ api_error = ApiError(500, {"errorMessage": "Server Error"})
254
+ mock_proximl._query = AsyncMock(side_effect=api_error)
255
+ with patch("proximl.cloudbender.services.asyncio.sleep", new_callable=AsyncMock):
256
+ with raises(ApiError):
257
+ await service.wait_for("archived", timeout=10)
258
+
259
+ @mark.asyncio
260
+ async def test_service_generate_certificate(self, service, mock_proximl):
261
+ """Test generate_certificate method."""
262
+ api_response = {
263
+ "provider_uuid": "1",
264
+ "region_uuid": "a",
265
+ "service_id": "x",
266
+ "certificate": "cert-data",
267
+ }
268
+ mock_proximl._query = AsyncMock(return_value=api_response)
269
+ result = await service.generate_certificate()
270
+ mock_proximl._query.assert_called_once_with(
271
+ "/provider/1/region/a/service/x/certificate",
272
+ "POST",
273
+ {},
274
+ dict(algorithm="ed25519"),
275
+ )
276
+ assert result == service
277
+
278
+ @mark.asyncio
279
+ async def test_service_generate_certificate_custom_algorithm(self, service, mock_proximl):
280
+ """Test generate_certificate with custom algorithm."""
281
+ api_response = {
282
+ "provider_uuid": "1",
283
+ "region_uuid": "a",
284
+ "service_id": "x",
285
+ "certificate": "cert-data",
286
+ }
287
+ mock_proximl._query = AsyncMock(return_value=api_response)
288
+ result = await service.generate_certificate(algorithm="rsa")
289
+ mock_proximl._query.assert_called_once_with(
290
+ "/provider/1/region/a/service/x/certificate",
291
+ "POST",
292
+ {},
293
+ dict(algorithm="rsa"),
294
+ )
295
+
296
+ @mark.asyncio
297
+ async def test_service_sign_client_certificate(self, service, mock_proximl):
298
+ """Test sign_client_certificate method."""
299
+ api_response = {"certificate": "signed-cert-data"}
300
+ mock_proximl._query = AsyncMock(return_value=api_response)
301
+ result = await service.sign_client_certificate("csr-data")
302
+ mock_proximl._query.assert_called_once_with(
303
+ "/provider/1/region/a/service/x/certificate/sign",
304
+ "POST",
305
+ {},
306
+ dict(csr="csr-data"),
307
+ )
308
+ assert result == api_response
tests/unit/conftest.py CHANGED
@@ -4,7 +4,7 @@ from pytest import fixture, mark
4
4
  from unittest.mock import Mock, AsyncMock, patch, create_autospec
5
5
 
6
6
  from proximl.proximl import ProxiML
7
- from proximl.auth import Auth
7
+ from proximl.utils.auth import Auth
8
8
  from proximl.datasets import Dataset, Datasets
9
9
  from proximl.checkpoints import Checkpoint, Checkpoints
10
10
  from proximl.volumes import Volume, Volumes
@@ -12,14 +12,16 @@ from proximl.models import Model, Models
12
12
  from proximl.gpu_types import GpuType, GpuTypes
13
13
  from proximl.environments import Environment, Environments
14
14
  from proximl.jobs import Job, Jobs
15
- from proximl.connections import Connections
16
15
  from proximl.projects import (
17
16
  Projects,
18
17
  Project,
19
18
  )
20
19
  from proximl.projects.datastores import ProjectDatastores, ProjectDatastore
21
20
  from proximl.projects.services import ProjectServices, ProjectService
22
- from proximl.projects.data_connectors import ProjectDataConnectors, ProjectDataConnector
21
+ from proximl.projects.data_connectors import (
22
+ ProjectDataConnectors,
23
+ ProjectDataConnector,
24
+ )
23
25
  from proximl.projects.credentials import ProjectCredentials, ProjectCredential
24
26
  from proximl.projects.secrets import ProjectSecrets, ProjectSecret
25
27
 
@@ -1130,12 +1132,13 @@ def mock_proximl(
1130
1132
  proximl.gpu_types = create_autospec(GpuTypes)
1131
1133
  proximl.environments = create_autospec(Environments)
1132
1134
  proximl.jobs = create_autospec(Jobs)
1133
- proximl.connections = create_autospec(Connections)
1134
1135
  proximl.projects = create_autospec(Projects)
1135
1136
  proximl.datasets.list = AsyncMock(return_value=mock_my_datasets)
1136
1137
  proximl.datasets.list_public = AsyncMock(return_value=mock_public_datasets)
1137
1138
  proximl.checkpoints.list = AsyncMock(return_value=mock_my_checkpoints)
1138
- proximl.checkpoints.list_public = AsyncMock(return_value=mock_public_checkpoints)
1139
+ proximl.checkpoints.list_public = AsyncMock(
1140
+ return_value=mock_public_checkpoints
1141
+ )
1139
1142
  proximl.models.list = AsyncMock(return_value=mock_models)
1140
1143
  proximl.volumes.list = AsyncMock(return_value=mock_my_volumes)
1141
1144
  proximl.gpu_types.list = AsyncMock(return_value=mock_gpu_types)
@@ -1143,17 +1146,25 @@ def mock_proximl(
1143
1146
  proximl.jobs.list = AsyncMock(return_value=mock_jobs)
1144
1147
  proximl.projects.list = AsyncMock(return_value=mock_projects)
1145
1148
  proximl.projects.datastores = create_autospec(ProjectDatastores)
1146
- proximl.projects.datastores.list = AsyncMock(return_value=mock_project_datastores)
1149
+ proximl.projects.datastores.list = AsyncMock(
1150
+ return_value=mock_project_datastores
1151
+ )
1147
1152
  proximl.projects.services = create_autospec(ProjectServices)
1148
- proximl.projects.services.list = AsyncMock(return_value=mock_project_services)
1153
+ proximl.projects.services.list = AsyncMock(
1154
+ return_value=mock_project_services
1155
+ )
1149
1156
  proximl.projects.data_connectors = create_autospec(ProjectDataConnectors)
1150
1157
  proximl.projects.data_connectors.list = AsyncMock(
1151
1158
  return_value=mock_project_data_connectors
1152
1159
  )
1153
1160
  proximl.projects.credentials = create_autospec(ProjectCredentials)
1154
- proximl.projects.credentials.list = AsyncMock(return_value=mock_project_credentials)
1161
+ proximl.projects.credentials.list = AsyncMock(
1162
+ return_value=mock_project_credentials
1163
+ )
1155
1164
  proximl.projects.secrets = create_autospec(ProjectSecrets)
1156
- proximl.projects.secrets.list = AsyncMock(return_value=mock_project_secrets)
1165
+ proximl.projects.secrets.list = AsyncMock(
1166
+ return_value=mock_project_secrets
1167
+ )
1157
1168
 
1158
1169
  proximl.cloudbender = create_autospec(Cloudbender)
1159
1170
 
@@ -1166,7 +1177,9 @@ def mock_proximl(
1166
1177
  proximl.cloudbender.devices = create_autospec(Devices)
1167
1178
  proximl.cloudbender.devices.list = AsyncMock(return_value=mock_devices)
1168
1179
  proximl.cloudbender.datastores = create_autospec(Datastores)
1169
- proximl.cloudbender.datastores.list = AsyncMock(return_value=mock_datastores)
1180
+ proximl.cloudbender.datastores.list = AsyncMock(
1181
+ return_value=mock_datastores
1182
+ )
1170
1183
  proximl.cloudbender.services = create_autospec(Services)
1171
1184
  proximl.cloudbender.services.list = AsyncMock(return_value=mock_services)
1172
1185
  proximl.cloudbender.data_connectors = create_autospec(DataConnectors)
@@ -33,6 +33,25 @@ def project_data_connector(mock_proximl):
33
33
 
34
34
 
35
35
  class ProjectDataConnectorsTests:
36
+ @mark.asyncio
37
+ async def test_project_data_connectors_get(
38
+ self, project_data_connectors, mock_proximl
39
+ ):
40
+ """Test get method (lines 11-14)."""
41
+ api_response = {
42
+ "project_uuid": "proj-id-1",
43
+ "region_uuid": "reg-id-1",
44
+ "id": "connector-id-1",
45
+ "type": "custom",
46
+ "name": "On-Prem Connection A",
47
+ }
48
+ mock_proximl._query = AsyncMock(return_value=api_response)
49
+ result = await project_data_connectors.get("connector-id-1", param1="value1")
50
+ mock_proximl._query.assert_called_once_with(
51
+ "/project/1/data_connectors/connector-id-1", "GET", dict(param1="value1")
52
+ )
53
+ assert result.id == "connector-id-1"
54
+
36
55
  @mark.asyncio
37
56
  async def test_project_data_connectors_refresh(
38
57
  self, project_data_connectors, mock_proximl
@@ -100,3 +119,23 @@ class ProjectDataConnectorTests:
100
119
  empty_project_data_connector = specimen.ProjectDataConnector(mock_proximl)
101
120
  assert bool(project_data_connector)
102
121
  assert not bool(empty_project_data_connector)
122
+
123
+ @mark.asyncio
124
+ async def test_project_data_connector_enable(self, project_data_connector, mock_proximl):
125
+ """Test enable method (line 72)."""
126
+ api_response = dict()
127
+ mock_proximl._query = AsyncMock(return_value=api_response)
128
+ await project_data_connector.enable()
129
+ mock_proximl._query.assert_called_once_with(
130
+ "/project/proj-id-1/data_connectors/ds-id-1/enable", "PATCH"
131
+ )
132
+
133
+ @mark.asyncio
134
+ async def test_project_data_connector_disable(self, project_data_connector, mock_proximl):
135
+ """Test disable method (line 77)."""
136
+ api_response = dict()
137
+ mock_proximl._query = AsyncMock(return_value=api_response)
138
+ await project_data_connector.disable()
139
+ mock_proximl._query.assert_called_once_with(
140
+ "/project/proj-id-1/data_connectors/ds-id-1/disable", "PATCH"
141
+ )
@@ -33,6 +33,23 @@ def project_datastore(mock_proximl):
33
33
 
34
34
 
35
35
  class ProjectDatastoresTests:
36
+ @mark.asyncio
37
+ async def test_project_datastores_get(self, project_datastores, mock_proximl):
38
+ """Test get method (lines 11-14)."""
39
+ api_response = {
40
+ "project_uuid": "proj-id-1",
41
+ "region_uuid": "reg-id-1",
42
+ "id": "store-id-1",
43
+ "type": "nfs",
44
+ "name": "On-prem NFS",
45
+ }
46
+ mock_proximl._query = AsyncMock(return_value=api_response)
47
+ result = await project_datastores.get("store-id-1", param1="value1")
48
+ mock_proximl._query.assert_called_once_with(
49
+ "/project/1/datastores/store-id-1", "GET", dict(param1="value1")
50
+ )
51
+ assert result.id == "store-id-1"
52
+
36
53
  @mark.asyncio
37
54
  async def test_project_datastores_refresh(self, project_datastores, mock_proximl):
38
55
  api_response = dict()
@@ -94,3 +111,23 @@ class ProjectDatastoreTests:
94
111
  empty_project_datastore = specimen.ProjectDatastore(mock_proximl)
95
112
  assert bool(project_datastore)
96
113
  assert not bool(empty_project_datastore)
114
+
115
+ @mark.asyncio
116
+ async def test_project_datastore_enable(self, project_datastore, mock_proximl):
117
+ """Test enable method (line 67)."""
118
+ api_response = dict()
119
+ mock_proximl._query = AsyncMock(return_value=api_response)
120
+ await project_datastore.enable()
121
+ mock_proximl._query.assert_called_once_with(
122
+ "/project/proj-id-1/datastores/ds-id-1/enable", "PATCH"
123
+ )
124
+
125
+ @mark.asyncio
126
+ async def test_project_datastore_disable(self, project_datastore, mock_proximl):
127
+ """Test disable method (line 72)."""
128
+ api_response = dict()
129
+ mock_proximl._query = AsyncMock(return_value=api_response)
130
+ await project_datastore.disable()
131
+ mock_proximl._query.assert_called_once_with(
132
+ "/project/proj-id-1/datastores/ds-id-1/disable", "PATCH"
133
+ )
@@ -37,6 +37,42 @@ def project_member(mock_proximl):
37
37
 
38
38
 
39
39
  class ProjectMembersTests:
40
+ @mark.asyncio
41
+ async def test_project_members_add(self, project_members, mock_proximl):
42
+ """Test add method (lines 18-31)."""
43
+ api_response = {
44
+ "project_uuid": "proj-id-1",
45
+ "email": "newuser@gmail.com",
46
+ "owner": False,
47
+ "job": "all",
48
+ "dataset": "read",
49
+ "model": "all",
50
+ "checkpoint": "read",
51
+ "volume": "all",
52
+ }
53
+ mock_proximl._query = AsyncMock(return_value=api_response)
54
+ result = await project_members.add(
55
+ email="newuser@gmail.com",
56
+ job="all",
57
+ dataset="read",
58
+ model="all",
59
+ checkpoint="read",
60
+ volume="all",
61
+ param1="value1",
62
+ )
63
+ expected_payload = dict(
64
+ email="newuser@gmail.com",
65
+ job="all",
66
+ dataset="read",
67
+ model="all",
68
+ checkpoint="read",
69
+ volume="all",
70
+ )
71
+ mock_proximl._query.assert_called_once_with(
72
+ "/project/1/access", "POST", dict(param1="value1"), expected_payload
73
+ )
74
+ assert result.email == "newuser@gmail.com"
75
+
40
76
  @mark.asyncio
41
77
  async def test_project_members_list(self, project_members, mock_proximl):
42
78
  api_response = [
@@ -72,6 +108,16 @@ class ProjectMembersTests:
72
108
  )
73
109
  assert len(resp) == 2
74
110
 
111
+ @mark.asyncio
112
+ async def test_project_members_remove(self, project_members, mock_proximl):
113
+ """Test remove method (line 35)."""
114
+ api_response = dict()
115
+ mock_proximl._query = AsyncMock(return_value=api_response)
116
+ await project_members.remove("user@gmail.com", param1="value1")
117
+ mock_proximl._query.assert_called_once_with(
118
+ "/project/1/access", "DELETE", dict(param1="value1", email="user@gmail.com")
119
+ )
120
+
75
121
 
76
122
  class ProjectMemberTests:
77
123
  def test_project_member_properties(self, project_member):
@@ -34,6 +34,24 @@ def project_service(mock_proximl):
34
34
 
35
35
 
36
36
  class ProjectServicesTests:
37
+ @mark.asyncio
38
+ async def test_project_services_get(self, project_services, mock_proximl):
39
+ """Test get method (lines 11-14)."""
40
+ api_response = {
41
+ "project_uuid": "proj-id-1",
42
+ "region_uuid": "reg-id-1",
43
+ "id": "res-id-1",
44
+ "type": "port",
45
+ "name": "On-Prem Service A",
46
+ "hostname": "service-a.local",
47
+ }
48
+ mock_proximl._query = AsyncMock(return_value=api_response)
49
+ result = await project_services.get("res-id-1", param1="value1")
50
+ mock_proximl._query.assert_called_once_with(
51
+ "/project/1/services/res-id-1", "GET", dict(param1="value1")
52
+ )
53
+ assert result.id == "res-id-1"
54
+
37
55
  @mark.asyncio
38
56
  async def test_project_services_refresh(self, project_services, mock_proximl):
39
57
  api_response = dict()
@@ -100,3 +118,50 @@ class ProjectServiceTests:
100
118
  empty_project_service = specimen.ProjectService(mock_proximl)
101
119
  assert bool(project_service)
102
120
  assert not bool(empty_project_service)
121
+
122
+ @mark.asyncio
123
+ async def test_project_service_enable(self, project_service, mock_proximl):
124
+ """Test enable method (line 72)."""
125
+ api_response = dict()
126
+ mock_proximl._query = AsyncMock(return_value=api_response)
127
+ await project_service.enable()
128
+ mock_proximl._query.assert_called_once_with(
129
+ "/project/proj-id-1/services/res-id-1/enable", "PATCH"
130
+ )
131
+
132
+ @mark.asyncio
133
+ async def test_project_service_disable(self, project_service, mock_proximl):
134
+ """Test disable method (line 77)."""
135
+ api_response = dict()
136
+ mock_proximl._query = AsyncMock(return_value=api_response)
137
+ await project_service.disable()
138
+ mock_proximl._query.assert_called_once_with(
139
+ "/project/proj-id-1/services/res-id-1/disable", "PATCH"
140
+ )
141
+
142
+ @mark.asyncio
143
+ async def test_project_service_get_service_ca_certificate(self, project_service, mock_proximl):
144
+ """Test get_service_ca_certificate method (lines 82-87)."""
145
+ api_response = {"certificate": "ca-cert-data"}
146
+ mock_proximl._query = AsyncMock(return_value=api_response)
147
+ result = await project_service.get_service_ca_certificate(param1="value1")
148
+ mock_proximl._query.assert_called_once_with(
149
+ "/project/proj-id-1/services/res-id-1/certificate/ca",
150
+ "GET",
151
+ dict(param1="value1"),
152
+ )
153
+ assert result == api_response
154
+
155
+ @mark.asyncio
156
+ async def test_project_service_sign_client_certificate(self, project_service, mock_proximl):
157
+ """Test sign_client_certificate method (lines 90-96)."""
158
+ api_response = {"certificate": "signed-cert-data"}
159
+ mock_proximl._query = AsyncMock(return_value=api_response)
160
+ result = await project_service.sign_client_certificate("csr-data", param1="value1")
161
+ mock_proximl._query.assert_called_once_with(
162
+ "/project/proj-id-1/services/res-id-1/certificate/sign",
163
+ "POST",
164
+ dict(param1="value1"),
165
+ dict(csr="csr-data"),
166
+ )
167
+ assert result == api_response
@@ -48,6 +48,22 @@ class ProjectsTests:
48
48
  await projects.get("1234")
49
49
  mock_proximl._query.assert_called_once_with("/project/1234", "GET", dict())
50
50
 
51
+ @mark.asyncio
52
+ async def test_get_current_project(self, projects, mock_proximl):
53
+ """Test get_current method (lines 20-23)."""
54
+ api_response = {
55
+ "id": "project-id-1",
56
+ "name": "current project",
57
+ "owner": True,
58
+ }
59
+ mock_proximl.project = "project-id-1"
60
+ mock_proximl._query = AsyncMock(return_value=api_response)
61
+ result = await projects.get_current(param1="value1")
62
+ mock_proximl._query.assert_called_once_with(
63
+ "/project/project-id-1", "GET", dict(param1="value1")
64
+ )
65
+ assert result.id == "project-id-1"
66
+
51
67
  @mark.asyncio
52
68
  async def test_list_projects(
53
69
  self,
@@ -6,7 +6,7 @@ from unittest.mock import AsyncMock, patch, mock_open, MagicMock
6
6
  from pytest import mark, fixture, raises
7
7
  from aiohttp import WSMessage, WSMsgType
8
8
 
9
- import proximl.auth as specimen
9
+ import proximl.utils.auth as specimen
10
10
 
11
11
  pytestmark = [mark.sdk, mark.unit]
12
12
 
@@ -21,7 +21,22 @@ pytestmark = [mark.sdk, mark.unit]
21
21
  "PROXIML_POOL_ID": "pool_id",
22
22
  },
23
23
  )
24
- def test_auth_from_envs():
24
+ @patch("proximl.utils.auth.boto3.client")
25
+ @patch("proximl.utils.auth.requests.get")
26
+ @patch("builtins.open", side_effect=FileNotFoundError)
27
+ def test_auth_from_envs(mock_open, mock_requests_get, mock_boto3_client):
28
+ # Mock the auth config request
29
+ mock_response = MagicMock()
30
+ mock_response.json.return_value = {
31
+ "region": "us-east-1",
32
+ "userPoolSDKClientId": "default_client_id",
33
+ "userPoolId": "default_pool_id",
34
+ }
35
+ mock_requests_get.return_value = mock_response
36
+
37
+ # Mock boto3 client
38
+ mock_boto3_client.return_value = MagicMock()
39
+
25
40
  auth = specimen.Auth(config_dir=os.path.expanduser("~/.proximl"))
26
41
  assert auth.__dict__.get("username") == "user-id"
27
42
  assert auth.__dict__.get("password") == "key"