summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/vsphere/vsphere_test.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/vsphere/vsphere_test.go488
1 files changed, 488 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/vsphere_test.go b/src/go/collectors/go.d.plugin/modules/vsphere/vsphere_test.go
new file mode 100644
index 000000000..8c0045d88
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vsphere/vsphere_test.go
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+package vsphere
+
+import (
+ "crypto/tls"
+ "os"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+ "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/discover"
+ "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/match"
+ rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/web"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/vmware/govmomi/performance"
+ "github.com/vmware/govmomi/simulator"
+)
+
+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 TestVSphere_ConfigurationSerialize(t *testing.T) {
+ module.TestConfigurationSerialize(t, &VSphere{}, dataConfigJSON, dataConfigYAML)
+}
+
+func TestVSphere_Init(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+
+ assert.NoError(t, vSphere.Init())
+ assert.NotNil(t, vSphere.discoverer)
+ assert.NotNil(t, vSphere.scraper)
+ assert.NotNil(t, vSphere.resources)
+ assert.NotNil(t, vSphere.discoveryTask)
+ assert.True(t, vSphere.discoveryTask.isRunning())
+}
+
+func TestVSphere_Init_ReturnsFalseIfURLNotSet(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+ vSphere.URL = ""
+
+ assert.Error(t, vSphere.Init())
+}
+
+func TestVSphere_Init_ReturnsFalseIfUsernameNotSet(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+ vSphere.Username = ""
+
+ assert.Error(t, vSphere.Init())
+}
+
+func TestVSphere_Init_ReturnsFalseIfPasswordNotSet(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+ vSphere.Password = ""
+
+ assert.Error(t, vSphere.Init())
+}
+
+func TestVSphere_Init_ReturnsFalseIfClientWrongTLSCA(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+ vSphere.Client.TLSConfig.TLSCA = "testdata/tls"
+
+ assert.Error(t, vSphere.Init())
+}
+
+func TestVSphere_Init_ReturnsFalseIfConnectionRefused(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+ vSphere.URL = "http://127.0.0.1:32001"
+
+ assert.Error(t, vSphere.Init())
+}
+
+func TestVSphere_Init_ReturnsFalseIfInvalidHostVMIncludeFormat(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+
+ vSphere.HostsInclude = match.HostIncludes{"invalid"}
+ assert.Error(t, vSphere.Init())
+
+ vSphere.HostsInclude = vSphere.HostsInclude[:0]
+
+ vSphere.VMsInclude = match.VMIncludes{"invalid"}
+ assert.Error(t, vSphere.Init())
+}
+
+func TestVSphere_Check(t *testing.T) {
+ assert.NoError(t, New().Check())
+}
+
+func TestVSphere_Charts(t *testing.T) {
+ assert.NotNil(t, New().Charts())
+}
+
+func TestVSphere_Cleanup(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+
+ require.NoError(t, vSphere.Init())
+
+ vSphere.Cleanup()
+ time.Sleep(time.Second)
+ assert.True(t, vSphere.discoveryTask.isStopped())
+ assert.False(t, vSphere.discoveryTask.isRunning())
+}
+
+func TestVSphere_Cleanup_NotPanicsIfNotInitialized(t *testing.T) {
+ assert.NotPanics(t, New().Cleanup)
+}
+
+func TestVSphere_Collect(t *testing.T) {
+ vSphere, model, teardown := prepareVSphereSim(t)
+ defer teardown()
+
+ require.NoError(t, vSphere.Init())
+
+ vSphere.scraper = mockScraper{vSphere.scraper}
+
+ expected := map[string]int64{
+ "host-20_cpu.usage.average": 100,
+ "host-20_disk.maxTotalLatency.latest": 100,
+ "host-20_disk.read.average": 100,
+ "host-20_disk.write.average": 100,
+ "host-20_mem.active.average": 100,
+ "host-20_mem.consumed.average": 100,
+ "host-20_mem.granted.average": 100,
+ "host-20_mem.shared.average": 100,
+ "host-20_mem.sharedcommon.average": 100,
+ "host-20_mem.swapinRate.average": 100,
+ "host-20_mem.swapoutRate.average": 100,
+ "host-20_mem.usage.average": 100,
+ "host-20_net.bytesRx.average": 100,
+ "host-20_net.bytesTx.average": 100,
+ "host-20_net.droppedRx.summation": 100,
+ "host-20_net.droppedTx.summation": 100,
+ "host-20_net.errorsRx.summation": 100,
+ "host-20_net.errorsTx.summation": 100,
+ "host-20_net.packetsRx.summation": 100,
+ "host-20_net.packetsTx.summation": 100,
+ "host-20_overall.status.gray": 1,
+ "host-20_overall.status.green": 0,
+ "host-20_overall.status.red": 0,
+ "host-20_overall.status.yellow": 0,
+ "host-20_sys.uptime.latest": 100,
+ "host-34_cpu.usage.average": 100,
+ "host-34_disk.maxTotalLatency.latest": 100,
+ "host-34_disk.read.average": 100,
+ "host-34_disk.write.average": 100,
+ "host-34_mem.active.average": 100,
+ "host-34_mem.consumed.average": 100,
+ "host-34_mem.granted.average": 100,
+ "host-34_mem.shared.average": 100,
+ "host-34_mem.sharedcommon.average": 100,
+ "host-34_mem.swapinRate.average": 100,
+ "host-34_mem.swapoutRate.average": 100,
+ "host-34_mem.usage.average": 100,
+ "host-34_net.bytesRx.average": 100,
+ "host-34_net.bytesTx.average": 100,
+ "host-34_net.droppedRx.summation": 100,
+ "host-34_net.droppedTx.summation": 100,
+ "host-34_net.errorsRx.summation": 100,
+ "host-34_net.errorsTx.summation": 100,
+ "host-34_net.packetsRx.summation": 100,
+ "host-34_net.packetsTx.summation": 100,
+ "host-34_overall.status.gray": 1,
+ "host-34_overall.status.green": 0,
+ "host-34_overall.status.red": 0,
+ "host-34_overall.status.yellow": 0,
+ "host-34_sys.uptime.latest": 100,
+ "host-42_cpu.usage.average": 100,
+ "host-42_disk.maxTotalLatency.latest": 100,
+ "host-42_disk.read.average": 100,
+ "host-42_disk.write.average": 100,
+ "host-42_mem.active.average": 100,
+ "host-42_mem.consumed.average": 100,
+ "host-42_mem.granted.average": 100,
+ "host-42_mem.shared.average": 100,
+ "host-42_mem.sharedcommon.average": 100,
+ "host-42_mem.swapinRate.average": 100,
+ "host-42_mem.swapoutRate.average": 100,
+ "host-42_mem.usage.average": 100,
+ "host-42_net.bytesRx.average": 100,
+ "host-42_net.bytesTx.average": 100,
+ "host-42_net.droppedRx.summation": 100,
+ "host-42_net.droppedTx.summation": 100,
+ "host-42_net.errorsRx.summation": 100,
+ "host-42_net.errorsTx.summation": 100,
+ "host-42_net.packetsRx.summation": 100,
+ "host-42_net.packetsTx.summation": 100,
+ "host-42_overall.status.gray": 1,
+ "host-42_overall.status.green": 0,
+ "host-42_overall.status.red": 0,
+ "host-42_overall.status.yellow": 0,
+ "host-42_sys.uptime.latest": 100,
+ "host-50_cpu.usage.average": 100,
+ "host-50_disk.maxTotalLatency.latest": 100,
+ "host-50_disk.read.average": 100,
+ "host-50_disk.write.average": 100,
+ "host-50_mem.active.average": 100,
+ "host-50_mem.consumed.average": 100,
+ "host-50_mem.granted.average": 100,
+ "host-50_mem.shared.average": 100,
+ "host-50_mem.sharedcommon.average": 100,
+ "host-50_mem.swapinRate.average": 100,
+ "host-50_mem.swapoutRate.average": 100,
+ "host-50_mem.usage.average": 100,
+ "host-50_net.bytesRx.average": 100,
+ "host-50_net.bytesTx.average": 100,
+ "host-50_net.droppedRx.summation": 100,
+ "host-50_net.droppedTx.summation": 100,
+ "host-50_net.errorsRx.summation": 100,
+ "host-50_net.errorsTx.summation": 100,
+ "host-50_net.packetsRx.summation": 100,
+ "host-50_net.packetsTx.summation": 100,
+ "host-50_overall.status.gray": 1,
+ "host-50_overall.status.green": 0,
+ "host-50_overall.status.red": 0,
+ "host-50_overall.status.yellow": 0,
+ "host-50_sys.uptime.latest": 100,
+ "vm-55_cpu.usage.average": 200,
+ "vm-55_disk.maxTotalLatency.latest": 200,
+ "vm-55_disk.read.average": 200,
+ "vm-55_disk.write.average": 200,
+ "vm-55_mem.active.average": 200,
+ "vm-55_mem.consumed.average": 200,
+ "vm-55_mem.granted.average": 200,
+ "vm-55_mem.shared.average": 200,
+ "vm-55_mem.swapinRate.average": 200,
+ "vm-55_mem.swapoutRate.average": 200,
+ "vm-55_mem.swapped.average": 200,
+ "vm-55_mem.usage.average": 200,
+ "vm-55_net.bytesRx.average": 200,
+ "vm-55_net.bytesTx.average": 200,
+ "vm-55_net.droppedRx.summation": 200,
+ "vm-55_net.droppedTx.summation": 200,
+ "vm-55_net.packetsRx.summation": 200,
+ "vm-55_net.packetsTx.summation": 200,
+ "vm-55_overall.status.gray": 0,
+ "vm-55_overall.status.green": 1,
+ "vm-55_overall.status.red": 0,
+ "vm-55_overall.status.yellow": 0,
+ "vm-55_sys.uptime.latest": 200,
+ "vm-58_cpu.usage.average": 200,
+ "vm-58_disk.maxTotalLatency.latest": 200,
+ "vm-58_disk.read.average": 200,
+ "vm-58_disk.write.average": 200,
+ "vm-58_mem.active.average": 200,
+ "vm-58_mem.consumed.average": 200,
+ "vm-58_mem.granted.average": 200,
+ "vm-58_mem.shared.average": 200,
+ "vm-58_mem.swapinRate.average": 200,
+ "vm-58_mem.swapoutRate.average": 200,
+ "vm-58_mem.swapped.average": 200,
+ "vm-58_mem.usage.average": 200,
+ "vm-58_net.bytesRx.average": 200,
+ "vm-58_net.bytesTx.average": 200,
+ "vm-58_net.droppedRx.summation": 200,
+ "vm-58_net.droppedTx.summation": 200,
+ "vm-58_net.packetsRx.summation": 200,
+ "vm-58_net.packetsTx.summation": 200,
+ "vm-58_overall.status.gray": 0,
+ "vm-58_overall.status.green": 1,
+ "vm-58_overall.status.red": 0,
+ "vm-58_overall.status.yellow": 0,
+ "vm-58_sys.uptime.latest": 200,
+ "vm-61_cpu.usage.average": 200,
+ "vm-61_disk.maxTotalLatency.latest": 200,
+ "vm-61_disk.read.average": 200,
+ "vm-61_disk.write.average": 200,
+ "vm-61_mem.active.average": 200,
+ "vm-61_mem.consumed.average": 200,
+ "vm-61_mem.granted.average": 200,
+ "vm-61_mem.shared.average": 200,
+ "vm-61_mem.swapinRate.average": 200,
+ "vm-61_mem.swapoutRate.average": 200,
+ "vm-61_mem.swapped.average": 200,
+ "vm-61_mem.usage.average": 200,
+ "vm-61_net.bytesRx.average": 200,
+ "vm-61_net.bytesTx.average": 200,
+ "vm-61_net.droppedRx.summation": 200,
+ "vm-61_net.droppedTx.summation": 200,
+ "vm-61_net.packetsRx.summation": 200,
+ "vm-61_net.packetsTx.summation": 200,
+ "vm-61_overall.status.gray": 0,
+ "vm-61_overall.status.green": 1,
+ "vm-61_overall.status.red": 0,
+ "vm-61_overall.status.yellow": 0,
+ "vm-61_sys.uptime.latest": 200,
+ "vm-64_cpu.usage.average": 200,
+ "vm-64_disk.maxTotalLatency.latest": 200,
+ "vm-64_disk.read.average": 200,
+ "vm-64_disk.write.average": 200,
+ "vm-64_mem.active.average": 200,
+ "vm-64_mem.consumed.average": 200,
+ "vm-64_mem.granted.average": 200,
+ "vm-64_mem.shared.average": 200,
+ "vm-64_mem.swapinRate.average": 200,
+ "vm-64_mem.swapoutRate.average": 200,
+ "vm-64_mem.swapped.average": 200,
+ "vm-64_mem.usage.average": 200,
+ "vm-64_net.bytesRx.average": 200,
+ "vm-64_net.bytesTx.average": 200,
+ "vm-64_net.droppedRx.summation": 200,
+ "vm-64_net.droppedTx.summation": 200,
+ "vm-64_net.packetsRx.summation": 200,
+ "vm-64_net.packetsTx.summation": 200,
+ "vm-64_overall.status.gray": 0,
+ "vm-64_overall.status.green": 1,
+ "vm-64_overall.status.red": 0,
+ "vm-64_overall.status.yellow": 0,
+ "vm-64_sys.uptime.latest": 200,
+ }
+
+ collected := vSphere.Collect()
+ require.Equal(t, expected, collected)
+
+ count := model.Count()
+ assert.Len(t, vSphere.discoveredHosts, count.Host)
+ assert.Len(t, vSphere.discoveredVMs, count.Machine)
+ assert.Len(t, vSphere.charted, count.Host+count.Machine)
+
+ assert.Len(t, *vSphere.Charts(), count.Host*len(hostChartsTmpl)+count.Machine*len(vmChartsTmpl))
+ ensureCollectedHasAllChartsDimsVarsIDs(t, vSphere, collected)
+}
+
+func TestVSphere_Collect_RemoveHostsVMsInRuntime(t *testing.T) {
+ vSphere, _, teardown := prepareVSphereSim(t)
+ defer teardown()
+
+ require.NoError(t, vSphere.Init())
+ require.NoError(t, vSphere.Check())
+
+ okHostID := "host-50"
+ okVMID := "vm-64"
+ vSphere.discoverer.(*discover.Discoverer).HostMatcher = mockHostMatcher{okHostID}
+ vSphere.discoverer.(*discover.Discoverer).VMMatcher = mockVMMatcher{okVMID}
+
+ require.NoError(t, vSphere.discoverOnce())
+
+ numOfRuns := 5
+ for i := 0; i < numOfRuns; i++ {
+ vSphere.Collect()
+ }
+
+ host := vSphere.resources.Hosts.Get(okHostID)
+ for k, v := range vSphere.discoveredHosts {
+ if k == host.ID {
+ assert.Equal(t, 0, v)
+ } else {
+ assert.Equal(t, numOfRuns, v)
+ }
+ }
+
+ vm := vSphere.resources.VMs.Get(okVMID)
+ for id, fails := range vSphere.discoveredVMs {
+ if id == vm.ID {
+ assert.Equal(t, 0, fails)
+ } else {
+ assert.Equal(t, numOfRuns, fails)
+ }
+
+ }
+
+ for i := numOfRuns; i < failedUpdatesLimit; i++ {
+ vSphere.Collect()
+ }
+
+ assert.Len(t, vSphere.discoveredHosts, 1)
+ assert.Len(t, vSphere.discoveredVMs, 1)
+ assert.Len(t, vSphere.charted, 2)
+
+ for _, c := range *vSphere.Charts() {
+ if strings.HasPrefix(c.ID, okHostID) || strings.HasPrefix(c.ID, okVMID) {
+ assert.False(t, c.Obsolete)
+ } else {
+ assert.True(t, c.Obsolete)
+ }
+ }
+}
+
+func TestVSphere_Collect_Run(t *testing.T) {
+ vSphere, model, teardown := prepareVSphereSim(t)
+ defer teardown()
+
+ vSphere.DiscoveryInterval = web.Duration(time.Second * 2)
+ require.NoError(t, vSphere.Init())
+ require.NoError(t, vSphere.Check())
+
+ runs := 20
+ for i := 0; i < runs; i++ {
+ assert.True(t, len(vSphere.Collect()) > 0)
+ if i < 6 {
+ time.Sleep(time.Second)
+ }
+ }
+
+ count := model.Count()
+ assert.Len(t, vSphere.discoveredHosts, count.Host)
+ assert.Len(t, vSphere.discoveredVMs, count.Machine)
+ assert.Len(t, vSphere.charted, count.Host+count.Machine)
+ assert.Len(t, *vSphere.charts, count.Host*len(hostChartsTmpl)+count.Machine*len(vmChartsTmpl))
+}
+
+func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, vSphere *VSphere, collected map[string]int64) {
+ for _, chart := range *vSphere.Charts() {
+ for _, dim := range chart.Dims {
+ _, ok := collected[dim.ID]
+ assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID)
+ }
+ for _, v := range chart.Vars {
+ _, ok := collected[v.ID]
+ assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID)
+ }
+ }
+}
+
+func prepareVSphereSim(t *testing.T) (vSphere *VSphere, model *simulator.Model, teardown func()) {
+ model, srv := createSim(t)
+ vSphere = New()
+ teardown = func() { model.Remove(); srv.Close(); vSphere.Cleanup() }
+
+ vSphere.Username = "administrator"
+ vSphere.Password = "password"
+ vSphere.URL = srv.URL.String()
+ vSphere.TLSConfig.InsecureSkipVerify = true
+
+ return vSphere, model, teardown
+}
+
+func createSim(t *testing.T) (*simulator.Model, *simulator.Server) {
+ model := simulator.VPX()
+ err := model.Create()
+ require.NoError(t, err)
+ model.Service.TLS = new(tls.Config)
+ return model, model.Service.NewServer()
+}
+
+type mockScraper struct {
+ scraper
+}
+
+func (s mockScraper) ScrapeHosts(hosts rs.Hosts) []performance.EntityMetric {
+ ms := s.scraper.ScrapeHosts(hosts)
+ return populateMetrics(ms, 100)
+}
+func (s mockScraper) ScrapeVMs(vms rs.VMs) []performance.EntityMetric {
+ ms := s.scraper.ScrapeVMs(vms)
+ return populateMetrics(ms, 200)
+}
+
+func populateMetrics(ms []performance.EntityMetric, value int64) []performance.EntityMetric {
+ for i := range ms {
+ for ii := range ms[i].Value {
+ v := &ms[i].Value[ii].Value
+ if *v == nil {
+ *v = append(*v, value)
+ } else {
+ (*v)[0] = value
+ }
+ }
+ }
+ return ms
+}
+
+type mockHostMatcher struct{ name string }
+type mockVMMatcher struct{ name string }
+
+func (m mockHostMatcher) Match(host *rs.Host) bool { return m.name == host.ID }
+func (m mockVMMatcher) Match(vm *rs.VM) bool { return m.name == vm.ID }