From c129979350639142458371dee212be9a30123d37 Mon Sep 17 00:00:00 2001 From: Victor Antonovich Date: Thu, 18 Oct 2018 18:26:44 +0300 Subject: [PATCH] Add tests --- .travis.yml | 2 +- Gopkg.lock | 138 ++++++++++++++++++++++++- README.md | 1 - app_test.go | 44 ++++++++ client.go | 2 +- client_test.go | 29 ++++++ deps_test.go | 21 ++++ logging.go | 4 + template_test.go | 34 ++++++ testdata/TestAppRunOnce.out.golden | 3 + testdata/TestAppRunOnce.template | 3 + testdata/TestTemplateRender.out.golden | 7 ++ testdata/TestTemplateRender.template | 7 ++ util_test.go | 32 ++++++ 14 files changed, 322 insertions(+), 5 deletions(-) create mode 100644 app_test.go create mode 100644 client_test.go create mode 100644 deps_test.go create mode 100644 template_test.go create mode 100644 testdata/TestAppRunOnce.out.golden create mode 100644 testdata/TestAppRunOnce.template create mode 100644 testdata/TestTemplateRender.out.golden create mode 100644 testdata/TestTemplateRender.template create mode 100644 util_test.go diff --git a/.travis.yml b/.travis.yml index a9a00b6..dbf1c8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,4 +22,4 @@ before_script: - make vendor_install vendor_sync script: - - make lint build + - make lint build test diff --git a/Gopkg.lock b/Gopkg.lock index f2e810d..e546e08 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -41,6 +41,22 @@ pruneopts = "UT" revision = "691ee98543af2f262f35fbb54bdd42f00b9b9cc5" +[[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "UT" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + digest = "1:f1f2bd73c025d24c3b93abf6364bccb802cf2fdedaa44360804c67800e8fab8d" + name = "github.com/evanphx/json-patch" + packages = ["."] + pruneopts = "UT" + revision = "72bf35d0ff611848c1dc9df0f976c81192392fa5" + version = "v4.1.0" + [[projects]] digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" name = "github.com/fsnotify/fsnotify" @@ -133,6 +149,17 @@ pruneopts = "UT" revision = "c8947f7d1c5126259bed8769515ce34399db23ca" +[[projects]] + digest = "1:8ec8d88c248041a6df5f6574b87bc00e7e0b493881dad2e7ef47b11dc69093b5" + name = "github.com/hashicorp/golang-lru" + packages = [ + ".", + "simplelru", + ] + pruneopts = "UT" + revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" + version = "v0.5.0" + [[projects]] digest = "1:a361611b8c8c75a1091f00027767f7779b29cb37c456a71b8f2604c88057ab40" name = "github.com/hashicorp/hcl" @@ -229,6 +256,14 @@ pruneopts = "UT" revision = "c2dbbc24a97911339e01bda0b8cabdbd8f13b602" +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + [[projects]] digest = "1:2ee0f15eb0fb04f918db7c2dcf39745f40d69f798ef171610a730e8a56aaa4fd" name = "github.com/russross/blackfriday" @@ -297,6 +332,17 @@ revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9" version = "v1.1.0" +[[projects]] + digest = "1:c40d65817cdd41fac9aa7af8bed56927bb2d6d47e4fea566a74880f5c2b1c41e" + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require", + ] + pruneopts = "UT" + revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" + version = "v1.2.2" + [[projects]] branch = "master" digest = "1:69b3fcb7a41b18436a85471cbdcfc70ad10ba3206f8c87563e1c773610e1bcad" @@ -453,14 +499,23 @@ revision = "0f11257a8a25954878633ebdc9841c67d8f83bdb" version = "kubernetes-1.10.6" +[[projects]] + branch = "master" + digest = "1:fa432f3acd7631bca4888e8d0f1db60cc46aef6a2d85a7f87f0ade54ea0ba56e" + name = "k8s.io/apiextensions-apiserver" + packages = ["pkg/features"] + pruneopts = "UT" + revision = "5ca6f4b7a8c88a0318b42e3c75f1610f0d5b67b4" + [[projects]] branch = "release-1.10" - digest = "1:bc7920d9796bd371e092d379b27b6b9bd3b50d135260cbdc10512dde51aec449" + digest = "1:70a58294cbd04d964352103cc6c91b4e3ac5bab7f63f8ab614f40803a7b18b33" name = "k8s.io/apimachinery" packages = [ "pkg/api/errors", "pkg/api/meta", "pkg/api/resource", + "pkg/apis/meta/internalversion", "pkg/apis/meta/v1", "pkg/apis/meta/v1/unstructured", "pkg/apis/meta/v1beta1", @@ -478,60 +533,106 @@ "pkg/runtime/serializer/versioning", "pkg/selection", "pkg/types", + "pkg/util/cache", "pkg/util/clock", + "pkg/util/diff", "pkg/util/errors", "pkg/util/framer", "pkg/util/intstr", "pkg/util/json", + "pkg/util/mergepatch", "pkg/util/net", "pkg/util/runtime", "pkg/util/sets", + "pkg/util/strategicpatch", "pkg/util/validation", "pkg/util/validation/field", "pkg/util/wait", "pkg/util/yaml", "pkg/version", "pkg/watch", + "third_party/forked/golang/json", "third_party/forked/golang/reflect", ] pruneopts = "UT" revision = "e386b2658ed20923da8cc9250e552f082899a1ee" [[projects]] - digest = "1:90c5844dd0b42fb9cdc6a186051d30adc0e0c94e913e25b372a61440dd690d2d" + branch = "master" + digest = "1:3c51e5ed4b64fbaa21384608be9c81b381b56d4b3ed29be9ea742c3b2486d05d" + name = "k8s.io/apiserver" + packages = [ + "pkg/features", + "pkg/util/feature", + ] + pruneopts = "UT" + revision = "0deca6c827f580ebbd9cd8c2fe6fca0858313386" + +[[projects]] + digest = "1:df2754e0df76b02ed991de8c2cb2847f11e7e289a5e42c64d109ad000e68575a" name = "k8s.io/client-go" packages = [ "discovery", + "discovery/fake", "kubernetes", + "kubernetes/fake", "kubernetes/scheme", "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1alpha1/fake", "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/admissionregistration/v1beta1/fake", "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1/fake", "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta1/fake", "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/apps/v1beta2/fake", "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1/fake", "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authentication/v1beta1/fake", "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1/fake", "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/authorization/v1beta1/fake", "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v1/fake", "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/autoscaling/v2beta1/fake", "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1/fake", "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v1beta1/fake", "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/batch/v2alpha1/fake", "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/certificates/v1beta1/fake", "kubernetes/typed/core/v1", + "kubernetes/typed/core/v1/fake", "kubernetes/typed/events/v1beta1", + "kubernetes/typed/events/v1beta1/fake", "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/extensions/v1beta1/fake", "kubernetes/typed/networking/v1", + "kubernetes/typed/networking/v1/fake", "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/policy/v1beta1/fake", "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1/fake", "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1alpha1/fake", "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/rbac/v1beta1/fake", "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/scheduling/v1alpha1/fake", "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/settings/v1alpha1/fake", "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1/fake", "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1alpha1/fake", "kubernetes/typed/storage/v1beta1", + "kubernetes/typed/storage/v1beta1/fake", "pkg/apis/clientauthentication", "pkg/apis/clientauthentication/v1alpha1", "pkg/version", @@ -541,25 +642,53 @@ "plugin/pkg/client/auth/openstack", "rest", "rest/watch", + "testing", "third_party/forked/golang/template", "tools/auth", + "tools/cache", "tools/clientcmd", "tools/clientcmd/api", "tools/clientcmd/api/latest", "tools/clientcmd/api/v1", "tools/metrics", + "tools/pager", "tools/reference", "transport", + "util/buffer", "util/cert", "util/flowcontrol", "util/homedir", "util/integer", "util/jsonpath", + "util/retry", ] pruneopts = "UT" revision = "23781f4d6632d88e869066eaebb743857aa1ef9b" version = "v7.0.0" +[[projects]] + branch = "master" + digest = "1:a2c842a1e0aed96fd732b535514556323a6f5edfded3b63e5e0ab1bce188aa54" + name = "k8s.io/kube-openapi" + packages = ["pkg/util/proto"] + pruneopts = "UT" + revision = "9dfdf9be683f61f82cda12362c44c784e0778b56" + +[[projects]] + digest = "1:29910bd9556d85231eef9829bafac148cb402f0a878ba1cd7ad03219e744d149" + name = "k8s.io/kubernetes" + packages = [ + "pkg/api/legacyscheme", + "pkg/apis/core", + "pkg/controller/testutil", + "pkg/features", + "pkg/kubelet/apis", + "pkg/util/node", + ] + pruneopts = "UT" + revision = "4ed3216f3ec431b140b1d899130a69fc671678f4" + version = "v1.12.1" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 @@ -570,16 +699,21 @@ "github.com/spf13/cobra/doc", "github.com/spf13/pflag", "github.com/spf13/viper", + "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/require", "k8s.io/api/core/v1", "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/runtime", "k8s.io/apimachinery/pkg/util/wait", "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/fake", "k8s.io/client-go/plugin/pkg/client/auth/exec", "k8s.io/client-go/plugin/pkg/client/auth/gcp", "k8s.io/client-go/plugin/pkg/client/auth/oidc", "k8s.io/client-go/plugin/pkg/client/auth/openstack", "k8s.io/client-go/rest", "k8s.io/client-go/tools/clientcmd", + "k8s.io/kubernetes/pkg/controller/testutil", ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/README.md b/README.md index cfb23a4..8fb4cf9 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,6 @@ listen test-pod-balancer ### TODO * Track Kubernetes changes using resource watch API * More API and helper template functions -* Add tests ## Contributing diff --git a/app_test.go b/app_test.go new file mode 100644 index 0000000..849437b --- /dev/null +++ b/app_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + + "github.com/stretchr/testify/require" + "testing" +) + +func TestAppRunOnce(t *testing.T) { + cmd := newCmd() + buf := new(bytes.Buffer) + cmd.SetOutput(buf) + testgolden := testGoldenFileName(t) + var testout string + if *update { + testout = testgolden + } else { + testoutfile, err := ioutil.TempFile("", "testout") + require.NoError(t, err) + testout = testoutfile.Name() + defer testFileUnlink(testout) + } + err := cmd.ParseFlags([]string{ + "--once", + fmt.Sprintf("--template=%s:%s", testTemplateName(t), testout), + }) + require.NoError(t, err) + cfg, err := newConfig(cmd) + require.NoError(t, err) + app, err := newApp(cfg) + require.NoError(t, err) + tc := newTestClient() + app.client = tc + app.dm.client = tc + app.RunOnce() + actual, err := ioutil.ReadFile(testout) + require.NoError(t, err) + expected, err := ioutil.ReadFile(testgolden) + require.NoError(t, err) + require.Equal(t, string(expected), string(actual)) +} diff --git a/client.go b/client.go index 27e1fdf..5144dd4 100644 --- a/client.go +++ b/client.go @@ -33,7 +33,7 @@ const ( ) type Client struct { - kubeClient *kubernetes.Clientset + kubeClient kubernetes.Interface } func newClient(cfg *Config) (*Client, error) { diff --git a/client_test.go b/client_test.go new file mode 100644 index 0000000..d6d41df --- /dev/null +++ b/client_test.go @@ -0,0 +1,29 @@ +package main + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/kubernetes/pkg/controller/testutil" + + "github.com/stretchr/testify/require" + "testing" +) + +func newTestClient() *Client { + client := Client{} + objects := []runtime.Object{ + &v1.PodList{Items: []v1.Pod{*testutil.NewPod("pod1", "host1")}}, + } + client.kubeClient = fake.NewSimpleClientset(objects...) + return &client +} + +func TestClientGetPods(t *testing.T) { + tc := newTestClient() + pods, err := tc.Pods("", "") + require.NoError(t, err) + require.Len(t, pods, 1) + require.Equal(t, "pod1", pods[0].Name) + require.Equal(t, "host1", pods[0].Spec.NodeName) +} diff --git a/deps_test.go b/deps_test.go new file mode 100644 index 0000000..9225466 --- /dev/null +++ b/deps_test.go @@ -0,0 +1,21 @@ +package main + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func TestDependencyManager(t *testing.T) { + client := newTestClient() + dm := newDependencyManager(client) + require.Empty(t, dm.cachedDeps) + pods, err := dm.Pods("", "") + require.NoError(t, err) + require.Len(t, pods, 1) + require.NotEmpty(t, dm.cachedDeps) + pod := pods[0] + pods, err = dm.Pods("", "") + require.NoError(t, err) + require.Len(t, pods, 1) + require.Equal(t, pod, pods[0]) +} diff --git a/logging.go b/logging.go index 01cf473..8880efc 100644 --- a/logging.go +++ b/logging.go @@ -29,6 +29,10 @@ import ( var logFlushFreq = pflag.Duration("log-flush-frequency", 5*time.Second, "Maximum number of seconds between log flushes") func init() { + // Don't steal command line arguments from `go test` + if flag.Lookup("test.v") != nil { + return + } // Trick to avoid 'logging before flag.Parse' warning if err := flag.CommandLine.Parse([]string{}); err != nil { return diff --git a/template_test.go b/template_test.go new file mode 100644 index 0000000..505b31d --- /dev/null +++ b/template_test.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "io/ioutil" + + "github.com/stretchr/testify/require" + "testing" +) + +func testTemplateName(t *testing.T) string { + return testDataFilePrefix(t) + ".template" +} + +func TestTemplateRender(t *testing.T) { + client := newTestClient() + dm := newDependencyManager(client) + testtemplate := testTemplateName(t) + testgolden := testGoldenFileName(t) + td, err := parseTemplateDescriptor(fmt.Sprintf("%s:%s", testtemplate, testgolden)) + require.NoError(t, err) + cfg := new(Config) + template, err := newTemplate(dm, td, cfg) + require.NoError(t, err) + if *update { + _, err := template.Process(false) + require.NoError(t, err) + } + actual, err := template.Render() + require.NoError(t, err) + expected, err := ioutil.ReadFile(testgolden) + require.NoError(t, err) + require.Equal(t, string(expected), actual) +} diff --git a/testdata/TestAppRunOnce.out.golden b/testdata/TestAppRunOnce.out.golden new file mode 100644 index 0000000..d146460 --- /dev/null +++ b/testdata/TestAppRunOnce.out.golden @@ -0,0 +1,3 @@ +the quick brown fox jumps over the lazy dog + +pods: pod1 diff --git a/testdata/TestAppRunOnce.template b/testdata/TestAppRunOnce.template new file mode 100644 index 0000000..1691a9c --- /dev/null +++ b/testdata/TestAppRunOnce.template @@ -0,0 +1,3 @@ +the quick brown fox jumps over the lazy dog + +pods: {{range pods}}{{.Name}}{{end}} diff --git a/testdata/TestTemplateRender.out.golden b/testdata/TestTemplateRender.out.golden new file mode 100644 index 0000000..ed1d325 --- /dev/null +++ b/testdata/TestTemplateRender.out.golden @@ -0,0 +1,7 @@ +plain text: the quick brown fox jumps over the lazy dog + +helper math functions: 2+2=4, 2-2=0, 2*2=4, 2/2=1 + +helper string functions: TOUPPER, tolower, UPPER, lower + +pod names: pod1 diff --git a/testdata/TestTemplateRender.template b/testdata/TestTemplateRender.template new file mode 100644 index 0000000..ccc56f8 --- /dev/null +++ b/testdata/TestTemplateRender.template @@ -0,0 +1,7 @@ +plain text: the quick brown fox jumps over the lazy dog + +helper math functions: 2+2={{add 2 2}}, 2-2={{sub 2 2}}, 2*2={{mul 2 2}}, 2/2={{div 2 2}} + +helper string functions: {{ "toUpper" | toUpper }}, {{ "toLower" | toLower }}, {{ "upper" | upper }}, {{ "LOWER" | lower }} + +pod names: {{range pods}}{{.Name}}{{end}} diff --git a/util_test.go b/util_test.go new file mode 100644 index 0000000..3e7e688 --- /dev/null +++ b/util_test.go @@ -0,0 +1,32 @@ +package main + +import ( + "flag" + "path/filepath" + "syscall" + + "github.com/stretchr/testify/assert" + "testing" +) + +var update = flag.Bool("update", false, "update .golden files") + +func testDataFilePrefix(t *testing.T) string { + return filepath.Join("testdata", t.Name()) +} + +func testGoldenFileName(t *testing.T) string { + return testDataFilePrefix(t) + ".out.golden" +} + +func testFileUnlink(path string) { + _ = syscall.Unlink(path) +} + +func TestIsPresent(t *testing.T) { + assert.True(t, IsPresent([]string{"a", "b", "c"}, "a")) + assert.True(t, IsPresent([]string{""}, "")) + assert.False(t, IsPresent([]string{}, "")) + assert.False(t, IsPresent([]string{}, "a")) + assert.False(t, IsPresent([]string{"d", "e", "f"}, "a")) +}