| // Copyright 2021 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 ( |
| "os" |
| "path/filepath" |
| "testing" |
| |
| grpc_logsettable "github.com/grpc-ecosystem/go-grpc-middleware/logging/settable" |
| "go.etcd.io/etcd/client/pkg/v3/testutil" |
| clientv3 "go.etcd.io/etcd/client/v3" |
| "go.etcd.io/etcd/server/v3/embed" |
| "go.etcd.io/etcd/server/v3/verify" |
| "go.uber.org/zap/zapcore" |
| "go.uber.org/zap/zapgrpc" |
| "go.uber.org/zap/zaptest" |
| ) |
| |
| var grpc_logger grpc_logsettable.SettableLoggerV2 |
| var insideTestContext bool |
| |
| func init() { |
| grpc_logger = grpc_logsettable.ReplaceGrpcLoggerV2() |
| } |
| |
| type testOptions struct { |
| goLeakDetection bool |
| skipInShort bool |
| } |
| |
| func newTestOptions(opts ...TestOption) *testOptions { |
| o := &testOptions{goLeakDetection: true, skipInShort: true} |
| for _, opt := range opts { |
| opt(o) |
| } |
| return o |
| } |
| |
| type TestOption func(opt *testOptions) |
| |
| // WithoutGoLeakDetection disables checking whether a testcase leaked a goroutine. |
| func WithoutGoLeakDetection() TestOption { |
| return func(opt *testOptions) { opt.goLeakDetection = false } |
| } |
| |
| func WithoutSkipInShort() TestOption { |
| return func(opt *testOptions) { opt.skipInShort = false } |
| } |
| |
| // BeforeTestExternal initializes test context and is targeted for external APIs. |
| // In general the `integration` package is not targeted to be used outside of |
| // etcd project, but till the dedicated package is developed, this is |
| // the best entry point so far (without backward compatibility promise). |
| func BeforeTestExternal(t testutil.TB) { |
| BeforeTest(t, WithoutSkipInShort(), WithoutGoLeakDetection()) |
| } |
| |
| func BeforeTest(t testutil.TB, opts ...TestOption) { |
| t.Helper() |
| options := newTestOptions(opts...) |
| |
| if options.skipInShort { |
| testutil.SkipTestIfShortMode(t, "Cannot create clusters in --short tests") |
| } |
| |
| if options.goLeakDetection { |
| testutil.RegisterLeakDetection(t) |
| } |
| |
| previousWD, err := os.Getwd() |
| if err != nil { |
| t.Fatal(err) |
| } |
| previousInsideTestContext := insideTestContext |
| |
| // Registering cleanup early, such it will get executed even if the helper fails. |
| t.Cleanup(func() { |
| grpc_logger.Reset() |
| insideTestContext = previousInsideTestContext |
| os.Chdir(previousWD) |
| }) |
| |
| if insideTestContext { |
| t.Fatal("already in test context. BeforeTest was likely already called") |
| } |
| |
| grpc_logger.Set(zapgrpc.NewLogger(zaptest.NewLogger(t).Named("grpc"))) |
| insideTestContext = true |
| |
| // Integration tests should verify written state as much as possible. |
| os.Setenv(verify.ENV_VERIFY, verify.ENV_VERIFY_ALL_VALUE) |
| os.Chdir(t.TempDir()) |
| } |
| |
| func assertInTestContext(t testutil.TB) { |
| if !insideTestContext { |
| t.Errorf("the function can be called only in the test context. Was integration.BeforeTest() called ?") |
| } |
| } |
| |
| func MustAbsPath(path string) string { |
| abs, err := filepath.Abs(path) |
| if err != nil { |
| panic(err) |
| } |
| return abs |
| } |
| |
| func NewEmbedConfig(t testing.TB, name string) *embed.Config { |
| cfg := embed.NewConfig() |
| cfg.Name = name |
| lg := zaptest.NewLogger(t, zaptest.Level(zapcore.InfoLevel)).Named(cfg.Name) |
| cfg.ZapLoggerBuilder = embed.NewZapLoggerBuilder(lg) |
| cfg.Dir = t.TempDir() |
| return cfg |
| } |
| |
| func NewClient(t testing.TB, cfg clientv3.Config) (*clientv3.Client, error) { |
| if cfg.Logger == nil { |
| cfg.Logger = zaptest.NewLogger(t).Named("client") |
| } |
| return clientv3.New(cfg) |
| } |