package solr import ( "fmt" "io/fs" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "time" "github.com/docker/go-connections/nat" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go/wait" "github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/plugins/parsers/influx" "github.com/influxdata/telegraf/testutil" ) func TestCases(t *testing.T) { // Get all directories in testcases folders, err := os.ReadDir("testcases") require.NoError(t, err) // Make sure tests contains data require.NotEmpty(t, folders) options := []cmp.Option{ testutil.IgnoreTime(), testutil.SortMetrics(), } for _, f := range folders { // Only handle folders if !f.IsDir() { continue } fname := f.Name() t.Run(fname, func(t *testing.T) { testdataPath := filepath.Join("testcases", fname) configFilename := filepath.Join(testdataPath, "telegraf.conf") expectedFilename := filepath.Join(testdataPath, "expected.out") // Load the expected output parser := &influx.Parser{} require.NoError(t, parser.Init()) expected, err := testutil.ParseMetricsFromFile(expectedFilename, parser) require.NoError(t, err) // Load the pages for the test case pages, err := loadPages(testdataPath) require.NoError(t, err) // Create a HTTP server that delivers all files in the test-directory server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !strings.HasPrefix(r.URL.Path, "/solr/") { w.WriteHeader(http.StatusNotFound) return } path := strings.TrimPrefix(r.URL.Path, "/solr/") page, found := pages[path] if !found { w.WriteHeader(http.StatusNotFound) return } if _, err := w.Write(page); err != nil { w.WriteHeader(http.StatusInternalServerError) t.Error(err) return } })) require.NotNil(t, server) defer server.Close() // Configure the plugin cfg := config.NewConfig() require.NoError(t, cfg.LoadConfig(configFilename)) require.Len(t, cfg.Inputs, 1) // Setup the plugin plugin := cfg.Inputs[0].Input.(*Solr) plugin.Servers = []string{server.URL} require.NoError(t, plugin.Init()) // Gather data and compare results var acc testutil.Accumulator require.NoError(t, plugin.Start(&acc)) require.NoError(t, plugin.Gather(&acc)) plugin.Stop() actual := acc.GetTelegrafMetrics() testutil.RequireMetricsEqual(t, expected, actual, options...) }) } } func TestIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } // Get all integration test files in testcases resultFiles, err := filepath.Glob(filepath.Join("testcases", "*.result")) require.NoError(t, err) // Make sure tests contains data require.NotEmpty(t, resultFiles) options := []cmp.Option{ testutil.IgnoreTime(), testutil.SortMetrics(), } const servicePort = "8983" for _, f := range resultFiles { fname := strings.TrimSuffix(filepath.Base(f), ".result") t.Run(fname, func(t *testing.T) { expectedFilename := filepath.Join("testcases", fname+".result") // Load the expected output parser := &influx.Parser{} require.NoError(t, parser.Init()) expected, err := testutil.ParseMetricsFromFile(expectedFilename, parser) require.NoError(t, err) // Determine container version for the integration test // The version number is the last element in the filename separated // by a dash and prefixed with a 'v'. image := "solr" parts := strings.Split(fname, "-") if len(parts) > 1 { version := parts[len(parts)-1] require.True(t, strings.HasPrefix(version, "v")) image += ":" + strings.TrimPrefix(version, "v") } // Start the container container := testutil.Container{ Image: image, ExposedPorts: []string{servicePort}, Cmd: []string{"solr-precreate", "main"}, WaitingFor: wait.ForAll( wait.ForListeningPort(nat.Port(servicePort)), wait.ForLog("Registered new searcher"), ), } require.NoError(t, container.Start(), "failed to start container") defer container.Terminate() server := []string{fmt.Sprintf("http://%s:%s", container.Address, container.Ports[servicePort])} // Setup the plugin plugin := &Solr{ Servers: server, HTTPTimeout: config.Duration(5 * time.Second), Log: &testutil.Logger{}, } require.NoError(t, plugin.Init()) // Gather data and compare results var acc testutil.Accumulator require.NoError(t, plugin.Start(&acc)) require.NoError(t, plugin.Gather(&acc)) plugin.Stop() actual := acc.GetTelegrafMetrics() testutil.RequireMetricsStructureEqual(t, expected, actual, options...) }) } } func loadPages(path string) (map[string][]byte, error) { abspath, err := filepath.Abs(path) if err != nil { return nil, err } responses := make(map[string][]byte) err = filepath.Walk(abspath, func(path string, info fs.FileInfo, err error) error { if err != nil { return err } if info.IsDir() || !strings.HasSuffix(path, ".json") { // Ignore directories and files not matching the expectations return nil } relpath, err := filepath.Rel(abspath, path) if err != nil { return err } relpath = strings.TrimSuffix(relpath, ".json") data, err := os.ReadFile(path) if err != nil { return err } responses[filepath.ToSlash(relpath)] = data return nil }) return responses, err }