summaryrefslogtreecommitdiffstats
path: root/src/go/plugin/go.d/modules/memcached/memcached_test.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/plugin/go.d/modules/memcached/memcached_test.go296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/memcached/memcached_test.go b/src/go/plugin/go.d/modules/memcached/memcached_test.go
new file mode 100644
index 000000000..33a85d330
--- /dev/null
+++ b/src/go/plugin/go.d/modules/memcached/memcached_test.go
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package memcached
+
+import (
+ "errors"
+ "os"
+ "testing"
+
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+var (
+ dataConfigJSON, _ = os.ReadFile("testdata/config.json")
+ dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
+
+ dataMemcachedStats, _ = os.ReadFile("testdata/stats.txt")
+)
+
+func Test_testDataIsValid(t *testing.T) {
+ for name, data := range map[string][]byte{
+ "dataConfigJSON": dataConfigJSON,
+ "dataConfigYAML": dataConfigYAML,
+
+ "dataMemcachedStats": dataMemcachedStats,
+ } {
+ require.NotNil(t, data, name)
+ }
+}
+
+func TestMemcached_ConfigurationSerialize(t *testing.T) {
+ module.TestConfigurationSerialize(t, &Memcached{}, dataConfigJSON, dataConfigYAML)
+}
+
+func TestMemcached_Init(t *testing.T) {
+ tests := map[string]struct {
+ config Config
+ wantFail bool
+ }{
+ "success with default config": {
+ wantFail: false,
+ config: New().Config,
+ },
+ "fails if address not set": {
+ wantFail: true,
+ config: func() Config {
+ conf := New().Config
+ conf.Address = ""
+ return conf
+ }(),
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ mem := New()
+ mem.Config = test.config
+
+ if test.wantFail {
+ assert.Error(t, mem.Init())
+ } else {
+ assert.NoError(t, mem.Init())
+ }
+ })
+ }
+}
+
+func TestMemcached_Cleanup(t *testing.T) {
+ tests := map[string]struct {
+ prepare func() *Memcached
+ }{
+ "not initialized": {
+ prepare: func() *Memcached {
+ return New()
+ },
+ },
+ "after check": {
+ prepare: func() *Memcached {
+ mem := New()
+ mem.newMemcachedConn = func(config Config) memcachedConn { return prepareMockOk() }
+ _ = mem.Check()
+ return mem
+ },
+ },
+ "after collect": {
+ prepare: func() *Memcached {
+ mem := New()
+ mem.newMemcachedConn = func(config Config) memcachedConn { return prepareMockOk() }
+ _ = mem.Collect()
+ return mem
+ },
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ mem := test.prepare()
+
+ assert.NotPanics(t, mem.Cleanup)
+ })
+ }
+}
+
+func TestMemcached_Charts(t *testing.T) {
+ assert.NotNil(t, New().Charts())
+}
+
+func TestMemcached_Check(t *testing.T) {
+ tests := map[string]struct {
+ prepareMock func() *mockMemcachedConn
+ wantFail bool
+ }{
+ "success case": {
+ wantFail: false,
+ prepareMock: prepareMockOk,
+ },
+ "err on connect": {
+ wantFail: true,
+ prepareMock: prepareMockErrOnConnect,
+ },
+ "unexpected response": {
+ wantFail: true,
+ prepareMock: prepareMockUnexpectedResponse,
+ },
+ "empty response": {
+ wantFail: true,
+ prepareMock: prepareMockEmptyResponse,
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ mem := New()
+ mock := test.prepareMock()
+ mem.newMemcachedConn = func(config Config) memcachedConn { return mock }
+
+ if test.wantFail {
+ assert.Error(t, mem.Check())
+ } else {
+ assert.NoError(t, mem.Check())
+ }
+ })
+ }
+}
+
+func TestMemcached_Collect(t *testing.T) {
+ tests := map[string]struct {
+ prepareMock func() *mockMemcachedConn
+ wantMetrics map[string]int64
+ disconnectBeforeCleanup bool
+ disconnectAfterCleanup bool
+ }{
+ "success case": {
+ prepareMock: prepareMockOk,
+ disconnectBeforeCleanup: false,
+ disconnectAfterCleanup: true,
+ wantMetrics: map[string]int64{
+ "avail": 67108831,
+ "bytes": 33,
+ "bytes_read": 108662,
+ "bytes_written": 9761348,
+ "cas_badval": 0,
+ "cas_hits": 0,
+ "cas_misses": 0,
+ "cmd_get": 1,
+ "cmd_set": 1,
+ "cmd_touch": 0,
+ "curr_connections": 3,
+ "curr_items": 0,
+ "decr_hits": 0,
+ "decr_misses": 0,
+ "delete_hits": 0,
+ "delete_misses": 0,
+ "evictions": 0,
+ "get_hits": 0,
+ "get_misses": 1,
+ "incr_hits": 0,
+ "incr_misses": 0,
+ "limit_maxbytes": 67108864,
+ "reclaimed": 1,
+ "rejected_connections": 0,
+ "total_connections": 39,
+ "total_items": 1,
+ "touch_hits": 0,
+ "touch_misses": 0,
+ },
+ },
+ "error response": {
+ prepareMock: prepareMockErrorResponse,
+ disconnectBeforeCleanup: false,
+ disconnectAfterCleanup: true,
+ },
+ "unexpected response": {
+ prepareMock: prepareMockUnexpectedResponse,
+ disconnectBeforeCleanup: false,
+ disconnectAfterCleanup: true,
+ },
+ "empty response": {
+ prepareMock: prepareMockEmptyResponse,
+ disconnectBeforeCleanup: false,
+ disconnectAfterCleanup: true,
+ },
+ "err on connect": {
+ prepareMock: prepareMockErrOnConnect,
+ disconnectBeforeCleanup: false,
+ disconnectAfterCleanup: false,
+ },
+ "err on query stats": {
+ prepareMock: prepareMockErrOnQueryStats,
+ disconnectBeforeCleanup: true,
+ disconnectAfterCleanup: true,
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ mem := New()
+ mock := test.prepareMock()
+ mem.newMemcachedConn = func(config Config) memcachedConn { return mock }
+
+ mx := mem.Collect()
+
+ require.Equal(t, test.wantMetrics, mx)
+
+ if len(test.wantMetrics) > 0 {
+ module.TestMetricsHasAllChartsDims(t, mem.Charts(), mx)
+ }
+
+ assert.Equal(t, test.disconnectBeforeCleanup, mock.disconnectCalled, "disconnect before cleanup")
+ mem.Cleanup()
+ assert.Equal(t, test.disconnectAfterCleanup, mock.disconnectCalled, "disconnect after cleanup")
+ })
+ }
+}
+
+func prepareMockOk() *mockMemcachedConn {
+ return &mockMemcachedConn{
+ statsResponse: dataMemcachedStats,
+ }
+}
+
+func prepareMockErrorResponse() *mockMemcachedConn {
+ return &mockMemcachedConn{
+ statsResponse: []byte("ERROR"),
+ }
+}
+
+func prepareMockErrOnConnect() *mockMemcachedConn {
+ return &mockMemcachedConn{
+ errOnConnect: true,
+ }
+}
+
+func prepareMockErrOnQueryStats() *mockMemcachedConn {
+ return &mockMemcachedConn{
+ errOnQueryStats: true,
+ }
+}
+
+func prepareMockUnexpectedResponse() *mockMemcachedConn {
+ return &mockMemcachedConn{
+ statsResponse: []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit."),
+ }
+}
+
+func prepareMockEmptyResponse() *mockMemcachedConn {
+ return &mockMemcachedConn{}
+}
+
+type mockMemcachedConn struct {
+ errOnConnect bool
+ errOnQueryStats bool
+ statsResponse []byte
+ disconnectCalled bool
+}
+
+func (m *mockMemcachedConn) connect() error {
+ if m.errOnConnect {
+ return errors.New("mock.connect() error")
+ }
+ return nil
+}
+
+func (m *mockMemcachedConn) disconnect() {
+ m.disconnectCalled = true
+}
+
+func (m *mockMemcachedConn) queryStats() ([]byte, error) {
+ if m.errOnQueryStats {
+ return nil, errors.New("mock.queryStats() error")
+ }
+ return m.statsResponse, nil
+}