Skip to content

Commit 02d893b

Browse files
committed
test: use responses in test/test_create.py
This allows us to get more coverage out of these tests.
1 parent 51941c5 commit 02d893b

File tree

2 files changed

+81
-24
lines changed

2 files changed

+81
-24
lines changed

test/test_create.py

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,73 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5-
5+
import json
6+
import re
67
import unittest
78
from unittest import mock
89

10+
import responses
11+
from taskcluster.exceptions import TaskclusterRestFailure
12+
913
from taskgraph import create
1014
from taskgraph.config import GraphConfig
1115
from taskgraph.graph import Graph
1216
from taskgraph.task import Task
1317
from taskgraph.taskgraph import TaskGraph
18+
from taskgraph.util import taskcluster as tc_util
1419

1520
GRAPH_CONFIG = GraphConfig({"trust-domain": "domain"}, "/var/empty")
1621

1722

18-
class TestCreate(unittest.TestCase):
19-
def setUp(self):
20-
self.created_tasks = {}
21-
self.old_create_task = create.create_task
22-
create.create_task = self.fake_create_task
23+
def mock_taskcluster_api(
24+
created_tasks=None, error_status=None, error_message=None, error_task_ids=None
25+
):
26+
"""Mock the Taskcluster Queue API for create task calls."""
27+
28+
def request_callback(request):
29+
task_id = request.url.split("/")[-1]
30+
31+
# Check if this task should error
32+
if error_status is not None:
33+
if error_task_ids is None or task_id in error_task_ids:
34+
# Support per-task error messages
35+
if isinstance(error_message, dict):
36+
message = error_message.get(task_id, "error")
37+
else:
38+
message = error_message or "error"
39+
return (error_status, {}, f'{{"message": "{message}"}}')
40+
41+
# Success case - capture task definition if requested
42+
if created_tasks is not None:
43+
task_def = json.loads(request.body)
44+
created_tasks[task_id] = task_def
45+
46+
return (200, {}, f'{{"status": {{"taskId": "{task_id}"}}}}')
2347

24-
def tearDown(self):
25-
create.create_task = self.old_create_task
48+
responses.add_callback(
49+
responses.PUT,
50+
re.compile(r"https://tc\.example\.com/api/queue/v1/task/.*"),
51+
callback=request_callback,
52+
content_type="application/json",
53+
)
2654

27-
def fake_create_task(self, session, task_id, label, task_def):
28-
self.created_tasks[task_id] = task_def
2955

56+
class TestCreate(unittest.TestCase):
57+
def setUp(self):
58+
# Clear cached Taskcluster clients/sessions since we're mocking the environment
59+
tc_util.get_taskcluster_client.cache_clear()
60+
tc_util.get_session.cache_clear()
61+
62+
@responses.activate
63+
@mock.patch.dict(
64+
"os.environ",
65+
{"TASKCLUSTER_ROOT_URL": "https://tc.example.com"},
66+
clear=True,
67+
)
3068
def test_create_tasks(self):
69+
created_tasks = {}
70+
mock_taskcluster_api(created_tasks=created_tasks)
71+
3172
tasks = {
3273
"tid-a": Task(
3374
kind="test", label="a", attributes={}, task={"payload": "hello world"}
@@ -48,18 +89,28 @@ def test_create_tasks(self):
4889
decision_task_id="decisiontask",
4990
)
5091

51-
for tid, task in self.created_tasks.items():
92+
assert created_tasks
93+
for tid, task in created_tasks.items():
5294
self.assertEqual(task["payload"], "hello world")
5395
self.assertEqual(task["schedulerId"], "domain-level-4")
5496
# make sure the dependencies exist, at least
5597
for depid in task.get("dependencies", []):
5698
if depid == "decisiontask":
5799
# Don't look for decisiontask here
58100
continue
59-
self.assertIn(depid, self.created_tasks)
60-
101+
self.assertIn(depid, created_tasks)
102+
103+
@responses.activate
104+
@mock.patch.dict(
105+
"os.environ",
106+
{"TASKCLUSTER_ROOT_URL": "https://tc.example.com"},
107+
clear=True,
108+
)
61109
def test_create_task_without_dependencies(self):
62110
"a task with no dependencies depends on the decision task"
111+
created_tasks = {}
112+
mock_taskcluster_api(created_tasks=created_tasks)
113+
63114
tasks = {
64115
"tid-a": Task(
65116
kind="test", label="a", attributes={}, task={"payload": "hello world"}
@@ -77,12 +128,20 @@ def test_create_task_without_dependencies(self):
77128
decision_task_id="decisiontask",
78129
)
79130

80-
for tid, task in self.created_tasks.items():
131+
assert created_tasks
132+
for tid, task in created_tasks.items():
81133
self.assertEqual(task.get("dependencies"), ["decisiontask"])
82134

83-
@mock.patch("taskgraph.create.create_task")
84-
def test_create_tasks_fails_if_create_fails(self, create_task):
85-
"creat_tasks fails if a single create_task call fails"
135+
@responses.activate
136+
@mock.patch.dict(
137+
"os.environ",
138+
{"TASKCLUSTER_ROOT_URL": "https://tc.example.com"},
139+
clear=True,
140+
)
141+
def test_create_tasks_fails_if_create_fails(self):
142+
"create_tasks fails if a single create_task call fails"
143+
mock_taskcluster_api(error_status=403, error_message="oh no!")
144+
86145
tasks = {
87146
"tid-a": Task(
88147
kind="test", label="a", attributes={}, task={"payload": "hello world"}
@@ -92,13 +151,7 @@ def test_create_tasks_fails_if_create_fails(self, create_task):
92151
graph = Graph(nodes={"tid-a"}, edges=set())
93152
taskgraph = TaskGraph(tasks, graph)
94153

95-
def fail(*args):
96-
print("UHOH")
97-
raise RuntimeError("oh no!")
98-
99-
create_task.side_effect = fail
100-
101-
with self.assertRaises(RuntimeError):
154+
with self.assertRaises(TaskclusterRestFailure):
102155
create.create_tasks(
103156
GRAPH_CONFIG,
104157
taskgraph,

test/test_docker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from taskgraph import docker
99
from taskgraph.config import GraphConfig
1010
from taskgraph.transforms.docker_image import IMAGE_BUILDER_IMAGE
11+
from taskgraph.util import taskcluster as tc_util
1112
from taskgraph.util.vcs import get_repository
1213

1314
from .conftest import nowin
@@ -22,6 +23,9 @@ def root_url():
2223
def mock_environ(monkeypatch, root_url):
2324
# Ensure user specified environment variables don't interfere with URLs.
2425
monkeypatch.setattr(os, "environ", {"TASKCLUSTER_ROOT_URL": root_url})
26+
# Clear cached Taskcluster clients/sessions since we're mocking the environment
27+
tc_util.get_taskcluster_client.cache_clear()
28+
tc_util.get_session.cache_clear()
2529

2630

2731
@pytest.fixture(autouse=True, scope="module")

0 commit comments

Comments
 (0)