11import pytest
22import responses # https://github.com/getsentry/responses
33
4- from verda .clusters import Cluster , ClusterNode , ClustersService
4+ from verda .clusters import Cluster , ClusterWorkerNode , ClustersService
55from verda .constants import ErrorCodes , Locations
66from verda .exceptions import APIException
77
88INVALID_REQUEST = ErrorCodes .INVALID_REQUEST
9- INVALID_REQUEST_MESSAGE = 'Invalid cluster request'
9+ INVALID_REQUEST_MESSAGE = 'Invalid request'
1010
1111CLUSTER_ID = 'deadc0de-a5d2-4972-ae4e-d429115d055b'
1212SSH_KEY_ID = '12345dc1-a5d2-4972-ae4e-d429115d055b'
1313
14- CLUSTER_NAME = 'test-cluster'
14+ CLUSTER_HOSTNAME = 'test-cluster'
1515CLUSTER_DESCRIPTION = 'Test compute cluster'
1616CLUSTER_STATUS = 'running'
17- CLUSTER_INSTANCE_TYPE = '8V100.48V '
18- CLUSTER_NODE_COUNT = 3
19- CLUSTER_LOCATION = Locations .FIN_01
20- CLUSTER_IMAGE = 'ubuntu-24 .04-cuda-12.8-open-docker '
17+ CLUSTER_CLUSTER_TYPE = '16H200 '
18+ CLUSTER_NODE_COUNT = 2
19+ CLUSTER_LOCATION = Locations .FIN_03
20+ CLUSTER_IMAGE = 'ubuntu-22 .04-cuda-12.4-cluster '
2121CLUSTER_CREATED_AT = '2024-01-01T00:00:00Z'
22- CLUSTER_MASTER_IP = '10.0.0.1'
23- CLUSTER_ENDPOINT = 'cluster-endpoint.verda.com'
22+ CLUSTER_IP = '10.0.0.1'
2423
2524NODE_1_ID = 'node1-c0de-a5d2-4972-ae4e-d429115d055b'
2625NODE_2_ID = 'node2-c0de-a5d2-4972-ae4e-d429115d055b'
27- NODE_3_ID = 'node3-c0de-a5d2-4972-ae4e-d429115d055b'
2826
2927NODES_PAYLOAD = [
3028 {
3129 'id' : NODE_1_ID ,
32- 'instance_type' : CLUSTER_INSTANCE_TYPE ,
3330 'status' : 'running' ,
3431 'hostname' : 'test-cluster-node-1' ,
35- 'ip' : '10.0.0.2' ,
36- 'created_at' : CLUSTER_CREATED_AT ,
32+ 'private_ip' : '10.0.0.1' ,
3733 },
3834 {
3935 'id' : NODE_2_ID ,
40- 'instance_type' : CLUSTER_INSTANCE_TYPE ,
4136 'status' : 'running' ,
4237 'hostname' : 'test-cluster-node-2' ,
43- 'ip' : '10.0.0.3' ,
44- 'created_at' : CLUSTER_CREATED_AT ,
45- },
46- {
47- 'id' : NODE_3_ID ,
48- 'instance_type' : CLUSTER_INSTANCE_TYPE ,
49- 'status' : 'running' ,
50- 'hostname' : 'test-cluster-node-3' ,
51- 'ip' : '10.0.0.4' ,
52- 'created_at' : CLUSTER_CREATED_AT ,
38+ 'private_ip' : '10.0.0.2' ,
5339 },
5440]
5541
5642CLUSTER_PAYLOAD = [
5743 {
5844 'id' : CLUSTER_ID ,
59- 'name ' : CLUSTER_NAME ,
45+ 'hostname ' : CLUSTER_HOSTNAME ,
6046 'description' : CLUSTER_DESCRIPTION ,
6147 'status' : CLUSTER_STATUS ,
6248 'created_at' : CLUSTER_CREATED_AT ,
6349 'location' : CLUSTER_LOCATION ,
64- 'instance_type' : CLUSTER_INSTANCE_TYPE ,
65- 'node_count' : CLUSTER_NODE_COUNT ,
66- 'nodes' : NODES_PAYLOAD ,
50+ 'cluster_type' : CLUSTER_CLUSTER_TYPE ,
51+ 'worker_nodes' : NODES_PAYLOAD ,
6752 'ssh_key_ids' : [SSH_KEY_ID ],
6853 'image' : CLUSTER_IMAGE ,
69- 'master_ip' : CLUSTER_MASTER_IP ,
70- 'endpoint' : CLUSTER_ENDPOINT ,
54+ 'ip' : CLUSTER_IP ,
7155 }
7256]
7357
@@ -94,95 +78,20 @@ def test_get_clusters(self, clusters_service, endpoint):
9478 assert len (clusters ) == 1
9579 assert isinstance (cluster , Cluster )
9680 assert cluster .id == CLUSTER_ID
97- assert cluster .name == CLUSTER_NAME
81+ assert cluster .hostname == CLUSTER_HOSTNAME
9882 assert cluster .description == CLUSTER_DESCRIPTION
9983 assert cluster .status == CLUSTER_STATUS
10084 assert cluster .created_at == CLUSTER_CREATED_AT
10185 assert cluster .location == CLUSTER_LOCATION
102- assert cluster .instance_type == CLUSTER_INSTANCE_TYPE
103- assert cluster .node_count == CLUSTER_NODE_COUNT
104- assert isinstance (cluster .nodes , list )
105- assert len (cluster .nodes ) == CLUSTER_NODE_COUNT
106- assert isinstance (cluster .nodes [0 ], ClusterNode )
86+ assert cluster .cluster_type == CLUSTER_CLUSTER_TYPE
87+ assert isinstance (cluster .worker_nodes , list )
88+ assert len (cluster .worker_nodes ) == CLUSTER_NODE_COUNT
89+ assert isinstance (cluster .worker_nodes [0 ], ClusterWorkerNode )
10790 assert cluster .ssh_key_ids == [SSH_KEY_ID ]
10891 assert cluster .image == CLUSTER_IMAGE
109- assert cluster .master_ip == CLUSTER_MASTER_IP
110- assert cluster .endpoint == CLUSTER_ENDPOINT
92+ assert cluster .ip == CLUSTER_IP
11193 assert responses .assert_call_count (endpoint , 1 ) is True
11294
113- def test_get_clusters_by_status_successful (self , clusters_service , endpoint ):
114- # arrange - add response mock
115- url = endpoint + '?status=running'
116- responses .add (responses .GET , url , json = CLUSTER_PAYLOAD , status = 200 )
117-
118- # act
119- clusters = clusters_service .get (status = 'running' )
120- cluster = clusters [0 ]
121-
122- # assert
123- assert isinstance (clusters , list )
124- assert len (clusters ) == 1
125- assert isinstance (cluster , Cluster )
126- assert cluster .id == CLUSTER_ID
127- assert cluster .status == CLUSTER_STATUS
128- assert responses .assert_call_count (url , 1 ) is True
129-
130- def test_get_clusters_by_status_failed (self , clusters_service , endpoint ):
131- # arrange - add response mock
132- url = endpoint + '?status=invalid_status'
133- responses .add (
134- responses .GET ,
135- url ,
136- json = {'code' : INVALID_REQUEST , 'message' : INVALID_REQUEST_MESSAGE },
137- status = 400 ,
138- )
139-
140- # act
141- with pytest .raises (APIException ) as excinfo :
142- clusters_service .get (status = 'invalid_status' )
143-
144- # assert
145- assert excinfo .value .code == INVALID_REQUEST
146- assert excinfo .value .message == INVALID_REQUEST_MESSAGE
147- assert responses .assert_call_count (url , 1 ) is True
148-
149- def test_get_cluster_by_id_successful (self , clusters_service , endpoint ):
150- # arrange - add response mock
151- url = endpoint + '/' + CLUSTER_ID
152- responses .add (responses .GET , url , json = CLUSTER_PAYLOAD [0 ], status = 200 )
153-
154- # act
155- cluster = clusters_service .get_by_id (CLUSTER_ID )
156-
157- # assert
158- assert isinstance (cluster , Cluster )
159- assert cluster .id == CLUSTER_ID
160- assert cluster .name == CLUSTER_NAME
161- assert cluster .description == CLUSTER_DESCRIPTION
162- assert cluster .status == CLUSTER_STATUS
163- assert cluster .instance_type == CLUSTER_INSTANCE_TYPE
164- assert cluster .node_count == CLUSTER_NODE_COUNT
165- assert responses .assert_call_count (url , 1 ) is True
166-
167- def test_get_cluster_by_id_failed (self , clusters_service , endpoint ):
168- # arrange - add response mock
169- url = endpoint + '/invalid_id'
170- responses .add (
171- responses .GET ,
172- url ,
173- json = {'code' : INVALID_REQUEST , 'message' : INVALID_REQUEST_MESSAGE },
174- status = 400 ,
175- )
176-
177- # act
178- with pytest .raises (APIException ) as excinfo :
179- clusters_service .get_by_id ('invalid_id' )
180-
181- # assert
182- assert excinfo .value .code == INVALID_REQUEST
183- assert excinfo .value .message == INVALID_REQUEST_MESSAGE
184- assert responses .assert_call_count (url , 1 ) is True
185-
18695 def test_create_cluster_successful (self , clusters_service , endpoint ):
18796 # arrange - add response mock
18897 # create cluster
@@ -193,9 +102,8 @@ def test_create_cluster_successful(self, clusters_service, endpoint):
193102
194103 # act
195104 cluster = clusters_service .create (
196- name = CLUSTER_NAME ,
197- instance_type = CLUSTER_INSTANCE_TYPE ,
198- node_count = CLUSTER_NODE_COUNT ,
105+ hostname = CLUSTER_HOSTNAME ,
106+ cluster_type = CLUSTER_CLUSTER_TYPE ,
199107 image = CLUSTER_IMAGE ,
200108 description = CLUSTER_DESCRIPTION ,
201109 ssh_key_ids = [SSH_KEY_ID ],
@@ -205,10 +113,10 @@ def test_create_cluster_successful(self, clusters_service, endpoint):
205113 # assert
206114 assert isinstance (cluster , Cluster )
207115 assert cluster .id == CLUSTER_ID
208- assert cluster .name == CLUSTER_NAME
116+ assert cluster .hostname == CLUSTER_HOSTNAME
209117 assert cluster .description == CLUSTER_DESCRIPTION
210118 assert cluster .status == CLUSTER_STATUS
211- assert cluster .instance_type == CLUSTER_INSTANCE_TYPE
119+ assert cluster .cluster_type == CLUSTER_CLUSTER_TYPE
212120 assert cluster .node_count == CLUSTER_NODE_COUNT
213121 assert cluster .ssh_key_ids == [SSH_KEY_ID ]
214122 assert cluster .location == CLUSTER_LOCATION
@@ -228,8 +136,8 @@ def test_create_cluster_failed(self, clusters_service, endpoint):
228136 # act
229137 with pytest .raises (APIException ) as excinfo :
230138 clusters_service .create (
231- name = CLUSTER_NAME ,
232- instance_type = CLUSTER_INSTANCE_TYPE ,
139+ name = CLUSTER_HOSTNAME ,
140+ cluster_type = CLUSTER_CLUSTER_TYPE ,
233141 node_count = CLUSTER_NODE_COUNT ,
234142 image = CLUSTER_IMAGE ,
235143 description = CLUSTER_DESCRIPTION ,
@@ -246,7 +154,7 @@ def test_delete_cluster_successful(self, clusters_service, endpoint):
246154 responses .add (responses .DELETE , url , status = 202 )
247155
248156 # act
249- result = clusters_service .delete (CLUSTER_ID )
157+ result = clusters_service .action (CLUSTER_ID , 'delete' )
250158
251159 # assert
252160 assert result is None
@@ -271,83 +179,3 @@ def test_delete_cluster_failed(self, clusters_service, endpoint):
271179 assert excinfo .value .message == INVALID_REQUEST_MESSAGE
272180 assert responses .assert_call_count (url , 1 ) is True
273181
274- def test_scale_cluster_successful (self , clusters_service , endpoint ):
275- # arrange - add response mock
276- new_node_count = 5
277- scaled_payload = CLUSTER_PAYLOAD [0 ].copy ()
278- scaled_payload ['node_count' ] = new_node_count
279-
280- # scale endpoint
281- scale_url = endpoint + '/' + CLUSTER_ID + '/scale'
282- responses .add (responses .PUT , scale_url , status = 200 )
283-
284- # get cluster by id
285- get_url = endpoint + '/' + CLUSTER_ID
286- responses .add (responses .GET , get_url , json = scaled_payload , status = 200 )
287-
288- # act
289- cluster = clusters_service .scale (CLUSTER_ID , new_node_count )
290-
291- # assert
292- assert isinstance (cluster , Cluster )
293- assert cluster .id == CLUSTER_ID
294- assert cluster .node_count == new_node_count
295- assert responses .assert_call_count (scale_url , 1 ) is True
296- assert responses .assert_call_count (get_url , 1 ) is True
297-
298- def test_scale_cluster_failed (self , clusters_service , endpoint ):
299- # arrange - add response mock
300- url = endpoint + '/' + CLUSTER_ID + '/scale'
301- responses .add (
302- responses .PUT ,
303- url ,
304- json = {'code' : INVALID_REQUEST , 'message' : INVALID_REQUEST_MESSAGE },
305- status = 400 ,
306- )
307-
308- # act
309- with pytest .raises (APIException ) as excinfo :
310- clusters_service .scale (CLUSTER_ID , 5 )
311-
312- # assert
313- assert excinfo .value .code == INVALID_REQUEST
314- assert excinfo .value .message == INVALID_REQUEST_MESSAGE
315- assert responses .assert_call_count (url , 1 ) is True
316-
317- def test_get_cluster_nodes_successful (self , clusters_service , endpoint ):
318- # arrange - add response mock
319- url = endpoint + '/' + CLUSTER_ID + '/nodes'
320- responses .add (responses .GET , url , json = NODES_PAYLOAD , status = 200 )
321-
322- # act
323- nodes = clusters_service .get_nodes (CLUSTER_ID )
324-
325- # assert
326- assert isinstance (nodes , list )
327- assert len (nodes ) == CLUSTER_NODE_COUNT
328- assert isinstance (nodes [0 ], ClusterNode )
329- assert nodes [0 ].id == NODE_1_ID
330- assert nodes [0 ].instance_type == CLUSTER_INSTANCE_TYPE
331- assert nodes [0 ].status == 'running'
332- assert nodes [1 ].id == NODE_2_ID
333- assert nodes [2 ].id == NODE_3_ID
334- assert responses .assert_call_count (url , 1 ) is True
335-
336- def test_get_cluster_nodes_failed (self , clusters_service , endpoint ):
337- # arrange - add response mock
338- url = endpoint + '/invalid_id/nodes'
339- responses .add (
340- responses .GET ,
341- url ,
342- json = {'code' : INVALID_REQUEST , 'message' : INVALID_REQUEST_MESSAGE },
343- status = 400 ,
344- )
345-
346- # act
347- with pytest .raises (APIException ) as excinfo :
348- clusters_service .get_nodes ('invalid_id' )
349-
350- # assert
351- assert excinfo .value .code == INVALID_REQUEST
352- assert excinfo .value .message == INVALID_REQUEST_MESSAGE
353- assert responses .assert_call_count (url , 1 ) is True
0 commit comments