Browse Source

Add stub of preflight integration tests

Rodolfo Carvalho 8 years ago
parent
commit
634a8957e1

+ 1 - 0
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

+ 12 - 0
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
+```

+ 99 - 0
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)
+}

+ 26 - 0
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)
+}

+ 14 - 0
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:

+ 14 - 0
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:

+ 11 - 0
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

+ 23 - 0
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

+ 24 - 0
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)
+}

+ 8 - 0
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/...