test_config.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import sys
  2. import yaml
  3. import pytest
  4. from ray_release.test import Test
  5. from ray_release.config import (
  6. read_and_validate_release_test_collection,
  7. validate_cluster_compute,
  8. load_schema_file,
  9. parse_test_definition,
  10. validate_test,
  11. )
  12. from ray_release.exception import ReleaseTestConfigError
  13. _TEST_COLLECTION_FILES = [
  14. "release/release_tests.yaml",
  15. "release/ray_release/tests/test_collection_data.yaml",
  16. ]
  17. VALID_TEST = Test(
  18. **{
  19. "name": "validation_test",
  20. "group": "validation_group",
  21. "working_dir": "validation_dir",
  22. "python": "3.9",
  23. "frequency": "nightly",
  24. "team": "release",
  25. "cluster": {
  26. "byod": {"type": "gpu"},
  27. "cluster_compute": "tpl_cpu_small.yaml",
  28. "autosuspend_mins": 10,
  29. },
  30. "run": {
  31. "timeout": 100,
  32. "script": "python validate.py",
  33. "wait_for_nodes": {"num_nodes": 2, "timeout": 100},
  34. "type": "client",
  35. },
  36. "smoke_test": {"run": {"timeout": 20}, "frequency": "multi"},
  37. "alert": "default",
  38. }
  39. )
  40. def test_parse_test_definition():
  41. """
  42. Unit test for the ray_release.config.parse_test_definition function. In particular,
  43. we check that the code correctly parse a test definition that have the 'variations'
  44. field.
  45. """
  46. test_definitions = yaml.safe_load(
  47. """
  48. - name: sample_test
  49. working_dir: sample_dir
  50. frequency: nightly
  51. team: sample
  52. cluster:
  53. byod:
  54. type: gpu
  55. cluster_compute: compute.yaml
  56. run:
  57. timeout: 100
  58. script: python script.py
  59. variations:
  60. - __suffix__: aws
  61. - __suffix__: gce
  62. cluster:
  63. cluster_compute: compute_gce.yaml
  64. """
  65. )
  66. # Check that parsing returns two tests, one for each variation (aws and gce). Check
  67. # that both tests are valid, and their fields are populated correctly
  68. tests = parse_test_definition(test_definitions)
  69. aws_test = tests[0]
  70. gce_test = tests[1]
  71. schema = load_schema_file()
  72. assert not validate_test(aws_test, schema)
  73. assert not validate_test(gce_test, schema)
  74. assert aws_test["name"] == "sample_test.aws"
  75. assert gce_test["cluster"]["cluster_compute"] == "compute_gce.yaml"
  76. assert gce_test["cluster"]["byod"]["type"] == "gpu"
  77. invalid_test_definition = test_definitions[0]
  78. # Intentionally make the test definition invalid by create an empty 'variations'
  79. # field. Check that the parser throws exception at runtime
  80. invalid_test_definition["variations"] = []
  81. with pytest.raises(ReleaseTestConfigError):
  82. parse_test_definition([invalid_test_definition])
  83. # Intentionally make the test definition invalid by making one 'variation' entry
  84. # missing the __suffix__ entry. Check that the parser throws exception at runtime
  85. invalid_test_definition["variations"] = [{"__suffix__": "aws"}, {}]
  86. with pytest.raises(ReleaseTestConfigError):
  87. parse_test_definition([invalid_test_definition])
  88. def test_schema_validation():
  89. test = VALID_TEST.copy()
  90. schema = load_schema_file()
  91. assert not validate_test(test, schema)
  92. # Remove some optional arguments
  93. del test["alert"]
  94. del test["python"]
  95. del test["run"]["wait_for_nodes"]
  96. del test["cluster"]["autosuspend_mins"]
  97. assert not validate_test(test, schema)
  98. # Add some faulty arguments
  99. # Faulty frequency
  100. invalid_test = test.copy()
  101. invalid_test["frequency"] = "invalid"
  102. assert validate_test(invalid_test, schema)
  103. # Faulty job type
  104. invalid_test = test.copy()
  105. invalid_test["run"]["type"] = "invalid"
  106. assert validate_test(invalid_test, schema)
  107. # Faulty file manager type
  108. invalid_test = test.copy()
  109. invalid_test["run"]["file_manager"] = "invalid"
  110. assert validate_test(invalid_test, schema)
  111. # Faulty smoke test
  112. invalid_test = test.copy()
  113. del invalid_test["smoke_test"]["frequency"]
  114. assert validate_test(invalid_test, schema)
  115. # Faulty Python version
  116. invalid_test = test.copy()
  117. invalid_test["python"] = "invalid"
  118. assert validate_test(invalid_test, schema)
  119. def test_compute_config_invalid_ebs():
  120. compute_config = {
  121. "aws": {
  122. "BlockDeviceMappings": [
  123. {
  124. "DeviceName": "/dev/sda1",
  125. "Ebs": {
  126. "VolumeSize": 1000,
  127. },
  128. }
  129. ]
  130. }
  131. }
  132. assert validate_cluster_compute(compute_config)
  133. compute_config["aws"]["BlockDeviceMappings"][0]["Ebs"][
  134. "DeleteOnTermination"
  135. ] = False
  136. assert validate_cluster_compute(compute_config)
  137. compute_config["aws"]["BlockDeviceMappings"][0]["Ebs"]["DeleteOnTermination"] = True
  138. assert not validate_cluster_compute(compute_config)
  139. compute_config["head_node_type"] = {}
  140. compute_config["head_node_type"]["aws_advanced_configurations"] = {
  141. "BlockDeviceMappings": [
  142. {
  143. "DeviceName": "/dev/sda1",
  144. "Ebs": {
  145. "VolumeSize": 1000,
  146. },
  147. }
  148. ]
  149. }
  150. assert validate_cluster_compute(compute_config)
  151. compute_config["head_node_type"]["aws_advanced_configurations"][
  152. "BlockDeviceMappings"
  153. ][0]["Ebs"]["DeleteOnTermination"] = False
  154. assert validate_cluster_compute(compute_config)
  155. compute_config["head_node_type"]["aws_advanced_configurations"][
  156. "BlockDeviceMappings"
  157. ][0]["Ebs"]["DeleteOnTermination"] = True
  158. assert not validate_cluster_compute(compute_config)
  159. compute_config["worker_node_types"] = [{}]
  160. compute_config["worker_node_types"][0]["aws_advanced_configurations"] = {
  161. "BlockDeviceMappings": [
  162. {
  163. "DeviceName": "/dev/sda1",
  164. "Ebs": {
  165. "VolumeSize": 1000,
  166. },
  167. }
  168. ]
  169. }
  170. assert validate_cluster_compute(compute_config)
  171. compute_config["worker_node_types"][0]["aws_advanced_configurations"][
  172. "BlockDeviceMappings"
  173. ][0]["Ebs"]["DeleteOnTermination"] = False
  174. assert validate_cluster_compute(compute_config)
  175. compute_config["worker_node_types"][0]["aws_advanced_configurations"][
  176. "BlockDeviceMappings"
  177. ][0]["Ebs"]["DeleteOnTermination"] = True
  178. assert not validate_cluster_compute(compute_config)
  179. def test_load_and_validate_test_collection_file():
  180. tests = read_and_validate_release_test_collection(_TEST_COLLECTION_FILES)
  181. assert [test for test in tests if test.get_name() == "test_name"]
  182. if __name__ == "__main__":
  183. sys.exit(pytest.main(["-v", __file__]))