master
go 215 lines 5.65 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package vsphere
4
5 import (
6 "context"
7 "testing"
8
9 "github.com/stretchr/testify/require"
10 "github.com/vmware/govmomi/performance"
11
12 "github.com/netdata/netdata/go/plugins/pkg/funcapi"
13 rs "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/vsphere/resources"
14 scrapepkg "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/vsphere/scrape"
15 )
16
17 func TestVSphereMethods(t *testing.T) {
18 methods := vsphereMethods()
19
20 require.Len(t, methods, 2)
21 byID := make(map[string]funcapi.MethodConfig, len(methods))
22 for _, method := range methods {
23 byID[method.ID] = method
24 }
25
26 tests := map[string]struct {
27 wantName string
28 responseType string
29 alias string
30 presentation bool
31 }{
32 "readiness": {
33 wantName: "vSphere Readiness",
34 },
35 "topology:vsphere": {
36 wantName: "vSphere Topology",
37 responseType: "topology",
38 alias: "topology:vsphere",
39 },
40 }
41
42 for id, tc := range tests {
43 t.Run(id, func(t *testing.T) {
44 method := byID[id]
45 require.Equal(t, tc.wantName, method.Name)
46 require.Equal(t, 30, method.UpdateEvery)
47 require.True(t, method.RequireCloud)
48 require.False(t, method.AgentWide)
49 if tc.alias != "" {
50 require.Contains(t, method.Aliases, tc.alias)
51 }
52 if tc.responseType != "" {
53 require.Equal(t, tc.responseType, method.ResponseType)
54 }
55 if tc.presentation {
56 require.NotNil(t, method.Presentation())
57 }
58 })
59 }
60 }
61
62 func TestFuncReadiness_Handle(t *testing.T) {
63 tests := map[string]struct {
64 method string
65 collector func() *Collector
66 want int
67 check func(*testing.T, map[string][]any)
68 }{
69 "without discovery": {
70 method: "readiness",
71 collector: New,
72 want: 200,
73 check: func(t *testing.T, rows map[string][]any) {
74 require.Equal(t, "not_ready", rows["target_url"][2])
75 require.Equal(t, "not_ready", rows["inventory_cache"][2])
76 require.Equal(t, "disabled", rows["vsan"][2])
77 },
78 },
79 "partial init state": {
80 method: "readiness",
81 collector: func() *Collector {
82 collr := New()
83 collr.URL = "https://vcenter.local"
84 collr.Username = "user"
85 collr.Password = "[REDACTED_SECRET]"
86 return collr
87 },
88 want: 200,
89 check: func(t *testing.T, rows map[string][]any) {
90 require.Equal(t, "ok", rows["target_url"][2])
91 require.Equal(t, "ok", rows["credentials"][2])
92 require.Equal(t, "not_ready", rows["client"][2])
93 require.Equal(t, "not_ready", rows["inventory_cache"][2])
94 },
95 },
96 "client row requires vSphere client": {
97 method: "readiness",
98 collector: func() *Collector {
99 collr := New()
100 collr.URL = "https://vcenter.local"
101 collr.Username = "user"
102 collr.Password = "[REDACTED_SECRET]"
103 collr.discoverer = readinessDiscoverer{}
104 collr.scraper = readinessScraper{}
105 return collr
106 },
107 want: 200,
108 check: func(t *testing.T, rows map[string][]any) {
109 require.Equal(t, "not_ready", rows["client"][2])
110 },
111 },
112 "with vSAN cached data": {
113 method: "readiness",
114 collector: func() *Collector {
115 collr := newVSANTestCollector(true)
116 collr.URL = "https://vcenter.local"
117 collr.Username = "user"
118 collr.Password = "[REDACTED_SECRET]"
119 for _, cluster := range collr.resources.Clusters {
120 cluster.MetricList = performance.MetricList{{CounterId: 1}}
121 }
122 for _, host := range collr.resources.Hosts {
123 host.MetricList = performance.MetricList{{CounterId: 1}}
124 }
125 for _, vm := range collr.resources.VMs {
126 vm.MetricList = performance.MetricList{{CounterId: 1}}
127 }
128 return collr
129 },
130 want: 200,
131 check: func(t *testing.T, rows map[string][]any) {
132 require.Equal(t, "ok", rows["target_url"][2])
133 require.Equal(t, "ok", rows["credentials"][2])
134 require.Equal(t, "ok", rows["inventory_cache"][2])
135 require.Equal(t, "ok", rows["vsan"][2])
136 require.Contains(t, rows["vsan"][3], "vSAN data cached")
137 },
138 },
139 "with empty vSAN cached data": {
140 method: "readiness",
141 collector: func() *Collector {
142 collr := newVSANTestCollector(true)
143 collr.vsanMetrics = &scrapepkg.VSANMetrics{}
144 return collr
145 },
146 want: 200,
147 check: func(t *testing.T, rows map[string][]any) {
148 require.Equal(t, "warning", rows["vsan"][2])
149 require.Contains(t, rows["vsan"][3], "last vSAN scrape returned no data")
150 },
151 },
152 "unknown method": {
153 method: "unknown",
154 collector: New,
155 want: 404,
156 },
157 }
158
159 for name, tc := range tests {
160 t.Run(name, func(t *testing.T) {
161 handler := &funcReadiness{collector: tc.collector()}
162
163 resp := handler.Handle(context.Background(), tc.method, nil)
164
165 require.Equal(t, tc.want, resp.Status)
166 if tc.check != nil {
167 require.NotEmpty(t, resp.Columns)
168 tc.check(t, readinessRowsFromResponse(t, resp))
169 }
170 })
171 }
172 }
173
174 func readinessRowsFromResponse(t *testing.T, resp *funcapi.FunctionResponse) map[string][]any {
175 t.Helper()
176
177 rows, ok := resp.Data.([][]any)
178 require.True(t, ok)
179 byCheck := make(map[string][]any, len(rows))
180 for _, row := range rows {
181 require.Len(t, row, len(readinessColumns))
182 check, ok := row[0].(string)
183 require.True(t, ok)
184 byCheck[check] = row
185 }
186 return byCheck
187 }
188
189 type readinessDiscoverer struct{}
190
191 func (readinessDiscoverer) Discover() (*rs.Resources, error) {
192 return nil, nil
193 }
194
195 type readinessScraper struct{}
196
197 func (readinessScraper) ScrapeHosts(rs.Hosts) []performance.EntityMetric {
198 return nil
199 }
200
201 func (readinessScraper) ScrapeVMs(rs.VMs) []performance.EntityMetric {
202 return nil
203 }
204
205 func (readinessScraper) ScrapeDatastores(rs.Datastores) []performance.EntityMetric {
206 return nil
207 }
208
209 func (readinessScraper) ScrapeClusters(rs.Clusters) []performance.EntityMetric {
210 return nil
211 }
212
213 func (readinessScraper) ScrapeVSAN(rs.Clusters, rs.Hosts, rs.VMs) *scrapepkg.VSANMetrics {
214 return nil
215 }