Bug 1501776: [taskgraph] Apply extra taskgraph checks to when extending schemas; r=dustin
authorTom Prince <mozilla@hocat.ca>
Thu, 25 Oct 2018 00:37:50 +0000
changeset 491240 63d0906068ff45e427a5b09ebfc5d0c2f3b07ebe
parent 491239 ccfeb561645b499025c28c26287ee0b8d96cc7ad
child 491241 8dd04e593157e5a1b83734af12ddb2665a5ab70d
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersdustin
bugs1501776
milestone65.0a1
Bug 1501776: [taskgraph] Apply extra taskgraph checks to when extending schemas; r=dustin Differential Revision: https://phabricator.services.mozilla.com/D9720
taskcluster/taskgraph/test/test_util_schema.py
taskcluster/taskgraph/util/schema.py
--- a/taskcluster/taskgraph/test/test_util_schema.py
+++ b/taskcluster/taskgraph/test/test_util_schema.py
@@ -4,18 +4,18 @@
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import unittest
 from mozunit import main
 from taskgraph.util.schema import (
     validate_schema,
     resolve_keyed_by,
+    Schema,
 )
-from voluptuous import Schema
 
 schema = Schema({
     'x': int,
     'y': basestring,
 })
 
 
 class TestValidateSchema(unittest.TestCase):
@@ -26,16 +26,34 @@ class TestValidateSchema(unittest.TestCa
     def test_invalid(self):
         try:
             validate_schema(schema, {'x': 'not-int'}, "pfx")
             self.fail("no exception raised")
         except Exception as e:
             self.failUnless(str(e).startswith("pfx\n"))
 
 
+class TestCheckSchema(unittest.TestCase):
+
+    def test_schema(self):
+        "Creating a schema applies taskgraph checks."
+        with self.assertRaises(Exception):
+            Schema({"camelCase": int})
+
+    def test_extend_schema(self):
+        "Extending a schema applies taskgraph checks."
+        with self.assertRaises(Exception):
+            Schema({"kebab-case": int}).extend({"camelCase": int})
+
+    def test_extend_schema(self):
+        "Extending a schema twice applies taskgraph checks."
+        with self.assertRaises(Exception):
+            Schema({"kebab-case": int}).extend({'more-kebab': int}).extend({"camelCase": int})
+
+
 class TestResolveKeyedBy(unittest.TestCase):
 
     def test_no_by(self):
         self.assertEqual(
             resolve_keyed_by({'x': 10}, 'z', 'n'),
             {'x': 10})
 
     def test_no_by_dotted(self):
--- a/taskcluster/taskgraph/util/schema.py
+++ b/taskcluster/taskgraph/util/schema.py
@@ -194,24 +194,31 @@ def check_schema(schema):
             for i, v in enumerate(sch):
                 iter("{}[{}]".format(path, i), v)
         elif isinstance(sch, voluptuous.Any):
             for v in sch.validators:
                 iter(path, v)
     iter('schema', schema.schema)
 
 
-def Schema(*args, **kwargs):
+class Schema(voluptuous.Schema):
     """
     Operates identically to voluptuous.Schema, but applying some taskgraph-specific checks
     in the process.
     """
-    schema = voluptuous.Schema(*args, **kwargs)
-    check_schema(schema)
-    return schema
+    def __init__(self, *args, **kwargs):
+        super(Schema, self).__init__(*args, **kwargs)
+        check_schema(self)
+
+    def extend(self, *args, **kwargs):
+        schema = super(Schema, self).extend(*args, **kwargs)
+        check_schema(schema)
+        # We want twice extend schema to be checked too.
+        schema.__class__ = Schema
+        return schema
 
 
 OptimizationSchema = voluptuous.Any(
     # always run this task (default)
     None,
     # search the index for the given index namespaces, and replace this task if found
     # the search occurs in order, with the first match winning
     {'index-search': [basestring]},