123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- package couchdbreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/couchdbreceiver"
- import (
- "context"
- "encoding/json"
- "errors"
- "os"
- "path"
- "path/filepath"
- "testing"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/stretchr/testify/require"
- "go.opentelemetry.io/collector/component"
- "go.opentelemetry.io/collector/component/componenttest"
- "go.opentelemetry.io/collector/config/confighttp"
- "go.opentelemetry.io/collector/receiver/receivertest"
- "go.opentelemetry.io/collector/receiver/scrapererror"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "go.uber.org/zap/zaptest/observer"
- "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden"
- "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pmetrictest"
- "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/couchdbreceiver/internal/metadata"
- )
- func TestScrape(t *testing.T) {
- f := NewFactory()
- cfg := f.CreateDefaultConfig().(*Config)
- cfg.Username = "otelu"
- cfg.Password = "otelp"
- require.NoError(t, component.ValidateConfig(cfg))
- t.Run("scrape from couchdb version 2.31", func(t *testing.T) {
- mockClient := new(mockClient)
- mockClient.On("GetStats", "_local").Return(getStats("response_2.31.json"))
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- scraper.client = mockClient
- actualMetrics, err := scraper.scrape(context.Background())
- require.NoError(t, err)
- expectedFile := filepath.Join("testdata", "scraper", "expected.yaml")
- expectedMetrics, err := golden.ReadMetrics(expectedFile)
- require.NoError(t, err)
- require.NoError(t, pmetrictest.CompareMetrics(expectedMetrics, actualMetrics,
- pmetrictest.IgnoreMetricDataPointsOrder(), pmetrictest.IgnoreStartTimestamp(), pmetrictest.IgnoreTimestamp()))
- })
- t.Run("scrape from couchdb 3.12", func(t *testing.T) {
- mockClient := new(mockClient)
- mockClient.On("GetStats", "_local").Return(getStats("response_3.12.json"))
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- scraper.client = mockClient
- actualMetrics, err := scraper.scrape(context.Background())
- require.NoError(t, err)
- expectedFile := filepath.Join("testdata", "scraper", "expected.yaml")
- expectedMetrics, err := golden.ReadMetrics(expectedFile)
- require.NoError(t, err)
- require.NoError(t, pmetrictest.CompareMetrics(expectedMetrics, actualMetrics,
- pmetrictest.IgnoreMetricDataPointsOrder(), pmetrictest.IgnoreStartTimestamp(), pmetrictest.IgnoreTimestamp()))
- })
- t.Run("scrape returns nothing", func(t *testing.T) {
- mockClient := new(mockClient)
- mockClient.On("GetStats", "_local").Return(map[string]any{}, nil)
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- scraper.client = mockClient
- metrics, err := scraper.scrape(context.Background())
- require.Error(t, err)
- assert.Equal(t, 0, metrics.DataPointCount(), "Expected 0 datapoints to be collected")
- var partialScrapeErr scrapererror.PartialScrapeError
- require.True(t, errors.As(err, &partialScrapeErr), "returned error was not PartialScrapeError")
- require.True(t, partialScrapeErr.Failed > 0, "Expected scrape failures, but none were recorded!")
- })
- t.Run("scrape error: failed to connect to client", func(t *testing.T) {
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- _, err := scraper.scrape(context.Background())
- require.NotNil(t, err)
- require.Equal(t, err, errors.New("no client available"))
- })
- t.Run("scrape error: get stats endpoint error", func(t *testing.T) {
- obs, logs := observer.New(zap.ErrorLevel)
- settings := receivertest.NewNopCreateSettings()
- settings.Logger = zap.New(obs)
- mockClient := new(mockClient)
- mockClient.On("GetStats", "_local").Return(getStats(""))
- scraper := newCouchdbScraper(settings, cfg)
- scraper.client = mockClient
- _, err := scraper.scrape(context.Background())
- require.NotNil(t, err)
- require.Equal(t, 1, logs.Len())
- require.Equal(t, []observer.LoggedEntry{
- {
- Entry: zapcore.Entry{Level: zap.ErrorLevel, Message: "Failed to fetch couchdb stats"},
- Context: []zapcore.Field{
- zap.String("endpoint", cfg.Endpoint),
- zap.Error(errors.New("bad response")),
- },
- },
- }, logs.AllUntimed())
- })
- }
- func TestStart(t *testing.T) {
- t.Run("start success", func(t *testing.T) {
- f := NewFactory()
- cfg := f.CreateDefaultConfig().(*Config)
- cfg.Username = "otelu"
- cfg.Password = "otelp"
- require.NoError(t, component.ValidateConfig(cfg))
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- err := scraper.start(context.Background(), componenttest.NewNopHost())
- require.NoError(t, err)
- })
- t.Run("start fail", func(t *testing.T) {
- f := NewFactory()
- cfg := f.CreateDefaultConfig().(*Config)
- cfg.HTTPClientSettings.TLSSetting.CAFile = "/non/existent"
- cfg.Username = "otelu"
- cfg.Password = "otelp"
- require.NoError(t, component.ValidateConfig(cfg))
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- err := scraper.start(context.Background(), componenttest.NewNopHost())
- require.NotNil(t, err)
- })
- }
- func TestMetricSettings(t *testing.T) {
- mockClient := new(mockClient)
- mockClient.On("GetStats", "_local").Return(getStats("response_2.31.json"))
- mbc := metadata.DefaultMetricsBuilderConfig()
- mbc.Metrics = metadata.MetricsConfig{
- CouchdbAverageRequestTime: metadata.MetricConfig{Enabled: false},
- CouchdbDatabaseOpen: metadata.MetricConfig{Enabled: false},
- CouchdbDatabaseOperations: metadata.MetricConfig{Enabled: true},
- CouchdbFileDescriptorOpen: metadata.MetricConfig{Enabled: false},
- CouchdbHttpdBulkRequests: metadata.MetricConfig{Enabled: false},
- CouchdbHttpdRequests: metadata.MetricConfig{Enabled: false},
- CouchdbHttpdResponses: metadata.MetricConfig{Enabled: false},
- CouchdbHttpdViews: metadata.MetricConfig{Enabled: false},
- }
- cfg := &Config{
- HTTPClientSettings: confighttp.HTTPClientSettings{},
- MetricsBuilderConfig: mbc,
- }
- scraper := newCouchdbScraper(receivertest.NewNopCreateSettings(), cfg)
- scraper.client = mockClient
- metrics, err := scraper.scrape(context.Background())
- require.NoError(t, err)
- expected, err := golden.ReadMetrics(filepath.Join("testdata", "scraper", "only_db_ops.yaml"))
- require.NoError(t, err)
- require.NoError(t, pmetrictest.CompareMetrics(expected, metrics, pmetrictest.IgnoreMetricDataPointsOrder(),
- pmetrictest.IgnoreStartTimestamp(), pmetrictest.IgnoreTimestamp()))
- require.Equal(t, metrics.MetricCount(), 1)
- }
- func getStats(filename string) (map[string]any, error) {
- var stats map[string]any
- if filename == "" {
- return nil, errors.New("bad response")
- }
- if filename == "empty" {
- _ = json.Unmarshal([]byte{}, &stats)
- return stats, nil
- }
- body, err := os.ReadFile(path.Join("testdata", "scraper", filename))
- if err != nil {
- return nil, err
- }
- err = json.Unmarshal(body, &stats)
- if err != nil {
- return nil, err
- }
- return stats, nil
- }
- // mockClient is an autogenerated mock type for the client type
- type mockClient struct {
- mock.Mock
- }
- // Get provides a mock function with given fields: path
- func (_m *mockClient) Get(path string) ([]byte, error) {
- ret := _m.Called(path)
- var r0 []byte
- if rf, ok := ret.Get(0).(func(string) []byte); ok {
- r0 = rf(path)
- } else if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- var r1 error
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(path)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
- }
- // GetStats provides a mock function with given fields: nodeName
- func (_m *mockClient) GetStats(nodeName string) (map[string]any, error) {
- ret := _m.Called(nodeName)
- var r0 map[string]any
- if rf, ok := ret.Get(0).(func(string) map[string]any); ok {
- r0 = rf(nodeName)
- } else if ret.Get(0) != nil {
- r0 = ret.Get(0).(map[string]any)
- }
- var r1 error
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(nodeName)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
- }
|