summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--test-requirements.txt1
-rw-r--r--test/integration/README.md12
-rw-r--r--test/integration/openshift_health_checker/common.go99
-rw-r--r--test/integration/openshift_health_checker/example/example_test.go26
-rw-r--r--test/integration/openshift_health_checker/example/playbooks/test_fail.yml14
-rw-r--r--test/integration/openshift_health_checker/example/playbooks/test_ping.yml14
-rw-r--r--test/integration/openshift_health_checker/preflight/playbooks/preflight_fail_all.yml11
-rw-r--r--test/integration/openshift_health_checker/preflight/playbooks/setup_container.yml23
-rw-r--r--test/integration/openshift_health_checker/preflight/preflight_test.go24
-rw-r--r--tox.ini8
10 files changed, 232 insertions, 0 deletions
diff --git a/test-requirements.txt b/test-requirements.txt
index 585cca0b9..06883390b 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -12,3 +12,4 @@ coverage==4.3.4
mock==2.0.0
pytest==3.0.7
pytest-cov==2.4.0
+docker-py==1.10.6
diff --git a/test/integration/README.md b/test/integration/README.md
new file mode 100644
index 000000000..0edbccd74
--- /dev/null
+++ b/test/integration/README.md
@@ -0,0 +1,12 @@
+# Integration tests
+
+Integration tests exercise the OpenShift Ansible playbooks by performing
+simulated installations in Docker containers.
+
+## Running the tests
+
+From the repository root, run with:
+
+```
+tox -e integration
+```
diff --git a/test/integration/openshift_health_checker/common.go b/test/integration/openshift_health_checker/common.go
new file mode 100644
index 000000000..aea85342f
--- /dev/null
+++ b/test/integration/openshift_health_checker/common.go
@@ -0,0 +1,99 @@
+package test
+
+import (
+ "bytes"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+// A PlaybookTest executes a given Ansible playbook and checks the exit code and
+// output contents.
+type PlaybookTest struct {
+ // inputs
+ Path string
+ // expected outputs
+ ExitCode int
+ Output []string // zero or more strings that should be in the output
+}
+
+// Run runs the PlaybookTest.
+func (p PlaybookTest) Run(t *testing.T) {
+ // A PlaybookTest is intended to be run in parallel with other tests.
+ t.Parallel()
+
+ cmd := exec.Command("ansible-playbook", p.Path)
+ cmd.Env = append(os.Environ(), "ANSIBLE_FORCE_COLOR=1")
+ b, err := cmd.CombinedOutput()
+
+ // Check exit code.
+ if (err == nil) && (p.ExitCode != 0) {
+ p.checkExitCode(t, 0, p.ExitCode, cmd, b)
+ }
+ if (err != nil) && (p.ExitCode == 0) {
+ got, ok := getExitCode(err)
+ if !ok {
+ t.Logf("unexpected error (%T): %[1]v", err)
+ p.logCmdAndOutput(t, cmd, b)
+ t.FailNow()
+ }
+ p.checkExitCode(t, got, p.ExitCode, cmd, b)
+ }
+
+ // Check output contents.
+ var missing []string
+ for _, s := range p.Output {
+ if !bytes.Contains(b, []byte(s)) {
+ missing = append(missing, s)
+ }
+ }
+ if len(missing) > 0 {
+ t.Logf("missing in output: %q", missing)
+ p.logCmdAndOutput(t, cmd, b)
+ t.FailNow()
+ }
+}
+
+// getExitCode returns an exit code and true if the exit code could be taken
+// from err, false otherwise.
+// The implementation is GOOS-specific, and currently only supports Linux.
+func getExitCode(err error) (int, bool) {
+ exitErr, ok := err.(*exec.ExitError)
+ if !ok {
+ return -1, false
+ }
+ waitStatus, ok := exitErr.Sys().(syscall.WaitStatus)
+ if !ok {
+ return -1, false
+ }
+ return waitStatus.ExitStatus(), true
+}
+
+// checkExitCode marks the test as failed when got is different than want.
+func (p PlaybookTest) checkExitCode(t *testing.T, got, want int, cmd *exec.Cmd, output []byte) {
+ if got == want {
+ return
+ }
+ t.Logf("got exit code %v, want %v", got, want)
+ p.logCmdAndOutput(t, cmd, output)
+ t.FailNow()
+}
+
+// logCmdAndOutput logs how to re-run a command and a summary of the output of
+// its last execution for debugging.
+func (p PlaybookTest) logCmdAndOutput(t *testing.T, cmd *exec.Cmd, output []byte) {
+ const maxLines = 10
+ lines := bytes.Split(bytes.TrimRight(output, "\n"), []byte("\n"))
+ if len(lines) > maxLines {
+ lines = append([][]byte{[]byte("...")}, lines[len(lines)-maxLines:len(lines)]...)
+ }
+ output = bytes.Join(lines, []byte("\n"))
+ dir, err := filepath.Abs(cmd.Dir)
+ if err != nil {
+ panic(err)
+ }
+ t.Logf("\n$ (cd %s && %s)\n%s", dir, strings.Join(cmd.Args, " "), output)
+}
diff --git a/test/integration/openshift_health_checker/example/example_test.go b/test/integration/openshift_health_checker/example/example_test.go
new file mode 100644
index 000000000..f59c21291
--- /dev/null
+++ b/test/integration/openshift_health_checker/example/example_test.go
@@ -0,0 +1,26 @@
+package example
+
+import (
+ "testing"
+
+ . ".."
+)
+
+// TestPing and TestFail below are just examples of tests that involve running
+// 'ansible-playbook' with a given playbook and verifying the outcome. Real
+// tests look similar, but call more interesting playbooks.
+
+func TestPing(t *testing.T) {
+ PlaybookTest{
+ Path: "playbooks/test_ping.yml",
+ Output: []string{"[test ping]"},
+ }.Run(t)
+}
+
+func TestFail(t *testing.T) {
+ PlaybookTest{
+ Path: "playbooks/test_fail.yml",
+ ExitCode: 2,
+ Output: []string{"[test fail]", `"msg": "Failed as requested from task"`},
+ }.Run(t)
+}
diff --git a/test/integration/openshift_health_checker/example/playbooks/test_fail.yml b/test/integration/openshift_health_checker/example/playbooks/test_fail.yml
new file mode 100644
index 000000000..318f1c507
--- /dev/null
+++ b/test/integration/openshift_health_checker/example/playbooks/test_fail.yml
@@ -0,0 +1,14 @@
+---
+# This is just a placeholder playbook. Our aim is to make it:
+# 1. Build one or more Docker images with a certain interesting state;
+# 2. Ensure one or more containers (with random names) are running with the
+# latest build of the image;
+# 3. Run the byo OpenShift installation playbook targeting the container.
+- hosts: localhost
+ gather_facts: no
+ tasks:
+ - name: waste some time
+ pause:
+ seconds: 1
+ - name: test fail
+ fail:
diff --git a/test/integration/openshift_health_checker/example/playbooks/test_ping.yml b/test/integration/openshift_health_checker/example/playbooks/test_ping.yml
new file mode 100644
index 000000000..da31b3d85
--- /dev/null
+++ b/test/integration/openshift_health_checker/example/playbooks/test_ping.yml
@@ -0,0 +1,14 @@
+---
+# This is just a placeholder playbook. Our aim is to make it:
+# 1. Build one or more Docker images with a certain interesting state;
+# 2. Ensure one or more containers (with random names) are running with the
+# latest build of the image;
+# 3. Run the byo OpenShift installation playbook targeting the container.
+- hosts: localhost
+ gather_facts: no
+ tasks:
+ - name: waste some time
+ pause:
+ seconds: 1
+ - name: test ping
+ ping:
diff --git a/test/integration/openshift_health_checker/preflight/playbooks/preflight_fail_all.yml b/test/integration/openshift_health_checker/preflight/playbooks/preflight_fail_all.yml
new file mode 100644
index 000000000..e7790a0d4
--- /dev/null
+++ b/test/integration/openshift_health_checker/preflight/playbooks/preflight_fail_all.yml
@@ -0,0 +1,11 @@
+---
+- include: setup_container.yml
+ vars:
+ name: preflight_fail_all
+
+- name: Run preflight checks
+ include: ../../../../../playbooks/byo/openshift-preflight/check.yml
+
+# - include: tasks/teardown_container.yml
+# vars:
+# name: preflight_fail_all
diff --git a/test/integration/openshift_health_checker/preflight/playbooks/setup_container.yml b/test/integration/openshift_health_checker/preflight/playbooks/setup_container.yml
new file mode 100644
index 000000000..fff797c27
--- /dev/null
+++ b/test/integration/openshift_health_checker/preflight/playbooks/setup_container.yml
@@ -0,0 +1,23 @@
+---
+# Required vars:
+# * name = name of the container to be started
+
+- name: Start CentOS 7 container
+ gather_facts: no
+ hosts: localhost
+ connection: local
+ vars:
+ container_name: openshift_ansible_test_{{ name }}
+ tasks:
+ - name: start container
+ docker_container:
+ name: "{{ container_name }}"
+ image: centos:7
+ command: sleep infinity
+ recreate: yes
+ - name: add host
+ add_host:
+ name: "{{ container_name }}"
+ ansible_connection: docker
+ groups: OSEv3,masters,nodes
+ deployment_type: origin
diff --git a/test/integration/openshift_health_checker/preflight/preflight_test.go b/test/integration/openshift_health_checker/preflight/preflight_test.go
new file mode 100644
index 000000000..a1b98bf0f
--- /dev/null
+++ b/test/integration/openshift_health_checker/preflight/preflight_test.go
@@ -0,0 +1,24 @@
+package preflight
+
+import (
+ "testing"
+
+ . ".."
+)
+
+func TestPreflightFailAll(t *testing.T) {
+ PlaybookTest{
+ Path: "playbooks/preflight_fail_all.yml",
+ ExitCode: 2,
+ Output: []string{
+ "Failure summary",
+ "Cannot install all of the necessary packages",
+ "origin-clients",
+ "origin-master",
+ "origin-node",
+ "origin-sdn-ovs",
+ "python-httplib2",
+ "failed=1",
+ },
+ }.Run(t)
+}
diff --git a/tox.ini b/tox.ini
index 8678ff463..6755dc625 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,6 +3,7 @@ minversion=2.3.1
envlist =
py{27,35}-{flake8,pylint,unit}
py27-{yamllint,ansible_syntax,generate_validation}
+ integration
skipsdist=True
skip_missing_interpreters=True
@@ -13,6 +14,8 @@ deps =
-rtest-requirements.txt
py35-flake8: flake8-bugbear==17.3.0
+whitelist_externals = env
+
commands =
unit: pip install -e utils
unit: pytest {posargs}
@@ -22,3 +25,8 @@ commands =
generate_validation: python setup.py generate_validation
# TODO(rhcarvalho): check syntax of other important entrypoint playbooks
ansible_syntax: python setup.py ansible_syntax
+
+ # Unset GOPATH because tests use relative imports. This should be removed if
+ # we require openshift-ansible to live in a Go work space and use absolute
+ # imports in tests (desirable).
+ integration: env -u GOPATH go test -v ./test/integration/...