From 52c9fb552cd00d120578351588f98b6edc5629a9 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Tue, 24 Dec 2019 15:33:50 -0800 Subject: [PATCH 1/7] Ensure the plan test mocks' expectations are met [#33] --- internal/helm/plan_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/helm/plan_test.go b/internal/helm/plan_test.go index e5a1a96..e61a51c 100644 --- a/internal/helm/plan_test.go +++ b/internal/helm/plan_test.go @@ -20,6 +20,7 @@ func TestPlanTestSuite(t *testing.T) { func (suite *PlanTestSuite) TestNewPlan() { ctrl := gomock.NewController(suite.T()) + defer ctrl.Finish() stepOne := NewMockStep(ctrl) stepTwo := NewMockStep(ctrl) @@ -63,6 +64,7 @@ func (suite *PlanTestSuite) TestNewPlan() { func (suite *PlanTestSuite) TestNewPlanAbortsOnError() { ctrl := gomock.NewController(suite.T()) + defer ctrl.Finish() stepOne := NewMockStep(ctrl) stepTwo := NewMockStep(ctrl) From d86ac72529f873a483978c730e18e88b60b3d0eb Mon Sep 17 00:00:00 2001 From: Erin Call Date: Tue, 24 Dec 2019 15:47:26 -0800 Subject: [PATCH 2/7] Test Plan.Execute [#33] --- internal/helm/plan_test.go | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/internal/helm/plan_test.go b/internal/helm/plan_test.go index e61a51c..7c8c22b 100644 --- a/internal/helm/plan_test.go +++ b/internal/helm/plan_test.go @@ -87,6 +87,51 @@ func (suite *PlanTestSuite) TestNewPlanAbortsOnError() { suite.EqualError(err, "while preparing *helm.MockStep step: I'm starry Dave, aye, cat blew that") } +func (suite *PlanTestSuite) TestExecute() { + ctrl := gomock.NewController(suite.T()) + defer ctrl.Finish() + stepOne := NewMockStep(ctrl) + stepTwo := NewMockStep(ctrl) + + runCfg := run.Config{} + + plan := Plan{ + steps: []Step{stepOne, stepTwo}, + runCfg: runCfg, + } + + stepOne.EXPECT(). + Execute(runCfg). + Times(1) + stepTwo.EXPECT(). + Execute(runCfg). + Times(1) + + suite.NoError(plan.Execute()) +} + +func (suite *PlanTestSuite) TestExecuteAbortsOnError() { + ctrl := gomock.NewController(suite.T()) + defer ctrl.Finish() + stepOne := NewMockStep(ctrl) + stepTwo := NewMockStep(ctrl) + + runCfg := run.Config{} + + plan := Plan{ + steps: []Step{stepOne, stepTwo}, + runCfg: runCfg, + } + + stepOne.EXPECT(). + Execute(runCfg). + Times(1). + Return(fmt.Errorf("oh, he'll gnaw")) + + err := plan.Execute() + suite.EqualError(err, "in execution step 0: oh, he'll gnaw") +} + func (suite *PlanTestSuite) TestUpgrade() { cfg := Config{ ChartVersion: "seventeen", From cb58b5a021f8c330c3f53ba2fcd35c3d62806453 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Tue, 24 Dec 2019 15:49:47 -0800 Subject: [PATCH 3/7] Phrase errors in Execute the same as in Prepare [#33] --- internal/helm/plan.go | 2 +- internal/helm/plan_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/helm/plan.go b/internal/helm/plan.go index 1d4ced9..7a753e5 100644 --- a/internal/helm/plan.go +++ b/internal/helm/plan.go @@ -85,7 +85,7 @@ func (p *Plan) Execute() error { } if err := step.Execute(p.runCfg); err != nil { - return fmt.Errorf("in execution step %d: %w", i, err) + return fmt.Errorf("while executing %T step: %w", step, err) } } diff --git a/internal/helm/plan_test.go b/internal/helm/plan_test.go index 7c8c22b..5a6550a 100644 --- a/internal/helm/plan_test.go +++ b/internal/helm/plan_test.go @@ -129,7 +129,7 @@ func (suite *PlanTestSuite) TestExecuteAbortsOnError() { Return(fmt.Errorf("oh, he'll gnaw")) err := plan.Execute() - suite.EqualError(err, "in execution step 0: oh, he'll gnaw") + suite.EqualError(err, "while executing *helm.MockStep step: oh, he'll gnaw") } func (suite *PlanTestSuite) TestUpgrade() { From 801598e1c5d690fbc131fcd3c6a03e34b1e4022a Mon Sep 17 00:00:00 2001 From: Erin Call Date: Tue, 24 Dec 2019 16:16:22 -0800 Subject: [PATCH 4/7] Use a clearer filepath for the kubeconfig template [#13] --- Dockerfile | 2 +- kubeconfig => assets/kubeconfig.tpl | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename kubeconfig => assets/kubeconfig.tpl (100%) diff --git a/Dockerfile b/Dockerfile index 492dd54..c8fa2ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM alpine/helm MAINTAINER Erin Call COPY build/drone-helm /bin/drone-helm -COPY kubeconfig /root/.kube/config.tpl +COPY assets/kubeconfig.tpl /root/.kube/config.tpl LABEL description="Helm 3 plugin for Drone 3" LABEL base="alpine/helm" diff --git a/kubeconfig b/assets/kubeconfig.tpl similarity index 100% rename from kubeconfig rename to assets/kubeconfig.tpl From 6b331fdf03d3818bfb751a95684b995c56501566 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Wed, 25 Dec 2019 10:10:30 -0800 Subject: [PATCH 5/7] Check the validity of the kubeconfig template [#13] It's a little tricky to find a balance between "brittle" and "thorough" in this test--I'd like to verify that e.g. the certificate is in clusters[0].cluster.certificate-authority-data, not at the root. On the other hand, we can't actually show that it's a valid kubeconfig file without actually *using* it, so there's a hard upper limit on the strength of the assertions. I've settled on verifying that all the settings make it into the file and the file is syntactically-valid yaml. --- go.mod | 1 + go.sum | 2 ++ internal/run/initkube_test.go | 59 +++++++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4f4371b..e62b5d2 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/pelotech/drone-helm3 go 1.13 require ( + github.com/go-yaml/yaml v2.1.0+incompatible github.com/golang/mock v1.3.1 github.com/kelseyhightower/envconfig v1.4.0 github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index c0d66c9..49faf36 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= diff --git a/internal/run/initkube_test.go b/internal/run/initkube_test.go index fb32b15..1d9d81f 100644 --- a/internal/run/initkube_test.go +++ b/internal/run/initkube_test.go @@ -1,12 +1,12 @@ package run import ( + "github.com/go-yaml/yaml" + "github.com/stretchr/testify/suite" "io/ioutil" "os" - "text/template" - // "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" "testing" + "text/template" ) type InitKubeTestSuite struct { @@ -58,6 +58,59 @@ namespace: Cisco suite.Equal(want, string(conf)) } +func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() { + configFile, err := tempfile("kubeconfig********.yml", "") + defer os.Remove(configFile.Name()) + suite.Require().NoError(err) + + cfg := Config{ + KubeConfig: configFile.Name(), + Namespace: "marshmallow", + } + init := InitKube{ + TemplateFile: "../../assets/kubeconfig.tpl", // the actual kubeconfig template + APIServer: "https://kube.cluster/peanut", + ServiceAccount: "chef", + Token: "eWVhaCB3ZSB0b2tpbic=", + Certificate: "d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE", + } + suite.Require().NoError(init.Prepare(cfg)) + suite.Require().NoError(init.Execute(cfg)) + + contents, err := ioutil.ReadFile(configFile.Name()) + suite.Require().NoError(err) + + // each setting should be reflected in the generated file + expectations := []string{ + "namespace: marshmallow", + "server: https://kube.cluster/peanut", + "user: chef", + "name: chef", + "token: eWVhaCB3ZSB0b2tpbic", + "certificate-authority-data: d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE", + } + for _, expected := range expectations { + suite.Contains(string(contents), expected) + } + + // the generated config should be valid yaml, with no repeated keys + conf := map[string]interface{}{} + suite.NoError(yaml.UnmarshalStrict(contents, &conf)) + + // test the other branch of the certificate/SkipTLSVerify conditional + init.SkipTLSVerify = true + init.Certificate = "" + + suite.Require().NoError(init.Prepare(cfg)) + suite.Require().NoError(init.Execute(cfg)) + contents, err = ioutil.ReadFile(configFile.Name()) + suite.Require().NoError(err) + suite.Contains(string(contents), "insecure-skip-tls-verify: true") + + conf = map[string]interface{}{} + suite.NoError(yaml.UnmarshalStrict(contents, &conf)) +} + func (suite *InitKubeTestSuite) TestPrepareParseError() { templateFile, err := tempfile("kubeconfig********.yml.tpl", `{{ NonexistentFunction }}`) defer os.Remove(templateFile.Name()) From 2a13fff548e27d67d7f5aaba4258e075f0e9a6f3 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Thu, 26 Dec 2019 12:39:02 -0800 Subject: [PATCH 6/7] Don't check the generated config's yaml syntax [#13] See discussion on https://github.com/pelotech/drone-helm3/pull/36 --it doesn't really make sense to add a dependency on yaml just for testing. --- go.mod | 1 - go.sum | 2 -- internal/run/initkube_test.go | 8 -------- 3 files changed, 11 deletions(-) diff --git a/go.mod b/go.mod index e62b5d2..4f4371b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/pelotech/drone-helm3 go 1.13 require ( - github.com/go-yaml/yaml v2.1.0+incompatible github.com/golang/mock v1.3.1 github.com/kelseyhightower/envconfig v1.4.0 github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index 49faf36..c0d66c9 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= -github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= diff --git a/internal/run/initkube_test.go b/internal/run/initkube_test.go index 479bf56..a3542d8 100644 --- a/internal/run/initkube_test.go +++ b/internal/run/initkube_test.go @@ -1,7 +1,6 @@ package run import ( - "github.com/go-yaml/yaml" "github.com/stretchr/testify/suite" "io/ioutil" "os" @@ -93,10 +92,6 @@ func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() { suite.Contains(string(contents), expected) } - // the generated config should be valid yaml, with no repeated keys - conf := map[string]interface{}{} - suite.NoError(yaml.UnmarshalStrict(contents, &conf)) - // test the other branch of the certificate/SkipTLSVerify conditional init.SkipTLSVerify = true init.Certificate = "" @@ -106,9 +101,6 @@ func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() { contents, err = ioutil.ReadFile(configFile.Name()) suite.Require().NoError(err) suite.Contains(string(contents), "insecure-skip-tls-verify: true") - - conf = map[string]interface{}{} - suite.NoError(yaml.UnmarshalStrict(contents, &conf)) } func (suite *InitKubeTestSuite) TestPrepareParseError() { From 3b85c3871409e353968a7b7ce9ae8f28fd70c1d4 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Thu, 26 Dec 2019 12:53:36 -0800 Subject: [PATCH 7/7] Test yaml validity without a new dependency [#15] It turns out testify already depends on yaml, so we aren't adding anything new by using it here. --- go.mod | 1 + internal/run/initkube_test.go | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/go.mod b/go.mod index 4f4371b..c34f191 100644 --- a/go.mod +++ b/go.mod @@ -8,4 +8,5 @@ require ( github.com/stretchr/testify v1.4.0 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect golang.org/x/tools v0.0.0-20191209225234-22774f7dae43 // indirect + gopkg.in/yaml.v2 v2.2.2 ) diff --git a/internal/run/initkube_test.go b/internal/run/initkube_test.go index 87471ba..72452a8 100644 --- a/internal/run/initkube_test.go +++ b/internal/run/initkube_test.go @@ -2,6 +2,7 @@ package run import ( "github.com/stretchr/testify/suite" + yaml "gopkg.in/yaml.v2" "io/ioutil" "os" "testing" @@ -92,6 +93,10 @@ func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() { suite.Contains(string(contents), expected) } + // the generated config should be valid yaml, with no repeated keys + conf := map[string]interface{}{} + suite.NoError(yaml.UnmarshalStrict(contents, &conf)) + // test the other branch of the certificate/SkipTLSVerify conditional init.SkipTLSVerify = true init.Certificate = "" @@ -101,6 +106,9 @@ func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() { contents, err = ioutil.ReadFile(configFile.Name()) suite.Require().NoError(err) suite.Contains(string(contents), "insecure-skip-tls-verify: true") + + conf = map[string]interface{}{} + suite.NoError(yaml.UnmarshalStrict(contents, &conf)) } func (suite *InitKubeTestSuite) TestPrepareParseError() {