trainml 0.5.5__py3-none-any.whl → 0.5.7__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.
@@ -6,10 +6,19 @@ import asyncio
6
6
  import aiohttp
7
7
  from pytest import mark, fixture, raises
8
8
  from trainml.exceptions import ApiError
9
+ from urllib.parse import urlparse
9
10
 
10
11
  pytestmark = [mark.sdk, mark.integration, mark.jobs]
11
12
 
12
13
 
14
+ def extract_domain_suffix(hostname):
15
+ parts = hostname.split(".")
16
+ if len(parts) >= 2:
17
+ return ".".join(parts[-2:])
18
+ else:
19
+ return None
20
+
21
+
13
22
  @fixture(scope="class")
14
23
  async def job(trainml):
15
24
  job = await trainml.jobs.create(
@@ -34,6 +43,8 @@ class JobLifeCycleTests:
34
43
  assert job.status != "running"
35
44
  job = await job.wait_for("running")
36
45
  assert job.status == "running"
46
+ assert job.url
47
+ assert extract_domain_suffix(urlparse(job.url).hostname) == "proximl.cloud"
37
48
 
38
49
  async def test_stop_job(self, job):
39
50
  assert job.status == "running"
@@ -518,6 +529,7 @@ class JobIOTests:
518
529
  @mark.asyncio
519
530
  class JobTypeTests:
520
531
  async def test_endpoint(self, trainml):
532
+
521
533
  job = await trainml.jobs.create(
522
534
  "CLI Automated Tests - Endpoint",
523
535
  type="endpoint",
@@ -544,6 +556,7 @@ class JobTypeTests:
544
556
  await job.wait_for("running")
545
557
  await job.refresh()
546
558
  assert job.url
559
+ assert extract_domain_suffix(urlparse(job.url).hostname) == "proximl.cloud"
547
560
  tries = 0
548
561
  await asyncio.sleep(30)
549
562
  async with aiohttp.ClientSession() as session:
@@ -4,35 +4,31 @@ import click
4
4
  from unittest.mock import AsyncMock, patch
5
5
  from pytest import mark, fixture, raises
6
6
 
7
- pytestmark = [mark.cli, mark.unit, mark.cloudbender, mark.reservations]
7
+ pytestmark = [mark.cli, mark.unit, mark.cloudbender, mark.services]
8
8
 
9
- from trainml.cli.cloudbender import reservation as specimen
10
- from trainml.cloudbender.reservations import Reservation
9
+ from trainml.cli.cloudbender import service as specimen
10
+ from trainml.cloudbender.services import Service
11
11
 
12
12
 
13
- def test_list(runner, mock_reservations):
13
+ def test_list(runner, mock_services):
14
14
  with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
15
15
  mock_trainml.cloudbender = AsyncMock()
16
- mock_trainml.cloudbender.reservations = AsyncMock()
17
- mock_trainml.cloudbender.reservations.list = AsyncMock(
18
- return_value=mock_reservations
19
- )
16
+ mock_trainml.cloudbender.services = AsyncMock()
17
+ mock_trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
20
18
  result = runner.invoke(
21
19
  specimen,
22
20
  args=["list", "--provider=prov-id-1", "--region=reg-id-1"],
23
21
  )
24
22
  assert result.exit_code == 0
25
- mock_trainml.cloudbender.reservations.list.assert_called_once_with(
23
+ mock_trainml.cloudbender.services.list.assert_called_once_with(
26
24
  provider_uuid="prov-id-1", region_uuid="reg-id-1"
27
25
  )
28
26
 
29
27
 
30
- def test_list_no_provider(runner, mock_reservations):
28
+ def test_list_no_provider(runner, mock_services):
31
29
  with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
32
30
  mock_trainml.cloudbender = AsyncMock()
33
- mock_trainml.cloudbender.reservations = AsyncMock()
34
- mock_trainml.cloudbender.reservations.list = AsyncMock(
35
- return_value=mock_reservations
36
- )
31
+ mock_trainml.cloudbender.services = AsyncMock()
32
+ mock_trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
37
33
  result = runner.invoke(specimen, ["list"])
38
34
  assert result.exit_code != 0
@@ -0,0 +1,34 @@
1
+ import re
2
+ import json
3
+ import click
4
+ from unittest.mock import AsyncMock, patch
5
+ from pytest import mark, fixture, raises
6
+
7
+ pytestmark = [mark.cli, mark.unit, mark.cloudbender, mark.services]
8
+
9
+ from trainml.cli.cloudbender import service as specimen
10
+ from trainml.cloudbender.services import Service
11
+
12
+
13
+ def test_list(runner, mock_services):
14
+ with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
15
+ mock_trainml.cloudbender = AsyncMock()
16
+ mock_trainml.cloudbender.services = AsyncMock()
17
+ mock_trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
18
+ result = runner.invoke(
19
+ specimen,
20
+ args=["list", "--provider=prov-id-1", "--region=reg-id-1"],
21
+ )
22
+ assert result.exit_code == 0
23
+ mock_trainml.cloudbender.services.list.assert_called_once_with(
24
+ provider_uuid="prov-id-1", region_uuid="reg-id-1"
25
+ )
26
+
27
+
28
+ def test_list_no_provider(runner, mock_services):
29
+ with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
30
+ mock_trainml.cloudbender = AsyncMock()
31
+ mock_trainml.cloudbender.services = AsyncMock()
32
+ mock_trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
33
+ result = runner.invoke(specimen, ["list"])
34
+ assert result.exit_code != 0
@@ -23,9 +23,7 @@ def test_list(runner, mock_projects):
23
23
  def test_list_datastores(runner, mock_project_datastores):
24
24
  with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
25
25
  mock_project = create_autospec(Project)
26
- mock_project.list_datastores = AsyncMock(
27
- return_value=mock_project_datastores
28
- )
26
+ mock_project.list_datastores = AsyncMock(return_value=mock_project_datastores)
29
27
  mock_trainml.projects.get = AsyncMock(return_value=mock_project)
30
28
  result = runner.invoke(specimen, ["list-datastores"])
31
29
  print(result)
@@ -33,14 +31,12 @@ def test_list_datastores(runner, mock_project_datastores):
33
31
  mock_project.list_datastores.assert_called_once()
34
32
 
35
33
 
36
- def test_list_reservations(runner, mock_project_reservations):
34
+ def test_list_services(runner, mock_project_services):
37
35
  with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
38
36
  mock_project = create_autospec(Project)
39
- mock_project.list_reservations = AsyncMock(
40
- return_value=mock_project_reservations
41
- )
37
+ mock_project.list_services = AsyncMock(return_value=mock_project_services)
42
38
  mock_trainml.projects.get = AsyncMock(return_value=mock_project)
43
- result = runner.invoke(specimen, ["list-reservations"])
39
+ result = runner.invoke(specimen, ["list-services"])
44
40
  print(result)
45
41
  assert result.exit_code == 0
46
- mock_project.list_reservations.assert_called_once()
42
+ mock_project.list_services.assert_called_once()
@@ -0,0 +1,176 @@
1
+ import re
2
+ import json
3
+ import logging
4
+ from unittest.mock import AsyncMock, patch
5
+ from pytest import mark, fixture, raises
6
+ from aiohttp import WSMessage, WSMsgType
7
+
8
+ import trainml.cloudbender.data_connectors as specimen
9
+ from trainml.exceptions import (
10
+ ApiError,
11
+ SpecificationError,
12
+ TrainMLException,
13
+ )
14
+
15
+ pytestmark = [mark.sdk, mark.unit, mark.cloudbender, mark.data_connectors]
16
+
17
+
18
+ @fixture
19
+ def data_connectors(mock_trainml):
20
+ yield specimen.DataConnectors(mock_trainml)
21
+
22
+
23
+ @fixture
24
+ def data_connector(mock_trainml):
25
+ yield specimen.DataConnector(
26
+ mock_trainml,
27
+ provider_uuid="1",
28
+ region_uuid="a",
29
+ connector_id="x",
30
+ name="On-Prem Data Connector",
31
+ type="custom",
32
+ cidr="192.168.0.50/32",
33
+ port="443",
34
+ protocol="tcp",
35
+ )
36
+
37
+
38
+ class RegionsTests:
39
+ @mark.asyncio
40
+ async def test_get_data_connector(
41
+ self,
42
+ data_connectors,
43
+ mock_trainml,
44
+ ):
45
+ api_response = dict()
46
+ mock_trainml._query = AsyncMock(return_value=api_response)
47
+ await data_connectors.get("1234", "5687", "91011")
48
+ mock_trainml._query.assert_called_once_with(
49
+ "/provider/1234/region/5687/data_connector/91011", "GET", {}
50
+ )
51
+
52
+ @mark.asyncio
53
+ async def test_list_data_connectors(
54
+ self,
55
+ data_connectors,
56
+ mock_trainml,
57
+ ):
58
+ api_response = dict()
59
+ mock_trainml._query = AsyncMock(return_value=api_response)
60
+ await data_connectors.list("1234", "5687")
61
+ mock_trainml._query.assert_called_once_with(
62
+ "/provider/1234/region/5687/data_connector", "GET", {}
63
+ )
64
+
65
+ @mark.asyncio
66
+ async def test_remove_data_connector(
67
+ self,
68
+ data_connectors,
69
+ mock_trainml,
70
+ ):
71
+ api_response = dict()
72
+ mock_trainml._query = AsyncMock(return_value=api_response)
73
+ await data_connectors.remove("1234", "4567", "8910")
74
+ mock_trainml._query.assert_called_once_with(
75
+ "/provider/1234/region/4567/data_connector/8910", "DELETE", {}
76
+ )
77
+
78
+ @mark.asyncio
79
+ async def test_create_data_connector(self, data_connectors, mock_trainml):
80
+ requested_config = dict(
81
+ provider_uuid="provider-id-1",
82
+ region_uuid="region-id-1",
83
+ name="On-Prem DataConnector",
84
+ type="custom",
85
+ cidr="192.168.0.50/32",
86
+ port="443",
87
+ protocol="tcp",
88
+ )
89
+ expected_payload = dict(
90
+ name="On-Prem DataConnector",
91
+ type="custom",
92
+ cidr="192.168.0.50/32",
93
+ port="443",
94
+ protocol="tcp",
95
+ )
96
+ api_response = {
97
+ "provider_uuid": "provider-id-1",
98
+ "region_uuid": "region-id-1",
99
+ "connector_id": "connector-id-1",
100
+ "name": "On-Prem DataConnector",
101
+ "type": "custom",
102
+ "cidr": "192.168.0.50/32",
103
+ "port": "443",
104
+ "protocol": "tcp",
105
+ "createdAt": "2020-12-31T23:59:59.000Z",
106
+ }
107
+
108
+ mock_trainml._query = AsyncMock(return_value=api_response)
109
+ response = await data_connectors.create(**requested_config)
110
+ mock_trainml._query.assert_called_once_with(
111
+ "/provider/provider-id-1/region/region-id-1/data_connector",
112
+ "POST",
113
+ None,
114
+ expected_payload,
115
+ )
116
+ assert response.id == "connector-id-1"
117
+
118
+
119
+ class DataConnectorTests:
120
+ def test_data_connector_properties(self, data_connector):
121
+ assert isinstance(data_connector.id, str)
122
+ assert isinstance(data_connector.provider_uuid, str)
123
+ assert isinstance(data_connector.region_uuid, str)
124
+ assert isinstance(data_connector.type, str)
125
+ assert isinstance(data_connector.name, str)
126
+
127
+ def test_data_connector_str(self, data_connector):
128
+ string = str(data_connector)
129
+ regex = r"^{.*\"connector_id\": \"" + data_connector.id + r"\".*}$"
130
+ assert isinstance(string, str)
131
+ assert re.match(regex, string)
132
+
133
+ def test_data_connector_repr(self, data_connector):
134
+ string = repr(data_connector)
135
+ regex = (
136
+ r"^DataConnector\( trainml , \*\*{.*'connector_id': '"
137
+ + data_connector.id
138
+ + r"'.*}\)$"
139
+ )
140
+ assert isinstance(string, str)
141
+ assert re.match(regex, string)
142
+
143
+ def test_data_connector_bool(self, data_connector, mock_trainml):
144
+ empty_data_connector = specimen.DataConnector(mock_trainml)
145
+ assert bool(data_connector)
146
+ assert not bool(empty_data_connector)
147
+
148
+ @mark.asyncio
149
+ async def test_data_connector_remove(self, data_connector, mock_trainml):
150
+ api_response = dict()
151
+ mock_trainml._query = AsyncMock(return_value=api_response)
152
+ await data_connector.remove()
153
+ mock_trainml._query.assert_called_once_with(
154
+ "/provider/1/region/a/data_connector/x", "DELETE"
155
+ )
156
+
157
+ @mark.asyncio
158
+ async def test_data_connector_refresh(self, data_connector, mock_trainml):
159
+ api_response = {
160
+ "provider_uuid": "provider-id-1",
161
+ "region_uuid": "region-id-1",
162
+ "connector_id": "connector-id-1",
163
+ "name": "On-Prem DataConnector",
164
+ "type": "custom",
165
+ "cidr": "192.168.0.50/32",
166
+ "port": "443",
167
+ "protocol": "tcp",
168
+ "createdAt": "2020-12-31T23:59:59.000Z",
169
+ }
170
+ mock_trainml._query = AsyncMock(return_value=api_response)
171
+ response = await data_connector.refresh()
172
+ mock_trainml._query.assert_called_once_with(
173
+ f"/provider/1/region/a/data_connector/x", "GET"
174
+ )
175
+ assert data_connector.id == "connector-id-1"
176
+ assert response.id == "connector-id-1"
@@ -0,0 +1,167 @@
1
+ import re
2
+ import json
3
+ import logging
4
+ from unittest.mock import AsyncMock, patch
5
+ from pytest import mark, fixture, raises
6
+ from aiohttp import WSMessage, WSMsgType
7
+
8
+ import trainml.cloudbender.services as specimen
9
+ from trainml.exceptions import (
10
+ ApiError,
11
+ SpecificationError,
12
+ TrainMLException,
13
+ )
14
+
15
+ pytestmark = [mark.sdk, mark.unit, mark.cloudbender, mark.services]
16
+
17
+
18
+ @fixture
19
+ def services(mock_trainml):
20
+ yield specimen.Services(mock_trainml)
21
+
22
+
23
+ @fixture
24
+ def service(mock_trainml):
25
+ yield specimen.Service(
26
+ mock_trainml,
27
+ provider_uuid="1",
28
+ region_uuid="a",
29
+ service_id="x",
30
+ name="On-Prem Service",
31
+ type="https",
32
+ public=False,
33
+ hostname="app1.proximl.cloud",
34
+ )
35
+
36
+
37
+ class RegionsTests:
38
+ @mark.asyncio
39
+ async def test_get_service(
40
+ self,
41
+ services,
42
+ mock_trainml,
43
+ ):
44
+ api_response = dict()
45
+ mock_trainml._query = AsyncMock(return_value=api_response)
46
+ await services.get("1234", "5687", "91011")
47
+ mock_trainml._query.assert_called_once_with(
48
+ "/provider/1234/region/5687/service/91011", "GET", {}
49
+ )
50
+
51
+ @mark.asyncio
52
+ async def test_list_services(
53
+ self,
54
+ services,
55
+ mock_trainml,
56
+ ):
57
+ api_response = dict()
58
+ mock_trainml._query = AsyncMock(return_value=api_response)
59
+ await services.list("1234", "5687")
60
+ mock_trainml._query.assert_called_once_with(
61
+ "/provider/1234/region/5687/service", "GET", {}
62
+ )
63
+
64
+ @mark.asyncio
65
+ async def test_remove_service(
66
+ self,
67
+ services,
68
+ mock_trainml,
69
+ ):
70
+ api_response = dict()
71
+ mock_trainml._query = AsyncMock(return_value=api_response)
72
+ await services.remove("1234", "4567", "8910")
73
+ mock_trainml._query.assert_called_once_with(
74
+ "/provider/1234/region/4567/service/8910", "DELETE", {}
75
+ )
76
+
77
+ @mark.asyncio
78
+ async def test_create_service(self, services, mock_trainml):
79
+ requested_config = dict(
80
+ provider_uuid="provider-id-1",
81
+ region_uuid="region-id-1",
82
+ name="On-Prem Service",
83
+ type="https",
84
+ public=False,
85
+ )
86
+ expected_payload = dict(
87
+ name="On-Prem Service",
88
+ type="https",
89
+ public=False,
90
+ )
91
+ api_response = {
92
+ "provider_uuid": "provider-id-1",
93
+ "region_uuid": "region-id-1",
94
+ "service_id": "service-id-1",
95
+ "name": "On-Prem Service",
96
+ "type": "https",
97
+ "public": False,
98
+ "hostname": "app1.proximl.cloud",
99
+ "createdAt": "2020-12-31T23:59:59.000Z",
100
+ }
101
+
102
+ mock_trainml._query = AsyncMock(return_value=api_response)
103
+ response = await services.create(**requested_config)
104
+ mock_trainml._query.assert_called_once_with(
105
+ "/provider/provider-id-1/region/region-id-1/service",
106
+ "POST",
107
+ None,
108
+ expected_payload,
109
+ )
110
+ assert response.id == "service-id-1"
111
+
112
+
113
+ class serviceTests:
114
+ def test_service_properties(self, service):
115
+ assert isinstance(service.id, str)
116
+ assert isinstance(service.provider_uuid, str)
117
+ assert isinstance(service.region_uuid, str)
118
+ assert isinstance(service.public, bool)
119
+ assert isinstance(service.name, str)
120
+ assert isinstance(service.hostname, str)
121
+ assert isinstance(service.type, str)
122
+
123
+ def test_service_str(self, service):
124
+ string = str(service)
125
+ regex = r"^{.*\"service_id\": \"" + service.id + r"\".*}$"
126
+ assert isinstance(string, str)
127
+ assert re.match(regex, string)
128
+
129
+ def test_service_repr(self, service):
130
+ string = repr(service)
131
+ regex = r"^Service\( trainml , \*\*{.*'service_id': '" + service.id + r"'.*}\)$"
132
+ assert isinstance(string, str)
133
+ assert re.match(regex, string)
134
+
135
+ def test_service_bool(self, service, mock_trainml):
136
+ empty_service = specimen.Service(mock_trainml)
137
+ assert bool(service)
138
+ assert not bool(empty_service)
139
+
140
+ @mark.asyncio
141
+ async def test_service_remove(self, service, mock_trainml):
142
+ api_response = dict()
143
+ mock_trainml._query = AsyncMock(return_value=api_response)
144
+ await service.remove()
145
+ mock_trainml._query.assert_called_once_with(
146
+ "/provider/1/region/a/service/x", "DELETE"
147
+ )
148
+
149
+ @mark.asyncio
150
+ async def test_service_refresh(self, service, mock_trainml):
151
+ api_response = {
152
+ "provider_uuid": "provider-id-1",
153
+ "region_uuid": "region-id-1",
154
+ "service_id": "service-id-1",
155
+ "name": "On-Prem Service",
156
+ "type": "https",
157
+ "public": False,
158
+ "hostname": "app1.proximl.cloud",
159
+ "createdAt": "2020-12-31T23:59:59.000Z",
160
+ }
161
+ mock_trainml._query = AsyncMock(return_value=api_response)
162
+ response = await service.refresh()
163
+ mock_trainml._query.assert_called_once_with(
164
+ f"/provider/1/region/a/service/x", "GET"
165
+ )
166
+ assert service.id == "service-id-1"
167
+ assert response.id == "service-id-1"
tests/unit/conftest.py CHANGED
@@ -17,7 +17,7 @@ from trainml.projects import (
17
17
  Projects,
18
18
  Project,
19
19
  ProjectDatastore,
20
- ProjectReservation,
20
+ ProjectService,
21
21
  )
22
22
  from trainml.cloudbender import Cloudbender
23
23
  from trainml.cloudbender.providers import Provider, Providers
@@ -25,7 +25,7 @@ from trainml.cloudbender.regions import Region, Regions
25
25
  from trainml.cloudbender.nodes import Node, Nodes
26
26
  from trainml.cloudbender.devices import Device, Devices
27
27
  from trainml.cloudbender.datastores import Datastore, Datastores
28
- from trainml.cloudbender.reservations import Reservation, Reservations
28
+ from trainml.cloudbender.services import Service, Services
29
29
  from trainml.cloudbender.device_configs import DeviceConfig, DeviceConfigs
30
30
 
31
31
 
@@ -887,27 +887,27 @@ def mock_project_datastores():
887
887
 
888
888
 
889
889
  @fixture(scope="session")
890
- def mock_reservations():
890
+ def mock_services():
891
891
  trainml = Mock()
892
892
  yield [
893
- Reservation(
893
+ Service(
894
894
  trainml,
895
895
  **{
896
896
  "provider_uuid": "prov-id-1",
897
897
  "region_uuid": "reg-id-1",
898
- "reservation_id": "res-id-1",
898
+ "service_id": "res-id-1",
899
899
  "type": "port",
900
900
  "name": "On-Prem Service A",
901
901
  "resource": "8001",
902
902
  "hostname": "service-a.local",
903
903
  },
904
904
  ),
905
- Reservation(
905
+ Service(
906
906
  trainml,
907
907
  **{
908
908
  "provider_uuid": "prov-id-2",
909
909
  "region_uuid": "reg-id-2",
910
- "reservation_id": "res-id-2",
910
+ "service_id": "res-id-2",
911
911
  "type": "port",
912
912
  "name": "Cloud Service B",
913
913
  "resource": "8001",
@@ -918,10 +918,10 @@ def mock_reservations():
918
918
 
919
919
 
920
920
  @fixture(scope="session")
921
- def mock_project_reservations():
921
+ def mock_project_services():
922
922
  trainml = Mock()
923
923
  yield [
924
- ProjectReservation(
924
+ ProjectService(
925
925
  trainml,
926
926
  **{
927
927
  "project_uuid": "proj-id-1",
@@ -933,7 +933,7 @@ def mock_project_reservations():
933
933
  "hostname": "service-a.local",
934
934
  },
935
935
  ),
936
- ProjectReservation(
936
+ ProjectService(
937
937
  trainml,
938
938
  **{
939
939
  "project_uuid": "proj-id-1",
@@ -990,7 +990,7 @@ def mock_trainml(
990
990
  mock_nodes,
991
991
  mock_devices,
992
992
  mock_datastores,
993
- mock_reservations,
993
+ mock_services,
994
994
  mock_device_configs,
995
995
  ):
996
996
  trainml = create_autospec(TrainML)
@@ -1028,8 +1028,8 @@ def mock_trainml(
1028
1028
  trainml.cloudbender.devices.list = AsyncMock(return_value=mock_devices)
1029
1029
  trainml.cloudbender.datastores = create_autospec(Datastores)
1030
1030
  trainml.cloudbender.datastores.list = AsyncMock(return_value=mock_datastores)
1031
- trainml.cloudbender.reservations = create_autospec(Reservations)
1032
- trainml.cloudbender.reservations.list = AsyncMock(return_value=mock_reservations)
1031
+ trainml.cloudbender.services = create_autospec(Services)
1032
+ trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
1033
1033
  trainml.cloudbender.device_configs = create_autospec(DeviceConfigs)
1034
1034
  trainml.cloudbender.device_configs.list = AsyncMock(
1035
1035
  return_value=mock_device_configs