github.com/vmware/govmomi@v0.43.0/simulator/performance_manager_test.go (about) 1 /* 2 Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 package simulator 17 18 import ( 19 "context" 20 "errors" 21 "fmt" 22 "strings" 23 "testing" 24 25 "github.com/vmware/govmomi/performance" 26 "github.com/vmware/govmomi/simulator/esx" 27 "github.com/vmware/govmomi/simulator/vpx" 28 "github.com/vmware/govmomi/vim25/mo" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 func testMetricsConsistency(counterInfo []types.PerfCounterInfo, ids [][]types.PerfMetricId) error { 33 34 // Build a lookup table for speed and convenience 35 lookup := make(map[int32]bool, len(counterInfo)) 36 for _, pc := range counterInfo { 37 lookup[pc.Key] = true 38 } 39 40 // Check metric ids against map 41 for _, list := range ids { 42 for _, id := range list { 43 if _, ok := lookup[id.CounterId]; !ok { 44 return fmt.Errorf("Counter with ID %d not found in PerfCounter", id.CounterId) 45 } 46 } 47 } 48 return nil 49 } 50 51 func TestMetricsConsistency(t *testing.T) { 52 esxIds := [][]types.PerfMetricId{esx.VmMetrics, esx.HostMetrics, esx.ResourcePoolMetrics} 53 vpxIds := [][]types.PerfMetricId{vpx.VmMetrics, vpx.HostMetrics, vpx.ClusterMetrics, 54 vpx.DatastoreMetrics, vpx.ResourcePoolMetrics} 55 if err := testMetricsConsistency(esx.PerfCounter, esxIds); err != nil { 56 t.Fatal(err) 57 } 58 if err := testMetricsConsistency(vpx.PerfCounter, vpxIds); err != nil { 59 t.Fatal(err) 60 } 61 } 62 63 func checkDuplicates(ids []types.PerfMetricId) error { 64 m := make(map[string]bool, len(ids)) 65 for _, id := range ids { 66 k := fmt.Sprintf("%d|%s", id.CounterId, id.Instance) 67 if _, ok := m[k]; ok { 68 return fmt.Errorf("Duplicate metric key: %s", k) 69 } 70 m[k] = true 71 } 72 return nil 73 } 74 75 func TestMetricsDuplicates(t *testing.T) { 76 if err := checkDuplicates(esx.VmMetrics); err != nil { 77 t.Fatal(err) 78 } 79 if err := checkDuplicates(esx.HostMetrics); err != nil { 80 t.Fatal(err) 81 } 82 if err := checkDuplicates(vpx.VmMetrics); err != nil { 83 t.Fatal(err) 84 } 85 if err := checkDuplicates(vpx.HostMetrics); err != nil { 86 t.Fatal(err) 87 } 88 if err := checkDuplicates(vpx.ClusterMetrics); err != nil { 89 t.Fatal(err) 90 } 91 if err := checkDuplicates(vpx.DatastoreMetrics); err != nil { 92 t.Fatal(err) 93 } 94 } 95 96 func TestQueryProviderSummary(t *testing.T) { 97 ctx := context.Background() 98 99 m := VPX() 100 101 err := m.Create() 102 if err != nil { 103 t.Fatal(err) 104 } 105 106 defer m.Remove() 107 108 c := m.Service.client 109 110 p := performance.NewManager(c) 111 112 vm := Map.Any("VirtualMachine").(*VirtualMachine) 113 if info, err := p.ProviderSummary(ctx, vm.Reference()); err != nil { 114 t.Fatal(err) 115 } else { 116 if info.RefreshRate != 20 { 117 t.Fatalf("VM wefresh rate is %d, should be 20", info.RefreshRate) 118 } 119 } 120 121 host := Map.Any("HostSystem").(*HostSystem) 122 if info, err := p.ProviderSummary(ctx, host.Reference()); err != nil { 123 t.Fatal(err) 124 } else { 125 if info.RefreshRate != 20 { 126 t.Fatalf("Host refresh rate is %d, should be 20", info.RefreshRate) 127 } 128 } 129 130 pool := Map.Any("ResourcePool").(*ResourcePool) 131 if info, err := p.ProviderSummary(ctx, pool.Reference()); err != nil { 132 t.Fatal(err) 133 } else { 134 if info.RefreshRate != 20 { 135 t.Fatalf("ResourcePool refresh rate is %d, should be 20", info.RefreshRate) 136 } 137 } 138 139 cluster := Map.Any("ClusterComputeResource").(*ClusterComputeResource) 140 if info, err := p.ProviderSummary(ctx, cluster.Reference()); err != nil { 141 t.Fatal(err) 142 } else { 143 if info.RefreshRate != -1 { 144 t.Fatalf("Cluster refresh rate is %d, should be -1", info.RefreshRate) 145 } 146 } 147 148 datastore := Map.Any("Datastore").(*Datastore) 149 if info, err := p.ProviderSummary(ctx, datastore.Reference()); err != nil { 150 t.Fatal(err) 151 } else { 152 if info.RefreshRate != -1 { 153 t.Fatalf("Datastore refresh rate is %d, should be -1", info.RefreshRate) 154 } 155 } 156 157 nonExistent := types.ManagedObjectReference{ 158 Type: "Not a valid type", 159 Value: "This object doesn't exist", 160 } 161 if _, err := p.ProviderSummary(ctx, nonExistent); err == nil { 162 t.Fatal("This should have failed (nonexistent object)") 163 } 164 } 165 166 func TestQueryAvailablePerfMetric(t *testing.T) { 167 ctx := context.Background() 168 169 m := VPX() 170 171 err := m.Create() 172 if err != nil { 173 t.Fatal(err) 174 } 175 176 defer m.Remove() 177 178 c := m.Service.client 179 p := performance.NewManager(c) 180 181 vm := Map.Any("VirtualMachine").(*VirtualMachine) 182 if info, err := p.AvailableMetric(ctx, vm.Reference(), 20); err != nil { 183 t.Fatal(err) 184 } else { 185 if len(info) == 0 { 186 t.Fatal("Expected non-empty list of vm") 187 } 188 } 189 190 host := Map.Any("HostSystem").(*HostSystem) 191 if info, err := p.AvailableMetric(ctx, host.Reference(), 20); err != nil { 192 t.Fatal(err) 193 } else { 194 if len(info) == 0 { 195 t.Fatal("Expected non-empty list of host") 196 } 197 var ids []int32 198 for i := range info { 199 ids = append(ids, info[i].CounterId) 200 } 201 perf, err := p.QueryCounter(ctx, ids) 202 if err != nil { 203 t.Fatal(err) 204 } 205 if len(perf) != len(ids) { 206 t.Errorf("%d counters", len(perf)) 207 } 208 } 209 210 pool := Map.Any("ResourcePool").(*ResourcePool) 211 if info, err := p.AvailableMetric(ctx, pool.Reference(), 20); err != nil { 212 t.Fatal(err) 213 } else { 214 if len(info) == 0 { 215 t.Fatal("Expected non-empty list of resource pool") 216 } 217 } 218 219 cluster := Map.Any("ClusterComputeResource").(*ClusterComputeResource) 220 if info, err := p.AvailableMetric(ctx, cluster.Reference(), 300); err != nil { 221 t.Fatal(err) 222 } else { 223 if len(info) == 0 { 224 t.Fatal("Expected non-empty list of clusters") 225 } 226 } 227 228 if info, err := p.AvailableMetric(ctx, cluster.Reference(), 20); err != nil { 229 t.Fatal(err) 230 } else { 231 if len(info) != 0 { 232 t.Fatal("Expected empty list of clusters") 233 } 234 } 235 236 ds := Map.Any("Datastore").(*Datastore) 237 if info, err := p.AvailableMetric(ctx, ds.Reference(), 300); err != nil { 238 t.Fatal(err) 239 } else { 240 if len(info) == 0 { 241 t.Fatal("Expected non-empty list of datastores") 242 } 243 } 244 245 if info, err := p.AvailableMetric(ctx, ds.Reference(), 20); err != nil { 246 t.Fatal(err) 247 } else { 248 if len(info) != 0 { 249 t.Fatal("Expected empty list of datastores") 250 } 251 } 252 253 dc := Map.Any("Datacenter").(*Datacenter) 254 if info, err := p.AvailableMetric(ctx, dc.Reference(), 300); err != nil { 255 t.Fatal(err) 256 } else { 257 if len(info) == 0 { 258 t.Fatal("Expected non-empty list of datacenters") 259 } 260 } 261 262 if info, err := p.AvailableMetric(ctx, dc.Reference(), 20); err != nil { 263 t.Fatal(err) 264 } else { 265 if len(info) != 0 { 266 t.Fatal("Expected empty list of datacenters") 267 } 268 } 269 270 } 271 272 func testPerfQuery(ctx context.Context, m *Model, e mo.Entity, interval int32, maxSample int32) error { 273 c := m.Service.client 274 275 p := performance.NewManager(c) 276 277 // Single metric, single VM 278 // 279 qs := []types.PerfQuerySpec{ 280 { 281 MaxSample: maxSample, 282 IntervalId: interval, 283 MetricId: []types.PerfMetricId{{CounterId: 1, Instance: ""}}, 284 Entity: e.Reference(), 285 }, 286 } 287 result, err := p.Query(ctx, qs) 288 if err != nil { 289 return err 290 } 291 if len(result) == 0 { 292 return errors.New("Empty result set") 293 } 294 ms, err := p.ToMetricSeries(ctx, result) 295 if err != nil { 296 return err 297 } 298 if len(ms) == 0 { 299 return errors.New("Empty metric series") 300 } 301 for _, em := range ms { 302 if len(em.SampleInfo) == 0 { 303 return errors.New("Empty SampleInfo") 304 } 305 } 306 307 return nil 308 } 309 310 func testPerfQueryCSV(ctx context.Context, m *Model, e mo.Entity, interval int32, maxSample int32) error { 311 c := m.Service.client 312 313 p := performance.NewManager(c) 314 315 // Single metric, single VM 316 // 317 qs := []types.PerfQuerySpec{ 318 { 319 MaxSample: maxSample, 320 IntervalId: interval, 321 MetricId: []types.PerfMetricId{{CounterId: 1, Instance: ""}}, 322 Entity: e.Reference(), 323 Format: string(types.PerfFormatCsv), 324 }, 325 } 326 series, err := p.Query(ctx, qs) 327 if err != nil { 328 return err 329 } 330 if len(series) == 0 { 331 return errors.New("Empty result set") 332 } 333 for i := range series { 334 s, ok := series[i].(*types.PerfEntityMetricCSV) 335 if !ok { 336 panic(fmt.Errorf("expected type %T, got: %T", s, series[i])) 337 } 338 if len(s.SampleInfoCSV) == 0 { 339 return errors.New("Empty SampleInfoCSV") 340 } 341 if len(strings.Split(s.SampleInfoCSV, ",")) == 0 { 342 return errors.New("SampleInfoCSV not in CSV format") 343 } 344 for _, v := range s.Value { 345 if len(v.Value) == 0 { 346 return errors.New("Empty PerfEntityMetricCSV.Value") 347 } 348 if len(strings.Split(v.Value, ",")) == 0 { 349 return errors.New("PerfEntityMetricCSV.Value not in CSV format") 350 } 351 } 352 } 353 354 return nil 355 } 356 357 func TestQueryPerf(t *testing.T) { 358 ctx := context.Background() 359 360 m := VPX() 361 362 err := m.Create() 363 if err != nil { 364 t.Fatal(err) 365 } 366 367 defer m.Remove() 368 369 for _, maxSample := range []int32{4, 0} { 370 if err := testPerfQuery(ctx, m, Map.Any("VirtualMachine"), 20, maxSample); err != nil { 371 t.Fatal(err) 372 } 373 if err := testPerfQuery(ctx, m, Map.Any("HostSystem"), 20, maxSample); err != nil { 374 t.Fatal(err) 375 } 376 if err := testPerfQuery(ctx, m, Map.Any("ClusterComputeResource"), 300, maxSample); err != nil { 377 t.Fatal(err) 378 } 379 if err := testPerfQuery(ctx, m, Map.Any("Datastore"), 300, maxSample); err != nil { 380 t.Fatal(err) 381 } 382 if err := testPerfQuery(ctx, m, Map.Any("Datacenter"), 300, maxSample); err != nil { 383 t.Fatal(err) 384 } 385 if err := testPerfQuery(ctx, m, Map.Any("ResourcePool"), 300, maxSample); err != nil { 386 t.Fatal(err) 387 } 388 389 //csv format 390 if err := testPerfQueryCSV(ctx, m, Map.Any("VirtualMachine"), 20, maxSample); err != nil { 391 t.Fatal(err) 392 } 393 if err := testPerfQueryCSV(ctx, m, Map.Any("HostSystem"), 20, maxSample); err != nil { 394 t.Fatal(err) 395 } 396 if err := testPerfQueryCSV(ctx, m, Map.Any("ClusterComputeResource"), 300, maxSample); err != nil { 397 t.Fatal(err) 398 } 399 if err := testPerfQueryCSV(ctx, m, Map.Any("Datastore"), 300, maxSample); err != nil { 400 t.Fatal(err) 401 } 402 if err := testPerfQueryCSV(ctx, m, Map.Any("Datacenter"), 300, maxSample); err != nil { 403 t.Fatal(err) 404 } 405 if err := testPerfQueryCSV(ctx, m, Map.Any("ResourcePool"), 300, maxSample); err != nil { 406 t.Fatal(err) 407 } 408 } 409 }