From aca4ea2a29939939e670aef11de6f32a10943b60 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Tue, 28 Feb 2017 14:38:04 -0800 Subject: [PATCH 1/3] etcdctl: modify etcdctl v2 and v3 for code coverage --- etcdctl/ctlv2/ctl.go | 2 +- etcdctl/ctlv2/ctl_cov.go | 28 ++++++++++++++++++++++++++++ etcdctl/ctlv2/ctl_nocov.go | 27 +++++++++++++++++++++++++++ etcdctl/ctlv3/ctl.go | 11 ----------- etcdctl/ctlv3/ctl_cov.go | 33 +++++++++++++++++++++++++++++++++ etcdctl/ctlv3/ctl_nocov.go | 28 ++++++++++++++++++++++++++++ etcdctl/main_test.go | 29 +++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 etcdctl/ctlv2/ctl_cov.go create mode 100644 etcdctl/ctlv2/ctl_nocov.go create mode 100644 etcdctl/ctlv3/ctl_cov.go create mode 100644 etcdctl/ctlv3/ctl_nocov.go create mode 100644 etcdctl/main_test.go diff --git a/etcdctl/ctlv2/ctl.go b/etcdctl/ctlv2/ctl.go index 41018fb63..800ac85e4 100644 --- a/etcdctl/ctlv2/ctl.go +++ b/etcdctl/ctlv2/ctl.go @@ -71,7 +71,7 @@ func Start() { command.NewAuthCommands(), } - err := app.Run(os.Args) + err := runCtlV2(app) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/etcdctl/ctlv2/ctl_cov.go b/etcdctl/ctlv2/ctl_cov.go new file mode 100644 index 000000000..f76125dce --- /dev/null +++ b/etcdctl/ctlv2/ctl_cov.go @@ -0,0 +1,28 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cov + +package ctlv2 + +import ( + "os" + "strings" + + "github.com/urfave/cli" +) + +func runCtlV2(app *cli.App) error { + return app.Run(strings.Split(os.Getenv("ETCDCTL_ARGS"), "\xff")) +} diff --git a/etcdctl/ctlv2/ctl_nocov.go b/etcdctl/ctlv2/ctl_nocov.go new file mode 100644 index 000000000..1591360e5 --- /dev/null +++ b/etcdctl/ctlv2/ctl_nocov.go @@ -0,0 +1,27 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !cov + +package ctlv2 + +import ( + "os" + + "github.com/urfave/cli" +) + +func runCtlV2(app *cli.App) error { + return app.Run(os.Args) +} diff --git a/etcdctl/ctlv3/ctl.go b/etcdctl/ctlv3/ctl.go index 780e9f7ff..4875b5278 100644 --- a/etcdctl/ctlv3/ctl.go +++ b/etcdctl/ctlv3/ctl.go @@ -86,14 +86,3 @@ func init() { func init() { cobra.EnablePrefixMatching = true } - -func Start() { - rootCmd.SetUsageFunc(usageFunc) - - // Make help just show the usage - rootCmd.SetHelpTemplate(`{{.UsageString}}`) - - if err := rootCmd.Execute(); err != nil { - command.ExitWithError(command.ExitError, err) - } -} diff --git a/etcdctl/ctlv3/ctl_cov.go b/etcdctl/ctlv3/ctl_cov.go new file mode 100644 index 000000000..79cf93cdc --- /dev/null +++ b/etcdctl/ctlv3/ctl_cov.go @@ -0,0 +1,33 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cov + +package ctlv3 + +import ( + "os" + "strings" + + "github.com/coreos/etcd/etcdctl/ctlv3/command" +) + +func Start() { + // ETCDCTL_ARGS=etcdctl_test arg1 arg2... + // SetArgs() takes arg1 arg2... + rootCmd.SetArgs(strings.Split(os.Getenv("ETCDCTL_ARGS"), "\xff")[1:]) + if err := rootCmd.Execute(); err != nil { + command.ExitWithError(command.ExitError, err) + } +} diff --git a/etcdctl/ctlv3/ctl_nocov.go b/etcdctl/ctlv3/ctl_nocov.go new file mode 100644 index 000000000..52751feec --- /dev/null +++ b/etcdctl/ctlv3/ctl_nocov.go @@ -0,0 +1,28 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !cov + +package ctlv3 + +import "github.com/coreos/etcd/etcdctl/ctlv3/command" + +func Start() { + rootCmd.SetUsageFunc(usageFunc) + // Make help just show the usage + rootCmd.SetHelpTemplate(`{{.UsageString}}`) + if err := rootCmd.Execute(); err != nil { + command.ExitWithError(command.ExitError, err) + } +} diff --git a/etcdctl/main_test.go b/etcdctl/main_test.go new file mode 100644 index 000000000..ccd3ba0ac --- /dev/null +++ b/etcdctl/main_test.go @@ -0,0 +1,29 @@ +// Copyright 2017 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "os" + "strings" + "testing" +) + +func TestMain(t *testing.T) { + // don't launch etcdctl when invoked via go test + if strings.HasSuffix(os.Args[0], "etcdctl.test") { + return + } + main() +} From 1f413cff64f286dfdcaf42d1101cb7482a00e904 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Tue, 28 Feb 2017 14:39:01 -0800 Subject: [PATCH 2/3] e2e: add etcdctl to e2e test --- e2e/etcd_spawn_cov.go | 55 ++++++++++++++++++++++++++++++++--------- e2e/etcd_spawn_nocov.go | 2 ++ e2e/etcd_test.go | 2 +- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/e2e/etcd_spawn_cov.go b/e2e/etcd_spawn_cov.go index 6a9571f28..840cde493 100644 --- a/e2e/etcd_spawn_cov.go +++ b/e2e/etcd_spawn_cov.go @@ -29,20 +29,13 @@ import ( "github.com/coreos/etcd/pkg/flags" ) +const noOutputLineCount = 2 // cov-enabled binaries emit PASS and coverage count lines + func spawnCmd(args []string) (*expect.ExpectProcess, error) { if args[0] == binPath { - coverPath := os.Getenv("COVERDIR") - if !filepath.IsAbs(coverPath) { - // COVERDIR is relative to etcd root but e2e test has its path set to be relative to the e2e folder. - // adding ".." in front of COVERDIR ensures that e2e saves coverage reports to the correct location. - coverPath = filepath.Join("..", coverPath) - } - if !fileutil.Exist(coverPath) { - return nil, fmt.Errorf("could not find coverage folder") - } - covArgs := []string{ - fmt.Sprintf("-test.coverprofile=e2e.%v.coverprofile", time.Now().UnixNano()), - "-test.outputdir=" + coverPath, + covArgs, err := getCovArgs() + if err != nil { + return nil, err } ep, err := expect.NewExpectWithEnv(binDir+"/etcd_test", covArgs, args2env(args[1:])) if err != nil { @@ -55,9 +48,47 @@ func spawnCmd(args []string) (*expect.ExpectProcess, error) { ep.StopSignal = syscall.SIGTERM return ep, nil } + + if args[0] == ctlBinPath { + covArgs, err := getCovArgs() + if err != nil { + return nil, err + } + // avoid test flag conflicts in coverage enabled etcdctl by putting flags in ETCDCTL_ARGS + ctl_cov_env := []string{ + "ETCDCTL_ARGS" + "=" + strings.Join(args, "\xff"), + } + // when withFlagByEnv() is used in testCtl(), env variables for ctl is set to os.env. + // they must be included in ctl_cov_env. + ctl_cov_env = append(ctl_cov_env, os.Environ()...) + ep, err := expect.NewExpectWithEnv(binDir+"/etcdctl_test", covArgs, ctl_cov_env) + if err != nil { + return nil, err + } + ep.StopSignal = syscall.SIGTERM + return ep, nil + } + return expect.NewExpect(args[0], args[1:]...) } +func getCovArgs() ([]string, error) { + coverPath := os.Getenv("COVERDIR") + if !filepath.IsAbs(coverPath) { + // COVERDIR is relative to etcd root but e2e test has its path set to be relative to the e2e folder. + // adding ".." in front of COVERDIR ensures that e2e saves coverage reports to the correct location. + coverPath = filepath.Join("..", coverPath) + } + if !fileutil.Exist(coverPath) { + return nil, fmt.Errorf("could not find coverage folder") + } + covArgs := []string{ + fmt.Sprintf("-test.coverprofile=e2e.%v.coverprofile", time.Now().UnixNano()), + "-test.outputdir=" + coverPath, + } + return covArgs, nil +} + func args2env(args []string) []string { var covEnvs []string for i := range args[1:] { diff --git a/e2e/etcd_spawn_nocov.go b/e2e/etcd_spawn_nocov.go index 1205432db..82243e7e0 100644 --- a/e2e/etcd_spawn_nocov.go +++ b/e2e/etcd_spawn_nocov.go @@ -18,6 +18,8 @@ package e2e import "github.com/coreos/etcd/pkg/expect" +const noOutputLineCount = 0 // regular binaries emit no extra lines + func spawnCmd(args []string) (*expect.ExpectProcess, error) { return expect.NewExpect(args[0], args[1:]...) } diff --git a/e2e/etcd_test.go b/e2e/etcd_test.go index 74d5a386f..713162bea 100644 --- a/e2e/etcd_test.go +++ b/e2e/etcd_test.go @@ -523,7 +523,7 @@ func spawnWithExpects(args []string, xs ...string) error { } } perr := proc.Close() - if len(xs) == 0 && proc.LineCount() != 0 { // expect no output + if len(xs) == 0 && proc.LineCount() != noOutputLineCount { // expect no output return fmt.Errorf("unexpected output (got lines %q, line count %d)", lines, proc.LineCount()) } return perr From edd298f85adbfe19f25c243f44aea6cb9fb2dd99 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Tue, 28 Feb 2017 14:39:29 -0800 Subject: [PATCH 3/3] test: build test binary for etcdctl --- test | 1 + 1 file changed, 1 insertion(+) diff --git a/test b/test index 8f8bf0199..b6bfbbf8c 100755 --- a/test +++ b/test @@ -300,6 +300,7 @@ function build_cov_pass { PKGS=$TEST ETCD_PKGS_DELIM=$(echo $PKGS | sed 's/ /,/g') go test -c -covermode=set -coverpkg=$ETCD_PKGS_DELIM -o ${out}/etcd_test + go test -tags cov -c -covermode=set -coverpkg=$ETCD_PKGS_DELIM -o ${out}/etcdctl_test ${REPO_PATH}/etcdctl/ } function compile_pass {