diff options
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/logind/logind_test.go | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/logind/logind_test.go b/src/go/collectors/go.d.plugin/modules/logind/logind_test.go new file mode 100644 index 000000000..7ba6b2258 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/logind_test.go @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +//go:build linux +// +build linux + +package logind + +import ( + "errors" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "github.com/coreos/go-systemd/v22/login1" + "github.com/godbus/dbus/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + } { + require.NotNil(t, data, name) + } +} + +func TestLogind_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &Logind{}, dataConfigJSON, dataConfigYAML) +} + +func TestLogind_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "default config": { + wantFail: false, + config: New().Config, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + l.Config = test.config + + if test.wantFail { + assert.Error(t, l.Init()) + } else { + assert.NoError(t, l.Init()) + } + }) + } +} + +func TestLogind_Charts(t *testing.T) { + assert.Equal(t, len(charts), len(*New().Charts())) +} + +func TestLogind_Cleanup(t *testing.T) { + tests := map[string]struct { + wantClose bool + prepare func(l *Logind) + }{ + "after New": { + wantClose: false, + prepare: func(l *Logind) {}, + }, + "after Init": { + wantClose: false, + prepare: func(l *Logind) { _ = l.Init() }, + }, + "after Check": { + wantClose: true, + prepare: func(l *Logind) { _ = l.Init(); _ = l.Check() }, + }, + "after Collect": { + wantClose: true, + prepare: func(l *Logind) { _ = l.Init(); l.Collect() }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + m := prepareConnOK() + l.newLogindConn = func(Config) (logindConnection, error) { return m, nil } + test.prepare(l) + + require.NotPanics(t, l.Cleanup) + + if test.wantClose { + assert.True(t, m.closeCalled) + } else { + assert.False(t, m.closeCalled) + } + }) + } +} + +func TestLogind_Check(t *testing.T) { + tests := map[string]struct { + wantFail bool + prepare func() *mockConn + }{ + "success when response contains sessions and users": { + wantFail: false, + prepare: prepareConnOK, + }, + "success when response does not contain sessions and users": { + wantFail: false, + prepare: prepareConnOKNoSessionsNoUsers, + }, + "fail when error on list sessions": { + wantFail: true, + prepare: prepareConnErrOnListSessions, + }, + "fail when error on get session properties": { + wantFail: true, + prepare: prepareConnErrOnGetSessionProperties, + }, + "fail when error on list users": { + wantFail: true, + prepare: prepareConnErrOnListUsers, + }, + "fail when error on get user property": { + wantFail: true, + prepare: prepareConnErrOnGetUserProperty, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + require.NoError(t, l.Init()) + l.conn = test.prepare() + + if test.wantFail { + assert.Error(t, l.Check()) + } else { + assert.NoError(t, l.Check()) + } + }) + } +} + +func TestLogind_Collect(t *testing.T) { + tests := map[string]struct { + prepare func() *mockConn + expected map[string]int64 + }{ + "success when response contains sessions and users": { + prepare: prepareConnOK, + expected: map[string]int64{ + "sessions_local": 3, + "sessions_remote": 0, + "sessions_state_active": 0, + "sessions_state_closing": 0, + "sessions_state_online": 3, + "sessions_type_console": 3, + "sessions_type_graphical": 0, + "sessions_type_other": 0, + "users_state_active": 3, + "users_state_closing": 0, + "users_state_lingering": 0, + "users_state_offline": 0, + "users_state_online": 0, + }, + }, + "success when response does not contain sessions and users": { + prepare: prepareConnOKNoSessionsNoUsers, + expected: map[string]int64{ + "sessions_local": 0, + "sessions_remote": 0, + "sessions_state_active": 0, + "sessions_state_closing": 0, + "sessions_state_online": 0, + "sessions_type_console": 0, + "sessions_type_graphical": 0, + "sessions_type_other": 0, + "users_state_active": 0, + "users_state_closing": 0, + "users_state_lingering": 0, + "users_state_offline": 0, + "users_state_online": 0, + }, + }, + "fail when error on list sessions": { + prepare: prepareConnErrOnListSessions, + expected: map[string]int64(nil), + }, + "fail when error on get session properties": { + prepare: prepareConnErrOnGetSessionProperties, + expected: map[string]int64(nil), + }, + "fail when error on list users": { + prepare: prepareConnErrOnListUsers, + expected: map[string]int64(nil), + }, + "fail when error on get user property": { + prepare: prepareConnErrOnGetUserProperty, + expected: map[string]int64(nil), + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + require.NoError(t, l.Init()) + l.conn = test.prepare() + + mx := l.Collect() + + assert.Equal(t, test.expected, mx) + }) + } +} + +func prepareConnOK() *mockConn { + return &mockConn{ + sessions: []login1.Session{ + {Path: "/org/freedesktop/login1/session/_3156", User: "user1", ID: "123"}, + {Path: "/org/freedesktop/login1/session/_3157", User: "user2", ID: "124"}, + {Path: "/org/freedesktop/login1/session/_3158", User: "user3", ID: "125"}, + }, + users: []login1.User{ + {Path: "/org/freedesktop/login1/user/_1000", Name: "user1", UID: 123}, + {Path: "/org/freedesktop/login1/user/_1001", Name: "user2", UID: 124}, + {Path: "/org/freedesktop/login1/user/_1002", Name: "user3", UID: 125}, + }, + errOnListSessions: false, + errOnGetSessionProperties: false, + errOnListUsers: false, + errOnGetUserProperty: false, + closeCalled: false, + } +} + +func prepareConnOKNoSessionsNoUsers() *mockConn { + conn := prepareConnOK() + conn.sessions = nil + conn.users = nil + return conn +} + +func prepareConnErrOnListSessions() *mockConn { + conn := prepareConnOK() + conn.errOnListSessions = true + return conn +} + +func prepareConnErrOnGetSessionProperties() *mockConn { + conn := prepareConnOK() + conn.errOnGetSessionProperties = true + return conn +} + +func prepareConnErrOnListUsers() *mockConn { + conn := prepareConnOK() + conn.errOnListUsers = true + return conn +} + +func prepareConnErrOnGetUserProperty() *mockConn { + conn := prepareConnOK() + conn.errOnGetUserProperty = true + return conn +} + +type mockConn struct { + sessions []login1.Session + users []login1.User + + errOnListSessions bool + errOnGetSessionProperties bool + errOnListUsers bool + errOnGetUserProperty bool + closeCalled bool +} + +func (m *mockConn) Close() { + m.closeCalled = true +} + +func (m *mockConn) ListSessions() ([]login1.Session, error) { + if m.errOnListSessions { + return nil, errors.New("mock.ListSessions() error") + } + return m.sessions, nil +} + +func (m *mockConn) GetSessionProperties(path dbus.ObjectPath) (map[string]dbus.Variant, error) { + if m.errOnGetSessionProperties { + return nil, errors.New("mock.GetSessionProperties() error") + } + + var found bool + for _, s := range m.sessions { + if s.Path == path { + found = true + break + } + } + + if !found { + return nil, errors.New("mock.GetUserProperty(): session is not found") + } + + return map[string]dbus.Variant{ + "Remote": dbus.MakeVariant("true"), + "Type": dbus.MakeVariant("tty"), + "State": dbus.MakeVariant("online"), + }, nil +} + +func (m *mockConn) ListUsers() ([]login1.User, error) { + if m.errOnListUsers { + return nil, errors.New("mock.ListUsers() error") + } + return m.users, nil +} + +func (m *mockConn) GetUserProperty(path dbus.ObjectPath, _ string) (*dbus.Variant, error) { + if m.errOnGetUserProperty { + return nil, errors.New("mock.GetUserProperty() error") + } + + var found bool + for _, u := range m.users { + if u.Path == path { + found = true + break + } + } + + if !found { + return nil, errors.New("mock.GetUserProperty(): user is not found") + } + + v := dbus.MakeVariant("active") + return &v, nil +} |