conftest.py (6714B)
1 # Any copyright is dedicated to the public domain. 2 # http://creativecommons.org/publicdomain/zero/1.0/ 3 4 import os 5 6 import pytest 7 from mach.logging import LoggingManager 8 from responses import RequestsMock 9 from taskgraph import generator as generator_mod 10 from taskgraph import target_tasks as target_tasks_mod 11 from taskgraph.config import GraphConfig, load_graph_config 12 from taskgraph.generator import Kind, TaskGraphGenerator 13 from taskgraph.optimize import base as optimize_mod 14 from taskgraph.optimize.base import OptimizationStrategy 15 from taskgraph.parameters import Parameters 16 from taskgraph.util.templates import merge 17 18 from gecko_taskgraph import GECKO 19 from gecko_taskgraph.actions import render_actions_json 20 21 22 @pytest.fixture 23 def responses(): 24 with RequestsMock() as rsps: 25 yield rsps 26 27 28 @pytest.fixture(scope="session", autouse=True) 29 def patch_prefherder(request): 30 from _pytest.monkeypatch import MonkeyPatch 31 32 m = MonkeyPatch() 33 m.setattr( 34 "gecko_taskgraph.util.bugbug._write_perfherder_data", 35 lambda lower_is_better: None, 36 ) 37 yield 38 m.undo() 39 40 41 @pytest.fixture(scope="session", autouse=True) 42 def enable_logging(): 43 """Ensure logs from gecko_taskgraph are displayed when a test fails.""" 44 lm = LoggingManager() 45 lm.add_terminal_logging() 46 47 48 @pytest.fixture(scope="session") 49 def graph_config(): 50 return load_graph_config(os.path.join(GECKO, "taskcluster")) 51 52 53 @pytest.fixture(scope="session") 54 def actions_json(graph_config): 55 decision_task_id = "abcdef" 56 return render_actions_json(Parameters(strict=False), graph_config, decision_task_id) 57 58 59 def fake_loader(kind, path, config, parameters, loaded_tasks, write_artifacts): 60 for i in range(3): 61 dependencies = {} 62 if i >= 1: 63 dependencies["prev"] = f"{kind}-t-{i - 1}" 64 65 task = { 66 "kind": kind, 67 "label": f"{kind}-t-{i}", 68 "description": f"{kind} task {i}", 69 "attributes": {"_tasknum": str(i)}, 70 "task": { 71 "i": i, 72 "metadata": {"name": f"t-{i}"}, 73 "deadline": "soon", 74 "provisionerId": "prov", 75 "workerType": "linux", 76 }, 77 "dependencies": dependencies, 78 "if-dependencies": [], 79 "soft-dependencies": [], 80 } 81 if "task-defaults" in config: 82 task = merge(config["task-defaults"], task) 83 yield task 84 85 86 class FakeTransform: 87 transforms = [] 88 params = {} 89 90 def __init__(self): 91 pass 92 93 @classmethod 94 def get(self, field, default): 95 try: 96 return getattr(self, field) 97 except AttributeError: 98 return default 99 100 101 class FakeKind(Kind): 102 def _get_loader(self): 103 return fake_loader 104 105 def load_tasks(self, parameters, loaded_tasks, write_artifacts): 106 FakeKind.loaded_kinds.append(self.name) 107 return super().load_tasks(parameters, loaded_tasks, write_artifacts) 108 109 @staticmethod 110 def create(name, extra_config, graph_config): 111 if name == "fullfake": 112 config = FakeTransform() 113 else: 114 config = {"transforms": []} 115 if extra_config: 116 config.update(extra_config) 117 return FakeKind(name, "/fake", config, graph_config) 118 119 120 class WithFakeKind(TaskGraphGenerator): 121 def _load_kinds(self, graph_config, target_kinds=None): 122 for kind_name, cfg in self.parameters["_kinds"]: 123 yield FakeKind.create(kind_name, cfg, graph_config) 124 125 126 class FakeGraphConfig(GraphConfig): 127 def register(self): 128 pass 129 130 131 def fake_load_graph_config(root_dir): 132 graph_config = FakeGraphConfig( 133 {"trust-domain": "test-domain", "taskgraph": {}}, root_dir 134 ) 135 return graph_config 136 137 138 class FakeParameters(dict): 139 strict = True 140 141 def file_url(self, path, pretty=False): 142 return "" 143 144 145 class FakeOptimization(OptimizationStrategy): 146 description = "Fake strategy for testing" 147 148 def __init__(self, mode, *args, **kwargs): 149 super().__init__(*args, **kwargs) 150 self.mode = mode 151 152 def should_remove_task(self, task, params, arg): 153 if self.mode == "always": 154 return True 155 if self.mode == "even": 156 return task.task["i"] % 2 == 0 157 if self.mode == "odd": 158 return task.task["i"] % 2 != 0 159 return False 160 161 162 class FakeTransformConfig: 163 kind = "fake-kind" 164 path = "/root/ci/fake-kind" 165 config = {} 166 params = FakeParameters() 167 kind_dependencies_tasks = {} 168 graph_config = {} 169 write_artifacts = False 170 171 def __init__(self, **kwargs): 172 for k, v in kwargs.items(): 173 setattr(self, k, v) 174 175 176 @pytest.fixture 177 def maketgg(monkeypatch): 178 def inner(target_tasks=None, kinds=[("_fake", [])], params=None): 179 params = params or {} 180 FakeKind.loaded_kinds = loaded_kinds = [] 181 target_tasks = target_tasks or [] 182 183 def target_tasks_method(full_task_graph, parameters, graph_config): 184 return target_tasks 185 186 fake_registry = { 187 mode: FakeOptimization(mode) for mode in ("always", "never", "even", "odd") 188 } 189 190 target_tasks_mod._target_task_methods["test_method"] = target_tasks_method 191 monkeypatch.setattr(optimize_mod, "registry", fake_registry) 192 193 parameters = FakeParameters({ 194 "_kinds": kinds, 195 "backstop": False, 196 "enable_always_target": False, 197 "level": 1, 198 "target_tasks_method": "test_method", 199 "test_manifest_loader": "default", 200 "try_mode": None, 201 "try_task_config": {}, 202 "tasks_for": "hg-push", 203 "project": "mozilla-central", 204 }) 205 parameters.update(params) 206 207 monkeypatch.setattr(generator_mod, "load_graph_config", fake_load_graph_config) 208 209 tgg = WithFakeKind("/root", parameters) 210 tgg.loaded_kinds = loaded_kinds 211 return tgg 212 213 return inner 214 215 216 @pytest.fixture 217 def run_transform(): 218 graph_config = fake_load_graph_config("/root") 219 config = FakeTransformConfig(graph_config=graph_config) 220 221 def inner(xform, tasks, **extra_config): 222 if extra_config: 223 for k, v in extra_config.items(): 224 setattr(config, k, v) 225 226 if isinstance(tasks, dict): 227 tasks = [tasks] 228 return xform(config, tasks) 229 230 return inner 231 232 233 @pytest.fixture 234 def run_full_config_transform(): 235 graph_config = fake_load_graph_config("/root") 236 kind = FakeKind.create("fullfake", {}, graph_config) 237 238 def inner(xform, tasks): 239 if isinstance(tasks, dict): 240 tasks = [tasks] 241 return xform(kind.config, tasks) 242 243 return inner