mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #12274 from ptabor/20200907-fix-cov-e2e-tests
tests/e2e,etcdctl,etcdmain: Fix go test --tags cov -v ./tests/e2e
This commit is contained in:
commit
e81cae77a3
@ -26,7 +26,7 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func Start() {
|
||||
func Start() error {
|
||||
app := cli.NewApp()
|
||||
app.Name = "etcdctl"
|
||||
app.Version = version.Version
|
||||
@ -72,8 +72,11 @@ func Start() {
|
||||
command.NewRoleCommands(),
|
||||
command.NewAuthCommands(),
|
||||
}
|
||||
return app.Run(os.Args)
|
||||
}
|
||||
|
||||
err := runCtlV2(app)
|
||||
func MustStart() {
|
||||
err := Start()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
|
@ -1,28 +0,0 @@
|
||||
// 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"), "\xe7\xcd"))
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// 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)
|
||||
}
|
@ -95,6 +95,19 @@ func init() {
|
||||
)
|
||||
}
|
||||
|
||||
func Start() error {
|
||||
rootCmd.SetUsageFunc(usageFunc)
|
||||
// Make help just show the usage
|
||||
rootCmd.SetHelpTemplate(`{{.UsageString}}`)
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
|
||||
func MustStart() {
|
||||
if err := Start(); err != nil {
|
||||
command.ExitWithError(command.ExitError, err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.EnablePrefixMatching = true
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
// 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"
|
||||
|
||||
"go.etcd.io/etcd/v3/etcdctl/ctlv3/command"
|
||||
)
|
||||
|
||||
func Start() {
|
||||
// ETCDCTL_ARGS=etcdctl_test arg1 arg2...
|
||||
// SetArgs() takes arg1 arg2...
|
||||
rootCmd.SetArgs(strings.Split(os.Getenv("ETCDCTL_ARGS"), "\xe7\xcd")[1:])
|
||||
os.Unsetenv("ETCDCTL_ARGS")
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
command.ExitWithError(command.ExitError, err)
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// 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 "go.etcd.io/etcd/v3/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)
|
||||
}
|
||||
}
|
@ -27,20 +27,44 @@ const (
|
||||
apiEnv = "ETCDCTL_API"
|
||||
)
|
||||
|
||||
/**
|
||||
mainWithError is fully analogous to main, but instead of signaling errors
|
||||
by os.Exit, it exposes the error explicitly, such that test-logic can intercept
|
||||
control to e.g. dump coverage data (even for test-for-failure scenarios).
|
||||
*/
|
||||
func mainWithError() error {
|
||||
apiv := os.Getenv(apiEnv)
|
||||
|
||||
// unset apiEnv to avoid side-effect for future env and flag parsing.
|
||||
os.Unsetenv(apiEnv)
|
||||
|
||||
if len(apiv) == 0 || apiv == "3" {
|
||||
return ctlv3.Start()
|
||||
}
|
||||
|
||||
if apiv == "2" {
|
||||
return ctlv2.Start()
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "unsupported API version: %s\n", apiv)
|
||||
return fmt.Errorf("unsupported API version: %s", apiv)
|
||||
}
|
||||
|
||||
func main() {
|
||||
apiv := os.Getenv(apiEnv)
|
||||
|
||||
// unset apiEnv to avoid side-effect for future env and flag parsing.
|
||||
os.Unsetenv(apiEnv)
|
||||
if len(apiv) == 0 || apiv == "3" {
|
||||
ctlv3.Start()
|
||||
ctlv3.MustStart()
|
||||
return
|
||||
}
|
||||
|
||||
if apiv == "2" {
|
||||
ctlv2.Start()
|
||||
ctlv2.MustStart()
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stderr, "unsupported API version", apiv)
|
||||
fmt.Fprintf(os.Stderr, "unsupported API version: %v\n", apiv)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -15,15 +15,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
func SplitTestArgs(args []string) (testArgs, appArgs []string) {
|
||||
for i, arg := range os.Args {
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "-test."):
|
||||
testArgs = append(testArgs, arg)
|
||||
case i == 0:
|
||||
appArgs = append(appArgs, arg)
|
||||
testArgs = append(testArgs, arg)
|
||||
default:
|
||||
appArgs = append(appArgs, arg)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Empty test to avoid no-tests warning.
|
||||
func TestEmpty(t *testing.T) {}
|
||||
|
||||
/**
|
||||
* The purpose of this "test" is to run etcdctl with code-coverage
|
||||
* collection turned on. The technique is documented here:
|
||||
*
|
||||
* https://www.cyphar.com/blog/post/20170412-golang-integration-coverage
|
||||
*/
|
||||
func TestMain(m *testing.M) {
|
||||
// don't launch etcdctl when invoked via go test
|
||||
if strings.HasSuffix(os.Args[0], "etcdctl.test") {
|
||||
return
|
||||
}
|
||||
main()
|
||||
|
||||
testArgs, appArgs := SplitTestArgs(os.Args)
|
||||
|
||||
os.Args = appArgs
|
||||
|
||||
err := mainWithError()
|
||||
if err != nil {
|
||||
log.Fatalf("etcdctl failed with: %v", err)
|
||||
}
|
||||
|
||||
// This will generate coverage files:
|
||||
os.Args = testArgs
|
||||
m.Run()
|
||||
}
|
||||
|
@ -49,13 +49,13 @@ var (
|
||||
dirEmpty = dirType("empty")
|
||||
)
|
||||
|
||||
func startEtcdOrProxyV2() {
|
||||
func startEtcdOrProxyV2(args []string) {
|
||||
grpc.EnableTracing = false
|
||||
|
||||
cfg := newConfig()
|
||||
defaultInitialCluster := cfg.ec.InitialCluster
|
||||
|
||||
err := cfg.parse(os.Args[1:])
|
||||
err := cfg.parse(args[1:])
|
||||
lg := cfg.ec.GetLogger()
|
||||
if lg == nil {
|
||||
var zapError error
|
||||
@ -66,6 +66,7 @@ func startEtcdOrProxyV2() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
lg.Info("Running: ", zap.Strings("args", args))
|
||||
if err != nil {
|
||||
lg.Warn("failed to verify flags", zap.Error(err))
|
||||
switch err {
|
||||
|
@ -99,6 +99,9 @@ func startGateway(cmd *cobra.Command, args []string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// We use os.Args to show all the arguments (not only passed-through Cobra).
|
||||
lg.Info("Running: ", zap.Strings("args", os.Args))
|
||||
|
||||
srvs := discoverEndpoints(lg, gatewayDNSCluster, gatewayCA, gatewayInsecureDiscovery, gatewayDNSClusterServiceName)
|
||||
if len(srvs.Endpoints) == 0 {
|
||||
// no endpoints discovered, fall back to provided endpoints
|
||||
|
@ -17,22 +17,16 @@ package etcdmain
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/go-systemd/v22/daemon"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Main() {
|
||||
func Main(args []string) {
|
||||
checkSupportArch()
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
cmd := os.Args[1]
|
||||
if covArgs := os.Getenv("ETCDCOV_ARGS"); len(covArgs) > 0 {
|
||||
args := strings.Split(os.Getenv("ETCDCOV_ARGS"), "\xe7\xcd")[1:]
|
||||
rootCmd.SetArgs(args)
|
||||
cmd = "grpc-proxy"
|
||||
}
|
||||
if len(args) > 1 {
|
||||
cmd := args[1]
|
||||
switch cmd {
|
||||
case "gateway", "grpc-proxy":
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
@ -43,7 +37,7 @@ func Main() {
|
||||
}
|
||||
}
|
||||
|
||||
startEtcdOrProxyV2()
|
||||
startEtcdOrProxyV2(args)
|
||||
}
|
||||
|
||||
func notifySystemd(lg *zap.Logger) {
|
||||
|
8
main.go
8
main.go
@ -22,8 +22,12 @@
|
||||
//
|
||||
package main
|
||||
|
||||
import "go.etcd.io/etcd/v3/etcdmain"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"go.etcd.io/etcd/v3/etcdmain"
|
||||
)
|
||||
|
||||
func main() {
|
||||
etcdmain.Main()
|
||||
etcdmain.Main(os.Args)
|
||||
}
|
||||
|
45
main_test.go
45
main_test.go
@ -15,25 +15,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"go.etcd.io/etcd/v3/etcdmain"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
func SplitTestArgs(args []string) (testArgs, appArgs []string) {
|
||||
for i, arg := range os.Args {
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "-test."):
|
||||
testArgs = append(testArgs, arg)
|
||||
case i == 0:
|
||||
appArgs = append(appArgs, arg)
|
||||
testArgs = append(testArgs, arg)
|
||||
default:
|
||||
appArgs = append(appArgs, arg)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {}
|
||||
|
||||
/**
|
||||
* The purpose of this "test" is to run etcd server with code-coverage
|
||||
* collection turned on. The technique is documented here:
|
||||
*
|
||||
* https://www.cyphar.com/blog/post/20170412-golang-integration-coverage
|
||||
*/
|
||||
func TestMain(m *testing.M) {
|
||||
// don't launch etcd server when invoked via go test
|
||||
// Note: module name has /v3 now
|
||||
if strings.HasSuffix(os.Args[0], "v3.test") {
|
||||
t.Skip("skip launching etcd server when invoked via go test")
|
||||
}
|
||||
if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "-test.") {
|
||||
t.Skip("skip launching etcd server when invoked via go test")
|
||||
if strings.HasSuffix(os.Args[0], ".test") {
|
||||
log.Printf("skip launching etcd server when invoked via go test")
|
||||
return
|
||||
}
|
||||
|
||||
testArgs, appArgs := SplitTestArgs(os.Args)
|
||||
|
||||
notifier := make(chan os.Signal, 1)
|
||||
signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM)
|
||||
go main()
|
||||
go etcdmain.Main(appArgs)
|
||||
<-notifier
|
||||
|
||||
// This will generate coverage files:
|
||||
os.Args = testArgs
|
||||
m.Run()
|
||||
}
|
||||
|
4
test
4
test
@ -304,6 +304,9 @@ function cov_pass {
|
||||
# strip out generated files (using GNU-style sed)
|
||||
sed --in-place '/generated.go/d' "$COVERDIR"/cover.out || true
|
||||
|
||||
echo -e "\nTo generate coverage report use:"
|
||||
echo -e " go tool cover --html=$COVERDIR/cover.out\n"
|
||||
|
||||
# held failures to generate the full coverage file, now fail
|
||||
if [ -n "$failed" ]; then
|
||||
for f in $failed; do
|
||||
@ -665,6 +668,7 @@ function build_cov_pass {
|
||||
out="bin"
|
||||
if [ -n "${BINDIR}" ]; then out="${BINDIR}"; fi
|
||||
go test -mod=mod -tags cov -c -covermode=set -coverpkg="$PKGS_COMMA" -o "${out}/etcd_test"
|
||||
|
||||
go test -mod=mod -tags cov -c -covermode=set -coverpkg="$PKGS_COMMA" -o "${out}/etcdctl_test" "${REPO_PATH}/etcdctl"
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.etcd.io/etcd/v3/pkg/fileutil"
|
||||
"go.etcd.io/etcd/v3/pkg/testutil"
|
||||
)
|
||||
|
||||
@ -37,11 +36,7 @@ func testCtlV2Set(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) {
|
||||
|
||||
cfg.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, cfg, quorum)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
@ -64,11 +59,7 @@ func testCtlV2Mk(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) {
|
||||
|
||||
cfg.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, cfg, quorum)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
@ -93,11 +84,7 @@ func testCtlV2Rm(t *testing.T, cfg *etcdProcessClusterConfig) {
|
||||
|
||||
cfg.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, cfg, true)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
@ -123,11 +110,7 @@ func testCtlV2Ls(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) {
|
||||
|
||||
cfg.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, cfg, quorum)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
@ -150,11 +133,7 @@ func testCtlV2Watch(t *testing.T, cfg *etcdProcessClusterConfig, noSync bool) {
|
||||
|
||||
cfg.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, cfg, true)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
key, value := "foo", "bar"
|
||||
errc := etcdctlWatch(epc, key, value, noSync)
|
||||
@ -180,11 +159,7 @@ func TestCtlV2GetRoleUser(t *testing.T) {
|
||||
copied := configNoTLS
|
||||
copied.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, &copied, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
if err := etcdctlRoleAdd(epc, "foo"); err != nil {
|
||||
t.Fatalf("failed to add role (%v)", err)
|
||||
@ -217,11 +192,7 @@ func testCtlV2UserList(t *testing.T, username string) {
|
||||
copied := configNoTLS
|
||||
copied.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, &copied, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
if err := etcdctlUserAdd(epc, username, "password"); err != nil {
|
||||
t.Fatalf("failed to add user (%v)", err)
|
||||
@ -239,11 +210,7 @@ func TestCtlV2RoleList(t *testing.T) {
|
||||
copied := configNoTLS
|
||||
copied.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, &copied, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
if err := etcdctlRoleAdd(epc, "foo"); err != nil {
|
||||
t.Fatalf("failed to add role (%v)", err)
|
||||
@ -307,6 +274,8 @@ func testCtlV2Backup(t *testing.T, snapCount int, v3 bool) {
|
||||
cfg2.forceNewCluster = true
|
||||
cfg2.enableV2 = true
|
||||
epc2 := setupEtcdctlTest(t, &cfg2, false)
|
||||
// Make sure a failing test is not leaking resources (running server).
|
||||
defer epc2.Close()
|
||||
|
||||
// check if backup went through correctly
|
||||
if err := etcdctlGet(epc2, "foo1", "bar1", false); err != nil {
|
||||
@ -348,11 +317,7 @@ func TestCtlV2AuthWithCommonName(t *testing.T) {
|
||||
copiedCfg.clientCertAuthEnabled = true
|
||||
copiedCfg.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, &copiedCfg, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
if err := etcdctlRoleAdd(epc, "testrole"); err != nil {
|
||||
t.Fatalf("failed to add role (%v)", err)
|
||||
@ -385,11 +350,7 @@ func TestCtlV2ClusterHealth(t *testing.T) {
|
||||
copied := configNoTLS
|
||||
copied.enableV2 = true
|
||||
epc := setupEtcdctlTest(t, &copied, true)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
defer cleanupEtcdProcessCluster(epc, t)
|
||||
|
||||
// all members available
|
||||
if err := etcdctlClusterHealth(epc, "cluster is healthy"); err != nil {
|
||||
@ -536,14 +497,7 @@ func etcdctlBackup(clus *etcdProcessCluster, dataDir, backupDir string, v3 bool)
|
||||
return proc.Close()
|
||||
}
|
||||
|
||||
func mustEtcdctl(t *testing.T) {
|
||||
if !fileutil.Exist(binDir + "/etcdctl") {
|
||||
t.Fatalf("could not find etcdctl binary")
|
||||
}
|
||||
}
|
||||
|
||||
func setupEtcdctlTest(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) *etcdProcessCluster {
|
||||
mustEtcdctl(t)
|
||||
if !quorum {
|
||||
cfg = configStandalone(*cfg)
|
||||
}
|
||||
@ -553,3 +507,9 @@ func setupEtcdctlTest(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool)
|
||||
}
|
||||
return epc
|
||||
}
|
||||
|
||||
func cleanupEtcdProcessCluster(epc *etcdProcessCluster, t *testing.T) {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,6 @@ func getSnapshotStatus(cx ctlCtx, fpath string) (snapshot.Status, error) {
|
||||
// syncs up with other members and serve correct data.
|
||||
func TestIssue6361(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
mustEtcdctl(t)
|
||||
os.Setenv("ETCDCTL_API", "3")
|
||||
defer os.Unsetenv("ETCDCTL_API")
|
||||
|
||||
|
@ -205,7 +205,6 @@ func testCtl(t *testing.T, testFunc func(ctlCtx), opts ...ctlOption) {
|
||||
}
|
||||
ret.applyOpts(opts)
|
||||
|
||||
mustEtcdctl(t)
|
||||
if !ret.quorum {
|
||||
ret.cfg = *configStandalone(ret.cfg)
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ type etcdServerProcessConfig struct {
|
||||
|
||||
func newEtcdServerProcess(cfg *etcdServerProcessConfig) (*etcdServerProcess, error) {
|
||||
if !fileutil.Exist(cfg.execPath) {
|
||||
return nil, fmt.Errorf("could not find etcd binary")
|
||||
return nil, fmt.Errorf("could not find etcd binary: %s", cfg.execPath)
|
||||
}
|
||||
if !cfg.keepDataDir {
|
||||
if err := os.RemoveAll(cfg.dataDirPath); err != nil {
|
||||
@ -117,7 +117,7 @@ func (ep *etcdServerProcess) Stop() (err error) {
|
||||
ep.donec = make(chan struct{})
|
||||
if ep.cfg.purl.Scheme == "unix" || ep.cfg.purl.Scheme == "unixs" {
|
||||
err = os.Remove(ep.cfg.purl.Host + ep.cfg.purl.Path)
|
||||
if err != nil {
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -18,73 +18,44 @@ package e2e
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"go.etcd.io/etcd/v3/pkg/expect"
|
||||
"go.etcd.io/etcd/v3/pkg/fileutil"
|
||||
"go.etcd.io/etcd/v3/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 {
|
||||
return spawnEtcd(args)
|
||||
}
|
||||
if args[0] == ctlBinPath || args[0] == ctlBinPath+"3" {
|
||||
// avoid test flag conflicts in coverage enabled etcdctl by putting flags in ETCDCTL_ARGS
|
||||
env := []string{
|
||||
// was \xff, but that's used for testing boundary conditions; 0xe7cd should be safe
|
||||
"ETCDCTL_ARGS=" + strings.Join(args, "\xe7\xcd"),
|
||||
}
|
||||
if args[0] == ctlBinPath+"3" {
|
||||
env = append(env, "ETCDCTL_API=3")
|
||||
}
|
||||
|
||||
covArgs, err := getCovArgs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// when withFlagByEnv() is used in testCtl(), env variables for ctl is set to os.env.
|
||||
// they must be included in ctl_cov_env.
|
||||
env = append(env, os.Environ()...)
|
||||
ep, err := expect.NewExpectWithEnv(binDir+"/etcdctl_test", covArgs, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ep.StopSignal = syscall.SIGTERM
|
||||
return ep, nil
|
||||
cmd := args[0]
|
||||
env := make([]string, 0)
|
||||
switch cmd {
|
||||
case binPath:
|
||||
cmd = "../../bin/etcd_test"
|
||||
case ctlBinPath:
|
||||
cmd = "../../bin/etcdctl_test"
|
||||
case ctlBinPath + "3":
|
||||
cmd = "../../bin/etcdctl_test"
|
||||
env = append(env, "ETCDCTL_API=3")
|
||||
}
|
||||
|
||||
return expect.NewExpect(args[0], args[1:]...)
|
||||
}
|
||||
|
||||
func spawnEtcd(args []string) (*expect.ExpectProcess, error) {
|
||||
covArgs, err := getCovArgs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var env []string
|
||||
if args[1] == "grpc-proxy" {
|
||||
// avoid test flag conflicts in coverage enabled etcd by putting flags in ETCDCOV_ARGS
|
||||
env = append(os.Environ(), "ETCDCOV_ARGS="+strings.Join(args, "\xe7\xcd"))
|
||||
} else {
|
||||
env = args2env(args[1:])
|
||||
}
|
||||
|
||||
ep, err := expect.NewExpectWithEnv(binDir+"/etcd_test", covArgs, env)
|
||||
// when withFlagByEnv() is used in testCtl(), env variables for ctl is set to os.env.
|
||||
// they must be included in ctl_cov_env.
|
||||
env = append(env, os.Environ()...)
|
||||
all_args := append(args[1:], covArgs...)
|
||||
log.Printf("Executing %v %v", cmd, all_args)
|
||||
ep, err := expect.NewExpectWithEnv(cmd, all_args, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// ep sends SIGTERM to etcd_test process on ep.close()
|
||||
// allowing the process to exit gracefully in order to generate a coverage report.
|
||||
// note: go runtime ignores SIGINT but not SIGTERM
|
||||
// if e2e test is run as a background process.
|
||||
ep.StopSignal = syscall.SIGTERM
|
||||
return ep, nil
|
||||
}
|
||||
@ -105,29 +76,3 @@ func getCovArgs() ([]string, error) {
|
||||
}
|
||||
return covArgs, nil
|
||||
}
|
||||
|
||||
func args2env(args []string) []string {
|
||||
var covEnvs []string
|
||||
for i := range args {
|
||||
if !strings.HasPrefix(args[i], "--") {
|
||||
continue
|
||||
}
|
||||
flag := strings.Split(args[i], "--")[1]
|
||||
val := "true"
|
||||
// split the flag that has "="
|
||||
// e.g --auto-tls=true" => flag=auto-tls and val=true
|
||||
if strings.Contains(args[i], "=") {
|
||||
split := strings.Split(flag, "=")
|
||||
flag = split[0]
|
||||
val = split[1]
|
||||
}
|
||||
|
||||
if i+1 < len(args) {
|
||||
if !strings.HasPrefix(args[i+1], "--") {
|
||||
val = args[i+1]
|
||||
}
|
||||
}
|
||||
covEnvs = append(covEnvs, flags.FlagToEnv("ETCD", flag)+"="+val)
|
||||
}
|
||||
return covEnvs
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func spawnWithExpectLines(args []string, xs ...string) ([]string, error) {
|
||||
l, lerr := proc.ExpectFunc(lineFunc)
|
||||
if lerr != nil {
|
||||
proc.Close()
|
||||
return nil, fmt.Errorf("%v (expected %q, got %q)", lerr, txt, lines)
|
||||
return nil, fmt.Errorf("%v %v (expected %q, got %q). Try EXPECT_DEBUG=TRUE", args, lerr, txt, lines)
|
||||
}
|
||||
lines = append(lines, l)
|
||||
if strings.Contains(l, txt) {
|
||||
@ -73,8 +73,9 @@ func spawnWithExpectLines(args []string, xs ...string) ([]string, error) {
|
||||
}
|
||||
}
|
||||
perr := proc.Close()
|
||||
if len(xs) == 0 && proc.LineCount() != noOutputLineCount { // expect no output
|
||||
return nil, fmt.Errorf("unexpected output (got lines %q, line count %d)", lines, proc.LineCount())
|
||||
l := proc.LineCount()
|
||||
if len(xs) == 0 && l != noOutputLineCount { // expect no output
|
||||
return nil, fmt.Errorf("unexpected output from %v (got lines %q, line count %d) %v. Try EXPECT_DEBUG=TRUE", args, lines, l, l != noOutputLineCount)
|
||||
}
|
||||
return lines, perr
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user