summaryrefslogtreecommitdiffstats
path: root/taskcluster/taskgraph/test/test_util_parameterization.py
diff options
context:
space:
mode:
Diffstat (limited to 'taskcluster/taskgraph/test/test_util_parameterization.py')
-rw-r--r--taskcluster/taskgraph/test/test_util_parameterization.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/taskcluster/taskgraph/test/test_util_parameterization.py b/taskcluster/taskgraph/test/test_util_parameterization.py
new file mode 100644
index 0000000000..73b6a98b5e
--- /dev/null
+++ b/taskcluster/taskgraph/test/test_util_parameterization.py
@@ -0,0 +1,232 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import unittest
+import datetime
+import mock
+import os
+
+from mozunit import main
+from taskgraph.util.parameterization import (
+ resolve_timestamps,
+ resolve_task_references,
+)
+
+
+class TestTimestamps(unittest.TestCase):
+ def test_no_change(self):
+ now = datetime.datetime(2018, 1, 1)
+ input = {
+ "key": "value",
+ "numeric": 10,
+ "list": ["a", True, False, None],
+ }
+ self.assertEqual(resolve_timestamps(now, input), input)
+
+ def test_buried_replacement(self):
+ now = datetime.datetime(2018, 1, 1)
+ input = {"key": [{"key2": [{"relative-datestamp": "1 day"}]}]}
+ self.assertEqual(
+ resolve_timestamps(now, input),
+ {"key": [{"key2": ["2018-01-02T00:00:00Z"]}]},
+ )
+
+ def test_appears_with_other_keys(self):
+ now = datetime.datetime(2018, 1, 1)
+ input = [{"relative-datestamp": "1 day", "another-key": True}]
+ self.assertEqual(
+ resolve_timestamps(now, input),
+ [{"relative-datestamp": "1 day", "another-key": True}],
+ )
+
+
+class TestTaskRefs(unittest.TestCase):
+ def do(self, input, output):
+ taskid_for_edge_name = {"edge%d" % n: "tid%d" % n for n in range(1, 4)}
+ self.assertEqual(
+ resolve_task_references(
+ "subject",
+ input,
+ "tid-self",
+ "tid-decision",
+ taskid_for_edge_name,
+ ),
+ output,
+ )
+
+ def test_no_change(self):
+ "resolve_task_references does nothing when there are no task references"
+ self.do(
+ {"in-a-list": ["stuff", {"property": "<edge1>"}]},
+ {"in-a-list": ["stuff", {"property": "<edge1>"}]},
+ )
+
+ def test_in_list(self):
+ "resolve_task_references resolves task references in a list"
+ self.do(
+ {"in-a-list": ["stuff", {"task-reference": "<edge1>"}]},
+ {"in-a-list": ["stuff", "tid1"]},
+ )
+
+ def test_in_dict(self):
+ "resolve_task_references resolves task references in a dict"
+ self.do(
+ {"in-a-dict": {"stuff": {"task-reference": "<edge2>"}}},
+ {"in-a-dict": {"stuff": "tid2"}},
+ )
+
+ def test_multiple(self):
+ "resolve_task_references resolves multiple references in the same string"
+ self.do(
+ {"multiple": {"task-reference": "stuff <edge1> stuff <edge2> after"}},
+ {"multiple": "stuff tid1 stuff tid2 after"},
+ )
+
+ def test_embedded(self):
+ "resolve_task_references resolves ebmedded references"
+ self.do(
+ {"embedded": {"task-reference": "stuff before <edge3> stuff after"}},
+ {"embedded": "stuff before tid3 stuff after"},
+ )
+
+ def test_escaping(self):
+ "resolve_task_references resolves escapes in task references"
+ self.do({"escape": {"task-reference": "<<><edge3>>"}}, {"escape": "<tid3>"})
+
+ def test_multikey(self):
+ "resolve_task_references is ignored when there is another key in the dict"
+ self.do(
+ {"escape": {"task-reference": "<edge3>", "another-key": True}},
+ {"escape": {"task-reference": "<edge3>", "another-key": True}},
+ )
+
+ def test_self(self):
+ "resolve_task_references resolves `self` to the provided task id"
+ self.do({"escape": {"task-reference": "<self>"}}, {"escape": "tid-self"})
+
+ def test_decision(self):
+ "resolve_task_references resolves `decision` to the provided decision task id"
+ self.do(
+ {"escape": {"task-reference": "<decision>"}}, {"escape": "tid-decision"}
+ )
+
+ def test_invalid(self):
+ "resolve_task_references raises a KeyError on reference to an invalid task"
+ self.assertRaisesRegexp(
+ KeyError,
+ "task 'subject' has no dependency named 'no-such'",
+ lambda: resolve_task_references(
+ "subject",
+ {"task-reference": "<no-such>"},
+ "tid-self",
+ "tid-decision",
+ {},
+ ),
+ )
+
+
+class TestArtifactRefs(unittest.TestCase):
+ def do(self, input, output):
+ taskid_for_edge_name = {"edge%d" % n: "tid%d" % n for n in range(1, 4)}
+ with mock.patch.dict(
+ os.environ, {"TASKCLUSTER_ROOT_URL": "https://tc-tests.localhost"}
+ ):
+ self.assertEqual(
+ resolve_task_references(
+ "subject", input, "tid-self", "tid-decision", taskid_for_edge_name
+ ),
+ output,
+ )
+
+ def test_in_list(self):
+ "resolve_task_references resolves artifact references in a list"
+ self.do(
+ {"in-a-list": ["stuff", {"artifact-reference": "<edge1/public/foo/bar>"}]},
+ {
+ "in-a-list": [
+ "stuff",
+ "https://tc-tests.localhost/api/queue/v1"
+ "/task/tid1/artifacts/public/foo/bar",
+ ]
+ },
+ )
+
+ def test_in_dict(self):
+ "resolve_task_references resolves artifact references in a dict"
+ self.do(
+ {"in-a-dict": {"stuff": {"artifact-reference": "<edge2/public/bar/foo>"}}},
+ {
+ "in-a-dict": {
+ "stuff": "https://tc-tests.localhost/api/queue/v1"
+ "/task/tid2/artifacts/public/bar/foo"
+ }
+ },
+ )
+
+ def test_in_string(self):
+ "resolve_task_references resolves artifact references embedded in a string"
+ self.do(
+ {
+ "stuff": {
+ "artifact-reference": "<edge1/public/filename> and <edge2/public/bar>"
+ }
+ },
+ {
+ "stuff": "https://tc-tests.localhost/api/queue/v1"
+ "/task/tid1/artifacts/public/filename and "
+ "https://tc-tests.localhost/api/queue/v1/task/tid2/artifacts/public/bar"
+ },
+ )
+
+ def test_self(self):
+ "resolve_task_references raises KeyError on artifact references to `self`"
+ self.assertRaisesRegexp(
+ KeyError,
+ "task 'subject' can't reference artifacts of self",
+ lambda: resolve_task_references(
+ "subject",
+ {"artifact-reference": "<self/public/artifact>"},
+ "tid-self",
+ "tid-decision",
+ {},
+ ),
+ )
+
+ def test_decision(self):
+ "resolve_task_references resolves `decision` to the provided decision task id"
+ self.do(
+ {"stuff": {"artifact-reference": "<decision/public/artifact>"}},
+ {
+ "stuff": "https://tc-tests.localhost/api/queue/v1/task/tid-decision/"
+ "artifacts/public/artifact"
+ },
+ )
+
+ def test_invalid(self):
+ "resolve_task_references raises a KeyError on reference to an invalid task"
+ self.assertRaisesRegexp(
+ KeyError,
+ "task 'subject' has no dependency named 'no-such'",
+ lambda: resolve_task_references(
+ "subject",
+ {"artifact-reference": "<no-such/public/artifact>"},
+ "tid-self",
+ "tid-decision",
+ {},
+ ),
+ )
+
+ def test_badly_formed(self):
+ "resolve_task_references ignores badly-formatted artifact references"
+ for inv in ["<edge1>", "edge1/foo>", "<edge1>/foo", "<edge1>foo"]:
+ resolved = resolve_task_references(
+ "subject", {"artifact-reference": inv}, "tid-self", "tid-decision", {}
+ )
+ self.assertEqual(resolved, inv)
+
+
+if __name__ == "__main__":
+ main()