test_target_tasks.py (16171B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 6 import re 7 import unittest 8 9 import pytest 10 from mozunit import main 11 from taskgraph.graph import Graph 12 from taskgraph.target_tasks import get_method 13 from taskgraph.task import Task 14 from taskgraph.taskgraph import TaskGraph 15 16 from gecko_taskgraph import target_tasks 17 18 19 class TestTargetTasks(unittest.TestCase): 20 def default_matches_project(self, run_on_projects, project): 21 return self.default_matches( 22 attributes={ 23 "run_on_projects": run_on_projects, 24 }, 25 parameters={ 26 "project": project, 27 "repository_type": "hg", 28 "hg_branch": "default", 29 }, 30 ) 31 32 def default_matches_hg_branch(self, run_on_hg_branches, hg_branch): 33 attributes = {"run_on_projects": ["all"]} 34 if run_on_hg_branches is not None: 35 attributes["run_on_hg_branches"] = run_on_hg_branches 36 37 return self.default_matches( 38 attributes=attributes, 39 parameters={ 40 "project": "mozilla-central", 41 "repository_type": "hg", 42 "hg_branch": hg_branch, 43 }, 44 ) 45 46 def default_matches(self, attributes, parameters): 47 method = get_method("default") 48 graph = TaskGraph( 49 tasks={ 50 "a": Task(kind="build", label="a", attributes=attributes, task={}), 51 }, 52 graph=Graph(nodes={"a"}, edges=set()), 53 ) 54 return "a" in method(graph, parameters, {}) 55 56 def test_default_all(self): 57 """run_on_projects=[all] includes release, integration, and other projects""" 58 self.assertTrue(self.default_matches_project(["all"], "mozilla-central")) 59 self.assertTrue(self.default_matches_project(["all"], "baobab")) 60 61 def test_default_integration(self): 62 """run_on_projects=[integration] includes integration projects""" 63 self.assertFalse( 64 self.default_matches_project(["integration"], "mozilla-central") 65 ) 66 self.assertFalse(self.default_matches_project(["integration"], "baobab")) 67 68 def test_default_release(self): 69 """run_on_projects=[release] includes release projects""" 70 self.assertTrue(self.default_matches_project(["release"], "mozilla-central")) 71 self.assertFalse(self.default_matches_project(["release"], "baobab")) 72 73 def test_default_nothing(self): 74 """run_on_projects=[] includes nothing""" 75 self.assertFalse(self.default_matches_project([], "mozilla-central")) 76 self.assertFalse(self.default_matches_project([], "baobab")) 77 78 def test_default_hg_branch(self): 79 self.assertTrue(self.default_matches_hg_branch(None, "default")) 80 self.assertTrue(self.default_matches_hg_branch(None, "GECKOVIEW_62_RELBRANCH")) 81 82 self.assertFalse(self.default_matches_hg_branch([], "default")) 83 self.assertFalse(self.default_matches_hg_branch([], "GECKOVIEW_62_RELBRANCH")) 84 85 self.assertTrue(self.default_matches_hg_branch(["all"], "default")) 86 self.assertTrue( 87 self.default_matches_hg_branch(["all"], "GECKOVIEW_62_RELBRANCH") 88 ) 89 90 self.assertTrue(self.default_matches_hg_branch(["default"], "default")) 91 self.assertTrue(self.default_matches_hg_branch([r"default"], "default")) 92 self.assertFalse( 93 self.default_matches_hg_branch([r"default"], "GECKOVIEW_62_RELBRANCH") 94 ) 95 96 self.assertTrue( 97 self.default_matches_hg_branch( 98 ["GECKOVIEW_62_RELBRANCH"], "GECKOVIEW_62_RELBRANCH" 99 ) 100 ) 101 self.assertTrue( 102 self.default_matches_hg_branch( 103 [r"GECKOVIEW_\d+_RELBRANCH"], "GECKOVIEW_62_RELBRANCH" 104 ) 105 ) 106 self.assertTrue( 107 self.default_matches_hg_branch( 108 [r"GECKOVIEW_\d+_RELBRANCH"], "GECKOVIEW_62_RELBRANCH" 109 ) 110 ) 111 self.assertFalse( 112 self.default_matches_hg_branch([r"GECKOVIEW_\d+_RELBRANCH"], "default") 113 ) 114 115 def make_task_graph(self): 116 tasks = { 117 "a": Task(kind=None, label="a", attributes={}, task={}), 118 "b": Task(kind=None, label="b", attributes={"at-at": "yep"}, task={}), 119 "c": Task( 120 kind=None, label="c", attributes={"run_on_projects": ["try"]}, task={} 121 ), 122 "ddd-1": Task(kind="test", label="ddd-1", attributes={}, task={}), 123 "ddd-2": Task(kind="test", label="ddd-2", attributes={}, task={}), 124 "ddd-1-cf": Task(kind="test", label="ddd-1-cf", attributes={}, task={}), 125 "ddd-2-cf": Task(kind="test", label="ddd-2-cf", attributes={}, task={}), 126 "ddd-var-1": Task(kind="test", label="ddd-var-1", attributes={}, task={}), 127 "ddd-var-2": Task(kind="test", label="ddd-var-2", attributes={}, task={}), 128 } 129 graph = Graph( 130 nodes=set([ 131 "a", 132 "b", 133 "c", 134 "ddd-1", 135 "ddd-2", 136 "ddd-1-cf", 137 "ddd-2-cf", 138 "ddd-var-1", 139 "ddd-var-2", 140 ]), 141 edges=set(), 142 ) 143 return TaskGraph(tasks, graph) 144 145 def test_empty_try(self): 146 "try_mode = None runs nothing" 147 tg = self.make_task_graph() 148 method = get_method("try_tasks") 149 params = { 150 "try_mode": None, 151 "project": "try", 152 "message": "", 153 } 154 # only runs the task with run_on_projects: try 155 self.assertEqual(method(tg, params, {}), []) 156 157 def test_try_task_config(self): 158 "try_mode = try_task_config uses the try config" 159 tg = self.make_task_graph() 160 method = get_method("try_tasks") 161 params = { 162 "try_mode": "try_task_config", 163 "try_task_config": {"tasks": ["a"]}, 164 } 165 self.assertEqual(method(tg, params, {}), ["a"]) 166 167 def test_try_task_config_regex(self): 168 "try_mode = try_task_config uses the try config with regex instead of chunk numbers" 169 tg = self.make_task_graph() 170 method = get_method("try_tasks") 171 params = { 172 "try_mode": "try_task_config", 173 "try_task_config": {"new-test-config": True, "tasks": ["ddd-*"]}, 174 "project": "try", 175 } 176 self.assertEqual(sorted(method(tg, params, {})), ["ddd-1", "ddd-2"]) 177 178 def test_try_task_config_regex_with_paths(self): 179 "try_mode = try_task_config uses the try config with regex instead of chunk numbers" 180 tg = self.make_task_graph() 181 method = get_method("try_tasks") 182 params = { 183 "try_mode": "try_task_config", 184 "try_task_config": { 185 "new-test-config": True, 186 "tasks": ["ddd-*"], 187 "env": {"MOZHARNESS_TEST_PATHS": "foo/bar"}, 188 }, 189 "project": "try", 190 } 191 self.assertEqual(sorted(method(tg, params, {})), ["ddd-1"]) 192 193 def test_try_task_config_absolute(self): 194 "try_mode = try_task_config uses the try config with full task labels" 195 tg = self.make_task_graph() 196 method = get_method("try_tasks") 197 params = { 198 "try_mode": "try_task_config", 199 "try_task_config": { 200 "new-test-config": True, 201 "tasks": ["ddd-var-2", "ddd-1"], 202 }, 203 "project": "try", 204 } 205 self.assertEqual(sorted(method(tg, params, {})), ["ddd-1", "ddd-var-2"]) 206 207 def test_try_task_config_regex_var(self): 208 "try_mode = try_task_config uses the try config with regex instead of chunk numbers and a test variant" 209 tg = self.make_task_graph() 210 method = get_method("try_tasks") 211 params = { 212 "try_mode": "try_task_config", 213 "try_task_config": {"new-test-config": True, "tasks": ["ddd-var-*"]}, 214 "project": "try", 215 } 216 self.assertEqual(sorted(method(tg, params, {})), ["ddd-var-1", "ddd-var-2"]) 217 218 219 # tests for specific filters 220 221 222 @pytest.mark.parametrize( 223 "name,params,expected", 224 ( 225 pytest.param( 226 "filter_tests_without_manifests", 227 { 228 "task": Task(kind="test", label="a", attributes={}, task={}), 229 "parameters": None, 230 }, 231 True, 232 id="filter_tests_without_manifests_not_in_attributes", 233 ), 234 pytest.param( 235 "filter_tests_without_manifests", 236 { 237 "task": Task( 238 kind="test", 239 label="a", 240 attributes={"test_manifests": ["foo"]}, 241 task={}, 242 ), 243 "parameters": None, 244 }, 245 True, 246 id="filter_tests_without_manifests_has_test_manifests", 247 ), 248 pytest.param( 249 "filter_tests_without_manifests", 250 { 251 "task": Task( 252 kind="build", 253 label="a", 254 attributes={"test_manifests": None}, 255 task={}, 256 ), 257 "parameters": None, 258 }, 259 True, 260 id="filter_tests_without_manifests_not_a_test", 261 ), 262 pytest.param( 263 "filter_tests_without_manifests", 264 { 265 "task": Task( 266 kind="test", label="a", attributes={"test_manifests": None}, task={} 267 ), 268 "parameters": None, 269 }, 270 False, 271 id="filter_tests_without_manifests_has_no_test_manifests", 272 ), 273 pytest.param( 274 "filter_by_regex", 275 { 276 "task_label": "build-linux64-debug", 277 "regexes": [re.compile("build")], 278 "mode": "include", 279 }, 280 True, 281 id="filter_regex_simple_include", 282 ), 283 pytest.param( 284 "filter_by_regex", 285 { 286 "task_label": "build-linux64-debug", 287 "regexes": [re.compile("linux(.+)debug")], 288 "mode": "include", 289 }, 290 True, 291 id="filter_regex_re_include", 292 ), 293 pytest.param( 294 "filter_by_regex", 295 { 296 "task_label": "build-linux64-debug", 297 "regexes": [re.compile("nothing"), re.compile("linux(.+)debug")], 298 "mode": "include", 299 }, 300 True, 301 id="filter_regex_re_include_multiple", 302 ), 303 pytest.param( 304 "filter_by_regex", 305 { 306 "task_label": "build-linux64-debug", 307 "regexes": [re.compile("build")], 308 "mode": "exclude", 309 }, 310 False, 311 id="filter_regex_simple_exclude", 312 ), 313 pytest.param( 314 "filter_by_regex", 315 { 316 "task_label": "build-linux64-debug", 317 "regexes": [re.compile("linux(.+)debug")], 318 "mode": "exclude", 319 }, 320 False, 321 id="filter_regex_re_exclude", 322 ), 323 pytest.param( 324 "filter_by_regex", 325 { 326 "task_label": "build-linux64-debug", 327 "regexes": [re.compile("linux(.+)debug"), re.compile("nothing")], 328 "mode": "exclude", 329 }, 330 False, 331 id="filter_regex_re_exclude_multiple", 332 ), 333 pytest.param( 334 "filter_unsupported_artifact_builds", 335 { 336 "task": Task( 337 kind="test", 338 label="a", 339 attributes={"supports-artifact-builds": False}, 340 task={}, 341 ), 342 "parameters": { 343 "try_task_config": { 344 "use-artifact-builds": False, 345 }, 346 }, 347 }, 348 True, 349 id="filter_unsupported_artifact_builds_no_artifact_builds", 350 ), 351 pytest.param( 352 "filter_unsupported_artifact_builds", 353 { 354 "task": Task( 355 kind="test", 356 label="a", 357 attributes={"supports-artifact-builds": False}, 358 task={}, 359 ), 360 "parameters": { 361 "try_task_config": { 362 "use-artifact-builds": True, 363 }, 364 }, 365 }, 366 False, 367 id="filter_unsupported_artifact_builds_removed", 368 ), 369 pytest.param( 370 "filter_unsupported_artifact_builds", 371 { 372 "task": Task( 373 kind="test", 374 label="a", 375 attributes={"supports-artifact-builds": True}, 376 task={}, 377 ), 378 "parameters": { 379 "try_task_config": { 380 "use-artifact-builds": True, 381 }, 382 }, 383 }, 384 True, 385 id="filter_unsupported_artifact_builds_not_removed", 386 ), 387 pytest.param( 388 "filter_unsupported_artifact_builds", 389 { 390 "task": Task(kind="test", label="a", attributes={}, task={}), 391 "parameters": { 392 "try_task_config": { 393 "use-artifact-builds": True, 394 }, 395 }, 396 }, 397 True, 398 id="filter_unsupported_artifact_builds_not_removed", 399 ), 400 pytest.param( 401 "filter_for_repo_type", 402 { 403 "task": Task(kind="test", label="a", attributes={}, task={}), 404 "parameters": { 405 "repository_type": "hg", 406 }, 407 }, 408 True, 409 id="filter_for_repo_type_default_hg_not_removed", 410 ), 411 pytest.param( 412 "filter_for_repo_type", 413 { 414 "task": Task(kind="test", label="a", attributes={}, task={}), 415 "parameters": { 416 "repository_type": "git", 417 }, 418 }, 419 True, 420 id="filter_for_repo_type_default_git_not_removed", 421 ), 422 pytest.param( 423 "filter_for_repo_type", 424 { 425 "task": Task( 426 kind="test", 427 label="a", 428 attributes={"run_on_repo_type": ["hg"]}, 429 task={}, 430 ), 431 "parameters": { 432 "repository_type": "git", 433 }, 434 }, 435 False, 436 id="filter_for_repo_type_no_match_removed", 437 ), 438 pytest.param( 439 "filter_for_repo_type", 440 { 441 "task": Task( 442 kind="test", 443 label="a", 444 attributes={"run_on_repo_type": ["git"]}, 445 task={}, 446 ), 447 "parameters": { 448 "repository_type": "git", 449 }, 450 }, 451 True, 452 id="filter_for_repo_type_match_not_removed", 453 ), 454 pytest.param( 455 "filter_for_repo_type", 456 { 457 "task": Task( 458 kind="test", 459 label="a", 460 attributes={"run_on_repo_type": ["all"]}, 461 task={}, 462 ), 463 "parameters": { 464 "repository_type": "git", 465 }, 466 }, 467 True, 468 id="filter_for_repo_type_all_not_removed", 469 ), 470 ), 471 ) 472 def test_filters(name, params, expected): 473 func = getattr(target_tasks, name) 474 assert func(**params) is expected 475 476 477 if __name__ == "__main__": 478 main()