test_pipeline_constructor.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. #
  2. # Copyright 2018-2022 Elyra Authors
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. import sys
  17. import pytest
  18. from elyra.pipeline.pipeline import GenericOperation
  19. from elyra.pipeline.pipeline import Operation
  20. from elyra.pipeline.pipeline import Pipeline
  21. @pytest.fixture
  22. def good_operation():
  23. component_parameters = {
  24. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  25. "runtime_image": "tensorflow/tensorflow:latest",
  26. }
  27. test_operation = GenericOperation(
  28. id="test-id",
  29. type="execution-node",
  30. classifier="execute-notebook-node",
  31. name="test",
  32. component_params=component_parameters,
  33. )
  34. return test_operation
  35. @pytest.fixture
  36. def good_pipeline():
  37. test_pipeline = Pipeline(
  38. id="Random-UUID-123123123123123", name="test-pipeline", runtime="kfp", runtime_config="default_kfp"
  39. )
  40. return test_pipeline
  41. def test_create_operation_minimal(good_operation):
  42. test_operation = good_operation
  43. assert test_operation.id == "test-id"
  44. assert test_operation.type == "execution-node"
  45. assert test_operation.classifier == "execute-notebook-node"
  46. assert test_operation.name == "test"
  47. assert test_operation.filename == "elyra/pipeline/tests/resources/archive/test.ipynb"
  48. assert test_operation.runtime_image == "tensorflow/tensorflow:latest"
  49. assert test_operation.name == "test"
  50. def test_create_operation_with_dependencies():
  51. dependencies = ["elyra/pipline/tests/resources", "elyra/pipline/tests/resources/archive"]
  52. component_parameters = {
  53. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  54. "dependencies": dependencies,
  55. "runtime_image": "tensorflow/tensorflow:latest",
  56. }
  57. test_operation = GenericOperation(
  58. id="test-id",
  59. type="execution-node",
  60. classifier="execute-notebook-node",
  61. name="test",
  62. component_params=component_parameters,
  63. )
  64. assert test_operation.dependencies == dependencies
  65. def test_create_operation_include_subdirectories():
  66. include_subdirectories = True
  67. component_parameters = {
  68. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  69. "include_subdirectories": include_subdirectories,
  70. "runtime_image": "tensorflow/tensorflow:latest",
  71. }
  72. test_operation = GenericOperation(
  73. id="test-id",
  74. type="execution-node",
  75. classifier="execute-notebook-node",
  76. name="test",
  77. component_params=component_parameters,
  78. )
  79. assert test_operation.include_subdirectories == include_subdirectories
  80. def test_create_operation_with_environmental_variables():
  81. env_variables = ['FOO="Bar"', 'BAR="Foo']
  82. component_parameters = {
  83. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  84. "env_vars": env_variables,
  85. "runtime_image": "tensorflow/tensorflow:latest",
  86. }
  87. test_operation = GenericOperation(
  88. id="test-id",
  89. type="execution-node",
  90. classifier="execute-notebook-node",
  91. name="test",
  92. component_params=component_parameters,
  93. )
  94. assert test_operation.env_vars == env_variables
  95. def test_create_operation_with_inputs():
  96. inputs = ["input1.txt", "input2.txt"]
  97. component_parameters = {
  98. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  99. "inputs": inputs,
  100. "runtime_image": "tensorflow/tensorflow:latest",
  101. }
  102. test_operation = GenericOperation(
  103. id="test-id",
  104. type="execution-node",
  105. classifier="execute-notebook-node",
  106. name="test",
  107. component_params=component_parameters,
  108. )
  109. assert test_operation.inputs == inputs
  110. def test_create_operation_with_outputs():
  111. outputs = ["output1.txt", "output2.txt"]
  112. component_parameters = {
  113. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  114. "outputs": outputs,
  115. "runtime_image": "tensorflow/tensorflow:latest",
  116. }
  117. test_operation = GenericOperation(
  118. id="test-id",
  119. type="execution-node",
  120. classifier="execute-notebook-node",
  121. name="test",
  122. component_params=component_parameters,
  123. )
  124. assert test_operation.outputs == outputs
  125. def test_create_operation_with_parent_operations():
  126. parent_operation_ids = ["id-123123-123123-123123", "id-456456-456456-456456"]
  127. component_parameters = {
  128. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  129. "runtime_image": "tensorflow/tensorflow:latest",
  130. }
  131. test_operation = GenericOperation(
  132. id="test-id",
  133. type="execution-node",
  134. classifier="execute-notebook-node",
  135. name="test",
  136. parent_operation_ids=parent_operation_ids,
  137. component_params=component_parameters,
  138. )
  139. assert test_operation.parent_operation_ids == parent_operation_ids
  140. def test_create_operation_correct_naming():
  141. label = "test.ipynb"
  142. filename = "elyra/pipeline/tests/resources/archive/" + label
  143. component_parameters = {"filename": filename, "runtime_image": "tensorflow/tensorflow:latest"}
  144. test_operation = GenericOperation(
  145. id="test-id",
  146. type="execution-node",
  147. classifier="execute-notebook-node",
  148. name=label,
  149. component_params=component_parameters,
  150. )
  151. assert test_operation.name == label.split(".")[0]
  152. def test_fail_create_operation_missing_id():
  153. component_parameters = {
  154. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  155. "runtime_image": "tensorflow/tensorflow:latest",
  156. }
  157. with pytest.raises(TypeError):
  158. Operation(
  159. type="execution-node",
  160. classifier="execute-notebook-node",
  161. name="test",
  162. component_params=component_parameters,
  163. )
  164. def test_fail_create_operation_missing_type():
  165. component_parameters = {
  166. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  167. "runtime_image": "tensorflow/tensorflow:latest",
  168. }
  169. with pytest.raises(TypeError):
  170. GenericOperation(
  171. id="test-id", classifier="execute-notebook-node", name="test", component_params=component_parameters
  172. )
  173. def test_fail_create_operation_missing_classifier():
  174. component_parameters = {
  175. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  176. "runtime_image": "tensorflow/tensorflow:latest",
  177. }
  178. with pytest.raises(TypeError):
  179. Operation(id="test-id", type="execution-node", name="test", component_params=component_parameters)
  180. def test_fail_create_operation_missing_runtime_image():
  181. component_parameters = {"filename": "elyra/pipeline/tests/resources/archive/test.ipynb"}
  182. with pytest.raises(ValueError):
  183. GenericOperation(
  184. id="test-id",
  185. type="execution-node",
  186. classifier="execute-notebook-node",
  187. name="test",
  188. component_params=component_parameters,
  189. )
  190. def test_fail_create_operation_missing_name():
  191. component_parameters = {
  192. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  193. "runtime_image": "tensorflow/tensorflow:latest",
  194. }
  195. with pytest.raises(TypeError):
  196. GenericOperation(
  197. id="test-id",
  198. type="execution-node",
  199. classifier="execute-notebook-node",
  200. component_params=component_parameters,
  201. )
  202. def test_fail_operations_are_equal(good_operation):
  203. parent_operation_ids = ["id-123123-123123-123123", "id-456456-456456-456456"]
  204. component_parameters = {
  205. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  206. "runtime_image": "tensorflow/tensorflow:latest",
  207. }
  208. compare_operation = GenericOperation(
  209. id="test-id",
  210. type="execution-node",
  211. classifier="execute-notebook-node",
  212. name="test",
  213. parent_operation_ids=parent_operation_ids,
  214. component_params=component_parameters,
  215. )
  216. with pytest.raises(AssertionError):
  217. assert compare_operation == good_operation
  218. def test_operations_are_equal(good_operation):
  219. component_parameters = {
  220. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  221. "runtime_image": "tensorflow/tensorflow:latest",
  222. }
  223. compare_operation = GenericOperation(
  224. id="test-id",
  225. type="execution-node",
  226. classifier="execute-notebook-node",
  227. name="test",
  228. component_params=component_parameters,
  229. )
  230. assert compare_operation == good_operation
  231. def test_create_pipeline_minimal(good_pipeline):
  232. test_pipeline = good_pipeline
  233. assert test_pipeline.id == "Random-UUID-123123123123123"
  234. assert test_pipeline.name == "test-pipeline"
  235. assert test_pipeline.runtime == "kfp"
  236. assert test_pipeline.runtime_config == "default_kfp"
  237. def test_fail_create_pipeline_missing_id():
  238. with pytest.raises(TypeError):
  239. Pipeline(name="test-pipeline", runtime="kfp", runtime_config="default_kfp")
  240. def test_fail_create_pipeline_missing_name():
  241. with pytest.raises(TypeError):
  242. Pipeline(id="Random-UUID-123123123123123", runtime="kfp", runtime_config="default_kfp")
  243. def test_fail_create_pipeline_missing_runtime():
  244. with pytest.raises(TypeError):
  245. Pipeline(id="Random-UUID-123123123123123", name="test-pipeline", runtime_config="default_kfp")
  246. def test_fail_create_pipeline_missing_runtime_config():
  247. with pytest.raises(TypeError):
  248. Pipeline(id="Random-UUID-123123123123123", name="test-pipeline", runtime="kfp")
  249. def test_pipelines_are_equal(good_pipeline):
  250. compare_pipeline = Pipeline(
  251. id="Random-UUID-123123123123123", name="test-pipeline", runtime="kfp", runtime_config="default_kfp"
  252. )
  253. assert compare_pipeline == good_pipeline
  254. def test_fail_pipelines_are_equal(good_pipeline):
  255. test_operations_dict = {"123123123": good_operation, "234234234": good_operation}
  256. compare_pipeline = Pipeline(
  257. id="Random-UUID-123123123123123", name="test-pipeline", runtime="kfp", runtime_config="default_kfp"
  258. )
  259. for key, operation in test_operations_dict.items():
  260. compare_pipeline.operations[key] = operation
  261. with pytest.raises(AssertionError):
  262. assert compare_pipeline == good_pipeline
  263. def test_env_list_to_dict_function():
  264. env_variables = [
  265. "KEY=value",
  266. None,
  267. "",
  268. " =empty_key",
  269. "=no_key",
  270. "EMPTY_VALUE= ",
  271. "NO_VALUE=",
  272. "KEY2=value2",
  273. "TWO_EQUALS=KEY=value",
  274. "==",
  275. ]
  276. env_variables_dict = {"KEY": "value", "KEY2": "value2", "TWO_EQUALS": "KEY=value"}
  277. component_parameters = {
  278. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  279. "env_vars": env_variables,
  280. "runtime_image": "tensorflow/tensorflow:latest",
  281. }
  282. test_operation = GenericOperation(
  283. id="test-id",
  284. type="execution-node",
  285. classifier="execute-notebook-node",
  286. name="test",
  287. component_params=component_parameters,
  288. )
  289. assert test_operation.env_vars.to_dict() == env_variables_dict
  290. def test_validate_resource_values():
  291. component_parameters = {
  292. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  293. "cpu": "4",
  294. "gpu": "6",
  295. "memory": "10",
  296. "runtime_image": "tensorflow/tensorflow:latest",
  297. }
  298. test_operation = GenericOperation(
  299. id="test-id",
  300. type="execution-node",
  301. classifier="execute-notebook-node",
  302. name="test",
  303. component_params=component_parameters,
  304. )
  305. assert test_operation.cpu == "4"
  306. assert test_operation.gpu == "6"
  307. assert test_operation.memory == "10"
  308. def test_validate_resource_values_as_none():
  309. component_parameters = {
  310. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  311. "runtime_image": "tensorflow/tensorflow:latest",
  312. }
  313. test_operation = GenericOperation(
  314. id="test-id",
  315. type="execution-node",
  316. classifier="execute-notebook-node",
  317. name="test",
  318. component_params=component_parameters,
  319. )
  320. assert test_operation.cpu is None
  321. assert test_operation.gpu is None
  322. assert test_operation.memory is None
  323. def test_validate_gpu_accepts_zero_as_value():
  324. component_parameters = {
  325. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  326. "cpu": "4",
  327. "gpu": "0",
  328. "memory": "10",
  329. "runtime_image": "tensorflow/tensorflow:latest",
  330. }
  331. test_operation = GenericOperation(
  332. id="test-id",
  333. type="execution-node",
  334. classifier="execute-notebook-node",
  335. name="test",
  336. component_params=component_parameters,
  337. )
  338. assert test_operation.gpu == "0"
  339. def test_validate_max_resource_value():
  340. system_max_size = str(sys.maxsize - 1)
  341. component_parameters = {
  342. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  343. "memory": system_max_size,
  344. "runtime_image": "tensorflow/tensorflow:latest",
  345. }
  346. test_operation = GenericOperation(
  347. id="test-id",
  348. type="execution-node",
  349. classifier="execute-notebook-node",
  350. name="test",
  351. component_params=component_parameters,
  352. )
  353. assert test_operation.memory == system_max_size
  354. def test_fail_validate_max_resource_value_exceeded():
  355. system_max_size = str(sys.maxsize)
  356. component_parameters = {
  357. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  358. "memory": system_max_size,
  359. "runtime_image": "tensorflow/tensorflow:latest",
  360. }
  361. with pytest.raises(ValueError):
  362. GenericOperation(
  363. id="test-id",
  364. type="execution-node",
  365. classifier="execute-notebook-node",
  366. name="test",
  367. component_params=component_parameters,
  368. )
  369. def test_fail_creating_operation_with_negative_gpu_resources():
  370. component_parameters = {
  371. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  372. "gpu": "-1",
  373. "runtime_image": "tensorflow/tensorflow:latest",
  374. }
  375. with pytest.raises(ValueError):
  376. GenericOperation(
  377. id="test-id",
  378. type="execution-node",
  379. classifier="execute-notebook-node",
  380. name="test",
  381. component_params=component_parameters,
  382. )
  383. def test_fail_creating_operation_with_0_cpu_resources():
  384. component_parameters = {
  385. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  386. "cpu": "0",
  387. "runtime_image": "tensorflow/tensorflow:latest",
  388. }
  389. with pytest.raises(ValueError):
  390. GenericOperation(
  391. id="test-id",
  392. type="execution-node",
  393. classifier="execute-notebook-node",
  394. name="test",
  395. component_params=component_parameters,
  396. )
  397. def test_fail_creating_operation_with_negative_cpu_resources():
  398. component_parameters = {
  399. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  400. "cpu": "-1",
  401. "runtime_image": "tensorflow/tensorflow:latest",
  402. }
  403. with pytest.raises(ValueError):
  404. GenericOperation(
  405. id="test-id",
  406. type="execution-node",
  407. classifier="execute-notebook-node",
  408. name="test",
  409. component_params=component_parameters,
  410. )
  411. def test_fail_creating_operation_with_0_memory_resources():
  412. component_parameters = {
  413. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  414. "memory": "0",
  415. "runtime_image": "tensorflow/tensorflow:latest",
  416. }
  417. with pytest.raises(ValueError):
  418. GenericOperation(
  419. id="test-id",
  420. type="execution-node",
  421. classifier="execute-notebook-node",
  422. name="test",
  423. component_params=component_parameters,
  424. )
  425. def test_fail_creating_operation_with_negative_memory_resources():
  426. component_parameters = {
  427. "filename": "elyra/pipeline/tests/resources/archive/test.ipynb",
  428. "memory": "-1",
  429. "runtime_image": "tensorflow/tensorflow:latest",
  430. }
  431. with pytest.raises(ValueError):
  432. GenericOperation(
  433. id="test-id",
  434. type="execution-node",
  435. classifier="execute-notebook-node",
  436. name="test",
  437. component_params=component_parameters,
  438. )
  439. def test_scrub_list_function():
  440. env_variables_input = ["FOO=Bar", "BAR=Foo", None, ""]
  441. env_variables_output = ["FOO=Bar", "BAR=Foo"]
  442. assert Operation._scrub_list(env_variables_input) == env_variables_output