test_buildkite.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. import os
  2. import sys
  3. import tempfile
  4. import unittest
  5. from typing import Dict, Callable
  6. from unittest.mock import patch
  7. import yaml
  8. from github import Repository
  9. from ray_release.buildkite.concurrency import (
  10. get_test_resources_from_cluster_compute,
  11. get_concurrency_group,
  12. )
  13. from ray_release.buildkite.filter import filter_tests, group_tests
  14. from ray_release.buildkite.settings import (
  15. split_ray_repo_str,
  16. get_default_settings,
  17. update_settings_from_environment,
  18. Frequency,
  19. update_settings_from_buildkite,
  20. Priority,
  21. get_test_attr_regex_filters,
  22. )
  23. from ray_release.buildkite.step import (
  24. get_step,
  25. RELEASE_QUEUE_DEFAULT,
  26. RELEASE_QUEUE_CLIENT,
  27. DOCKER_PLUGIN_KEY,
  28. )
  29. from ray_release.test import Test
  30. from ray_release.exception import ReleaseTestConfigError
  31. from ray_release.wheels import (
  32. DEFAULT_BRANCH,
  33. )
  34. class MockBuildkiteAgent:
  35. def __init__(self, return_dict: Dict):
  36. self.return_dict = return_dict
  37. def __call__(self, key: str):
  38. return self.return_dict.get(key, None)
  39. class MockReturn:
  40. return_dict = {}
  41. def __getattribute__(self, item):
  42. return_dict = object.__getattribute__(self, "return_dict")
  43. if item in return_dict:
  44. mocked = return_dict[item]
  45. if isinstance(mocked, Callable):
  46. return mocked()
  47. else:
  48. return lambda *a, **kw: mocked
  49. return object.__getattribute__(self, item)
  50. class MockBuildkitePythonAPI(MockReturn):
  51. def builds(self):
  52. return self
  53. def artifacts(self):
  54. return self
  55. class MockTest(Test):
  56. def update_from_s3(self) -> None:
  57. self["update_from_s3"] = True
  58. def is_jailed_with_open_issue(self, ray_github: Repository) -> bool:
  59. return False
  60. class BuildkiteSettingsTest(unittest.TestCase):
  61. def setUp(self) -> None:
  62. self.buildkite = {}
  63. self.buildkite_mock = MockBuildkiteAgent(self.buildkite)
  64. def testSplitRayRepoStr(self):
  65. url, branch = split_ray_repo_str("https://github.com/ray-project/ray.git")
  66. self.assertEqual(url, "https://github.com/ray-project/ray.git")
  67. self.assertEqual(branch, DEFAULT_BRANCH)
  68. url, branch = split_ray_repo_str(
  69. "https://github.com/ray-project/ray/tree/branch/sub"
  70. )
  71. self.assertEqual(url, "https://github.com/ray-project/ray.git")
  72. self.assertEqual(branch, "branch/sub")
  73. url, branch = split_ray_repo_str("https://github.com/user/ray/tree/branch/sub")
  74. self.assertEqual(url, "https://github.com/user/ray.git")
  75. self.assertEqual(branch, "branch/sub")
  76. url, branch = split_ray_repo_str("ray-project:branch/sub")
  77. self.assertEqual(url, "https://github.com/ray-project/ray.git")
  78. self.assertEqual(branch, "branch/sub")
  79. url, branch = split_ray_repo_str("user:branch/sub")
  80. self.assertEqual(url, "https://github.com/user/ray.git")
  81. self.assertEqual(branch, "branch/sub")
  82. url, branch = split_ray_repo_str("user")
  83. self.assertEqual(url, "https://github.com/user/ray.git")
  84. self.assertEqual(branch, DEFAULT_BRANCH)
  85. def testGetTestAttrRegexFilters(self):
  86. test_attr_regex_filters = get_test_attr_regex_filters("")
  87. self.assertDictEqual(test_attr_regex_filters, {})
  88. test_attr_regex_filters = get_test_attr_regex_filters("name:xxx")
  89. self.assertDictEqual(test_attr_regex_filters, {"name": "xxx"})
  90. test_attr_regex_filters = get_test_attr_regex_filters("name:xxx\n")
  91. self.assertDictEqual(test_attr_regex_filters, {"name": "xxx"})
  92. test_attr_regex_filters = get_test_attr_regex_filters("name:xxx\n\nteam:yyy")
  93. self.assertDictEqual(test_attr_regex_filters, {"name": "xxx", "team": "yyy"})
  94. test_attr_regex_filters = get_test_attr_regex_filters("name:xxx\n \nteam:yyy\n")
  95. self.assertDictEqual(test_attr_regex_filters, {"name": "xxx", "team": "yyy"})
  96. with self.assertRaises(ReleaseTestConfigError):
  97. get_test_attr_regex_filters("xxx")
  98. def testSettingsOverrideEnv(self):
  99. settings = get_default_settings()
  100. # With no environment variables, default settings shouldn't be updated
  101. updated_settings = settings.copy()
  102. update_settings_from_environment(updated_settings)
  103. self.assertDictEqual(settings, updated_settings)
  104. environ = os.environ.copy()
  105. # Invalid frequency
  106. os.environ.clear()
  107. os.environ.update(environ)
  108. os.environ["RELEASE_FREQUENCY"] = "invalid"
  109. updated_settings = settings.copy()
  110. with self.assertRaises(ReleaseTestConfigError):
  111. update_settings_from_environment(updated_settings)
  112. # Invalid priority
  113. os.environ.clear()
  114. os.environ.update(environ)
  115. os.environ["RELEASE_PRIORITY"] = "invalid"
  116. updated_settings = settings.copy()
  117. with self.assertRaises(ReleaseTestConfigError):
  118. update_settings_from_environment(updated_settings)
  119. # Invalid test attr regex filters
  120. os.environ.clear()
  121. os.environ.update(environ)
  122. os.environ["TEST_ATTR_REGEX_FILTERS"] = "xxxx"
  123. updated_settings = settings.copy()
  124. with self.assertRaises(ReleaseTestConfigError):
  125. update_settings_from_environment(updated_settings)
  126. os.environ.clear()
  127. os.environ.update(environ)
  128. os.environ["TEST_ATTR_REGEX_FILTERS"] = "name:xxx\nteam:yyy\n"
  129. updated_settings = settings.copy()
  130. update_settings_from_environment(updated_settings)
  131. self.assertDictEqual(
  132. updated_settings["test_attr_regex_filters"],
  133. {
  134. "name": "xxx",
  135. "team": "yyy",
  136. },
  137. )
  138. os.environ.clear()
  139. os.environ.update(environ)
  140. os.environ["RELEASE_FREQUENCY"] = "nightly"
  141. os.environ["RAY_TEST_REPO"] = "https://github.com/user/ray.git"
  142. os.environ["RAY_TEST_BRANCH"] = "sub/branch"
  143. os.environ["RAY_WHEELS"] = "custom-wheels"
  144. os.environ["TEST_NAME"] = "name_filter"
  145. os.environ["RELEASE_PRIORITY"] = "manual"
  146. updated_settings = settings.copy()
  147. update_settings_from_environment(updated_settings)
  148. self.assertDictEqual(
  149. updated_settings,
  150. {
  151. "frequency": Frequency.NIGHTLY,
  152. "prefer_smoke_tests": False,
  153. "test_attr_regex_filters": {"name": "name_filter"},
  154. "ray_wheels": "custom-wheels",
  155. "ray_test_repo": "https://github.com/user/ray.git",
  156. "ray_test_branch": "sub/branch",
  157. "priority": Priority.MANUAL,
  158. "no_concurrency_limit": False,
  159. },
  160. )
  161. os.environ["RELEASE_FREQUENCY"] = "any-smoke"
  162. update_settings_from_environment(updated_settings)
  163. self.assertDictEqual(
  164. updated_settings,
  165. {
  166. "frequency": Frequency.ANY,
  167. "prefer_smoke_tests": True,
  168. "test_attr_regex_filters": {"name": "name_filter"},
  169. "ray_wheels": "custom-wheels",
  170. "ray_test_repo": "https://github.com/user/ray.git",
  171. "ray_test_branch": "sub/branch",
  172. "priority": Priority.MANUAL,
  173. "no_concurrency_limit": False,
  174. },
  175. )
  176. ###
  177. # Buildkite PR build settings
  178. # Default PR
  179. os.environ.clear()
  180. os.environ.update(environ)
  181. os.environ["BUILDKITE_REPO"] = "https://github.com/ray-project/ray.git"
  182. os.environ[
  183. "BUILDKITE_PULL_REQUEST_REPO"
  184. ] = "https://github.com/user/ray-fork.git"
  185. os.environ["BUILDKITE_BRANCH"] = "user:some_branch"
  186. updated_settings = settings.copy()
  187. update_settings_from_environment(updated_settings)
  188. self.assertEqual(
  189. updated_settings["ray_test_repo"], "https://github.com/user/ray-fork.git"
  190. )
  191. self.assertEqual(updated_settings["ray_test_branch"], "some_branch")
  192. # PR without prefix
  193. os.environ.clear()
  194. os.environ.update(environ)
  195. os.environ["BUILDKITE_REPO"] = "https://github.com/ray-project/ray.git"
  196. os.environ["BUILDKITE_PULL_REQUEST_REPO"] = "git://github.com/user/ray-fork.git"
  197. os.environ["BUILDKITE_BRANCH"] = "some_branch"
  198. updated_settings = settings.copy()
  199. update_settings_from_environment(updated_settings)
  200. self.assertEqual(
  201. updated_settings["ray_test_repo"], "https://github.com/user/ray-fork.git"
  202. )
  203. self.assertEqual(updated_settings["ray_test_branch"], "some_branch")
  204. # Branch build but pointing to fork
  205. os.environ.clear()
  206. os.environ.update(environ)
  207. os.environ["BUILDKITE_REPO"] = "https://github.com/ray-project/ray.git"
  208. os.environ["BUILDKITE_BRANCH"] = "user:some_branch"
  209. updated_settings = settings.copy()
  210. update_settings_from_environment(updated_settings)
  211. self.assertEqual(
  212. updated_settings["ray_test_repo"], "https://github.com/user/ray.git"
  213. )
  214. self.assertEqual(updated_settings["ray_test_branch"], "some_branch")
  215. # Branch build but pointing to main repo branch
  216. os.environ.clear()
  217. os.environ.update(environ)
  218. os.environ["BUILDKITE_REPO"] = "https://github.com/ray-project/ray.git"
  219. os.environ["BUILDKITE_BRANCH"] = "some_branch"
  220. updated_settings = settings.copy()
  221. update_settings_from_environment(updated_settings)
  222. self.assertEqual(
  223. updated_settings["ray_test_repo"], "https://github.com/ray-project/ray.git"
  224. )
  225. self.assertEqual(updated_settings["ray_test_branch"], "some_branch")
  226. # Empty BUILDKITE_PULL_REQUEST_REPO
  227. os.environ.clear()
  228. os.environ.update(environ)
  229. os.environ["BUILDKITE_REPO"] = "https://github.com/ray-project/ray.git"
  230. os.environ["BUILDKITE_BRANCH"] = "some_branch"
  231. os.environ["BUILDKITE_PULL_REQUEST_REPO"] = ""
  232. updated_settings = settings.copy()
  233. update_settings_from_environment(updated_settings)
  234. self.assertEqual(
  235. updated_settings["ray_test_repo"], "https://github.com/ray-project/ray.git"
  236. )
  237. self.assertEqual(updated_settings["ray_test_branch"], "some_branch")
  238. def testSettingsOverrideBuildkite(self):
  239. settings = get_default_settings()
  240. with patch(
  241. "ray_release.buildkite.settings.get_buildkite_prompt_value",
  242. self.buildkite_mock,
  243. ):
  244. # With no buildkite variables, default settings shouldn't be updated
  245. updated_settings = settings.copy()
  246. update_settings_from_buildkite(updated_settings)
  247. self.assertDictEqual(settings, updated_settings)
  248. buildkite = self.buildkite.copy()
  249. # Invalid frequency
  250. self.buildkite.clear()
  251. self.buildkite.update(buildkite)
  252. self.buildkite["release-frequency"] = "invalid"
  253. updated_settings = settings.copy()
  254. with self.assertRaises(ReleaseTestConfigError):
  255. update_settings_from_buildkite(updated_settings)
  256. # Invalid priority
  257. self.buildkite.clear()
  258. self.buildkite.update(buildkite)
  259. self.buildkite["release-priority"] = "invalid"
  260. updated_settings = settings.copy()
  261. with self.assertRaises(ReleaseTestConfigError):
  262. update_settings_from_buildkite(updated_settings)
  263. # Invalid test attr regex filters
  264. self.buildkite.clear()
  265. self.buildkite.update(buildkite)
  266. self.buildkite["release-test-attr-regex-filters"] = "xxxx"
  267. updated_settings = settings.copy()
  268. with self.assertRaises(ReleaseTestConfigError):
  269. update_settings_from_buildkite(updated_settings)
  270. self.buildkite.clear()
  271. self.buildkite.update(buildkite)
  272. self.buildkite["release-test-attr-regex-filters"] = "name:xxx\ngroup:yyy"
  273. updated_settings = settings.copy()
  274. update_settings_from_buildkite(updated_settings)
  275. self.assertDictEqual(
  276. updated_settings["test_attr_regex_filters"],
  277. {
  278. "name": "xxx",
  279. "group": "yyy",
  280. },
  281. )
  282. self.buildkite.clear()
  283. self.buildkite.update(buildkite)
  284. self.buildkite["release-frequency"] = "nightly"
  285. self.buildkite["release-ray-test-repo-branch"] = "user:sub/branch"
  286. self.buildkite["release-ray-wheels"] = "custom-wheels"
  287. self.buildkite["release-test-name"] = "name_filter"
  288. self.buildkite["release-priority"] = "manual"
  289. updated_settings = settings.copy()
  290. update_settings_from_buildkite(updated_settings)
  291. self.assertDictEqual(
  292. updated_settings,
  293. {
  294. "frequency": Frequency.NIGHTLY,
  295. "prefer_smoke_tests": False,
  296. "test_attr_regex_filters": {"name": "name_filter"},
  297. "ray_wheels": "custom-wheels",
  298. "ray_test_repo": "https://github.com/user/ray.git",
  299. "ray_test_branch": "sub/branch",
  300. "priority": Priority.MANUAL,
  301. "no_concurrency_limit": False,
  302. },
  303. )
  304. self.buildkite["release-frequency"] = "any-smoke"
  305. update_settings_from_buildkite(updated_settings)
  306. self.assertDictEqual(
  307. updated_settings,
  308. {
  309. "frequency": Frequency.ANY,
  310. "prefer_smoke_tests": True,
  311. "test_attr_regex_filters": {"name": "name_filter"},
  312. "ray_wheels": "custom-wheels",
  313. "ray_test_repo": "https://github.com/user/ray.git",
  314. "ray_test_branch": "sub/branch",
  315. "priority": Priority.MANUAL,
  316. "no_concurrency_limit": False,
  317. },
  318. )
  319. def _filter_names_smoke(self, *args, **kwargs):
  320. filtered = filter_tests(*args, **kwargs)
  321. return [(t[0]["name"], t[1]) for t in filtered]
  322. @patch(
  323. "ray_release.test_automation.state_machine.TestStateMachine.get_ray_repo",
  324. return_value=None,
  325. )
  326. def testFilterTests(self, *args):
  327. test = MockTest(
  328. {
  329. "name": "test_1",
  330. "frequency": "nightly",
  331. "smoke_test": {"frequency": "nightly"},
  332. "team": "team_1",
  333. "run": {"type": "job"},
  334. }
  335. )
  336. tests = [
  337. test,
  338. MockTest(
  339. {
  340. "name": "test_2",
  341. "frequency": "weekly",
  342. "smoke_test": {"frequency": "nightly"},
  343. "team": "team_2",
  344. "run": {"type": "client"},
  345. }
  346. ),
  347. MockTest({"name": "other_1", "frequency": "weekly", "team": "team_2"}),
  348. MockTest(
  349. {
  350. "name": "other_2",
  351. "frequency": "nightly",
  352. "smoke_test": {"frequency": "multi"},
  353. "team": "team_2",
  354. "run": {"type": "job"},
  355. }
  356. ),
  357. MockTest({"name": "other_3", "frequency": "manual", "team": "team_2"}),
  358. MockTest({"name": "test_3", "frequency": "nightly", "team": "team_2"}),
  359. ]
  360. filtered = self._filter_names_smoke(tests, frequency=Frequency.ANY)
  361. self.assertSequenceEqual(
  362. filtered,
  363. [
  364. ("test_1", False),
  365. ("test_2", False),
  366. ("other_1", False),
  367. ("other_2", False),
  368. ("other_3", False),
  369. ("test_3", False),
  370. ],
  371. )
  372. assert not test.get("update_from_s3")
  373. filtered = self._filter_names_smoke(
  374. tests,
  375. frequency=Frequency.ANY,
  376. prefer_smoke_tests=True,
  377. )
  378. self.assertSequenceEqual(
  379. filtered,
  380. [
  381. ("test_1", True),
  382. ("test_2", True),
  383. ("other_1", False),
  384. ("other_2", True),
  385. ("other_3", False),
  386. ("test_3", False),
  387. ],
  388. )
  389. filtered = self._filter_names_smoke(tests, frequency=Frequency.NIGHTLY)
  390. self.assertSequenceEqual(
  391. filtered,
  392. [
  393. ("test_1", False),
  394. ("test_2", True),
  395. ("other_2", False),
  396. ("test_3", False),
  397. ],
  398. )
  399. filtered = self._filter_names_smoke(
  400. tests,
  401. frequency=Frequency.NIGHTLY,
  402. prefer_smoke_tests=True,
  403. )
  404. self.assertSequenceEqual(
  405. filtered,
  406. [
  407. ("test_1", True),
  408. ("test_2", True),
  409. ("other_2", True),
  410. ("test_3", False),
  411. ],
  412. )
  413. filtered = self._filter_names_smoke(tests, frequency=Frequency.WEEKLY)
  414. self.assertSequenceEqual(filtered, [("test_2", False), ("other_1", False)])
  415. filtered = self._filter_names_smoke(
  416. tests,
  417. frequency=Frequency.NIGHTLY,
  418. test_attr_regex_filters={"name": "other.*"},
  419. )
  420. self.assertSequenceEqual(
  421. filtered,
  422. [
  423. ("other_2", False),
  424. ],
  425. )
  426. filtered = self._filter_names_smoke(
  427. tests,
  428. frequency=Frequency.NIGHTLY,
  429. test_attr_regex_filters={"name": "test.*"},
  430. )
  431. self.assertSequenceEqual(
  432. filtered, [("test_1", False), ("test_2", True), ("test_3", False)]
  433. )
  434. filtered = self._filter_names_smoke(
  435. tests, frequency=Frequency.NIGHTLY, test_attr_regex_filters={"name": "test"}
  436. )
  437. self.assertSequenceEqual(filtered, [])
  438. filtered = self._filter_names_smoke(
  439. tests,
  440. frequency=Frequency.NIGHTLY,
  441. test_attr_regex_filters={"name": "test.*", "team": "team_1"},
  442. )
  443. self.assertSequenceEqual(filtered, [("test_1", False)])
  444. filtered = self._filter_names_smoke(
  445. tests,
  446. frequency=Frequency.NIGHTLY,
  447. test_attr_regex_filters={"name": "test_1|test_2"},
  448. )
  449. self.assertSequenceEqual(filtered, [("test_1", False), ("test_2", True)])
  450. # Filter by nested properties
  451. filtered = self._filter_names_smoke(
  452. tests,
  453. frequency=Frequency.ANY,
  454. test_attr_regex_filters={"run/type": "job"},
  455. )
  456. self.assertSequenceEqual(filtered, [("test_1", False), ("other_2", False)])
  457. filtered = self._filter_names_smoke(
  458. tests,
  459. frequency=Frequency.ANY,
  460. test_attr_regex_filters={"run/type": "client"},
  461. )
  462. self.assertSequenceEqual(filtered, [("test_2", False)])
  463. filtered = self._filter_names_smoke(
  464. tests,
  465. frequency=Frequency.ANY,
  466. test_attr_regex_filters={"run/invalid": "xxx"},
  467. )
  468. self.assertSequenceEqual(filtered, [])
  469. def testGroupTests(self):
  470. tests = [
  471. (Test(name="x1", group="x"), False),
  472. (Test(name="x2", group="x"), False),
  473. (Test(name="y1", group="y"), False),
  474. (Test(name="ungrouped"), False),
  475. (Test(name="x3", group="x"), False),
  476. ]
  477. grouped = group_tests(tests)
  478. self.assertEqual(len(grouped), 3) # Three groups
  479. self.assertEqual(len(grouped["x"]), 3)
  480. self.assertSequenceEqual(
  481. [t["name"] for t, _ in grouped["x"]], ["x1", "x2", "x3"]
  482. )
  483. self.assertEqual(len(grouped["y"]), 1)
  484. def testGetStep(self):
  485. test = MockTest(
  486. {
  487. "name": "test",
  488. "frequency": "nightly",
  489. "run": {"script": "test_script.py"},
  490. "smoke_test": {"frequency": "multi"},
  491. }
  492. )
  493. step = get_step(test, smoke_test=False)
  494. self.assertNotIn(
  495. "--smoke-test", step["plugins"][0][DOCKER_PLUGIN_KEY]["command"]
  496. )
  497. step = get_step(test, smoke_test=True)
  498. self.assertIn("--smoke-test", step["plugins"][0][DOCKER_PLUGIN_KEY]["command"])
  499. step = get_step(test, priority_val=20)
  500. self.assertEqual(step["priority"], 20)
  501. def testInstanceResources(self):
  502. # AWS instances
  503. cpus, gpus = get_test_resources_from_cluster_compute(
  504. {
  505. "head_node_type": {"instance_type": "m5.4xlarge"}, # 16 CPUs, 0 GPUs
  506. "worker_node_types": [
  507. {
  508. "instance_type": "m5.8xlarge", # 32 CPUS, 0 GPUs
  509. "max_workers": 4,
  510. },
  511. {
  512. "instance_type": "g3.8xlarge", # 32 CPUs, 2 GPUs
  513. "min_workers": 8,
  514. },
  515. ],
  516. }
  517. )
  518. self.assertEqual(cpus, 16 + 32 * 4 + 32 * 8)
  519. self.assertEqual(gpus, 2 * 8)
  520. cpus, gpus = get_test_resources_from_cluster_compute(
  521. {
  522. "head_node_type": {
  523. "instance_type": "n1-standard-16" # 16 CPUs, 0 GPUs
  524. },
  525. "worker_node_types": [
  526. {
  527. "instance_type": "random-str-xxx-32", # 32 CPUS, 0 GPUs
  528. "max_workers": 4,
  529. },
  530. {
  531. "instance_type": "a2-highgpu-2g", # 24 CPUs, 2 GPUs
  532. "min_workers": 8,
  533. },
  534. ],
  535. }
  536. )
  537. self.assertEqual(cpus, 16 + 32 * 4 + 24 * 8)
  538. self.assertEqual(gpus, 2 * 8)
  539. def testConcurrencyGroups(self):
  540. def _return(ret):
  541. def _inner(*args, **kwargs):
  542. return ret
  543. return _inner
  544. test = Test(
  545. {
  546. "name": "test_1",
  547. }
  548. )
  549. def test_concurrency(cpu, gpu, group):
  550. with patch(
  551. "ray_release.buildkite.concurrency.get_test_resources",
  552. _return((cpu, gpu)),
  553. ):
  554. group_name, _ = get_concurrency_group(test)
  555. self.assertEqual(group_name, group)
  556. test_concurrency(12800, 9, "large-gpu")
  557. test_concurrency(12800, 8, "small-gpu")
  558. test_concurrency(12800, 1, "small-gpu")
  559. test_concurrency(12800, 0, "enormous")
  560. test_concurrency(1025, 0, "enormous")
  561. test_concurrency(1024, 0, "large")
  562. test_concurrency(513, 0, "large")
  563. test_concurrency(512, 0, "medium")
  564. test_concurrency(129, 0, "medium")
  565. test_concurrency(128, 0, "small")
  566. test_concurrency(9, 0, "tiny")
  567. test_concurrency(32, 0, "tiny")
  568. test_concurrency(8, 0, "minuscule")
  569. test_concurrency(1, 0, "minuscule")
  570. test_concurrency(33, 0, "small")
  571. def testConcurrencyGroupSmokeTest(self):
  572. with tempfile.TemporaryDirectory() as tmpdir:
  573. cluster_config_full = {
  574. "head_node_type": {
  575. "instance_type": "n1-standard-16" # 16 CPUs, 0 GPUs
  576. },
  577. "worker_node_types": [
  578. {
  579. "instance_type": "random-str-xxx-32", # 32 CPUS, 0 GPUs
  580. "max_workers": 10,
  581. },
  582. ],
  583. }
  584. cluster_config_smoke = {
  585. "head_node_type": {
  586. "instance_type": "n1-standard-16" # 16 CPUs, 0 GPUs
  587. },
  588. "worker_node_types": [
  589. {
  590. "instance_type": "random-str-xxx-32", # 32 CPUS, 0 GPUs
  591. "max_workers": 1,
  592. },
  593. ],
  594. }
  595. cluster_config_full_path = os.path.join(tmpdir, "full.yaml")
  596. with open(cluster_config_full_path, "w") as fp:
  597. yaml.safe_dump(cluster_config_full, fp)
  598. cluster_config_smoke_path = os.path.join(tmpdir, "smoke.yaml")
  599. with open(cluster_config_smoke_path, "w") as fp:
  600. yaml.safe_dump(cluster_config_smoke, fp)
  601. test = MockTest(
  602. {
  603. "name": "test_1",
  604. "cluster": {"cluster_compute": cluster_config_full_path},
  605. "smoke_test": {
  606. "cluster": {"cluster_compute": cluster_config_smoke_path},
  607. },
  608. }
  609. )
  610. step = get_step(test, smoke_test=False)
  611. self.assertEquals(step["concurrency_group"], "medium")
  612. step = get_step(test, smoke_test=True)
  613. self.assertEquals(step["concurrency_group"], "small")
  614. def testStepQueueClient(self):
  615. test_regular = MockTest(
  616. {
  617. "name": "test",
  618. "frequency": "nightly",
  619. "run": {"script": "test_script.py"},
  620. }
  621. )
  622. test_client = MockTest(
  623. {
  624. "name": "test",
  625. "frequency": "nightly",
  626. "run": {"script": "test_script.py", "type": "client"},
  627. }
  628. )
  629. step = get_step(test_regular)
  630. self.assertEqual(step["agents"]["queue"], str(RELEASE_QUEUE_DEFAULT))
  631. step = get_step(test_client)
  632. self.assertEqual(step["agents"]["queue"], str(RELEASE_QUEUE_CLIENT))
  633. if __name__ == "__main__":
  634. import pytest
  635. sys.exit(pytest.main(["-v", __file__]))