Add layout file validation.
Based on voluptuous library.
Basic validation should catch typos, missing or extra attributes.
Can be expanded to do more serious validation (ie, specifying
a comment in a trigger should require the event be comment-added).
Adds a command line option to validate a named layout file and
exit.
(Also add dist/ to .gitignore.)
Change-Id: Ia864ebde1765141d4d1a52bc77033689b6210e81
Reviewed-on: https://review.openstack.org/19443
Reviewed-by: Clark Boylan <clark.boylan@gmail.com>
Reviewed-by: Jeremy Stanley <fungi@yuggoth.org>
Approved: James E. Blair <corvus@inaugust.com>
Tested-by: Jenkins
diff --git a/tests/fixtures/layouts/bad_pipelines b/tests/fixtures/layouts/bad_pipelines
new file mode 100644
index 0000000..f627208
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines
@@ -0,0 +1 @@
+pipelines:
diff --git a/tests/fixtures/layouts/bad_pipelines1.yaml b/tests/fixtures/layouts/bad_pipelines1.yaml
new file mode 100644
index 0000000..4207a2c
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines1.yaml
@@ -0,0 +1,4 @@
+pipelines:
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines10.yaml b/tests/fixtures/layouts/bad_pipelines10.yaml
new file mode 100644
index 0000000..5248c17
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines10.yaml
@@ -0,0 +1,7 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+
+projects:
+ - name: foo
+ merge-mode: foo
\ No newline at end of file
diff --git a/tests/fixtures/layouts/bad_pipelines2.yaml b/tests/fixtures/layouts/bad_pipelines2.yaml
new file mode 100644
index 0000000..e75a561
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines2.yaml
@@ -0,0 +1,6 @@
+pipelines:
+ - noname: check
+ manager: IndependentPipelineManager
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines3.yaml b/tests/fixtures/layouts/bad_pipelines3.yaml
new file mode 100644
index 0000000..0c11a85
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines3.yaml
@@ -0,0 +1,6 @@
+pipelines:
+ - name: check
+ manager: NonexistentPipelineManager
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines4.yaml b/tests/fixtures/layouts/bad_pipelines4.yaml
new file mode 100644
index 0000000..a99b9e2
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines4.yaml
@@ -0,0 +1,8 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+ trigger:
+ - event: non-event
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines5.yaml b/tests/fixtures/layouts/bad_pipelines5.yaml
new file mode 100644
index 0000000..7db7bd1
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines5.yaml
@@ -0,0 +1,9 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+ trigger:
+ - approval:
+ - approved: 1
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines6.yaml b/tests/fixtures/layouts/bad_pipelines6.yaml
new file mode 100644
index 0000000..8d313bc
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines6.yaml
@@ -0,0 +1,9 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+ trigger:
+ - event: comment-added
+ approved: 1
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines7.yaml b/tests/fixtures/layouts/bad_pipelines7.yaml
new file mode 100644
index 0000000..7517b9a
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines7.yaml
@@ -0,0 +1,5 @@
+pipelines:
+ - manager: IndependentPipelineManager
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines8.yaml b/tests/fixtures/layouts/bad_pipelines8.yaml
new file mode 100644
index 0000000..eeab038
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines8.yaml
@@ -0,0 +1,5 @@
+pipelines:
+ - name: check
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_pipelines9.yaml b/tests/fixtures/layouts/bad_pipelines9.yaml
new file mode 100644
index 0000000..ebb2e1f
--- /dev/null
+++ b/tests/fixtures/layouts/bad_pipelines9.yaml
@@ -0,0 +1,8 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+ - name: check
+ manager: IndependentPipelineManager
+
+projects:
+ - name: foo
diff --git a/tests/fixtures/layouts/bad_projects1.yaml b/tests/fixtures/layouts/bad_projects1.yaml
new file mode 100644
index 0000000..c210c43
--- /dev/null
+++ b/tests/fixtures/layouts/bad_projects1.yaml
@@ -0,0 +1,9 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+
+projects:
+ - name: foo
+ gate:
+ - test
+
diff --git a/tests/fixtures/layouts/bad_projects2.yaml b/tests/fixtures/layouts/bad_projects2.yaml
new file mode 100644
index 0000000..b91ed9d
--- /dev/null
+++ b/tests/fixtures/layouts/bad_projects2.yaml
@@ -0,0 +1,9 @@
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+
+projects:
+ - name: foo
+ check:
+ - test
+ - foo
diff --git a/tests/fixtures/layouts/good_layout.yaml b/tests/fixtures/layouts/good_layout.yaml
new file mode 100644
index 0000000..ca024ec
--- /dev/null
+++ b/tests/fixtures/layouts/good_layout.yaml
@@ -0,0 +1,58 @@
+includes:
+ - python-file: openstack_functions.py
+
+pipelines:
+ - name: check
+ manager: IndependentPipelineManager
+ trigger:
+ - event: patchset-created
+ success:
+ verified: 1
+ failure:
+ verified: -1
+
+ - name: post
+ manager: IndependentPipelineManager
+ trigger:
+ - event: ref-updated
+ ref: ^(?!refs/).*$
+
+ - name: gate
+ manager: DependentPipelineManager
+ trigger:
+ - event: comment-added
+ approval:
+ - approved: 1
+ success:
+ verified: 2
+ code-review: 1
+ submit: true
+ failure:
+ verified: -2
+ workinprogress: true
+ start:
+ verified: 0
+
+jobs:
+ - name: ^.*-merge$
+ failure-message: Unable to merge change
+ hold-following-changes: true
+ - name: test-merge
+ parameter-function: devstack_params
+ - name: test-test
+ - name: test-merge2
+ success-pattern: http://logs.example.com/{change.number}/{change.patchset}/{pipeline.name}/{job.name}/{build.number}/success
+ failure-pattern: http://logs.example.com/{change.number}/{change.patchset}/{pipeline.name}/{job.name}/{build.number}/fail
+
+projects:
+ - name: test-org/test
+ merge-mode: cherry-pick
+ check:
+ - test-merge2:
+ - test-thing1:
+ - test-thing2
+ - test-thing3
+ gate:
+ - test-thing
+ post:
+ - test-post
diff --git a/tests/test_layoutvalidator.py b/tests/test_layoutvalidator.py
new file mode 100644
index 0000000..343dc47
--- /dev/null
+++ b/tests/test_layoutvalidator.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+# Copyright 2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import unittest
+import os
+import re
+import yaml
+import voluptuous
+
+import zuul.layoutvalidator
+
+FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
+ 'fixtures')
+LAYOUT_RE = re.compile(r'^(good|bad)_.*\.yaml$')
+
+
+class testScheduler(unittest.TestCase):
+ def test_layouts(self):
+ """Test layout file validation"""
+ print
+ errors = []
+ for fn in os.listdir(os.path.join(FIXTURE_DIR, 'layouts')):
+ m = LAYOUT_RE.match(fn)
+ if not m:
+ continue
+ print fn
+ layout = os.path.join(FIXTURE_DIR, 'layouts', fn)
+ data = yaml.load(open(layout))
+ validator = zuul.layoutvalidator.LayoutValidator()
+ if m.group(1) == 'good':
+ try:
+ validator.validate(data)
+ except voluptuous.Invalid, e:
+ raise Exception(
+ 'Unexpected YAML syntax error in %s:\n %s' %
+ (fn, str(e)))
+ else:
+ try:
+ validator.validate(data)
+ raise Exception("Expected a YAML syntax error in %s." %
+ fn)
+ except voluptuous.Invalid, e:
+ error = str(e)
+ print ' ', error
+ if error in errors:
+ raise Exception("Error has already beed tested: %s" %
+ error)
+ else:
+ errors.append(error)
+ pass