github.com/netdata/go.d.plugin@v0.58.1/modules/logind/logind_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  //go:build linux
     4  // +build linux
     5  
     6  package logind
     7  
     8  import (
     9  	"errors"
    10  	"testing"
    11  
    12  	"github.com/coreos/go-systemd/v22/login1"
    13  	"github.com/godbus/dbus/v5"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestLogind_Init(t *testing.T) {
    19  	tests := map[string]struct {
    20  		config   Config
    21  		wantFail bool
    22  	}{
    23  		"default config": {
    24  			wantFail: false,
    25  			config:   New().Config,
    26  		},
    27  	}
    28  
    29  	for name, test := range tests {
    30  		t.Run(name, func(t *testing.T) {
    31  			l := New()
    32  			l.Config = test.config
    33  
    34  			if test.wantFail {
    35  				assert.False(t, l.Init())
    36  			} else {
    37  				assert.True(t, l.Init())
    38  			}
    39  		})
    40  	}
    41  }
    42  
    43  func TestLogind_Charts(t *testing.T) {
    44  	assert.Equal(t, len(charts), len(*New().Charts()))
    45  }
    46  
    47  func TestLogind_Cleanup(t *testing.T) {
    48  	tests := map[string]struct {
    49  		wantClose bool
    50  		prepare   func(l *Logind)
    51  	}{
    52  		"after New": {
    53  			wantClose: false,
    54  			prepare:   func(l *Logind) {},
    55  		},
    56  		"after Init": {
    57  			wantClose: false,
    58  			prepare:   func(l *Logind) { l.Init() },
    59  		},
    60  		"after Check": {
    61  			wantClose: true,
    62  			prepare:   func(l *Logind) { l.Init(); l.Check() },
    63  		},
    64  		"after Collect": {
    65  			wantClose: true,
    66  			prepare:   func(l *Logind) { l.Init(); l.Collect() },
    67  		},
    68  	}
    69  
    70  	for name, test := range tests {
    71  		t.Run(name, func(t *testing.T) {
    72  			l := New()
    73  			m := prepareConnOK()
    74  			l.newLogindConn = func(Config) (logindConnection, error) { return m, nil }
    75  			test.prepare(l)
    76  
    77  			require.NotPanics(t, l.Cleanup)
    78  
    79  			if test.wantClose {
    80  				assert.True(t, m.closeCalled)
    81  			} else {
    82  				assert.False(t, m.closeCalled)
    83  			}
    84  		})
    85  	}
    86  }
    87  
    88  func TestLogind_Check(t *testing.T) {
    89  	tests := map[string]struct {
    90  		wantFail bool
    91  		prepare  func() *mockConn
    92  	}{
    93  		"success when response contains sessions and users": {
    94  			wantFail: false,
    95  			prepare:  prepareConnOK,
    96  		},
    97  		"success when response does not contain sessions and users": {
    98  			wantFail: false,
    99  			prepare:  prepareConnOKNoSessionsNoUsers,
   100  		},
   101  		"fail when error on list sessions": {
   102  			wantFail: true,
   103  			prepare:  prepareConnErrOnListSessions,
   104  		},
   105  		"fail when error on get session properties": {
   106  			wantFail: true,
   107  			prepare:  prepareConnErrOnGetSessionProperties,
   108  		},
   109  		"fail when error on list users": {
   110  			wantFail: true,
   111  			prepare:  prepareConnErrOnListUsers,
   112  		},
   113  		"fail when error on get user property": {
   114  			wantFail: true,
   115  			prepare:  prepareConnErrOnGetUserProperty,
   116  		},
   117  	}
   118  
   119  	for name, test := range tests {
   120  		t.Run(name, func(t *testing.T) {
   121  			l := New()
   122  			require.True(t, l.Init())
   123  			l.conn = test.prepare()
   124  
   125  			if test.wantFail {
   126  				assert.False(t, l.Check())
   127  			} else {
   128  				assert.True(t, l.Check())
   129  			}
   130  		})
   131  	}
   132  }
   133  
   134  func TestLogind_Collect(t *testing.T) {
   135  	tests := map[string]struct {
   136  		prepare  func() *mockConn
   137  		expected map[string]int64
   138  	}{
   139  		"success when response contains sessions and users": {
   140  			prepare: prepareConnOK,
   141  			expected: map[string]int64{
   142  				"sessions_local":          3,
   143  				"sessions_remote":         0,
   144  				"sessions_state_active":   0,
   145  				"sessions_state_closing":  0,
   146  				"sessions_state_online":   3,
   147  				"sessions_type_console":   3,
   148  				"sessions_type_graphical": 0,
   149  				"sessions_type_other":     0,
   150  				"users_state_active":      3,
   151  				"users_state_closing":     0,
   152  				"users_state_lingering":   0,
   153  				"users_state_offline":     0,
   154  				"users_state_online":      0,
   155  			},
   156  		},
   157  		"success when response does not contain sessions and users": {
   158  			prepare: prepareConnOKNoSessionsNoUsers,
   159  			expected: map[string]int64{
   160  				"sessions_local":          0,
   161  				"sessions_remote":         0,
   162  				"sessions_state_active":   0,
   163  				"sessions_state_closing":  0,
   164  				"sessions_state_online":   0,
   165  				"sessions_type_console":   0,
   166  				"sessions_type_graphical": 0,
   167  				"sessions_type_other":     0,
   168  				"users_state_active":      0,
   169  				"users_state_closing":     0,
   170  				"users_state_lingering":   0,
   171  				"users_state_offline":     0,
   172  				"users_state_online":      0,
   173  			},
   174  		},
   175  		"fail when error on list sessions": {
   176  			prepare:  prepareConnErrOnListSessions,
   177  			expected: map[string]int64(nil),
   178  		},
   179  		"fail when error on get session properties": {
   180  			prepare:  prepareConnErrOnGetSessionProperties,
   181  			expected: map[string]int64(nil),
   182  		},
   183  		"fail when error on list users": {
   184  			prepare:  prepareConnErrOnListUsers,
   185  			expected: map[string]int64(nil),
   186  		},
   187  		"fail when error on get user property": {
   188  			prepare:  prepareConnErrOnGetUserProperty,
   189  			expected: map[string]int64(nil),
   190  		},
   191  	}
   192  
   193  	for name, test := range tests {
   194  		t.Run(name, func(t *testing.T) {
   195  			l := New()
   196  			require.True(t, l.Init())
   197  			l.conn = test.prepare()
   198  
   199  			mx := l.Collect()
   200  
   201  			assert.Equal(t, test.expected, mx)
   202  		})
   203  	}
   204  }
   205  
   206  func prepareConnOK() *mockConn {
   207  	return &mockConn{
   208  		sessions: []login1.Session{
   209  			{Path: "/org/freedesktop/login1/session/_3156", User: "user1", ID: "123"},
   210  			{Path: "/org/freedesktop/login1/session/_3157", User: "user2", ID: "124"},
   211  			{Path: "/org/freedesktop/login1/session/_3158", User: "user3", ID: "125"},
   212  		},
   213  		users: []login1.User{
   214  			{Path: "/org/freedesktop/login1/user/_1000", Name: "user1", UID: 123},
   215  			{Path: "/org/freedesktop/login1/user/_1001", Name: "user2", UID: 124},
   216  			{Path: "/org/freedesktop/login1/user/_1002", Name: "user3", UID: 125},
   217  		},
   218  		errOnListSessions:         false,
   219  		errOnGetSessionProperties: false,
   220  		errOnListUsers:            false,
   221  		errOnGetUserProperty:      false,
   222  		closeCalled:               false,
   223  	}
   224  }
   225  
   226  func prepareConnOKNoSessionsNoUsers() *mockConn {
   227  	conn := prepareConnOK()
   228  	conn.sessions = nil
   229  	conn.users = nil
   230  	return conn
   231  }
   232  
   233  func prepareConnErrOnListSessions() *mockConn {
   234  	conn := prepareConnOK()
   235  	conn.errOnListSessions = true
   236  	return conn
   237  }
   238  
   239  func prepareConnErrOnGetSessionProperties() *mockConn {
   240  	conn := prepareConnOK()
   241  	conn.errOnGetSessionProperties = true
   242  	return conn
   243  }
   244  
   245  func prepareConnErrOnListUsers() *mockConn {
   246  	conn := prepareConnOK()
   247  	conn.errOnListUsers = true
   248  	return conn
   249  }
   250  
   251  func prepareConnErrOnGetUserProperty() *mockConn {
   252  	conn := prepareConnOK()
   253  	conn.errOnGetUserProperty = true
   254  	return conn
   255  }
   256  
   257  type mockConn struct {
   258  	sessions []login1.Session
   259  	users    []login1.User
   260  
   261  	errOnListSessions         bool
   262  	errOnGetSessionProperties bool
   263  	errOnListUsers            bool
   264  	errOnGetUserProperty      bool
   265  	closeCalled               bool
   266  }
   267  
   268  func (m *mockConn) Close() {
   269  	m.closeCalled = true
   270  }
   271  
   272  func (m *mockConn) ListSessions() ([]login1.Session, error) {
   273  	if m.errOnListSessions {
   274  		return nil, errors.New("mock.ListSessions() error")
   275  	}
   276  	return m.sessions, nil
   277  }
   278  
   279  func (m *mockConn) GetSessionProperties(path dbus.ObjectPath) (map[string]dbus.Variant, error) {
   280  	if m.errOnGetSessionProperties {
   281  		return nil, errors.New("mock.GetSessionProperties() error")
   282  	}
   283  
   284  	var found bool
   285  	for _, s := range m.sessions {
   286  		if s.Path == path {
   287  			found = true
   288  			break
   289  		}
   290  	}
   291  
   292  	if !found {
   293  		return nil, errors.New("mock.GetUserProperty(): session is not found")
   294  	}
   295  
   296  	return map[string]dbus.Variant{
   297  		"Remote": dbus.MakeVariant("true"),
   298  		"Type":   dbus.MakeVariant("tty"),
   299  		"State":  dbus.MakeVariant("online"),
   300  	}, nil
   301  }
   302  
   303  func (m *mockConn) ListUsers() ([]login1.User, error) {
   304  	if m.errOnListUsers {
   305  		return nil, errors.New("mock.ListUsers() error")
   306  	}
   307  	return m.users, nil
   308  }
   309  
   310  func (m *mockConn) GetUserProperty(path dbus.ObjectPath, _ string) (*dbus.Variant, error) {
   311  	if m.errOnGetUserProperty {
   312  		return nil, errors.New("mock.GetUserProperty() error")
   313  	}
   314  
   315  	var found bool
   316  	for _, u := range m.users {
   317  		if u.Path == path {
   318  			found = true
   319  			break
   320  		}
   321  	}
   322  
   323  	if !found {
   324  		return nil, errors.New("mock.GetUserProperty(): user is not found")
   325  	}
   326  
   327  	v := dbus.MakeVariant("active")
   328  	return &v, nil
   329  }