github.com/netdata/go.d.plugin@v0.58.1/modules/vsphere/vsphere_test.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 package vsphere 3 4 import ( 5 "crypto/tls" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/netdata/go.d.plugin/modules/vsphere/discover" 11 "github.com/netdata/go.d.plugin/modules/vsphere/match" 12 rs "github.com/netdata/go.d.plugin/modules/vsphere/resources" 13 14 "github.com/netdata/go.d.plugin/agent/module" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 "github.com/vmware/govmomi/performance" 18 "github.com/vmware/govmomi/simulator" 19 ) 20 21 func TestNew(t *testing.T) { 22 job := New() 23 24 assert.Implements(t, (*module.Module)(nil), job) 25 } 26 27 func TestVSphere_Init(t *testing.T) { 28 vSphere, _, teardown := prepareVSphereSim(t) 29 defer teardown() 30 31 assert.True(t, vSphere.Init()) 32 assert.NotNil(t, vSphere.discoverer) 33 assert.NotNil(t, vSphere.scraper) 34 assert.NotNil(t, vSphere.resources) 35 assert.NotNil(t, vSphere.discoveryTask) 36 assert.True(t, vSphere.discoveryTask.isRunning()) 37 } 38 39 func TestVSphere_Init_ReturnsFalseIfURLNotSet(t *testing.T) { 40 vSphere, _, teardown := prepareVSphereSim(t) 41 defer teardown() 42 vSphere.URL = "" 43 44 assert.False(t, vSphere.Init()) 45 } 46 47 func TestVSphere_Init_ReturnsFalseIfUsernameNotSet(t *testing.T) { 48 vSphere, _, teardown := prepareVSphereSim(t) 49 defer teardown() 50 vSphere.Username = "" 51 52 assert.False(t, vSphere.Init()) 53 } 54 55 func TestVSphere_Init_ReturnsFalseIfPasswordNotSet(t *testing.T) { 56 vSphere, _, teardown := prepareVSphereSim(t) 57 defer teardown() 58 vSphere.Password = "" 59 60 assert.False(t, vSphere.Init()) 61 } 62 63 func TestVSphere_Init_ReturnsFalseIfClientWrongTLSCA(t *testing.T) { 64 vSphere, _, teardown := prepareVSphereSim(t) 65 defer teardown() 66 vSphere.Client.TLSConfig.TLSCA = "testdata/tls" 67 68 assert.False(t, vSphere.Init()) 69 } 70 71 func TestVSphere_Init_ReturnsFalseIfConnectionRefused(t *testing.T) { 72 vSphere, _, teardown := prepareVSphereSim(t) 73 defer teardown() 74 vSphere.URL = "http://127.0.0.1:32001" 75 76 assert.False(t, vSphere.Init()) 77 } 78 79 func TestVSphere_Init_ReturnsFalseIfInvalidHostVMIncludeFormat(t *testing.T) { 80 vSphere, _, teardown := prepareVSphereSim(t) 81 defer teardown() 82 83 vSphere.HostsInclude = match.HostIncludes{"invalid"} 84 assert.False(t, vSphere.Init()) 85 86 vSphere.HostsInclude = vSphere.HostsInclude[:0] 87 88 vSphere.VMsInclude = match.VMIncludes{"invalid"} 89 assert.False(t, vSphere.Init()) 90 } 91 92 func TestVSphere_Check(t *testing.T) { 93 assert.NotNil(t, New().Check()) 94 } 95 96 func TestVSphere_Charts(t *testing.T) { 97 assert.NotNil(t, New().Charts()) 98 } 99 100 func TestVSphere_Cleanup(t *testing.T) { 101 vSphere, _, teardown := prepareVSphereSim(t) 102 defer teardown() 103 104 require.True(t, vSphere.Init()) 105 106 vSphere.Cleanup() 107 time.Sleep(time.Second) 108 assert.True(t, vSphere.discoveryTask.isStopped()) 109 assert.False(t, vSphere.discoveryTask.isRunning()) 110 } 111 112 func TestVSphere_Cleanup_NotPanicsIfNotInitialized(t *testing.T) { 113 assert.NotPanics(t, New().Cleanup) 114 } 115 116 func TestVSphere_Collect(t *testing.T) { 117 vSphere, model, teardown := prepareVSphereSim(t) 118 defer teardown() 119 120 require.True(t, vSphere.Init()) 121 122 vSphere.scraper = mockScraper{vSphere.scraper} 123 124 expected := map[string]int64{ 125 "host-21_cpu.usage.average": 100, 126 "host-21_disk.maxTotalLatency.latest": 100, 127 "host-21_disk.read.average": 100, 128 "host-21_disk.write.average": 100, 129 "host-21_mem.active.average": 100, 130 "host-21_mem.consumed.average": 100, 131 "host-21_mem.granted.average": 100, 132 "host-21_mem.shared.average": 100, 133 "host-21_mem.sharedcommon.average": 100, 134 "host-21_mem.swapinRate.average": 100, 135 "host-21_mem.swapoutRate.average": 100, 136 "host-21_mem.usage.average": 100, 137 "host-21_net.bytesRx.average": 100, 138 "host-21_net.bytesTx.average": 100, 139 "host-21_net.droppedRx.summation": 100, 140 "host-21_net.droppedTx.summation": 100, 141 "host-21_net.errorsRx.summation": 100, 142 "host-21_net.errorsTx.summation": 100, 143 "host-21_net.packetsRx.summation": 100, 144 "host-21_net.packetsTx.summation": 100, 145 "host-21_overall.status.gray": 1, 146 "host-21_overall.status.green": 0, 147 "host-21_overall.status.red": 0, 148 "host-21_overall.status.yellow": 0, 149 "host-21_sys.uptime.latest": 100, 150 "host-34_cpu.usage.average": 100, 151 "host-34_disk.maxTotalLatency.latest": 100, 152 "host-34_disk.read.average": 100, 153 "host-34_disk.write.average": 100, 154 "host-34_mem.active.average": 100, 155 "host-34_mem.consumed.average": 100, 156 "host-34_mem.granted.average": 100, 157 "host-34_mem.shared.average": 100, 158 "host-34_mem.sharedcommon.average": 100, 159 "host-34_mem.swapinRate.average": 100, 160 "host-34_mem.swapoutRate.average": 100, 161 "host-34_mem.usage.average": 100, 162 "host-34_net.bytesRx.average": 100, 163 "host-34_net.bytesTx.average": 100, 164 "host-34_net.droppedRx.summation": 100, 165 "host-34_net.droppedTx.summation": 100, 166 "host-34_net.errorsRx.summation": 100, 167 "host-34_net.errorsTx.summation": 100, 168 "host-34_net.packetsRx.summation": 100, 169 "host-34_net.packetsTx.summation": 100, 170 "host-34_overall.status.gray": 1, 171 "host-34_overall.status.green": 0, 172 "host-34_overall.status.red": 0, 173 "host-34_overall.status.yellow": 0, 174 "host-34_sys.uptime.latest": 100, 175 "host-42_cpu.usage.average": 100, 176 "host-42_disk.maxTotalLatency.latest": 100, 177 "host-42_disk.read.average": 100, 178 "host-42_disk.write.average": 100, 179 "host-42_mem.active.average": 100, 180 "host-42_mem.consumed.average": 100, 181 "host-42_mem.granted.average": 100, 182 "host-42_mem.shared.average": 100, 183 "host-42_mem.sharedcommon.average": 100, 184 "host-42_mem.swapinRate.average": 100, 185 "host-42_mem.swapoutRate.average": 100, 186 "host-42_mem.usage.average": 100, 187 "host-42_net.bytesRx.average": 100, 188 "host-42_net.bytesTx.average": 100, 189 "host-42_net.droppedRx.summation": 100, 190 "host-42_net.droppedTx.summation": 100, 191 "host-42_net.errorsRx.summation": 100, 192 "host-42_net.errorsTx.summation": 100, 193 "host-42_net.packetsRx.summation": 100, 194 "host-42_net.packetsTx.summation": 100, 195 "host-42_overall.status.gray": 1, 196 "host-42_overall.status.green": 0, 197 "host-42_overall.status.red": 0, 198 "host-42_overall.status.yellow": 0, 199 "host-42_sys.uptime.latest": 100, 200 "host-50_cpu.usage.average": 100, 201 "host-50_disk.maxTotalLatency.latest": 100, 202 "host-50_disk.read.average": 100, 203 "host-50_disk.write.average": 100, 204 "host-50_mem.active.average": 100, 205 "host-50_mem.consumed.average": 100, 206 "host-50_mem.granted.average": 100, 207 "host-50_mem.shared.average": 100, 208 "host-50_mem.sharedcommon.average": 100, 209 "host-50_mem.swapinRate.average": 100, 210 "host-50_mem.swapoutRate.average": 100, 211 "host-50_mem.usage.average": 100, 212 "host-50_net.bytesRx.average": 100, 213 "host-50_net.bytesTx.average": 100, 214 "host-50_net.droppedRx.summation": 100, 215 "host-50_net.droppedTx.summation": 100, 216 "host-50_net.errorsRx.summation": 100, 217 "host-50_net.errorsTx.summation": 100, 218 "host-50_net.packetsRx.summation": 100, 219 "host-50_net.packetsTx.summation": 100, 220 "host-50_overall.status.gray": 1, 221 "host-50_overall.status.green": 0, 222 "host-50_overall.status.red": 0, 223 "host-50_overall.status.yellow": 0, 224 "host-50_sys.uptime.latest": 100, 225 "vm-55_cpu.usage.average": 200, 226 "vm-55_disk.maxTotalLatency.latest": 200, 227 "vm-55_disk.read.average": 200, 228 "vm-55_disk.write.average": 200, 229 "vm-55_mem.active.average": 200, 230 "vm-55_mem.consumed.average": 200, 231 "vm-55_mem.granted.average": 200, 232 "vm-55_mem.shared.average": 200, 233 "vm-55_mem.swapinRate.average": 200, 234 "vm-55_mem.swapoutRate.average": 200, 235 "vm-55_mem.swapped.average": 200, 236 "vm-55_mem.usage.average": 200, 237 "vm-55_net.bytesRx.average": 200, 238 "vm-55_net.bytesTx.average": 200, 239 "vm-55_net.droppedRx.summation": 200, 240 "vm-55_net.droppedTx.summation": 200, 241 "vm-55_net.packetsRx.summation": 200, 242 "vm-55_net.packetsTx.summation": 200, 243 "vm-55_overall.status.gray": 0, 244 "vm-55_overall.status.green": 1, 245 "vm-55_overall.status.red": 0, 246 "vm-55_overall.status.yellow": 0, 247 "vm-55_sys.uptime.latest": 200, 248 "vm-58_cpu.usage.average": 200, 249 "vm-58_disk.maxTotalLatency.latest": 200, 250 "vm-58_disk.read.average": 200, 251 "vm-58_disk.write.average": 200, 252 "vm-58_mem.active.average": 200, 253 "vm-58_mem.consumed.average": 200, 254 "vm-58_mem.granted.average": 200, 255 "vm-58_mem.shared.average": 200, 256 "vm-58_mem.swapinRate.average": 200, 257 "vm-58_mem.swapoutRate.average": 200, 258 "vm-58_mem.swapped.average": 200, 259 "vm-58_mem.usage.average": 200, 260 "vm-58_net.bytesRx.average": 200, 261 "vm-58_net.bytesTx.average": 200, 262 "vm-58_net.droppedRx.summation": 200, 263 "vm-58_net.droppedTx.summation": 200, 264 "vm-58_net.packetsRx.summation": 200, 265 "vm-58_net.packetsTx.summation": 200, 266 "vm-58_overall.status.gray": 0, 267 "vm-58_overall.status.green": 1, 268 "vm-58_overall.status.red": 0, 269 "vm-58_overall.status.yellow": 0, 270 "vm-58_sys.uptime.latest": 200, 271 "vm-61_cpu.usage.average": 200, 272 "vm-61_disk.maxTotalLatency.latest": 200, 273 "vm-61_disk.read.average": 200, 274 "vm-61_disk.write.average": 200, 275 "vm-61_mem.active.average": 200, 276 "vm-61_mem.consumed.average": 200, 277 "vm-61_mem.granted.average": 200, 278 "vm-61_mem.shared.average": 200, 279 "vm-61_mem.swapinRate.average": 200, 280 "vm-61_mem.swapoutRate.average": 200, 281 "vm-61_mem.swapped.average": 200, 282 "vm-61_mem.usage.average": 200, 283 "vm-61_net.bytesRx.average": 200, 284 "vm-61_net.bytesTx.average": 200, 285 "vm-61_net.droppedRx.summation": 200, 286 "vm-61_net.droppedTx.summation": 200, 287 "vm-61_net.packetsRx.summation": 200, 288 "vm-61_net.packetsTx.summation": 200, 289 "vm-61_overall.status.gray": 0, 290 "vm-61_overall.status.green": 1, 291 "vm-61_overall.status.red": 0, 292 "vm-61_overall.status.yellow": 0, 293 "vm-61_sys.uptime.latest": 200, 294 "vm-64_cpu.usage.average": 200, 295 "vm-64_disk.maxTotalLatency.latest": 200, 296 "vm-64_disk.read.average": 200, 297 "vm-64_disk.write.average": 200, 298 "vm-64_mem.active.average": 200, 299 "vm-64_mem.consumed.average": 200, 300 "vm-64_mem.granted.average": 200, 301 "vm-64_mem.shared.average": 200, 302 "vm-64_mem.swapinRate.average": 200, 303 "vm-64_mem.swapoutRate.average": 200, 304 "vm-64_mem.swapped.average": 200, 305 "vm-64_mem.usage.average": 200, 306 "vm-64_net.bytesRx.average": 200, 307 "vm-64_net.bytesTx.average": 200, 308 "vm-64_net.droppedRx.summation": 200, 309 "vm-64_net.droppedTx.summation": 200, 310 "vm-64_net.packetsRx.summation": 200, 311 "vm-64_net.packetsTx.summation": 200, 312 "vm-64_overall.status.gray": 0, 313 "vm-64_overall.status.green": 1, 314 "vm-64_overall.status.red": 0, 315 "vm-64_overall.status.yellow": 0, 316 "vm-64_sys.uptime.latest": 200, 317 } 318 319 collected := vSphere.Collect() 320 require.Equal(t, expected, collected) 321 322 count := model.Count() 323 assert.Len(t, vSphere.discoveredHosts, count.Host) 324 assert.Len(t, vSphere.discoveredVMs, count.Machine) 325 assert.Len(t, vSphere.charted, count.Host+count.Machine) 326 327 assert.Len(t, *vSphere.Charts(), count.Host*len(hostChartsTmpl)+count.Machine*len(vmChartsTmpl)) 328 ensureCollectedHasAllChartsDimsVarsIDs(t, vSphere, collected) 329 } 330 331 func TestVSphere_Collect_RemoveHostsVMsInRuntime(t *testing.T) { 332 vSphere, _, teardown := prepareVSphereSim(t) 333 defer teardown() 334 335 require.True(t, vSphere.Init()) 336 require.True(t, vSphere.Check()) 337 338 okHostID := "host-50" 339 okVMID := "vm-64" 340 vSphere.discoverer.(*discover.Discoverer).HostMatcher = mockHostMatcher{okHostID} 341 vSphere.discoverer.(*discover.Discoverer).VMMatcher = mockVMMatcher{okVMID} 342 343 require.NoError(t, vSphere.discoverOnce()) 344 345 numOfRuns := 5 346 for i := 0; i < numOfRuns; i++ { 347 vSphere.Collect() 348 } 349 350 host := vSphere.resources.Hosts.Get(okHostID) 351 for k, v := range vSphere.discoveredHosts { 352 if k == host.ID { 353 assert.Equal(t, 0, v) 354 } else { 355 assert.Equal(t, numOfRuns, v) 356 } 357 } 358 359 vm := vSphere.resources.VMs.Get(okVMID) 360 for id, fails := range vSphere.discoveredVMs { 361 if id == vm.ID { 362 assert.Equal(t, 0, fails) 363 } else { 364 assert.Equal(t, numOfRuns, fails) 365 } 366 367 } 368 369 for i := numOfRuns; i < failedUpdatesLimit; i++ { 370 vSphere.Collect() 371 } 372 373 assert.Len(t, vSphere.discoveredHosts, 1) 374 assert.Len(t, vSphere.discoveredVMs, 1) 375 assert.Len(t, vSphere.charted, 2) 376 377 for _, c := range *vSphere.Charts() { 378 if strings.HasPrefix(c.ID, okHostID) || strings.HasPrefix(c.ID, okVMID) { 379 assert.False(t, c.Obsolete) 380 } else { 381 assert.True(t, c.Obsolete) 382 } 383 } 384 } 385 386 func TestVSphere_Collect_Run(t *testing.T) { 387 vSphere, model, teardown := prepareVSphereSim(t) 388 defer teardown() 389 390 vSphere.DiscoveryInterval.Duration = time.Second * 2 391 require.True(t, vSphere.Init()) 392 require.True(t, vSphere.Check()) 393 394 runs := 20 395 for i := 0; i < runs; i++ { 396 assert.True(t, len(vSphere.Collect()) > 0) 397 if i < 6 { 398 time.Sleep(time.Second) 399 } 400 } 401 402 count := model.Count() 403 assert.Len(t, vSphere.discoveredHosts, count.Host) 404 assert.Len(t, vSphere.discoveredVMs, count.Machine) 405 assert.Len(t, vSphere.charted, count.Host+count.Machine) 406 assert.Len(t, *vSphere.charts, count.Host*len(hostChartsTmpl)+count.Machine*len(vmChartsTmpl)) 407 } 408 409 func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, vSphere *VSphere, collected map[string]int64) { 410 for _, chart := range *vSphere.Charts() { 411 for _, dim := range chart.Dims { 412 _, ok := collected[dim.ID] 413 assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) 414 } 415 for _, v := range chart.Vars { 416 _, ok := collected[v.ID] 417 assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) 418 } 419 } 420 } 421 422 func prepareVSphereSim(t *testing.T) (vSphere *VSphere, model *simulator.Model, teardown func()) { 423 model, srv := createSim(t) 424 vSphere = New() 425 teardown = func() { model.Remove(); srv.Close(); vSphere.Cleanup() } 426 427 vSphere.Username = "administrator" 428 vSphere.Password = "password" 429 vSphere.URL = srv.URL.String() 430 vSphere.TLSConfig.InsecureSkipVerify = true 431 432 return vSphere, model, teardown 433 } 434 435 func createSim(t *testing.T) (*simulator.Model, *simulator.Server) { 436 model := simulator.VPX() 437 err := model.Create() 438 require.NoError(t, err) 439 model.Service.TLS = new(tls.Config) 440 return model, model.Service.NewServer() 441 } 442 443 type mockScraper struct { 444 scraper 445 } 446 447 func (s mockScraper) ScrapeHosts(hosts rs.Hosts) []performance.EntityMetric { 448 ms := s.scraper.ScrapeHosts(hosts) 449 return populateMetrics(ms, 100) 450 } 451 func (s mockScraper) ScrapeVMs(vms rs.VMs) []performance.EntityMetric { 452 ms := s.scraper.ScrapeVMs(vms) 453 return populateMetrics(ms, 200) 454 } 455 456 func populateMetrics(ms []performance.EntityMetric, value int64) []performance.EntityMetric { 457 for i := range ms { 458 for ii := range ms[i].Value { 459 v := &ms[i].Value[ii].Value 460 if *v == nil { 461 *v = append(*v, value) 462 } else { 463 (*v)[0] = value 464 } 465 } 466 } 467 return ms 468 } 469 470 type mockHostMatcher struct{ name string } 471 type mockVMMatcher struct{ name string } 472 473 func (m mockHostMatcher) Match(host *rs.Host) bool { return m.name == host.ID } 474 func (m mockVMMatcher) Match(vm *rs.VM) bool { return m.name == vm.ID }