From e5cce50c7ea727c1c901b6e1443bd4291d62fce3 Mon Sep 17 00:00:00 2001
From: Daniel Nephin <dnephin@docker.com>
Date: Tue, 19 Sep 2017 18:00:54 -0400
Subject: [PATCH] Add code coverage report and codecov config

Signed-off-by: Daniel Nephin <dnephin@docker.com>
---
 .gitignore            |  2 ++
 client/client_test.go | 38 ++++++++++++++++++++------------------
 codecov.yml           | 17 +++++++++++++++++
 hack/ci/janky         |  2 ++
 hack/test/unit        | 18 +++++++++++++++++-
 5 files changed, 58 insertions(+), 19 deletions(-)
 create mode 100644 codecov.yml

diff --git a/.gitignore b/.gitignore
index 93a6df48e7..392bf963c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,5 @@ dockerversion/version_autogen.go
 dockerversion/version_autogen_unix.go
 vendor/pkg/
 hack/integration-cli-on-swarm/integration-cli-on-swarm
+coverage.txt
+profile.out
diff --git a/client/client_test.go b/client/client_test.go
index cb38d4da38..e0fa832d77 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -12,35 +12,40 @@ import (
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/internal/testutil"
+	"github.com/gotestyourself/gotestyourself/skip"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestNewEnvClient(t *testing.T) {
-	if runtime.GOOS == "windows" {
-		t.Skip("skipping unix only test for windows")
-	}
-	cases := []struct {
+	skip.IfCondition(t, runtime.GOOS == "windows")
+
+	testcases := []struct {
+		doc             string
 		envs            map[string]string
 		expectedError   string
 		expectedVersion string
 	}{
 		{
+			doc:             "default api version",
 			envs:            map[string]string{},
 			expectedVersion: api.DefaultVersion,
 		},
 		{
+			doc: "invalid cert path",
 			envs: map[string]string{
 				"DOCKER_CERT_PATH": "invalid/path",
 			},
 			expectedError: "Could not load X509 key pair: open invalid/path/cert.pem: no such file or directory",
 		},
 		{
+			doc: "default api version with cert path",
 			envs: map[string]string{
 				"DOCKER_CERT_PATH": "testdata/",
 			},
 			expectedVersion: api.DefaultVersion,
 		},
 		{
+			doc: "default api version with cert path and tls verify",
 			envs: map[string]string{
 				"DOCKER_CERT_PATH":  "testdata/",
 				"DOCKER_TLS_VERIFY": "1",
@@ -48,6 +53,7 @@ func TestNewEnvClient(t *testing.T) {
 			expectedVersion: api.DefaultVersion,
 		},
 		{
+			doc: "default api version with cert path and host",
 			envs: map[string]string{
 				"DOCKER_CERT_PATH": "testdata/",
 				"DOCKER_HOST":      "https://notaunixsocket",
@@ -55,24 +61,21 @@ func TestNewEnvClient(t *testing.T) {
 			expectedVersion: api.DefaultVersion,
 		},
 		{
+			doc: "invalid docker host",
 			envs: map[string]string{
 				"DOCKER_HOST": "host",
 			},
 			expectedError: "unable to parse docker host `host`",
 		},
 		{
+			doc: "invalid docker host, with good format",
 			envs: map[string]string{
 				"DOCKER_HOST": "invalid://url",
 			},
 			expectedVersion: api.DefaultVersion,
 		},
 		{
-			envs: map[string]string{
-				"DOCKER_API_VERSION": "anything",
-			},
-			expectedVersion: "anything",
-		},
-		{
+			doc: "override api version",
 			envs: map[string]string{
 				"DOCKER_API_VERSION": "1.22",
 			},
@@ -82,24 +85,23 @@ func TestNewEnvClient(t *testing.T) {
 
 	env := envToMap()
 	defer mapToEnv(env)
-	for _, c := range cases {
-		mapToEnv(env)
+	for _, c := range testcases {
 		mapToEnv(c.envs)
 		apiclient, err := NewEnvClient()
 		if c.expectedError != "" {
-			assert.Error(t, err)
-			assert.Equal(t, c.expectedError, err.Error())
+			assert.Error(t, err, c.doc)
+			assert.Equal(t, c.expectedError, err.Error(), c.doc)
 		} else {
-			assert.NoError(t, err)
+			assert.NoError(t, err, c.doc)
 			version := apiclient.ClientVersion()
-			assert.Equal(t, c.expectedVersion, version)
+			assert.Equal(t, c.expectedVersion, version, c.doc)
 		}
 
 		if c.envs["DOCKER_TLS_VERIFY"] != "" {
 			// pedantic checking that this is handled correctly
 			tr := apiclient.client.Transport.(*http.Transport)
-			assert.NotNil(t, tr.TLSClientConfig)
-			assert.Equal(t, tr.TLSClientConfig.InsecureSkipVerify, false)
+			assert.NotNil(t, tr.TLSClientConfig, c.doc)
+			assert.Equal(t, tr.TLSClientConfig.InsecureSkipVerify, false, c.doc)
 		}
 	}
 }
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000000..594265c6cf
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,17 @@
+comment:
+  layout: header, changes, diff, sunburst
+coverage:
+  status:
+    patch:
+      default:
+        target: 50%
+        only_pulls: true
+    # project will give us the diff in the total code coverage between a commit
+    # and its parent
+    project:
+      default:
+        target: auto
+        threshold: "15%"
+    changes: false
+ignore:
+  - "vendor/*"
diff --git a/hack/ci/janky b/hack/ci/janky
index 180f8c602d..1f8b1aad42 100755
--- a/hack/ci/janky
+++ b/hack/ci/janky
@@ -4,6 +4,8 @@ set -eu -o pipefail
 
 hack/validate/default
 hack/test/unit
+bash <(curl -s https://codecov.io/bash) -f coverage.txt || \
+    echo 'Codecov failed to upload'
 
 hack/make.sh \
 	binary-daemon \
diff --git a/hack/test/unit b/hack/test/unit
index 76e5d46d53..d0e85f1ad1 100755
--- a/hack/test/unit
+++ b/hack/test/unit
@@ -19,4 +19,20 @@ TESTDIRS="${TESTDIRS:-"./..."}"
 exclude_paths="/vendor/|/integration"
 pkg_list=$(go list $TESTDIRS | grep -vE "($exclude_paths)")
 
-go test -cover "${BUILDFLAGS[@]}" $TESTFLAGS $pkg_list
+# install test dependencies once before running tests for each package. This
+# significantly reduces the runtime.
+go test -i "${BUILDFLAGS[@]}" $pkg_list
+
+for pkg in $pkg_list; do
+    go test "${BUILDFLAGS[@]}" \
+        -cover \
+        -coverprofile=profile.out \
+        -covermode=atomic \
+        $TESTFLAGS \
+        "${pkg}"
+
+    if test -f profile.out; then
+        cat profile.out >> coverage.txt
+        rm profile.out
+    fi
+done