From a1f24e9afc07bd8790cb6368fb2910ef6228e6f4 Mon Sep 17 00:00:00 2001 From: kkkkun Date: Tue, 15 Mar 2022 22:50:56 +0800 Subject: [PATCH] tests: Migrate endpoint tests to common framework --- tests/common/endpoint_test.go | 58 ++++++++++++++++++ tests/e2e/ctl_v3_auth_test.go | 11 +++- tests/e2e/ctl_v3_endpoint_test.go | 93 ----------------------------- tests/framework/e2e/etcdctl.go | 67 +++++++++++++++++++++ tests/framework/integration.go | 41 +++++++++++++ tests/framework/interface.go | 4 ++ tests/integration/v3_health_test.go | 39 ------------ 7 files changed, 180 insertions(+), 133 deletions(-) create mode 100644 tests/common/endpoint_test.go delete mode 100644 tests/e2e/ctl_v3_endpoint_test.go delete mode 100644 tests/integration/v3_health_test.go diff --git a/tests/common/endpoint_test.go b/tests/common/endpoint_test.go new file mode 100644 index 00000000000..371e85fbbb8 --- /dev/null +++ b/tests/common/endpoint_test.go @@ -0,0 +1,58 @@ +// Copyright 2022 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 common + +import ( + "testing" + "time" + + "go.etcd.io/etcd/tests/v3/framework/config" + "go.etcd.io/etcd/tests/v3/framework/testutils" +) + +func TestEndpointStatus(t *testing.T) { + testRunner.BeforeTest(t) + clus := testRunner.NewCluster(t, config.ClusterConfig{ClusterSize: 3}) + defer clus.Close() + testutils.ExecuteWithTimeout(t, 10*time.Second, func() { + _, err := clus.Client().Status() + if err != nil { + t.Fatalf("get endpoint status error: %v", err) + } + }) +} + +func TestEndpointHashKV(t *testing.T) { + testRunner.BeforeTest(t) + clus := testRunner.NewCluster(t, config.ClusterConfig{ClusterSize: 3}) + defer clus.Close() + testutils.ExecuteWithTimeout(t, 10*time.Second, func() { + _, err := clus.Client().HashKV(0) + if err != nil { + t.Fatalf("get endpoint hashkv error: %v", err) + } + }) +} + +func TestEndpointHealth(t *testing.T) { + testRunner.BeforeTest(t) + clus := testRunner.NewCluster(t, config.ClusterConfig{ClusterSize: 3}) + defer clus.Close() + testutils.ExecuteWithTimeout(t, 10*time.Second, func() { + if err := clus.Client().Health(); err != nil { + t.Fatalf("get endpoint health error: %v", err) + } + }) +} diff --git a/tests/e2e/ctl_v3_auth_test.go b/tests/e2e/ctl_v3_auth_test.go index 4d376f64c8c..fd15a9e617e 100644 --- a/tests/e2e/ctl_v3_auth_test.go +++ b/tests/e2e/ctl_v3_auth_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - "go.etcd.io/etcd/client/v3" + clientv3 "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/tests/v3/framework/e2e" ) @@ -1256,3 +1256,12 @@ func authTestRevisionConsistency(cx ctlCtx) { cx.t.Fatalf("auth revison shouldn't change when restarting etcd, expected: %d, got: %d", oldAuthRevision, newAuthRevision) } } + +func ctlV3EndpointHealth(cx ctlCtx) error { + cmdArgs := append(cx.PrefixArgs(), "endpoint", "health") + lines := make([]string, cx.epc.Cfg.ClusterSize) + for i := range lines { + lines[i] = "is healthy" + } + return e2e.SpawnWithExpects(cmdArgs, cx.envMap, lines...) +} diff --git a/tests/e2e/ctl_v3_endpoint_test.go b/tests/e2e/ctl_v3_endpoint_test.go deleted file mode 100644 index 8e364e8b4b8..00000000000 --- a/tests/e2e/ctl_v3_endpoint_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2016 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 e2e - -import ( - "context" - "fmt" - "net/url" - "testing" - "time" - - "go.etcd.io/etcd/client/v3" - "go.etcd.io/etcd/tests/v3/framework/e2e" -) - -func TestCtlV3EndpointHealth(t *testing.T) { testCtl(t, endpointHealthTest, withQuorum()) } -func TestCtlV3EndpointStatus(t *testing.T) { testCtl(t, endpointStatusTest, withQuorum()) } -func TestCtlV3EndpointHashKV(t *testing.T) { testCtl(t, endpointHashKVTest, withQuorum()) } - -func endpointHealthTest(cx ctlCtx) { - if err := ctlV3EndpointHealth(cx); err != nil { - cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err) - } -} - -func ctlV3EndpointHealth(cx ctlCtx) error { - cmdArgs := append(cx.PrefixArgs(), "endpoint", "health") - lines := make([]string, cx.epc.Cfg.ClusterSize) - for i := range lines { - lines[i] = "is healthy" - } - return e2e.SpawnWithExpects(cmdArgs, cx.envMap, lines...) -} - -func endpointStatusTest(cx ctlCtx) { - if err := ctlV3EndpointStatus(cx); err != nil { - cx.t.Fatalf("endpointStatusTest ctlV3EndpointStatus error (%v)", err) - } -} - -func ctlV3EndpointStatus(cx ctlCtx) error { - cmdArgs := append(cx.PrefixArgs(), "endpoint", "status") - var eps []string - for _, ep := range cx.epc.EndpointsV3() { - u, _ := url.Parse(ep) - eps = append(eps, u.Host) - } - return e2e.SpawnWithExpects(cmdArgs, cx.envMap, eps...) -} - -func endpointHashKVTest(cx ctlCtx) { - if err := ctlV3EndpointHashKV(cx); err != nil { - cx.t.Fatalf("endpointHashKVTest ctlV3EndpointHashKV error (%v)", err) - } -} - -func ctlV3EndpointHashKV(cx ctlCtx) error { - eps := cx.epc.EndpointsV3() - - // get latest hash to compare - cli, err := clientv3.New(clientv3.Config{ - Endpoints: eps, - DialTimeout: 3 * time.Second, - }) - if err != nil { - cx.t.Fatal(err) - } - defer cli.Close() - hresp, err := cli.HashKV(context.TODO(), eps[0], 0) - if err != nil { - cx.t.Fatal(err) - } - - cmdArgs := append(cx.PrefixArgs(), "endpoint", "hashkv") - var ss []string - for _, ep := range cx.epc.EndpointsV3() { - u, _ := url.Parse(ep) - ss = append(ss, fmt.Sprintf("%s, %d", u.Host, hresp.Hash)) - } - return e2e.SpawnWithExpects(cmdArgs, cx.envMap, ss...) -} diff --git a/tests/framework/e2e/etcdctl.go b/tests/framework/e2e/etcdctl.go index f807c7fe67d..18c43674826 100644 --- a/tests/framework/e2e/etcdctl.go +++ b/tests/framework/e2e/etcdctl.go @@ -176,3 +176,70 @@ func (ctl *EtcdctlV3) Compact(rev int64, o config.CompactOption) (*clientv3.Comp return nil, SpawnWithExpect(args, fmt.Sprintf("compacted revision %v", rev)) } + +func (ctl *EtcdctlV3) Status() ([]*clientv3.StatusResponse, error) { + args := ctl.cmdArgs() + args = append(args, "endpoint", "status", "-w", "json") + args = append(args, "--endpoints", strings.Join(ctl.endpoints, ",")) + cmd, err := SpawnCmd(args, nil) + if err != nil { + return nil, err + } + + var epStatus []*struct { + Endpoint string + Status *clientv3.StatusResponse + } + line, err := cmd.Expect("header") + if err != nil { + return nil, err + } + err = json.Unmarshal([]byte(line), &epStatus) + if err != nil { + return nil, err + } + resp := make([]*clientv3.StatusResponse, len(epStatus)) + for _, e := range epStatus { + resp = append(resp, e.Status) + } + return resp, err +} + +func (ctl *EtcdctlV3) HashKV(rev int64) ([]*clientv3.HashKVResponse, error) { + args := ctl.cmdArgs() + args = append(args, "endpoint", "hashkv", "-w", "json") + args = append(args, "--endpoints", strings.Join(ctl.endpoints, ",")) + args = append(args, "--rev", fmt.Sprint(rev)) + cmd, err := SpawnCmd(args, nil) + if err != nil { + return nil, err + } + var epHashKVs []*struct { + Endpoint string + HashKV *clientv3.HashKVResponse + } + line, err := cmd.Expect("header") + if err != nil { + return nil, err + } + err = json.Unmarshal([]byte(line), &epHashKVs) + if err != nil { + return nil, err + } + resp := make([]*clientv3.HashKVResponse, len(epHashKVs)) + for _, e := range epHashKVs { + resp = append(resp, e.HashKV) + } + return resp, err +} + +func (ctl *EtcdctlV3) Health() error { + args := ctl.cmdArgs() + args = append(args, "endpoint", "health") + lines := make([]string, len(ctl.endpoints)) + for i := range lines { + lines[i] = "is healthy" + } + return SpawnWithExpects(args, map[string]string{}, lines...) + +} diff --git a/tests/framework/integration.go b/tests/framework/integration.go index 18aabed5a33..73e15f130ff 100644 --- a/tests/framework/integration.go +++ b/tests/framework/integration.go @@ -19,9 +19,12 @@ import ( "fmt" "testing" + healthpb "google.golang.org/grpc/health/grpc_health_v1" + "go.etcd.io/etcd/client/pkg/v3/testutil" "go.etcd.io/etcd/client/pkg/v3/transport" clientv3 "go.etcd.io/etcd/client/v3" + "go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/integration" "go.uber.org/zap" @@ -155,3 +158,41 @@ func (c integrationClient) Compact(rev int64, o config.CompactOption) (*clientv3 } return c.Client.Compact(ctx, rev, clientOpts...) } + +func (c integrationClient) Status() ([]*clientv3.StatusResponse, error) { + endpoints := c.Client.Endpoints() + var resp []*clientv3.StatusResponse + for _, ep := range endpoints { + status, err := c.Client.Status(context.Background(), ep) + if err != nil { + return nil, err + } + resp = append(resp, status) + } + return resp, nil +} + +func (c integrationClient) HashKV(rev int64) ([]*clientv3.HashKVResponse, error) { + endpoints := c.Client.Endpoints() + var resp []*clientv3.HashKVResponse + for _, ep := range endpoints { + hashKV, err := c.Client.HashKV(context.Background(), ep, rev) + if err != nil { + return nil, err + } + resp = append(resp, hashKV) + } + return resp, nil +} + +func (c integrationClient) Health() error { + cli := healthpb.NewHealthClient(c.Client.ActiveConnection()) + resp, err := cli.Check(context.TODO(), &healthpb.HealthCheckRequest{}) + if err != nil { + return err + } + if resp.Status != healthpb.HealthCheckResponse_SERVING { + return fmt.Errorf("status expected %s, got %s", healthpb.HealthCheckResponse_SERVING, resp.Status) + } + return nil +} diff --git a/tests/framework/interface.go b/tests/framework/interface.go index 5c1ac01145a..f6982f321a8 100644 --- a/tests/framework/interface.go +++ b/tests/framework/interface.go @@ -37,4 +37,8 @@ type Client interface { Get(key string, opts config.GetOptions) (*clientv3.GetResponse, error) Delete(key string, opts config.DeleteOptions) (*clientv3.DeleteResponse, error) Compact(rev int64, opts config.CompactOption) (*clientv3.CompactResponse, error) + + Status() ([]*clientv3.StatusResponse, error) + HashKV(rev int64) ([]*clientv3.HashKVResponse, error) + Health() error } diff --git a/tests/integration/v3_health_test.go b/tests/integration/v3_health_test.go deleted file mode 100644 index 98b64c63fe0..00000000000 --- a/tests/integration/v3_health_test.go +++ /dev/null @@ -1,39 +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. - -package integration - -import ( - "context" - "testing" - - "go.etcd.io/etcd/tests/v3/framework/integration" - healthpb "google.golang.org/grpc/health/grpc_health_v1" -) - -func TestHealthCheck(t *testing.T) { - integration.BeforeTest(t) - - clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) - defer clus.Terminate(t) - - cli := healthpb.NewHealthClient(clus.RandClient().ActiveConnection()) - resp, err := cli.Check(context.TODO(), &healthpb.HealthCheckRequest{}) - if err != nil { - t.Fatal(err) - } - if resp.Status != healthpb.HealthCheckResponse_SERVING { - t.Fatalf("status expected %s, got %s", healthpb.HealthCheckResponse_SERVING, resp.Status) - } -}