diff --git a/Makefile b/Makefile index e612076cb7f..40195b4fdaf 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ SHELL := /bin/bash JAEGER_IMPORT_PATH = github.com/jaegertracing/jaeger STORAGE_PKGS = ./plugin/storage/integration/... -JAEGER_STORAGE_PKGS = ./cmd/jaeger/internal/integration +JAEGER_V2_STORAGE_PKGS = ./cmd/jaeger/internal/integration # These DOCKER_xxx vars are used when building Docker images. DOCKER_NAMESPACE?=jaegertracing @@ -57,6 +57,7 @@ GOARCH ?= $(shell $(GO) env GOARCH) GOBUILD=CGO_ENABLED=0 installsuffix=cgo $(GO) build -trimpath GOTEST_QUIET=$(GO) test $(RACE) GOTEST=$(GOTEST_QUIET) -v +COVEROUT=cover.out GOFMT=gofmt GOFUMPT=gofumpt FMT_LOG=.fmt.log @@ -112,13 +113,6 @@ test: all-in-one-integration-test: TEST_MODE=integration $(GOTEST) ./cmd/all-in-one/ -.PHONY: storage-integration-test -storage-integration-test: - # Expire tests results for storage integration tests since the environment might change - # even though the code remains the same. - go clean -testcache - bash -c "set -e; set -o pipefail; $(GOTEST) -coverpkg=./... -coverprofile cover.out $(STORAGE_PKGS) $(COLORIZE)" - # A general integration tests for jaeger-v2 storage backends, # these tests placed at `./cmd/jaeger/internal/integration/*_test.go`. # The integration tests are filtered by STORAGE env, @@ -129,34 +123,37 @@ jaeger-storage-integration-test: # Expire tests results for jaeger storage integration tests since the environment might change # even though the code remains the same. go clean -testcache - bash -c "set -e; set -o pipefail; $(GOTEST) -coverpkg=./... -coverprofile cover.out $(JAEGER_STORAGE_PKGS) $(COLORIZE)" + bash -c "set -e; set -o pipefail; $(GOTEST) -coverpkg=./... -coverprofile $(COVEROUT) $(JAEGER_V2_STORAGE_PKGS) $(COLORIZE)" + +.PHONY: storage-integration-test +storage-integration-test: + # Expire tests results for storage integration tests since the environment might change + # even though the code remains the same. + go clean -testcache + bash -c "set -e; set -o pipefail; $(GOTEST) -coverpkg=./... -coverprofile $(COVEROUT) $(STORAGE_PKGS) $(COLORIZE)" .PHONY: badger-storage-integration-test badger-storage-integration-test: - bash -c "set -e; set -o pipefail; $(GOTEST) -tags=badger_storage_integration -coverpkg=./... -coverprofile cover.out $(STORAGE_PKGS) $(COLORIZE)" + STORAGE=badger $(MAKE) storage-integration-test .PHONY: grpc-storage-integration-test grpc-storage-integration-test: (cd examples/memstore-plugin/ && go build .) - bash -c "set -e; set -o pipefail; $(GOTEST) -tags=grpc_storage_integration -coverpkg=./... -coverprofile cover.out $(STORAGE_PKGS) $(COLORIZE)" + STORAGE=grpc $(MAKE) storage-integration-test +# this test assumes STORAGE environment variable is set to elasticsearch|opensearch .PHONY: index-cleaner-integration-test index-cleaner-integration-test: docker-images-elastic - # Expire test results for storage integration tests since the environment might change - # even though the code remains the same. - go clean -testcache - bash -c "set -e; set -o pipefail; $(GOTEST) -tags index_cleaner -coverpkg=./... -coverprofile cover-index-cleaner.out $(STORAGE_PKGS) $(COLORIZE)" + $(MAKE) storage-integration-test COVEROUT=cover-index-cleaner.out +# this test assumes STORAGE environment variable is set to elasticsearch|opensearch .PHONY: index-rollover-integration-test index-rollover-integration-test: docker-images-elastic - # Expire test results for storage integration tests since the environment might change - # even though the code remains the same. - go clean -testcache - bash -c "set -e; set -o pipefail; $(GOTEST) -tags index_rollover -coverpkg=./... -coverprofile cover-index-rollover.out $(STORAGE_PKGS) $(COLORIZE)" + $(MAKE) storage-integration-test COVEROUT=cover-index-rollover.out .PHONY: cover cover: nocover - bash -c "set -e; set -o pipefail; $(GOTEST) -tags=memory_storage_integration -timeout 5m -coverprofile cover.out ./... | tee test-results.json" + bash -c "set -e; set -o pipefail; STORAGE=memory $(GOTEST) -timeout 5m -coverprofile $(COVEROUT) ./... | tee test-results.json" go tool cover -html=cover.out -o cover.html .PHONY: nocover diff --git a/plugin/storage/integration/badgerstore_test.go b/plugin/storage/integration/badgerstore_test.go index d1e01dbc605..e3502a30582 100644 --- a/plugin/storage/integration/badgerstore_test.go +++ b/plugin/storage/integration/badgerstore_test.go @@ -11,8 +11,6 @@ // 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. -//go:build badger_storage_integration -// +build badger_storage_integration package integration @@ -33,60 +31,45 @@ type BadgerIntegrationStorage struct { factory *badger.Factory } -func (s *BadgerIntegrationStorage) initialize() error { +func (s *BadgerIntegrationStorage) initialize(t *testing.T) { s.factory = badger.NewFactory() err := s.factory.Initialize(metrics.NullFactory, zap.NewNop()) - if err != nil { - return err - } - - sw, err := s.factory.CreateSpanWriter() - if err != nil { - return err - } - sr, err := s.factory.CreateSpanReader() - if err != nil { - return err - } - if s.SamplingStore, err = s.factory.CreateSamplingStore(0); err != nil { - return err - } - - s.SpanReader = sr - s.SpanWriter = sw - - s.Refresh = s.refresh + require.NoError(t, err) + + s.SpanWriter, err = s.factory.CreateSpanWriter() + require.NoError(t, err) + + s.SpanReader, err = s.factory.CreateSpanReader() + require.NoError(t, err) + + s.SamplingStore, err = s.factory.CreateSamplingStore(0) + require.NoError(t, err) + + s.Refresh = func(_ *testing.T) {} s.CleanUp = s.cleanUp - logger, _ := testutils.NewLogger() - s.logger = logger + s.logger, _ = testutils.NewLogger() // TODO: remove this badger supports returning spanKind from GetOperations s.GetOperationsMissingSpanKind = true s.SkipArchiveTest = true - return nil } func (s *BadgerIntegrationStorage) clear() error { return s.factory.Close() } -func (s *BadgerIntegrationStorage) cleanUp() error { +func (s *BadgerIntegrationStorage) cleanUp(t *testing.T) { err := s.clear() - if err != nil { - return err - } - return s.initialize() -} - -func (s *BadgerIntegrationStorage) refresh() error { - return nil + require.NoError(t, err) + s.initialize(t) } func TestBadgerStorage(t *testing.T) { + skipUnlessEnv(t, "badger") s := &BadgerIntegrationStorage{} - require.NoError(t, s.initialize()) - s.IntegrationTestAll(t) + s.initialize(t) + s.RunAll(t) defer s.clear() } diff --git a/plugin/storage/integration/cassandra_test.go b/plugin/storage/integration/cassandra_test.go index 93af28cf4a8..0ba286a87e9 100644 --- a/plugin/storage/integration/cassandra_test.go +++ b/plugin/storage/integration/cassandra_test.go @@ -16,9 +16,6 @@ package integration import ( - "errors" - "fmt" - "os" "testing" "github.com/stretchr/testify/require" @@ -32,8 +29,6 @@ import ( "github.com/jaegertracing/jaeger/storage/dependencystore" ) -var errInitializeCassandraDependencyWriter = errors.New("failed to initialize cassandra dependency writer") - type CassandraStorageIntegration struct { StorageIntegration @@ -47,7 +42,7 @@ func newCassandraStorageIntegration() *CassandraStorageIntegration { GetDependenciesReturnsSource: true, SkipArchiveTest: true, - Refresh: func() error { return nil }, + Refresh: func(_ *testing.T) {}, SkipList: []string{ "Tags_+_Operation_name_+_Duration_range", "Tags_+_Duration_range", @@ -64,68 +59,58 @@ func newCassandraStorageIntegration() *CassandraStorageIntegration { return s } -func (s *CassandraStorageIntegration) cleanUp() error { - return s.session.Query("TRUNCATE traces").Exec() +func (s *CassandraStorageIntegration) cleanUp(t *testing.T) { + require.NoError(t, s.session.Query("TRUNCATE traces").Exec()) } -func (s *CassandraStorageIntegration) initializeCassandraFactory(flags []string) (*cassandra.Factory, error) { +func (s *CassandraStorageIntegration) initializeCassandraFactory(t *testing.T, flags []string) *cassandra.Factory { s.logger, _ = testutils.NewLogger() f := cassandra.NewFactory() v, command := config.Viperize(f.AddFlags) - if err := command.ParseFlags(flags); err != nil { - return nil, fmt.Errorf("unable to parse flags: %w", err) + { + err := command.ParseFlags(flags) + require.NoError(t, err) } f.InitFromViper(v, zap.NewNop()) - if err := f.Initialize(metrics.NullFactory, s.logger); err != nil { - return nil, err + { + err := f.Initialize(metrics.NullFactory, s.logger) + require.NoError(t, err) } - return f, nil + return f } -func (s *CassandraStorageIntegration) initializeCassandra() error { - f, err := s.initializeCassandraFactory([]string{ +func (s *CassandraStorageIntegration) initializeCassandra(t *testing.T) { + f := s.initializeCassandraFactory(t, []string{ "--cassandra.keyspace=jaeger_v1_dc1", }) - if err != nil { - return err - } s.session = f.PrimarySession() - if s.SpanWriter, err = f.CreateSpanWriter(); err != nil { - return err - } - if s.SpanReader, err = f.CreateSpanReader(); err != nil { - return err - } - if s.SamplingStore, err = f.CreateSamplingStore(0); err != nil { - return err - } - - if err = s.initializeDependencyReaderAndWriter(f); err != nil { - return err - } - return nil + var err error + s.SpanWriter, err = f.CreateSpanWriter() + require.NoError(t, err) + s.SpanReader, err = f.CreateSpanReader() + require.NoError(t, err) + s.SamplingStore, err = f.CreateSamplingStore(0) + require.NoError(t, err) + s.initializeDependencyReaderAndWriter(t, f) } -func (s *CassandraStorageIntegration) initializeDependencyReaderAndWriter(f *cassandra.Factory) error { +func (s *CassandraStorageIntegration) initializeDependencyReaderAndWriter(t *testing.T, f *cassandra.Factory) { var ( err error ok bool ) - if s.DependencyReader, err = f.CreateDependencyReader(); err != nil { - return err - } + s.DependencyReader, err = f.CreateDependencyReader() + require.NoError(t, err) + // TODO: Update this when the factory interface has CreateDependencyWriter if s.DependencyWriter, ok = s.DependencyReader.(dependencystore.Writer); !ok { - return errInitializeCassandraDependencyWriter + t.Log("DependencyWriter not implemented ") } - return nil } func TestCassandraStorage(t *testing.T) { - if os.Getenv("STORAGE") != "cassandra" { - t.Skip("Integration test against Cassandra skipped; set STORAGE env var to cassandra to run this") - } + skipUnlessEnv(t, "cassandra") s := newCassandraStorageIntegration() - require.NoError(t, s.initializeCassandra()) - s.IntegrationTestAll(t) + s.initializeCassandra(t) + s.RunAll(t) } diff --git a/plugin/storage/integration/elasticsearch_test.go b/plugin/storage/integration/elasticsearch_test.go index 7a92224d906..e386f802be9 100644 --- a/plugin/storage/integration/elasticsearch_test.go +++ b/plugin/storage/integration/elasticsearch_test.go @@ -19,7 +19,6 @@ import ( "context" "errors" "net/http" - "os" "strconv" "strings" "testing" @@ -117,9 +116,8 @@ func (s *ESStorageIntegration) initializeES(t *testing.T, allTagsAsFields bool) s.initSpanstore(t, allTagsAsFields) s.initSamplingStore(t) - s.CleanUp = func() error { + s.CleanUp = func(t *testing.T) { s.esCleanUp(t, allTagsAsFields) - return nil } s.Refresh = s.esRefresh s.esCleanUp(t, allTagsAsFields) @@ -252,13 +250,11 @@ func (s *ESStorageIntegration) initSpanstore(t *testing.T, allTagsAsFields bool) return nil } -func (s *ESStorageIntegration) esRefresh() error { +func (s *ESStorageIntegration) esRefresh(t *testing.T) { err := s.bulkProcessor.Flush() - if err != nil { - return err - } + require.NoError(t, err) _, err = s.client.Refresh().Do(context.Background()) - return err + require.NoError(t, err) } func healthCheck() error { @@ -272,9 +268,7 @@ func healthCheck() error { } func testElasticsearchStorage(t *testing.T, allTagsAsFields bool) { - if os.Getenv("STORAGE") != "elasticsearch" && os.Getenv("STORAGE") != "opensearch" { - t.Skip("Integration test against ElasticSearch skipped; set STORAGE env var to elasticsearch to run this") - } + skipUnlessEnv(t, "elasticsearch", "opensearch") if err := healthCheck(); err != nil { t.Fatal(err) } @@ -283,7 +277,7 @@ func testElasticsearchStorage(t *testing.T, allTagsAsFields bool) { s.Fixtures = LoadAndParseQueryTestCases(t, "fixtures/queries_es.json") - s.IntegrationTestAll(t) + s.RunAll(t) } func TestElasticsearchStorage(t *testing.T) { @@ -295,9 +289,7 @@ func TestElasticsearchStorage_AllTagsAsObjectFields(t *testing.T) { } func TestElasticsearchStorage_IndexTemplates(t *testing.T) { - if os.Getenv("STORAGE") != "elasticsearch" { - t.Skip("Integration test against ElasticSearch skipped; set STORAGE env var to elasticsearch to run this") - } + skipUnlessEnv(t, "elasticsearch", "opensearch") if err := healthCheck(); err != nil { t.Fatal(err) } diff --git a/plugin/storage/integration/es_index_cleaner_test.go b/plugin/storage/integration/es_index_cleaner_test.go index df19d463a0f..d500eb17033 100644 --- a/plugin/storage/integration/es_index_cleaner_test.go +++ b/plugin/storage/integration/es_index_cleaner_test.go @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build index_cleaner -// +build index_cleaner - package integration import ( @@ -43,6 +40,7 @@ const ( ) func TestIndexCleaner_doNotFailOnEmptyStorage(t *testing.T) { + skipUnlessEnv(t, "elasticsearch", "opensearch") client, err := createESClient() require.NoError(t, err) _, err = client.DeleteIndex("*").Do(context.Background()) @@ -62,6 +60,7 @@ func TestIndexCleaner_doNotFailOnEmptyStorage(t *testing.T) { } func TestIndexCleaner_doNotFailOnFullStorage(t *testing.T) { + skipUnlessEnv(t, "elasticsearch", "opensearch") client, err := createESClient() require.NoError(t, err) tests := []struct { @@ -83,6 +82,7 @@ func TestIndexCleaner_doNotFailOnFullStorage(t *testing.T) { } func TestIndexCleaner(t *testing.T) { + skipUnlessEnv(t, "elasticsearch", "opensearch") client, err := createESClient() require.NoError(t, err) v8Client, err := createESV8Client() @@ -157,7 +157,7 @@ func runIndexCleanerTest(t *testing.T, client *elastic.Client, v8Client *elastic indices, err := client.IndexNames() require.NoError(t, err) if prefix != "" { - prefix = prefix + "-" + prefix += "-" } var expected []string for _, index := range expectedIndices { @@ -169,7 +169,7 @@ func runIndexCleanerTest(t *testing.T, client *elastic.Client, v8Client *elastic func createAllIndices(client *elastic.Client, prefix string, adaptiveSampling bool) error { prefixWithSeparator := prefix if prefix != "" { - prefixWithSeparator = prefixWithSeparator + "-" + prefixWithSeparator += "-" } // create daily indices and archive index err := createEsIndices(client, []string{ diff --git a/plugin/storage/integration/es_index_rollover_test.go b/plugin/storage/integration/es_index_rollover_test.go index 853482dfe9c..930f1b19533 100644 --- a/plugin/storage/integration/es_index_rollover_test.go +++ b/plugin/storage/integration/es_index_rollover_test.go @@ -12,32 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build index_rollover -// +build index_rollover - package integration import ( "context" "fmt" - "os/exec" "strconv" "testing" - elasticsearch8 "github.com/elastic/go-elasticsearch/v8" "github.com/olivere/elastic" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/jaegertracing/jaeger/pkg/testutils" ) const ( defaultILMPolicyName = "jaeger-ilm-policy" - rolloverImage = "jaegertracing/jaeger-es-rollover:latest" ) func TestIndexRollover_FailIfILMNotPresent(t *testing.T) { + skipUnlessEnv(t, "elasticsearch", "opensearch") client, err := createESClient() require.NoError(t, err) esVersion, err := getVersion(client) @@ -57,13 +50,14 @@ func TestIndexRollover_FailIfILMNotPresent(t *testing.T) { } func TestIndexRollover_CreateIndicesWithILM(t *testing.T) { + skipUnlessEnv(t, "elasticsearch", "opensearch") // Test using the default ILM Policy Name, i.e. do not pass the ES_ILM_POLICY_NAME env var to the rollover script. - t.Run(fmt.Sprintf("DefaultPolicyName"), func(t *testing.T) { + t.Run("DefaultPolicyName", func(t *testing.T) { runCreateIndicesWithILM(t, defaultILMPolicyName) }) // Test using a configured ILM Policy Name, i.e. pass the ES_ILM_POLICY_NAME env var to the rollover script. - t.Run(fmt.Sprintf("SetPolicyName"), func(t *testing.T) { + t.Run("SetPolicyName", func(t *testing.T) { runCreateIndicesWithILM(t, "jaeger-test-policy") }) } @@ -94,13 +88,13 @@ func runCreateIndicesWithILM(t *testing.T, ilmPolicyName string) { } else { expectedIndices := []string{"jaeger-span-000001", "jaeger-service-000001", "jaeger-dependencies-000001"} - t.Run(fmt.Sprintf("NoPrefix"), func(t *testing.T) { + t.Run("NoPrefix", func(t *testing.T) { runIndexRolloverWithILMTest(t, client, "", expectedIndices, envVars, ilmPolicyName, false) }) - t.Run(fmt.Sprintf("WithPrefix"), func(t *testing.T) { + t.Run("WithPrefix", func(t *testing.T) { runIndexRolloverWithILMTest(t, client, indexPrefix, expectedIndices, append(envVars, "INDEX_PREFIX="+indexPrefix), ilmPolicyName, false) }) - t.Run(fmt.Sprintf("WithAdaptiveSampling"), func(t *testing.T) { + t.Run("WithAdaptiveSampling", func(t *testing.T) { runIndexRolloverWithILMTest(t, client, indexPrefix, expectedIndices, append(envVars, "INDEX_PREFIX="+indexPrefix), ilmPolicyName, true) }) } @@ -123,7 +117,7 @@ func runIndexRolloverWithILMTest(t *testing.T, client *elastic.Client, prefix st require.NoError(t, err) if prefix != "" { - prefix = prefix + "-" + prefix += "-" } var expected, expectedWriteAliases, actualWriteAliases []string for _, index := range expectedIndices { @@ -154,31 +148,6 @@ func runIndexRolloverWithILMTest(t *testing.T, client *elastic.Client, prefix st assert.ElementsMatch(t, actualWriteAliases, expectedWriteAliases, fmt.Sprintf("aliases found: %v, expected: %v", actualWriteAliases, expectedWriteAliases)) } -func createESClient() (*elastic.Client, error) { - return elastic.NewClient( - elastic.SetURL(queryURL), - elastic.SetSniff(false)) -} - -func createESV8Client() (*elasticsearch8.Client, error) { - return elasticsearch8.NewClient(elasticsearch8.Config{ - Addresses: []string{queryURL}, - DiscoverNodesOnStart: false, - }) -} - -func runEsRollover(action string, envs []string, adaptiveSampling bool) error { - var dockerEnv string - for _, e := range envs { - dockerEnv += fmt.Sprintf(" -e %s", e) - } - args := fmt.Sprintf("docker run %s --rm --net=host %s %s --adaptive-sampling=%t http://%s", dockerEnv, rolloverImage, action, adaptiveSampling, queryHostPort) - cmd := exec.Command("/bin/sh", "-c", args) - out, err := cmd.CombinedOutput() - fmt.Println(string(out)) - return err -} - func getVersion(client *elastic.Client) (uint, error) { pingResult, _, err := client.Ping(queryURL).Do(context.Background()) if err != nil { @@ -210,12 +179,3 @@ func cleanES(t *testing.T, client *elastic.Client, policyName string) { _, err = client.IndexDeleteTemplate("*").Do(context.Background()) require.NoError(t, err) } - -func cleanESIndexTemplates(t *testing.T, client *elastic.Client, v8Client *elasticsearch8.Client, prefix string) { - s := &ESStorageIntegration{ - client: client, - v8Client: v8Client, - } - s.logger, _ = testutils.NewLogger() - s.cleanESIndexTemplates(t, prefix) -} diff --git a/plugin/storage/integration/grpc_test.go b/plugin/storage/integration/grpc_test.go index f2c12bb9c41..0d1328cbeae 100644 --- a/plugin/storage/integration/grpc_test.go +++ b/plugin/storage/integration/grpc_test.go @@ -13,9 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build grpc_storage_integration -// +build grpc_storage_integration - package integration import ( @@ -102,55 +99,42 @@ type GRPCStorageIntegrationTestSuite struct { server *gRPCServer } -func (s *GRPCStorageIntegrationTestSuite) initialize() error { +func (s *GRPCStorageIntegrationTestSuite) initialize(t *testing.T) { s.logger, _ = testutils.NewLogger() if s.server != nil { - if err := s.server.Restart(); err != nil { - return err - } + err := s.server.Restart() + require.NoError(t, err) } f := grpc.NewFactory() v, command := config.Viperize(f.AddFlags) err := command.ParseFlags(s.flags) - if err != nil { - return err - } + require.NoError(t, err) f.InitFromViper(v, zap.NewNop()) - if err := f.Initialize(metrics.NullFactory, s.logger); err != nil { - return err - } + err = f.Initialize(metrics.NullFactory, s.logger) + require.NoError(t, err) s.factory = f - if s.SpanWriter, err = f.CreateSpanWriter(); err != nil { - return err - } - if s.SpanReader, err = f.CreateSpanReader(); err != nil { - return err - } - if s.ArchiveSpanReader, err = f.CreateArchiveSpanReader(); err != nil { - return err - } - if s.ArchiveSpanWriter, err = f.CreateArchiveSpanWriter(); err != nil { - return err - } + s.SpanWriter, err = f.CreateSpanWriter() + require.NoError(t, err) + s.SpanReader, err = f.CreateSpanReader() + require.NoError(t, err) + s.ArchiveSpanReader, err = f.CreateArchiveSpanReader() + require.NoError(t, err) + s.ArchiveSpanWriter, err = f.CreateArchiveSpanWriter() + require.NoError(t, err) + // TODO DependencyWriter is not implemented in grpc store - s.Refresh = s.refresh + s.Refresh = func(_ *testing.T) {} s.CleanUp = s.cleanUp - return nil -} - -func (s *GRPCStorageIntegrationTestSuite) refresh() error { - return nil } -func (s *GRPCStorageIntegrationTestSuite) cleanUp() error { - if err := s.factory.Close(); err != nil { - return err - } - return s.initialize() +func (s *GRPCStorageIntegrationTestSuite) cleanUp(t *testing.T) { + err := s.factory.Close() + require.NoError(t, err) + s.initialize(t) } func getPluginFlags(t *testing.T) []string { @@ -167,6 +151,7 @@ func getPluginFlags(t *testing.T) []string { } func TestGRPCStorage(t *testing.T) { + skipUnlessEnv(t, "grpc") flags := getPluginFlags(t) if configPath := os.Getenv("PLUGIN_CONFIG_PATH"); configPath == "" { t.Log("PLUGIN_CONFIG_PATH env var not set") @@ -177,11 +162,12 @@ func TestGRPCStorage(t *testing.T) { s := &GRPCStorageIntegrationTestSuite{ flags: flags, } - require.NoError(t, s.initialize()) - s.IntegrationTestAll(t) + s.initialize(t) + s.RunAll(t) } func TestGRPCStreamingWriter(t *testing.T) { + skipUnlessEnv(t, "grpc") flags := getPluginFlags(t) wd, err := os.Getwd() require.NoError(t, err) @@ -192,11 +178,12 @@ func TestGRPCStreamingWriter(t *testing.T) { s := &GRPCStorageIntegrationTestSuite{ flags: flags, } - require.NoError(t, s.initialize()) - s.IntegrationTestAll(t) + s.initialize(t) + s.RunAll(t) } func TestGRPCRemoteStorage(t *testing.T) { + skipUnlessEnv(t, "grpc") flags := []string{ "--grpc-storage.server=localhost:2001", "--grpc-storage.tls.enabled=false", @@ -208,6 +195,6 @@ func TestGRPCRemoteStorage(t *testing.T) { flags: flags, server: server, } - require.NoError(t, s.initialize()) - s.IntegrationTestAll(t) + s.initialize(t) + s.RunAll(t) } diff --git a/plugin/storage/integration/integration.go b/plugin/storage/integration/integration.go index 01539da2845..506900e8ee3 100644 --- a/plugin/storage/integration/integration.go +++ b/plugin/storage/integration/integration.go @@ -21,6 +21,7 @@ import ( "embed" "encoding/json" "fmt" + "os" "regexp" "sort" "strings" @@ -46,7 +47,14 @@ const ( //go:embed fixtures var fixtures embed.FS -// StorageIntegration holds components for storage integration test +// StorageIntegration holds components for storage integration test. +// The intended usage is as follows: +// - a specific storage implementation declares its own test functions +// - in those functions it instantiates and populates this struct +// - it then calls RunAll. +// +// Some implementations may declate multuple tests, with different settings, +// and RunAll() under different conditions. type StorageIntegration struct { SpanWriter spanstore.Writer SpanReader spanstore.Reader @@ -72,11 +80,11 @@ type StorageIntegration struct { // CleanUp() should ensure that the storage backend is clean before another test. // called either before or after each test, and should be idempotent - CleanUp func() error + CleanUp func(t *testing.T) // Refresh() should ensure that the storage backend is up to date before being queried. // called between set-up and queries in each test - Refresh func() error + Refresh func(t *testing.T) } // === SpanStore Integration Tests === @@ -96,12 +104,22 @@ type QueryFixtures struct { func (s *StorageIntegration) cleanUp(t *testing.T) { require.NotNil(t, s.CleanUp, "CleanUp function must be provided") - require.NoError(t, s.CleanUp()) + s.CleanUp(t) } func (s *StorageIntegration) refresh(t *testing.T) { require.NotNil(t, s.Refresh, "Refresh function must be provided") - require.NoError(t, s.Refresh()) + s.Refresh(t) +} + +func skipUnlessEnv(t *testing.T, storage ...string) { + env := os.Getenv("STORAGE") + for _, s := range storage { + if env == s { + return + } + } + t.Skipf("This test requires environment variable STORAGE=%s", strings.Join(storage, "|")) } func (s *StorageIntegration) skipIfNeeded(t *testing.T) { @@ -284,8 +302,7 @@ func (s *StorageIntegration) testFindTraces(t *testing.T) { trace, ok := allTraceFixtures[traceFixture] if !ok { trace = s.getTraceFixture(t, traceFixture) - err := s.writeTrace(t, trace) - require.NoError(t, err, "Unexpected error when writing trace %s to storage", traceFixture) + s.writeTrace(t, trace) allTraceFixtures[traceFixture] = trace } expected = append(expected, trace) @@ -320,19 +337,16 @@ func (s *StorageIntegration) findTracesByQuery(t *testing.T, query *spanstore.Tr return traces } -func (s *StorageIntegration) writeTrace(t *testing.T, trace *model.Trace) error { +func (s *StorageIntegration) writeTrace(t *testing.T, trace *model.Trace) { for _, span := range trace.Spans { - if err := s.SpanWriter.WriteSpan(context.Background(), span); err != nil { - return err - } + err := s.SpanWriter.WriteSpan(context.Background(), span) + require.NoError(t, err, "Not expecting error when writing trace to storage") } - return nil } func (s *StorageIntegration) loadParseAndWriteExampleTrace(t *testing.T) *model.Trace { trace := s.getTraceFixture(t, "example_trace") - err := s.writeTrace(t, trace) - require.NoError(t, err, "Not expecting error when writing example_trace to storage") + s.writeTrace(t, trace) return trace } @@ -349,8 +363,7 @@ func (s *StorageIntegration) loadParseAndWriteLargeTrace(t *testing.T) *model.Tr s.StartTime = s.StartTime.Add(time.Second * time.Duration(i+1)) trace.Spans = append(trace.Spans, s) } - err := s.writeTrace(t, trace) - require.NoError(t, err, "Not expecting error when writing example_trace to storage") + s.writeTrace(t, trace) return trace } @@ -513,8 +526,8 @@ func (s *StorageIntegration) insertThroughput(t *testing.T) { require.NoError(t, err) } -// IntegrationTestAll runs all integration tests -func (s *StorageIntegration) IntegrationTestAll(t *testing.T) { +// RunAll runs all integration tests +func (s *StorageIntegration) RunAll(t *testing.T) { t.Run("GetServices", s.testGetServices) t.Run("ArchiveTrace", s.testArchiveTrace) t.Run("GetOperations", s.testGetOperations) diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index fcd80e6ddff..598e711833f 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -16,7 +16,6 @@ package integration import ( "context" - "os" "strconv" "testing" "time" @@ -44,7 +43,7 @@ type KafkaIntegrationTestSuite struct { logger *zap.Logger } -func (s *KafkaIntegrationTestSuite) initialize() error { +func (s *KafkaIntegrationTestSuite) initialize(t *testing.T) { s.logger, _ = testutils.NewLogger() const encoding = "json" const groupID = "kafka-integration-test" @@ -62,17 +61,13 @@ func (s *KafkaIntegrationTestSuite) initialize() error { "--kafka.producer.encoding", encoding, }) - if err != nil { - return err - } + require.NoError(t, err) f.InitFromViper(v, zap.NewNop()) - if err := f.Initialize(metrics.NullFactory, s.logger); err != nil { - return err - } + err = f.Initialize(metrics.NullFactory, s.logger) + require.NoError(t, err) + spanWriter, err := f.CreateSpanWriter() - if err != nil { - return err - } + require.NoError(t, err) v, command = config.Viperize(app.AddFlags) err = command.ParseFlags([]string{ @@ -89,9 +84,7 @@ func (s *KafkaIntegrationTestSuite) initialize() error { "--ingester.parallelism", "1000", }) - if err != nil { - return err - } + require.NoError(t, err) options := app.Options{ Configuration: consumer.Configuration{ InitialOffset: sarama.OffsetOldest, @@ -100,17 +93,14 @@ func (s *KafkaIntegrationTestSuite) initialize() error { options.InitFromViper(v) traceStore := memory.NewStore() spanConsumer, err := builder.CreateConsumer(s.logger, metrics.NullFactory, traceStore, options) - if err != nil { - return err - } + require.NoError(t, err) spanConsumer.Start() s.SpanWriter = spanWriter s.SpanReader = &ingester{traceStore} - s.Refresh = func() error { return nil } - s.CleanUp = func() error { return nil } + s.Refresh = func(_ *testing.T) {} + s.CleanUp = func(_ *testing.T) {} s.SkipArchiveTest = true - return nil } // The ingester consumes spans from kafka and writes them to an in-memory traceStore @@ -142,10 +132,8 @@ func (r *ingester) FindTraceIDs(ctx context.Context, query *spanstore.TraceQuery } func TestKafkaStorage(t *testing.T) { - if os.Getenv("STORAGE") != "kafka" { - t.Skip("Integration test against kafka skipped; set STORAGE env var to kafka to run this") - } + skipUnlessEnv(t, "kafka") s := &KafkaIntegrationTestSuite{} - require.NoError(t, s.initialize()) + s.initialize(t) t.Run("GetTrace", s.testGetTrace) } diff --git a/plugin/storage/integration/memstore_test.go b/plugin/storage/integration/memstore_test.go index 2beff9f6c9a..875781a80ce 100644 --- a/plugin/storage/integration/memstore_test.go +++ b/plugin/storage/integration/memstore_test.go @@ -12,15 +12,12 @@ // 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. -//go:build memory_storage_integration -// +build memory_storage_integration package integration import ( "testing" - "github.com/stretchr/testify/require" "go.uber.org/zap" "github.com/jaegertracing/jaeger/pkg/testutils" @@ -32,7 +29,7 @@ type MemStorageIntegrationTestSuite struct { logger *zap.Logger } -func (s *MemStorageIntegrationTestSuite) initialize() error { +func (s *MemStorageIntegrationTestSuite) initialize(_ *testing.T) { s.logger, _ = testutils.NewLogger() store := memory.NewStore() @@ -45,21 +42,13 @@ func (s *MemStorageIntegrationTestSuite) initialize() error { // TODO DependencyWriter is not implemented in memory store - s.Refresh = s.refresh - s.CleanUp = s.cleanUp - return nil -} - -func (s *MemStorageIntegrationTestSuite) refresh() error { - return nil -} - -func (s *MemStorageIntegrationTestSuite) cleanUp() error { - return s.initialize() + s.Refresh = func(t *testing.T) {} + s.CleanUp = s.initialize } func TestMemoryStorage(t *testing.T) { + skipUnlessEnv(t, "memory") s := &MemStorageIntegrationTestSuite{} - require.NoError(t, s.initialize()) - s.IntegrationTestAll(t) + s.initialize(t) + s.RunAll(t) }