github.com/netdata/go.d.plugin@v0.58.1/modules/systemdunits/systemdunits_test.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 //go:build linux 4 // +build linux 5 6 package systemdunits 7 8 import ( 9 "context" 10 "errors" 11 "fmt" 12 "path/filepath" 13 "testing" 14 15 "github.com/netdata/go.d.plugin/agent/module" 16 17 "github.com/coreos/go-systemd/v22/dbus" 18 "github.com/stretchr/testify/assert" 19 "github.com/stretchr/testify/require" 20 ) 21 22 func TestNew(t *testing.T) { 23 assert.Implements(t, (*module.Module)(nil), New()) 24 } 25 26 func TestSystemdUnits_Init(t *testing.T) { 27 tests := map[string]struct { 28 config Config 29 wantFail bool 30 }{ 31 "success on default config": { 32 config: New().Config, 33 }, 34 "success when 'include' option set": { 35 config: Config{ 36 Include: []string{"*"}, 37 }, 38 }, 39 "fails when 'include' option not set": { 40 wantFail: true, 41 config: Config{Include: []string{}}, 42 }, 43 } 44 45 for name, test := range tests { 46 t.Run(name, func(t *testing.T) { 47 systemd := New() 48 systemd.Config = test.config 49 50 if test.wantFail { 51 assert.False(t, systemd.Init()) 52 } else { 53 assert.True(t, systemd.Init()) 54 } 55 }) 56 } 57 } 58 59 func TestSystemdUnits_Check(t *testing.T) { 60 tests := map[string]struct { 61 prepare func() *SystemdUnits 62 wantFail bool 63 }{ 64 "success on systemd v230+": { 65 prepare: func() *SystemdUnits { 66 systemd := New() 67 systemd.Include = []string{"*"} 68 systemd.client = prepareOKClient(230) 69 return systemd 70 }, 71 }, 72 "success on systemd v230-": { 73 prepare: func() *SystemdUnits { 74 systemd := New() 75 systemd.Include = []string{"*"} 76 systemd.client = prepareOKClient(220) 77 return systemd 78 }, 79 }, 80 "fails when all unites are filtered": { 81 wantFail: true, 82 prepare: func() *SystemdUnits { 83 systemd := New() 84 systemd.Include = []string{"*.not_exists"} 85 systemd.client = prepareOKClient(230) 86 return systemd 87 }, 88 }, 89 "fails on error on connect": { 90 wantFail: true, 91 prepare: func() *SystemdUnits { 92 systemd := New() 93 systemd.client = prepareClientErrOnConnect() 94 return systemd 95 }, 96 }, 97 "fails on error on get manager property": { 98 wantFail: true, 99 prepare: func() *SystemdUnits { 100 systemd := New() 101 systemd.client = prepareClientErrOnGetManagerProperty() 102 return systemd 103 }, 104 }, 105 "fails on error on list units": { 106 wantFail: true, 107 prepare: func() *SystemdUnits { 108 systemd := New() 109 systemd.client = prepareClientErrOnListUnits() 110 return systemd 111 }, 112 }, 113 } 114 115 for name, test := range tests { 116 t.Run(name, func(t *testing.T) { 117 systemd := test.prepare() 118 require.True(t, systemd.Init()) 119 120 if test.wantFail { 121 assert.False(t, systemd.Check()) 122 } else { 123 assert.True(t, systemd.Check()) 124 } 125 }) 126 } 127 } 128 129 func TestSystemdUnits_Charts(t *testing.T) { 130 systemd := New() 131 require.True(t, systemd.Init()) 132 assert.NotNil(t, systemd.Charts()) 133 } 134 135 func TestSystemdUnits_Cleanup(t *testing.T) { 136 systemd := New() 137 systemd.Include = []string{"*"} 138 client := prepareOKClient(230) 139 systemd.client = client 140 141 require.True(t, systemd.Init()) 142 require.NotNil(t, systemd.Collect()) 143 conn := systemd.conn 144 systemd.Cleanup() 145 146 assert.Nil(t, systemd.conn) 147 v, _ := conn.(*mockConn) 148 assert.True(t, v.closeCalled) 149 } 150 151 func TestSystemdUnits_Collect(t *testing.T) { 152 tests := map[string]struct { 153 prepare func() *SystemdUnits 154 wantCollected map[string]int64 155 }{ 156 "success on systemd v230+ on collecting all unit type": { 157 prepare: func() *SystemdUnits { 158 systemd := New() 159 systemd.Include = []string{"*"} 160 systemd.client = prepareOKClient(230) 161 return systemd 162 }, 163 wantCollected: map[string]int64{ 164 "unit_dbus_socket_state_activating": 0, 165 "unit_dbus_socket_state_active": 1, 166 "unit_dbus_socket_state_deactivating": 0, 167 "unit_dbus_socket_state_failed": 0, 168 "unit_dbus_socket_state_inactive": 0, 169 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_activating": 0, 170 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_active": 1, 171 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_deactivating": 0, 172 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_failed": 0, 173 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_inactive": 0, 174 "unit_dev-nvme0n1_device_state_activating": 0, 175 "unit_dev-nvme0n1_device_state_active": 1, 176 "unit_dev-nvme0n1_device_state_deactivating": 0, 177 "unit_dev-nvme0n1_device_state_failed": 0, 178 "unit_dev-nvme0n1_device_state_inactive": 0, 179 "unit_docker_socket_state_activating": 0, 180 "unit_docker_socket_state_active": 1, 181 "unit_docker_socket_state_deactivating": 0, 182 "unit_docker_socket_state_failed": 0, 183 "unit_docker_socket_state_inactive": 0, 184 "unit_getty-pre_target_state_activating": 0, 185 "unit_getty-pre_target_state_active": 0, 186 "unit_getty-pre_target_state_deactivating": 0, 187 "unit_getty-pre_target_state_failed": 0, 188 "unit_getty-pre_target_state_inactive": 1, 189 "unit_init_scope_state_activating": 0, 190 "unit_init_scope_state_active": 1, 191 "unit_init_scope_state_deactivating": 0, 192 "unit_init_scope_state_failed": 0, 193 "unit_init_scope_state_inactive": 0, 194 "unit_logrotate_timer_state_activating": 0, 195 "unit_logrotate_timer_state_active": 1, 196 "unit_logrotate_timer_state_deactivating": 0, 197 "unit_logrotate_timer_state_failed": 0, 198 "unit_logrotate_timer_state_inactive": 0, 199 "unit_lvm2-lvmetad_socket_state_activating": 0, 200 "unit_lvm2-lvmetad_socket_state_active": 1, 201 "unit_lvm2-lvmetad_socket_state_deactivating": 0, 202 "unit_lvm2-lvmetad_socket_state_failed": 0, 203 "unit_lvm2-lvmetad_socket_state_inactive": 0, 204 "unit_lvm2-lvmpolld_socket_state_activating": 0, 205 "unit_lvm2-lvmpolld_socket_state_active": 1, 206 "unit_lvm2-lvmpolld_socket_state_deactivating": 0, 207 "unit_lvm2-lvmpolld_socket_state_failed": 0, 208 "unit_lvm2-lvmpolld_socket_state_inactive": 0, 209 "unit_man-db_timer_state_activating": 0, 210 "unit_man-db_timer_state_active": 1, 211 "unit_man-db_timer_state_deactivating": 0, 212 "unit_man-db_timer_state_failed": 0, 213 "unit_man-db_timer_state_inactive": 0, 214 "unit_org.cups.cupsd_path_state_activating": 0, 215 "unit_org.cups.cupsd_path_state_active": 1, 216 "unit_org.cups.cupsd_path_state_deactivating": 0, 217 "unit_org.cups.cupsd_path_state_failed": 0, 218 "unit_org.cups.cupsd_path_state_inactive": 0, 219 "unit_pamac-cleancache_timer_state_activating": 0, 220 "unit_pamac-cleancache_timer_state_active": 1, 221 "unit_pamac-cleancache_timer_state_deactivating": 0, 222 "unit_pamac-cleancache_timer_state_failed": 0, 223 "unit_pamac-cleancache_timer_state_inactive": 0, 224 "unit_pamac-mirrorlist_timer_state_activating": 0, 225 "unit_pamac-mirrorlist_timer_state_active": 1, 226 "unit_pamac-mirrorlist_timer_state_deactivating": 0, 227 "unit_pamac-mirrorlist_timer_state_failed": 0, 228 "unit_pamac-mirrorlist_timer_state_inactive": 0, 229 "unit_proc-sys-fs-binfmt_misc_automount_state_activating": 0, 230 "unit_proc-sys-fs-binfmt_misc_automount_state_active": 1, 231 "unit_proc-sys-fs-binfmt_misc_automount_state_deactivating": 0, 232 "unit_proc-sys-fs-binfmt_misc_automount_state_failed": 0, 233 "unit_proc-sys-fs-binfmt_misc_automount_state_inactive": 0, 234 "unit_remote-fs-pre_target_state_activating": 0, 235 "unit_remote-fs-pre_target_state_active": 0, 236 "unit_remote-fs-pre_target_state_deactivating": 0, 237 "unit_remote-fs-pre_target_state_failed": 0, 238 "unit_remote-fs-pre_target_state_inactive": 1, 239 "unit_rpc_pipefs_target_state_activating": 0, 240 "unit_rpc_pipefs_target_state_active": 0, 241 "unit_rpc_pipefs_target_state_deactivating": 0, 242 "unit_rpc_pipefs_target_state_failed": 0, 243 "unit_rpc_pipefs_target_state_inactive": 1, 244 "unit_run-user-1000-gvfs_mount_state_activating": 0, 245 "unit_run-user-1000-gvfs_mount_state_active": 1, 246 "unit_run-user-1000-gvfs_mount_state_deactivating": 0, 247 "unit_run-user-1000-gvfs_mount_state_failed": 0, 248 "unit_run-user-1000-gvfs_mount_state_inactive": 0, 249 "unit_run-user-1000_mount_state_activating": 0, 250 "unit_run-user-1000_mount_state_active": 1, 251 "unit_run-user-1000_mount_state_deactivating": 0, 252 "unit_run-user-1000_mount_state_failed": 0, 253 "unit_run-user-1000_mount_state_inactive": 0, 254 "unit_session-1_scope_state_activating": 0, 255 "unit_session-1_scope_state_active": 1, 256 "unit_session-1_scope_state_deactivating": 0, 257 "unit_session-1_scope_state_failed": 0, 258 "unit_session-1_scope_state_inactive": 0, 259 "unit_session-2_scope_state_activating": 0, 260 "unit_session-2_scope_state_active": 1, 261 "unit_session-2_scope_state_deactivating": 0, 262 "unit_session-2_scope_state_failed": 0, 263 "unit_session-2_scope_state_inactive": 0, 264 "unit_session-3_scope_state_activating": 0, 265 "unit_session-3_scope_state_active": 1, 266 "unit_session-3_scope_state_deactivating": 0, 267 "unit_session-3_scope_state_failed": 0, 268 "unit_session-3_scope_state_inactive": 0, 269 "unit_session-6_scope_state_activating": 0, 270 "unit_session-6_scope_state_active": 1, 271 "unit_session-6_scope_state_deactivating": 0, 272 "unit_session-6_scope_state_failed": 0, 273 "unit_session-6_scope_state_inactive": 0, 274 "unit_shadow_timer_state_activating": 0, 275 "unit_shadow_timer_state_active": 1, 276 "unit_shadow_timer_state_deactivating": 0, 277 "unit_shadow_timer_state_failed": 0, 278 "unit_shadow_timer_state_inactive": 0, 279 "unit_sound_target_state_activating": 0, 280 "unit_sound_target_state_active": 1, 281 "unit_sound_target_state_deactivating": 0, 282 "unit_sound_target_state_failed": 0, 283 "unit_sound_target_state_inactive": 0, 284 "unit_sys-devices-virtual-net-loopback1_device_state_activating": 0, 285 "unit_sys-devices-virtual-net-loopback1_device_state_active": 1, 286 "unit_sys-devices-virtual-net-loopback1_device_state_deactivating": 0, 287 "unit_sys-devices-virtual-net-loopback1_device_state_failed": 0, 288 "unit_sys-devices-virtual-net-loopback1_device_state_inactive": 0, 289 "unit_sys-module-fuse_device_state_activating": 0, 290 "unit_sys-module-fuse_device_state_active": 1, 291 "unit_sys-module-fuse_device_state_deactivating": 0, 292 "unit_sys-module-fuse_device_state_failed": 0, 293 "unit_sys-module-fuse_device_state_inactive": 0, 294 "unit_sysinit_target_state_activating": 0, 295 "unit_sysinit_target_state_active": 1, 296 "unit_sysinit_target_state_deactivating": 0, 297 "unit_sysinit_target_state_failed": 0, 298 "unit_sysinit_target_state_inactive": 0, 299 "unit_system-getty_slice_state_activating": 0, 300 "unit_system-getty_slice_state_active": 1, 301 "unit_system-getty_slice_state_deactivating": 0, 302 "unit_system-getty_slice_state_failed": 0, 303 "unit_system-getty_slice_state_inactive": 0, 304 "unit_system-netctl_slice_state_activating": 0, 305 "unit_system-netctl_slice_state_active": 1, 306 "unit_system-netctl_slice_state_deactivating": 0, 307 "unit_system-netctl_slice_state_failed": 0, 308 "unit_system-netctl_slice_state_inactive": 0, 309 "unit_system-systemd-fsck_slice_state_activating": 0, 310 "unit_system-systemd-fsck_slice_state_active": 1, 311 "unit_system-systemd-fsck_slice_state_deactivating": 0, 312 "unit_system-systemd-fsck_slice_state_failed": 0, 313 "unit_system-systemd-fsck_slice_state_inactive": 0, 314 "unit_system_slice_state_activating": 0, 315 "unit_system_slice_state_active": 1, 316 "unit_system_slice_state_deactivating": 0, 317 "unit_system_slice_state_failed": 0, 318 "unit_system_slice_state_inactive": 0, 319 "unit_systemd-ask-password-console_path_state_activating": 0, 320 "unit_systemd-ask-password-console_path_state_active": 1, 321 "unit_systemd-ask-password-console_path_state_deactivating": 0, 322 "unit_systemd-ask-password-console_path_state_failed": 0, 323 "unit_systemd-ask-password-console_path_state_inactive": 0, 324 "unit_systemd-ask-password-wall_path_state_activating": 0, 325 "unit_systemd-ask-password-wall_path_state_active": 1, 326 "unit_systemd-ask-password-wall_path_state_deactivating": 0, 327 "unit_systemd-ask-password-wall_path_state_failed": 0, 328 "unit_systemd-ask-password-wall_path_state_inactive": 0, 329 "unit_systemd-ask-password-wall_service_state_activating": 0, 330 "unit_systemd-ask-password-wall_service_state_active": 0, 331 "unit_systemd-ask-password-wall_service_state_deactivating": 0, 332 "unit_systemd-ask-password-wall_service_state_failed": 0, 333 "unit_systemd-ask-password-wall_service_state_inactive": 1, 334 "unit_systemd-fsck-root_service_state_activating": 0, 335 "unit_systemd-fsck-root_service_state_active": 0, 336 "unit_systemd-fsck-root_service_state_deactivating": 0, 337 "unit_systemd-fsck-root_service_state_failed": 0, 338 "unit_systemd-fsck-root_service_state_inactive": 1, 339 "unit_systemd-udevd-kernel_socket_state_activating": 0, 340 "unit_systemd-udevd-kernel_socket_state_active": 1, 341 "unit_systemd-udevd-kernel_socket_state_deactivating": 0, 342 "unit_systemd-udevd-kernel_socket_state_failed": 0, 343 "unit_systemd-udevd-kernel_socket_state_inactive": 0, 344 "unit_tmp_mount_state_activating": 0, 345 "unit_tmp_mount_state_active": 1, 346 "unit_tmp_mount_state_deactivating": 0, 347 "unit_tmp_mount_state_failed": 0, 348 "unit_tmp_mount_state_inactive": 0, 349 "unit_user-runtime-dir@1000_service_state_activating": 0, 350 "unit_user-runtime-dir@1000_service_state_active": 1, 351 "unit_user-runtime-dir@1000_service_state_deactivating": 0, 352 "unit_user-runtime-dir@1000_service_state_failed": 0, 353 "unit_user-runtime-dir@1000_service_state_inactive": 0, 354 "unit_user@1000_service_state_activating": 0, 355 "unit_user@1000_service_state_active": 1, 356 "unit_user@1000_service_state_deactivating": 0, 357 "unit_user@1000_service_state_failed": 0, 358 "unit_user@1000_service_state_inactive": 0, 359 "unit_user_slice_state_activating": 0, 360 "unit_user_slice_state_active": 1, 361 "unit_user_slice_state_deactivating": 0, 362 "unit_user_slice_state_failed": 0, 363 "unit_user_slice_state_inactive": 0, 364 "unit_var-lib-nfs-rpc_pipefs_mount_state_activating": 0, 365 "unit_var-lib-nfs-rpc_pipefs_mount_state_active": 0, 366 "unit_var-lib-nfs-rpc_pipefs_mount_state_deactivating": 0, 367 "unit_var-lib-nfs-rpc_pipefs_mount_state_failed": 0, 368 "unit_var-lib-nfs-rpc_pipefs_mount_state_inactive": 1, 369 }, 370 }, 371 "success on systemd v230- on collecting all unit types": { 372 prepare: func() *SystemdUnits { 373 systemd := New() 374 systemd.Include = []string{"*"} 375 systemd.client = prepareOKClient(220) 376 return systemd 377 }, 378 wantCollected: map[string]int64{ 379 "unit_dbus_socket_state_activating": 0, 380 "unit_dbus_socket_state_active": 1, 381 "unit_dbus_socket_state_deactivating": 0, 382 "unit_dbus_socket_state_failed": 0, 383 "unit_dbus_socket_state_inactive": 0, 384 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_activating": 0, 385 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_active": 1, 386 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_deactivating": 0, 387 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_failed": 0, 388 "unit_dev-disk-by-uuid-DE44-CEE0_device_state_inactive": 0, 389 "unit_dev-nvme0n1_device_state_activating": 0, 390 "unit_dev-nvme0n1_device_state_active": 1, 391 "unit_dev-nvme0n1_device_state_deactivating": 0, 392 "unit_dev-nvme0n1_device_state_failed": 0, 393 "unit_dev-nvme0n1_device_state_inactive": 0, 394 "unit_docker_socket_state_activating": 0, 395 "unit_docker_socket_state_active": 1, 396 "unit_docker_socket_state_deactivating": 0, 397 "unit_docker_socket_state_failed": 0, 398 "unit_docker_socket_state_inactive": 0, 399 "unit_getty-pre_target_state_activating": 0, 400 "unit_getty-pre_target_state_active": 0, 401 "unit_getty-pre_target_state_deactivating": 0, 402 "unit_getty-pre_target_state_failed": 0, 403 "unit_getty-pre_target_state_inactive": 1, 404 "unit_init_scope_state_activating": 0, 405 "unit_init_scope_state_active": 1, 406 "unit_init_scope_state_deactivating": 0, 407 "unit_init_scope_state_failed": 0, 408 "unit_init_scope_state_inactive": 0, 409 "unit_logrotate_timer_state_activating": 0, 410 "unit_logrotate_timer_state_active": 1, 411 "unit_logrotate_timer_state_deactivating": 0, 412 "unit_logrotate_timer_state_failed": 0, 413 "unit_logrotate_timer_state_inactive": 0, 414 "unit_lvm2-lvmetad_socket_state_activating": 0, 415 "unit_lvm2-lvmetad_socket_state_active": 1, 416 "unit_lvm2-lvmetad_socket_state_deactivating": 0, 417 "unit_lvm2-lvmetad_socket_state_failed": 0, 418 "unit_lvm2-lvmetad_socket_state_inactive": 0, 419 "unit_lvm2-lvmpolld_socket_state_activating": 0, 420 "unit_lvm2-lvmpolld_socket_state_active": 1, 421 "unit_lvm2-lvmpolld_socket_state_deactivating": 0, 422 "unit_lvm2-lvmpolld_socket_state_failed": 0, 423 "unit_lvm2-lvmpolld_socket_state_inactive": 0, 424 "unit_man-db_timer_state_activating": 0, 425 "unit_man-db_timer_state_active": 1, 426 "unit_man-db_timer_state_deactivating": 0, 427 "unit_man-db_timer_state_failed": 0, 428 "unit_man-db_timer_state_inactive": 0, 429 "unit_org.cups.cupsd_path_state_activating": 0, 430 "unit_org.cups.cupsd_path_state_active": 1, 431 "unit_org.cups.cupsd_path_state_deactivating": 0, 432 "unit_org.cups.cupsd_path_state_failed": 0, 433 "unit_org.cups.cupsd_path_state_inactive": 0, 434 "unit_pamac-cleancache_timer_state_activating": 0, 435 "unit_pamac-cleancache_timer_state_active": 1, 436 "unit_pamac-cleancache_timer_state_deactivating": 0, 437 "unit_pamac-cleancache_timer_state_failed": 0, 438 "unit_pamac-cleancache_timer_state_inactive": 0, 439 "unit_pamac-mirrorlist_timer_state_activating": 0, 440 "unit_pamac-mirrorlist_timer_state_active": 1, 441 "unit_pamac-mirrorlist_timer_state_deactivating": 0, 442 "unit_pamac-mirrorlist_timer_state_failed": 0, 443 "unit_pamac-mirrorlist_timer_state_inactive": 0, 444 "unit_proc-sys-fs-binfmt_misc_automount_state_activating": 0, 445 "unit_proc-sys-fs-binfmt_misc_automount_state_active": 1, 446 "unit_proc-sys-fs-binfmt_misc_automount_state_deactivating": 0, 447 "unit_proc-sys-fs-binfmt_misc_automount_state_failed": 0, 448 "unit_proc-sys-fs-binfmt_misc_automount_state_inactive": 0, 449 "unit_remote-fs-pre_target_state_activating": 0, 450 "unit_remote-fs-pre_target_state_active": 0, 451 "unit_remote-fs-pre_target_state_deactivating": 0, 452 "unit_remote-fs-pre_target_state_failed": 0, 453 "unit_remote-fs-pre_target_state_inactive": 1, 454 "unit_rpc_pipefs_target_state_activating": 0, 455 "unit_rpc_pipefs_target_state_active": 0, 456 "unit_rpc_pipefs_target_state_deactivating": 0, 457 "unit_rpc_pipefs_target_state_failed": 0, 458 "unit_rpc_pipefs_target_state_inactive": 1, 459 "unit_run-user-1000-gvfs_mount_state_activating": 0, 460 "unit_run-user-1000-gvfs_mount_state_active": 1, 461 "unit_run-user-1000-gvfs_mount_state_deactivating": 0, 462 "unit_run-user-1000-gvfs_mount_state_failed": 0, 463 "unit_run-user-1000-gvfs_mount_state_inactive": 0, 464 "unit_run-user-1000_mount_state_activating": 0, 465 "unit_run-user-1000_mount_state_active": 1, 466 "unit_run-user-1000_mount_state_deactivating": 0, 467 "unit_run-user-1000_mount_state_failed": 0, 468 "unit_run-user-1000_mount_state_inactive": 0, 469 "unit_session-1_scope_state_activating": 0, 470 "unit_session-1_scope_state_active": 1, 471 "unit_session-1_scope_state_deactivating": 0, 472 "unit_session-1_scope_state_failed": 0, 473 "unit_session-1_scope_state_inactive": 0, 474 "unit_session-2_scope_state_activating": 0, 475 "unit_session-2_scope_state_active": 1, 476 "unit_session-2_scope_state_deactivating": 0, 477 "unit_session-2_scope_state_failed": 0, 478 "unit_session-2_scope_state_inactive": 0, 479 "unit_session-3_scope_state_activating": 0, 480 "unit_session-3_scope_state_active": 1, 481 "unit_session-3_scope_state_deactivating": 0, 482 "unit_session-3_scope_state_failed": 0, 483 "unit_session-3_scope_state_inactive": 0, 484 "unit_session-6_scope_state_activating": 0, 485 "unit_session-6_scope_state_active": 1, 486 "unit_session-6_scope_state_deactivating": 0, 487 "unit_session-6_scope_state_failed": 0, 488 "unit_session-6_scope_state_inactive": 0, 489 "unit_shadow_timer_state_activating": 0, 490 "unit_shadow_timer_state_active": 1, 491 "unit_shadow_timer_state_deactivating": 0, 492 "unit_shadow_timer_state_failed": 0, 493 "unit_shadow_timer_state_inactive": 0, 494 "unit_sound_target_state_activating": 0, 495 "unit_sound_target_state_active": 1, 496 "unit_sound_target_state_deactivating": 0, 497 "unit_sound_target_state_failed": 0, 498 "unit_sound_target_state_inactive": 0, 499 "unit_sys-devices-virtual-net-loopback1_device_state_activating": 0, 500 "unit_sys-devices-virtual-net-loopback1_device_state_active": 1, 501 "unit_sys-devices-virtual-net-loopback1_device_state_deactivating": 0, 502 "unit_sys-devices-virtual-net-loopback1_device_state_failed": 0, 503 "unit_sys-devices-virtual-net-loopback1_device_state_inactive": 0, 504 "unit_sys-module-fuse_device_state_activating": 0, 505 "unit_sys-module-fuse_device_state_active": 1, 506 "unit_sys-module-fuse_device_state_deactivating": 0, 507 "unit_sys-module-fuse_device_state_failed": 0, 508 "unit_sys-module-fuse_device_state_inactive": 0, 509 "unit_sysinit_target_state_activating": 0, 510 "unit_sysinit_target_state_active": 1, 511 "unit_sysinit_target_state_deactivating": 0, 512 "unit_sysinit_target_state_failed": 0, 513 "unit_sysinit_target_state_inactive": 0, 514 "unit_system-getty_slice_state_activating": 0, 515 "unit_system-getty_slice_state_active": 1, 516 "unit_system-getty_slice_state_deactivating": 0, 517 "unit_system-getty_slice_state_failed": 0, 518 "unit_system-getty_slice_state_inactive": 0, 519 "unit_system-netctl_slice_state_activating": 0, 520 "unit_system-netctl_slice_state_active": 1, 521 "unit_system-netctl_slice_state_deactivating": 0, 522 "unit_system-netctl_slice_state_failed": 0, 523 "unit_system-netctl_slice_state_inactive": 0, 524 "unit_system-systemd-fsck_slice_state_activating": 0, 525 "unit_system-systemd-fsck_slice_state_active": 1, 526 "unit_system-systemd-fsck_slice_state_deactivating": 0, 527 "unit_system-systemd-fsck_slice_state_failed": 0, 528 "unit_system-systemd-fsck_slice_state_inactive": 0, 529 "unit_system_slice_state_activating": 0, 530 "unit_system_slice_state_active": 1, 531 "unit_system_slice_state_deactivating": 0, 532 "unit_system_slice_state_failed": 0, 533 "unit_system_slice_state_inactive": 0, 534 "unit_systemd-ask-password-console_path_state_activating": 0, 535 "unit_systemd-ask-password-console_path_state_active": 1, 536 "unit_systemd-ask-password-console_path_state_deactivating": 0, 537 "unit_systemd-ask-password-console_path_state_failed": 0, 538 "unit_systemd-ask-password-console_path_state_inactive": 0, 539 "unit_systemd-ask-password-wall_path_state_activating": 0, 540 "unit_systemd-ask-password-wall_path_state_active": 1, 541 "unit_systemd-ask-password-wall_path_state_deactivating": 0, 542 "unit_systemd-ask-password-wall_path_state_failed": 0, 543 "unit_systemd-ask-password-wall_path_state_inactive": 0, 544 "unit_systemd-ask-password-wall_service_state_activating": 0, 545 "unit_systemd-ask-password-wall_service_state_active": 0, 546 "unit_systemd-ask-password-wall_service_state_deactivating": 0, 547 "unit_systemd-ask-password-wall_service_state_failed": 0, 548 "unit_systemd-ask-password-wall_service_state_inactive": 1, 549 "unit_systemd-fsck-root_service_state_activating": 0, 550 "unit_systemd-fsck-root_service_state_active": 0, 551 "unit_systemd-fsck-root_service_state_deactivating": 0, 552 "unit_systemd-fsck-root_service_state_failed": 0, 553 "unit_systemd-fsck-root_service_state_inactive": 1, 554 "unit_systemd-udevd-kernel_socket_state_activating": 0, 555 "unit_systemd-udevd-kernel_socket_state_active": 1, 556 "unit_systemd-udevd-kernel_socket_state_deactivating": 0, 557 "unit_systemd-udevd-kernel_socket_state_failed": 0, 558 "unit_systemd-udevd-kernel_socket_state_inactive": 0, 559 "unit_tmp_mount_state_activating": 0, 560 "unit_tmp_mount_state_active": 1, 561 "unit_tmp_mount_state_deactivating": 0, 562 "unit_tmp_mount_state_failed": 0, 563 "unit_tmp_mount_state_inactive": 0, 564 "unit_user-runtime-dir@1000_service_state_activating": 0, 565 "unit_user-runtime-dir@1000_service_state_active": 1, 566 "unit_user-runtime-dir@1000_service_state_deactivating": 0, 567 "unit_user-runtime-dir@1000_service_state_failed": 0, 568 "unit_user-runtime-dir@1000_service_state_inactive": 0, 569 "unit_user@1000_service_state_activating": 0, 570 "unit_user@1000_service_state_active": 1, 571 "unit_user@1000_service_state_deactivating": 0, 572 "unit_user@1000_service_state_failed": 0, 573 "unit_user@1000_service_state_inactive": 0, 574 "unit_user_slice_state_activating": 0, 575 "unit_user_slice_state_active": 1, 576 "unit_user_slice_state_deactivating": 0, 577 "unit_user_slice_state_failed": 0, 578 "unit_user_slice_state_inactive": 0, 579 "unit_var-lib-nfs-rpc_pipefs_mount_state_activating": 0, 580 "unit_var-lib-nfs-rpc_pipefs_mount_state_active": 0, 581 "unit_var-lib-nfs-rpc_pipefs_mount_state_deactivating": 0, 582 "unit_var-lib-nfs-rpc_pipefs_mount_state_failed": 0, 583 "unit_var-lib-nfs-rpc_pipefs_mount_state_inactive": 1, 584 }, 585 }, 586 "success on systemd v230+ on collecting only 'service' unit type": { 587 prepare: func() *SystemdUnits { 588 systemd := New() 589 systemd.Include = []string{"*.service"} 590 systemd.client = prepareOKClient(230) 591 return systemd 592 }, 593 wantCollected: map[string]int64{ 594 "unit_systemd-ask-password-wall_service_state_activating": 0, 595 "unit_systemd-ask-password-wall_service_state_active": 0, 596 "unit_systemd-ask-password-wall_service_state_deactivating": 0, 597 "unit_systemd-ask-password-wall_service_state_failed": 0, 598 "unit_systemd-ask-password-wall_service_state_inactive": 1, 599 "unit_systemd-fsck-root_service_state_activating": 0, 600 "unit_systemd-fsck-root_service_state_active": 0, 601 "unit_systemd-fsck-root_service_state_deactivating": 0, 602 "unit_systemd-fsck-root_service_state_failed": 0, 603 "unit_systemd-fsck-root_service_state_inactive": 1, 604 "unit_user-runtime-dir@1000_service_state_activating": 0, 605 "unit_user-runtime-dir@1000_service_state_active": 1, 606 "unit_user-runtime-dir@1000_service_state_deactivating": 0, 607 "unit_user-runtime-dir@1000_service_state_failed": 0, 608 "unit_user-runtime-dir@1000_service_state_inactive": 0, 609 "unit_user@1000_service_state_activating": 0, 610 "unit_user@1000_service_state_active": 1, 611 "unit_user@1000_service_state_deactivating": 0, 612 "unit_user@1000_service_state_failed": 0, 613 "unit_user@1000_service_state_inactive": 0, 614 }, 615 }, 616 "success on systemd v230- on collecting only 'service' unit type": { 617 prepare: func() *SystemdUnits { 618 systemd := New() 619 systemd.Include = []string{"*.service"} 620 systemd.client = prepareOKClient(220) 621 return systemd 622 }, 623 wantCollected: map[string]int64{ 624 "unit_systemd-ask-password-wall_service_state_activating": 0, 625 "unit_systemd-ask-password-wall_service_state_active": 0, 626 "unit_systemd-ask-password-wall_service_state_deactivating": 0, 627 "unit_systemd-ask-password-wall_service_state_failed": 0, 628 "unit_systemd-ask-password-wall_service_state_inactive": 1, 629 "unit_systemd-fsck-root_service_state_activating": 0, 630 "unit_systemd-fsck-root_service_state_active": 0, 631 "unit_systemd-fsck-root_service_state_deactivating": 0, 632 "unit_systemd-fsck-root_service_state_failed": 0, 633 "unit_systemd-fsck-root_service_state_inactive": 1, 634 "unit_user-runtime-dir@1000_service_state_activating": 0, 635 "unit_user-runtime-dir@1000_service_state_active": 1, 636 "unit_user-runtime-dir@1000_service_state_deactivating": 0, 637 "unit_user-runtime-dir@1000_service_state_failed": 0, 638 "unit_user-runtime-dir@1000_service_state_inactive": 0, 639 "unit_user@1000_service_state_activating": 0, 640 "unit_user@1000_service_state_active": 1, 641 "unit_user@1000_service_state_deactivating": 0, 642 "unit_user@1000_service_state_failed": 0, 643 "unit_user@1000_service_state_inactive": 0, 644 }, 645 }, 646 "fails when all unites are filtered": { 647 prepare: func() *SystemdUnits { 648 systemd := New() 649 systemd.Include = []string{"*.not_exists"} 650 systemd.client = prepareOKClient(230) 651 return systemd 652 }, 653 wantCollected: nil, 654 }, 655 "fails on error on connect": { 656 prepare: func() *SystemdUnits { 657 systemd := New() 658 systemd.client = prepareClientErrOnConnect() 659 return systemd 660 }, 661 wantCollected: nil, 662 }, 663 "fails on error on get manager property": { 664 prepare: func() *SystemdUnits { 665 systemd := New() 666 systemd.client = prepareClientErrOnGetManagerProperty() 667 return systemd 668 }, 669 wantCollected: nil, 670 }, 671 "fails on error on list units": { 672 prepare: func() *SystemdUnits { 673 systemd := New() 674 systemd.client = prepareClientErrOnListUnits() 675 return systemd 676 }, 677 wantCollected: nil, 678 }, 679 } 680 681 for name, test := range tests { 682 t.Run(name, func(t *testing.T) { 683 systemd := test.prepare() 684 require.True(t, systemd.Init()) 685 686 var collected map[string]int64 687 688 for i := 0; i < 10; i++ { 689 collected = systemd.Collect() 690 } 691 692 assert.Equal(t, test.wantCollected, collected) 693 if len(test.wantCollected) > 0 { 694 ensureCollectedHasAllChartsDimsVarsIDs(t, systemd, collected) 695 } 696 }) 697 } 698 } 699 700 func TestSystemdUnits_connectionReuse(t *testing.T) { 701 systemd := New() 702 systemd.Include = []string{"*"} 703 client := prepareOKClient(230) 704 systemd.client = client 705 require.True(t, systemd.Init()) 706 707 var collected map[string]int64 708 for i := 0; i < 10; i++ { 709 collected = systemd.Collect() 710 } 711 712 assert.NotEmpty(t, collected) 713 assert.Equal(t, 1, client.connectCalls) 714 } 715 716 func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, sd *SystemdUnits, collected map[string]int64) { 717 for _, chart := range *sd.Charts() { 718 if chart.Obsolete { 719 continue 720 } 721 for _, dim := range chart.Dims { 722 _, ok := collected[dim.ID] 723 assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) 724 } 725 for _, v := range chart.Vars { 726 _, ok := collected[v.ID] 727 assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) 728 } 729 } 730 } 731 732 func prepareOKClient(ver int) *mockClient { 733 return &mockClient{ 734 conn: &mockConn{ 735 version: ver, 736 units: mockSystemdUnits, 737 }, 738 } 739 } 740 741 func prepareClientErrOnConnect() *mockClient { 742 return &mockClient{ 743 errOnConnect: true, 744 } 745 } 746 747 func prepareClientErrOnGetManagerProperty() *mockClient { 748 return &mockClient{ 749 conn: &mockConn{ 750 version: 230, 751 errOnGetManagerProperty: true, 752 units: mockSystemdUnits, 753 }, 754 } 755 } 756 757 func prepareClientErrOnListUnits() *mockClient { 758 return &mockClient{ 759 conn: &mockConn{ 760 version: 230, 761 errOnListUnits: true, 762 units: mockSystemdUnits, 763 }, 764 } 765 } 766 767 type mockClient struct { 768 conn systemdConnection 769 connectCalls int 770 errOnConnect bool 771 } 772 773 func (m *mockClient) connect() (systemdConnection, error) { 774 m.connectCalls++ 775 if m.errOnConnect { 776 return nil, errors.New("mock 'connect' error") 777 } 778 return m.conn, nil 779 } 780 781 type mockConn struct { 782 version int 783 units []dbus.UnitStatus 784 errOnGetManagerProperty bool 785 errOnListUnits bool 786 closeCalled bool 787 } 788 789 func (m *mockConn) Close() { 790 m.closeCalled = true 791 } 792 793 func (m *mockConn) GetManagerProperty(prop string) (string, error) { 794 if m.errOnGetManagerProperty { 795 return "", errors.New("'GetManagerProperty' call error") 796 } 797 if prop != versionProperty { 798 return "", fmt.Errorf("'GetManagerProperty' unkown property: %s", prop) 799 } 800 return fmt.Sprintf("%d.6-1-manjaro", m.version), nil 801 } 802 803 func (m *mockConn) ListUnitsContext(_ context.Context) ([]dbus.UnitStatus, error) { 804 if m.errOnListUnits { 805 return nil, errors.New("'ListUnits' call error") 806 } 807 if m.version >= 230 { 808 return nil, errors.New("'ListUnits' unsupported function error") 809 } 810 return append([]dbus.UnitStatus{}, m.units...), nil 811 } 812 813 func (m *mockConn) ListUnitsByPatternsContext(_ context.Context, _ []string, ps []string) ([]dbus.UnitStatus, error) { 814 if m.errOnListUnits { 815 return nil, errors.New("'ListUnitsByPatterns' call error") 816 } 817 if m.version < 230 { 818 return nil, errors.New("'ListUnitsByPatterns' unsupported function error") 819 } 820 821 matches := func(name string) bool { 822 for _, p := range ps { 823 if ok, _ := filepath.Match(p, name); ok { 824 return true 825 } 826 } 827 return false 828 } 829 830 var units []dbus.UnitStatus 831 for _, unit := range m.units { 832 if matches(unit.Name) { 833 units = append(units, unit) 834 } 835 } 836 return units, nil 837 } 838 839 var mockSystemdUnits = []dbus.UnitStatus{ 840 {Name: `proc-sys-fs-binfmt_misc.automount`, LoadState: "loaded", ActiveState: "active"}, 841 {Name: `dev-nvme0n1.device`, LoadState: "loaded", ActiveState: "active"}, 842 {Name: `sys-devices-virtual-net-loopback1.device`, LoadState: "loaded", ActiveState: "active"}, 843 {Name: `sys-module-fuse.device`, LoadState: "loaded", ActiveState: "active"}, 844 {Name: `dev-disk-by\x2duuid-DE44\x2dCEE0.device`, LoadState: "loaded", ActiveState: "active"}, 845 846 {Name: `var-lib-nfs-rpc_pipefs.mount`, LoadState: "loaded", ActiveState: "inactive"}, 847 {Name: `var.mount`, LoadState: "not-found", ActiveState: "inactive"}, 848 {Name: `run-user-1000.mount`, LoadState: "loaded", ActiveState: "active"}, 849 {Name: `tmp.mount`, LoadState: "loaded", ActiveState: "active"}, 850 {Name: `run-user-1000-gvfs.mount`, LoadState: "loaded", ActiveState: "active"}, 851 852 {Name: `org.cups.cupsd.path`, LoadState: "loaded", ActiveState: "active"}, 853 {Name: `systemd-ask-password-wall.path`, LoadState: "loaded", ActiveState: "active"}, 854 {Name: `systemd-ask-password-console.path`, LoadState: "loaded", ActiveState: "active"}, 855 856 {Name: `init.scope`, LoadState: "loaded", ActiveState: "active"}, 857 {Name: `session-3.scope`, LoadState: "loaded", ActiveState: "active"}, 858 {Name: `session-6.scope`, LoadState: "loaded", ActiveState: "active"}, 859 {Name: `session-1.scope`, LoadState: "loaded", ActiveState: "active"}, 860 {Name: `session-2.scope`, LoadState: "loaded", ActiveState: "active"}, 861 862 {Name: `systemd-fsck-root.service`, LoadState: "loaded", ActiveState: "inactive"}, 863 {Name: `httpd.service`, LoadState: "not-found", ActiveState: "inactive"}, 864 {Name: `user-runtime-dir@1000.service`, LoadState: "loaded", ActiveState: "active"}, 865 {Name: `systemd-ask-password-wall.service`, LoadState: "loaded", ActiveState: "inactive"}, 866 {Name: `user@1000.service`, LoadState: "loaded", ActiveState: "active"}, 867 868 {Name: `user.slice`, LoadState: "loaded", ActiveState: "active"}, 869 {Name: `system-getty.slice`, LoadState: "loaded", ActiveState: "active"}, 870 {Name: `system-netctl.slice`, LoadState: "loaded", ActiveState: "active"}, 871 {Name: `system.slice`, LoadState: "loaded", ActiveState: "active"}, 872 {Name: `system-systemd\x2dfsck.slice`, LoadState: "loaded", ActiveState: "active"}, 873 874 {Name: `lvm2-lvmpolld.socket`, LoadState: "loaded", ActiveState: "active"}, 875 {Name: `docker.socket`, LoadState: "loaded", ActiveState: "active"}, 876 {Name: `systemd-udevd-kernel.socket`, LoadState: "loaded", ActiveState: "active"}, 877 {Name: `dbus.socket`, LoadState: "loaded", ActiveState: "active"}, 878 {Name: `lvm2-lvmetad.socket`, LoadState: "loaded", ActiveState: "active"}, 879 880 {Name: `getty-pre.target`, LoadState: "loaded", ActiveState: "inactive"}, 881 {Name: `rpc_pipefs.target`, LoadState: "loaded", ActiveState: "inactive"}, 882 {Name: `remote-fs-pre.target`, LoadState: "loaded", ActiveState: "inactive"}, 883 {Name: `sysinit.target`, LoadState: "loaded", ActiveState: "active"}, 884 {Name: `sound.target`, LoadState: "loaded", ActiveState: "active"}, 885 886 {Name: `man-db.timer`, LoadState: "loaded", ActiveState: "active"}, 887 {Name: `pamac-mirrorlist.timer`, LoadState: "loaded", ActiveState: "active"}, 888 {Name: `pamac-cleancache.timer`, LoadState: "loaded", ActiveState: "active"}, 889 {Name: `shadow.timer`, LoadState: "loaded", ActiveState: "active"}, 890 {Name: `logrotate.timer`, LoadState: "loaded", ActiveState: "active"}, 891 }