20
20
from marshmallow import ValidationError
21
21
22
22
from faculty .clients .environment import (
23
+ Apt ,
24
+ AptPackage ,
25
+ AptPackageSchema ,
26
+ AptSchema ,
27
+ Conda ,
28
+ CondaSchema ,
29
+ Constraint ,
23
30
Environment ,
24
31
EnvironmentClient ,
32
+ EnvironmentCreateUpdate ,
33
+ EnvironmentCreateUpdateSchema ,
34
+ EnvironmentCreationResponse ,
35
+ EnvironmentCreationResponseSchema ,
25
36
EnvironmentSchema ,
37
+ Pip ,
38
+ PipSchema ,
39
+ PythonSpecification ,
40
+ PythonPackage ,
41
+ PythonPackageSchema ,
42
+ PythonSpecificationSchema ,
43
+ PythonEnvironment ,
44
+ PythonEnvironmentSchema ,
45
+ Script ,
46
+ ScriptSchema ,
47
+ Specification ,
48
+ SpecificationSchema ,
49
+ Version ,
50
+ VersionSchema ,
26
51
)
27
52
53
+ VERSION_BODY = {"constraint" : "==" , "identifier" : "1.0.0" }
54
+ VERSION = Version (constraint = Constraint .EQUAL , identifier = "1.0.0" )
55
+
56
+ VERSION_BODY_LATEST = "latest"
57
+ VERSION_LATEST = "latest"
58
+
59
+ INVALID_VERSION_BODY = {"constraint" : "==" , "identifier" : "invalid-identifier" }
60
+ INVALID_VERSION = Version (
61
+ constraint = Constraint .EQUAL , identifier = "invalid-identifier"
62
+ )
63
+
64
+ PYTHON_PACKAGE_BODY = {"name" : "tensorflow" , "version" : VERSION_BODY }
65
+ PYTHON_PACKAGE = PythonPackage (name = "tensorflow" , version = VERSION )
66
+
67
+ PYTHON_PACKAGE_BODY_LATEST = {
68
+ "name" : "tensorflow" ,
69
+ "version" : VERSION_BODY_LATEST ,
70
+ }
71
+ PYTHON_PACKAGE_LATEST = PythonPackage (
72
+ name = "tensorflow" , version = VERSION_LATEST
73
+ )
74
+
75
+
76
+ PIP_BODY = {
77
+ "extraIndexUrls" : ["http://example.com/" ],
78
+ "packages" : [PYTHON_PACKAGE_BODY ],
79
+ }
80
+ PIP = Pip (extra_index_urls = ["http://example.com/" ], packages = [PYTHON_PACKAGE ])
81
+
82
+
83
+ CONDA_BODY = {"channels" : ["conda-forge" ], "packages" : [PYTHON_PACKAGE_BODY ]}
84
+ CONDA = Conda (channels = ["conda-forge" ], packages = [PYTHON_PACKAGE ])
85
+
86
+ PYTHON_ENVIRONMENT_BODY = {"pip" : PIP_BODY , "conda" : CONDA_BODY }
87
+ PYTHON_ENVIRONMENT = PythonEnvironment (conda = CONDA , pip = PIP )
88
+
89
+ APT_PACKAGE_BODY = {"name" : "cuda" }
90
+ APT_PACKAGE = AptPackage (name = "cuda" )
91
+
92
+ APT_BODY = {"packages" : [APT_PACKAGE_BODY ]}
93
+ APT = Apt (packages = [APT_PACKAGE ])
94
+
95
+ PYTHON_SPECIFICATION_BODY = {
96
+ "Python2" : PYTHON_ENVIRONMENT_BODY ,
97
+ "Python3" : PYTHON_ENVIRONMENT_BODY ,
98
+ }
99
+ PYTHON_SPECIFICATION = PythonSpecification (
100
+ python2 = PYTHON_ENVIRONMENT , python3 = PYTHON_ENVIRONMENT
101
+ )
102
+
103
+ PYTHON_SPECIFICATION_BODY_MISSING_PYTHON2 = {
104
+ "Python3" : PYTHON_ENVIRONMENT_BODY
105
+ }
106
+ PYTHON_SPECIFICATION_BODY_PYTHON2_NONE = {
107
+ "Python2" : None ,
108
+ "Python3" : PYTHON_ENVIRONMENT_BODY ,
109
+ }
110
+ PYTHON_SPECIFICATION_PYTHON2_NONE = PythonSpecification (
111
+ python2 = None , python3 = PYTHON_ENVIRONMENT
112
+ )
113
+
114
+ PYTHON_SPECIFICATION_BODY_MISSING_PYTHON3 = {
115
+ "Python2" : PYTHON_ENVIRONMENT_BODY
116
+ }
117
+ PYTHON_SPECIFICATION_BODY_PYTHON3_NONE = {
118
+ "Python2" : PYTHON_ENVIRONMENT_BODY ,
119
+ "Python3" : None ,
120
+ }
121
+ PYTHON_SPECIFICATION_PYTHON3_NONE = PythonSpecification (
122
+ python2 = PYTHON_ENVIRONMENT , python3 = None
123
+ )
124
+
125
+ PYTHON_SPECIFICATION_BODY_MISSING_KEYS = {}
126
+ PYTHON_SPECIFICATION_BODY_NONE = {"Python2" : None , "Python3" : None }
127
+ PYTHON_SPECIFICATION_NONE = PythonSpecification (python2 = None , python3 = None )
128
+
129
+ SCRIPT_STR = "# Edit your script\n "
130
+ SCRIPT_BODY = {"script" : SCRIPT_STR }
131
+ SCRIPT = Script (script = SCRIPT_STR )
132
+
133
+ SPECIFICATION_BODY = {
134
+ "apt" : APT_BODY ,
135
+ "bash" : [SCRIPT_BODY ],
136
+ "python" : PYTHON_SPECIFICATION_BODY ,
137
+ }
138
+ SPECIFICATION = Specification (
139
+ apt = APT , bash = [SCRIPT ], python = PYTHON_SPECIFICATION
140
+ )
28
141
29
142
PROJECT_ID = uuid .uuid4 ()
143
+ ENVIRONMENT_ID = uuid .uuid4 ()
144
+ AUTHOR_ID = uuid .uuid4 ()
145
+ NAME = "Test environment"
146
+ DESCRIPTION = "Environment description"
30
147
148
+ ENVIRONMENT_BODY = {
149
+ "environmentId" : str (ENVIRONMENT_ID ),
150
+ "projectId" : str (PROJECT_ID ),
151
+ "name" : NAME ,
152
+ "description" : DESCRIPTION ,
153
+ "authorId" : str (AUTHOR_ID ),
154
+ "createdAt" : "2018-10-03T04:20:00Z" ,
155
+ "updatedAt" : "2018-11-03T04:21:15Z" ,
156
+ "specification" : SPECIFICATION_BODY ,
157
+ }
31
158
ENVIRONMENT = Environment (
32
- id = uuid . uuid4 () ,
159
+ id = ENVIRONMENT_ID ,
33
160
project_id = PROJECT_ID ,
34
- name = "Test Environment" ,
35
- description = "Environment description" ,
36
- author_id = uuid . uuid4 () ,
161
+ name = NAME ,
162
+ description = DESCRIPTION ,
163
+ author_id = AUTHOR_ID ,
37
164
created_at = datetime .datetime (2018 , 10 , 3 , 4 , 20 , 0 , 0 , tzinfo = UTC ),
38
165
updated_at = datetime .datetime (2018 , 11 , 3 , 4 , 21 , 15 , 0 , tzinfo = UTC ),
166
+ specification = SPECIFICATION ,
39
167
)
40
168
41
- ENVIRONMENT_BODY = {
42
- "environmentId" : str (ENVIRONMENT .id ),
43
- "projectId" : str (PROJECT_ID ),
44
- "name" : ENVIRONMENT .name ,
45
- "description" : ENVIRONMENT .description ,
46
- "authorId" : str (ENVIRONMENT .author_id ),
47
- "createdAt" : "2018-10-03T04:20:00Z" ,
48
- "updatedAt" : "2018-11-03T04:21:15Z" ,
169
+ ENVIRONMENT_CREATION_RESPONSE_BODY = {"environmentId" : str (ENVIRONMENT_ID )}
170
+ ENVIRONMENT_CREATION_RESPONSE = EnvironmentCreationResponse (id = ENVIRONMENT_ID )
171
+
172
+ ENVIRONMENT_CREATE_UPDATE_BODY = {
173
+ "name" : NAME ,
174
+ "description" : DESCRIPTION ,
175
+ "specification" : SPECIFICATION_BODY ,
176
+ }
177
+ ENVIRONMENT_CREATE_UPDATE = EnvironmentCreateUpdate (
178
+ name = NAME , description = DESCRIPTION , specification = SPECIFICATION
179
+ )
180
+ ENVIRONMENT_CREATE_UPDATE_BODY_NO_DESCRIPTION = {
181
+ "name" : NAME ,
182
+ "description" : None ,
183
+ "specification" : SPECIFICATION_BODY ,
49
184
}
185
+ ENVIRONMENT_CREATE_UPDATE_NO_DESCRIPTION = EnvironmentCreateUpdate (
186
+ name = NAME , description = None , specification = SPECIFICATION
187
+ )
188
+
189
+
190
+ def test_version_schema_load ():
191
+ data = VersionSchema ().load (VERSION_BODY )
192
+ assert data == VERSION
193
+
194
+
195
+ def test_version_schema_dump ():
196
+ data = VersionSchema ().dump (VERSION )
197
+ assert data == VERSION_BODY
198
+
199
+
200
+ def test_version_schema_load_invalid ():
201
+ with pytest .raises (ValidationError ):
202
+ VersionSchema ().load (INVALID_VERSION_BODY )
203
+
204
+
205
+ def test_version_schema_dump_invalid ():
206
+ with pytest .raises (ValidationError ):
207
+ VersionSchema ().dump (INVALID_VERSION )
208
+
209
+
210
+ @pytest .mark .parametrize (
211
+ "body, expected" ,
212
+ [
213
+ (PYTHON_PACKAGE_BODY , PYTHON_PACKAGE ),
214
+ (PYTHON_PACKAGE_BODY_LATEST , PYTHON_PACKAGE_LATEST ),
215
+ ],
216
+ )
217
+ def test_python_package_schema_load (body , expected ):
218
+ data = PythonPackageSchema ().load (body )
219
+ assert data == expected
220
+
221
+
222
+ @pytest .mark .parametrize (
223
+ "object, expected" ,
224
+ [
225
+ (PYTHON_PACKAGE , PYTHON_PACKAGE_BODY ),
226
+ (PYTHON_PACKAGE_LATEST , PYTHON_PACKAGE_BODY_LATEST ),
227
+ ],
228
+ )
229
+ def test_python_package_schema_dump (object , expected ):
230
+ data = PythonPackageSchema ().dump (object )
231
+ assert data == expected
232
+
233
+
234
+ def test_pip_schema_load ():
235
+ data = PipSchema ().load (PIP_BODY )
236
+ assert data == PIP
237
+
238
+
239
+ def test_pip_schema_dump ():
240
+ data = PipSchema ().dump (PIP )
241
+ assert data == PIP_BODY
242
+
243
+
244
+ def test_conda_schema_load ():
245
+ data = CondaSchema ().load (CONDA_BODY )
246
+ assert data == CONDA
247
+
248
+
249
+ def test_conda_schema_dump ():
250
+ data = CondaSchema ().dump (CONDA )
251
+ assert data == CONDA_BODY
252
+
253
+
254
+ def test_python_environment_schema_load ():
255
+ data = PythonEnvironmentSchema ().load (PYTHON_ENVIRONMENT_BODY )
256
+ assert data == PYTHON_ENVIRONMENT
257
+
258
+
259
+ def test_python_environment_schema_dump ():
260
+ data = PythonEnvironmentSchema ().dump (PYTHON_ENVIRONMENT )
261
+ assert data == PYTHON_ENVIRONMENT_BODY
262
+
263
+
264
+ def test_apt_package_schema_load ():
265
+ data = AptPackageSchema ().load (APT_PACKAGE_BODY )
266
+ assert data == APT_PACKAGE
267
+
268
+
269
+ def test_apt_package_schema_dump ():
270
+ data = AptPackageSchema ().dump (APT_PACKAGE )
271
+ assert data == APT_PACKAGE_BODY
272
+
273
+
274
+ def test_apt_schema_load ():
275
+ data = AptSchema ().load (APT_BODY )
276
+ assert data == APT
277
+
278
+
279
+ def test_apt_schema_dump ():
280
+ data = AptSchema ().dump (APT )
281
+ assert data == APT_BODY
282
+
283
+
284
+ @pytest .mark .parametrize (
285
+ "body, expected" ,
286
+ [
287
+ (PYTHON_SPECIFICATION_BODY , PYTHON_SPECIFICATION ),
288
+ (
289
+ PYTHON_SPECIFICATION_BODY_MISSING_PYTHON2 ,
290
+ PYTHON_SPECIFICATION_PYTHON2_NONE ,
291
+ ),
292
+ (
293
+ PYTHON_SPECIFICATION_BODY_MISSING_PYTHON3 ,
294
+ PYTHON_SPECIFICATION_PYTHON3_NONE ,
295
+ ),
296
+ (PYTHON_SPECIFICATION_BODY_MISSING_KEYS , PYTHON_SPECIFICATION_NONE ),
297
+ ],
298
+ )
299
+ def test_python_specification_schema_load (body , expected ):
300
+ data = PythonSpecificationSchema ().load (body )
301
+ assert data == expected
302
+
303
+
304
+ @pytest .mark .parametrize (
305
+ "object, expected" ,
306
+ [
307
+ (PYTHON_SPECIFICATION , PYTHON_SPECIFICATION_BODY ),
308
+ (
309
+ PYTHON_SPECIFICATION_PYTHON2_NONE ,
310
+ PYTHON_SPECIFICATION_BODY_PYTHON2_NONE ,
311
+ ),
312
+ (
313
+ PYTHON_SPECIFICATION_PYTHON3_NONE ,
314
+ PYTHON_SPECIFICATION_BODY_PYTHON3_NONE ,
315
+ ),
316
+ (PYTHON_SPECIFICATION_NONE , PYTHON_SPECIFICATION_BODY_NONE ),
317
+ ],
318
+ )
319
+ def test_python_specification_schema_dump (object , expected ):
320
+ data = PythonSpecificationSchema ().dump (object )
321
+ assert data == expected
322
+
323
+
324
+ def test_script_schema_load ():
325
+ data = ScriptSchema ().load (SCRIPT_BODY )
326
+ assert data == SCRIPT
327
+
328
+
329
+ def test_script_schema_dump ():
330
+ data = ScriptSchema ().dump (SCRIPT )
331
+ assert data == SCRIPT_BODY
332
+
333
+
334
+ def test_specification_schema_load ():
335
+ data = SpecificationSchema ().load (SPECIFICATION_BODY )
336
+ assert data == SPECIFICATION
337
+
338
+
339
+ def test_specification_schema_dump ():
340
+ data = SpecificationSchema ().dump (SPECIFICATION )
341
+ assert data == SPECIFICATION_BODY
342
+
343
+
344
+ @pytest .mark .parametrize (
345
+ "body, expected" ,
346
+ [
347
+ (ENVIRONMENT_CREATE_UPDATE_BODY , ENVIRONMENT_CREATE_UPDATE ),
348
+ (
349
+ ENVIRONMENT_CREATE_UPDATE_BODY_NO_DESCRIPTION ,
350
+ ENVIRONMENT_CREATE_UPDATE_NO_DESCRIPTION ,
351
+ ),
352
+ ],
353
+ )
354
+ def test_environment_create_update_schema_load (body , expected ):
355
+ data = EnvironmentCreateUpdateSchema ().load (body )
356
+ assert data == expected
357
+
358
+
359
+ @pytest .mark .parametrize (
360
+ "object, expected" ,
361
+ [
362
+ (ENVIRONMENT_CREATE_UPDATE , ENVIRONMENT_CREATE_UPDATE_BODY ),
363
+ (
364
+ ENVIRONMENT_CREATE_UPDATE_NO_DESCRIPTION ,
365
+ ENVIRONMENT_CREATE_UPDATE_BODY_NO_DESCRIPTION ,
366
+ ),
367
+ ],
368
+ )
369
+ def test_environment_create_update_schema_dump (object , expected ):
370
+ data = EnvironmentCreateUpdateSchema ().dump (object )
371
+ assert data == expected
372
+
373
+
374
+ def test_environment_creation_response_schema ():
375
+ data = EnvironmentCreationResponseSchema ().load (
376
+ ENVIRONMENT_CREATION_RESPONSE_BODY
377
+ )
378
+ assert data == ENVIRONMENT_CREATION_RESPONSE
50
379
51
380
52
381
def test_environment_schema ():
@@ -70,3 +399,76 @@ def test_environment_client_list(mocker):
70
399
EnvironmentClient ._get .assert_called_once_with (
71
400
"/project/{}/environment" .format (PROJECT_ID ), schema_mock .return_value
72
401
)
402
+
403
+
404
+ def test_environment_client_get (mocker ):
405
+ mocker .patch .object (EnvironmentClient , "_get" , return_value = ENVIRONMENT )
406
+ schema_mock = mocker .patch ("faculty.clients.environment.EnvironmentSchema" )
407
+
408
+ client = EnvironmentClient (mocker .Mock ())
409
+ assert client .get (PROJECT_ID , ENVIRONMENT_ID ) == ENVIRONMENT
410
+
411
+ schema_mock .assert_called_once_with ()
412
+ EnvironmentClient ._get .assert_called_once_with (
413
+ "/project/{}/environment/{}" .format (PROJECT_ID , ENVIRONMENT_ID ),
414
+ schema_mock .return_value ,
415
+ )
416
+
417
+
418
+ def test_environment_client_update (mocker ):
419
+ mocker .patch .object (EnvironmentClient , "_put_raw" )
420
+ mocker .patch .object (
421
+ EnvironmentCreateUpdateSchema ,
422
+ "dump" ,
423
+ return_value = ENVIRONMENT_CREATE_UPDATE_BODY ,
424
+ )
425
+
426
+ client = EnvironmentClient (mocker .Mock ())
427
+ client .update (PROJECT_ID , ENVIRONMENT_ID , NAME , SPECIFICATION , DESCRIPTION )
428
+
429
+ EnvironmentCreateUpdateSchema .dump .assert_called_once_with (
430
+ ENVIRONMENT_CREATE_UPDATE
431
+ )
432
+ EnvironmentClient ._put_raw .assert_called_once_with (
433
+ "/project/{}/environment/{}" .format (PROJECT_ID , ENVIRONMENT_ID ),
434
+ json = ENVIRONMENT_CREATE_UPDATE_BODY ,
435
+ )
436
+
437
+
438
+ def test_environment_client_create (mocker ):
439
+ mocker .patch .object (
440
+ EnvironmentClient , "_post" , return_value = ENVIRONMENT_CREATION_RESPONSE
441
+ )
442
+ mocker .patch .object (
443
+ EnvironmentCreateUpdateSchema ,
444
+ "dump" ,
445
+ return_value = ENVIRONMENT_CREATE_UPDATE_BODY ,
446
+ )
447
+ schema_mock = mocker .patch (
448
+ "faculty.clients.environment.EnvironmentCreationResponseSchema"
449
+ )
450
+
451
+ client = EnvironmentClient (mocker .Mock ())
452
+ assert (
453
+ client .create (PROJECT_ID , NAME , SPECIFICATION , description = DESCRIPTION )
454
+ == ENVIRONMENT_CREATION_RESPONSE .id
455
+ )
456
+ EnvironmentCreateUpdateSchema .dump .assert_called_once_with (
457
+ ENVIRONMENT_CREATE_UPDATE
458
+ )
459
+ EnvironmentClient ._post .assert_called_once_with (
460
+ "/project/{}/environment" .format (PROJECT_ID ),
461
+ schema_mock .return_value ,
462
+ json = ENVIRONMENT_CREATE_UPDATE_BODY ,
463
+ )
464
+
465
+
466
+ def test_environment_client_delete (mocker ):
467
+ mocker .patch .object (EnvironmentClient , "_delete_raw" , return_value = None )
468
+
469
+ client = EnvironmentClient (mocker .Mock ())
470
+ client .delete (PROJECT_ID , ENVIRONMENT_ID )
471
+
472
+ EnvironmentClient ._delete_raw .assert_called_once_with (
473
+ "/project/{}/environment/{}" .format (PROJECT_ID , ENVIRONMENT_ID )
474
+ )
0 commit comments