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 }