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 }