| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- package scrape
- import (
- "fmt"
- "reflect"
- "testing"
- "time"
- "github.com/opencost/opencost/core/pkg/source"
- "github.com/opencost/opencost/modules/collector-source/pkg/metric"
- "github.com/opencost/opencost/modules/collector-source/pkg/util"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
- )
- type mockStatSummaryClient struct {
- results []*stats.Summary
- err error
- }
- func (m *mockStatSummaryClient) GetNodeData() ([]*stats.Summary, error) {
- return m.results, m.err
- }
- func TestStatScraper_Scrape(t *testing.T) {
- start1, _ := time.Parse(time.RFC3339, Start1Str)
- tests := map[string]struct {
- summaries []*stats.Summary
- err error
- expected []metric.Update
- }{
- "nil values": {
- summaries: []*stats.Summary{
- {
- Node: stats.NodeStats{
- NodeName: "node1",
- CPU: &stats.CPUStats{
- Time: metav1.Time{Time: start1},
- UsageCoreNanoSeconds: nil,
- },
- Fs: &stats.FsStats{
- Time: metav1.Time{Time: start1},
- CapacityBytes: nil,
- },
- },
- Pods: []stats.PodStats{
- {
- PodRef: stats.PodReference{
- Name: "pod1",
- Namespace: "namespace1",
- UID: "uid1",
- },
- Network: &stats.NetworkStats{
- Time: metav1.Time{Time: start1},
- InterfaceStats: stats.InterfaceStats{
- RxBytes: nil,
- TxBytes: nil,
- },
- },
- VolumeStats: []stats.VolumeStats{
- {
- Name: "vol1",
- PVCRef: &stats.PVCReference{
- Namespace: "namespace1",
- Name: "pvc1",
- },
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: nil,
- },
- },
- },
- Containers: []stats.ContainerStats{
- {
- Name: "container1",
- CPU: &stats.CPUStats{
- Time: metav1.Time{Time: start1},
- UsageCoreNanoSeconds: nil,
- },
- Memory: &stats.MemoryStats{
- Time: metav1.Time{Time: start1},
- WorkingSetBytes: nil,
- },
- Rootfs: &stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: nil,
- },
- },
- },
- },
- },
- },
- },
- expected: []metric.Update{},
- },
- "nil structs": {
- summaries: []*stats.Summary{
- {
- Node: stats.NodeStats{
- NodeName: "node1",
- CPU: nil,
- Fs: nil,
- },
- Pods: []stats.PodStats{
- {
- PodRef: stats.PodReference{
- Name: "pod1",
- Namespace: "namespace1",
- UID: "uid1",
- },
- Network: nil,
- VolumeStats: nil,
- Containers: []stats.ContainerStats{
- {
- Name: "container1",
- CPU: nil,
- Memory: nil,
- Rootfs: nil,
- },
- },
- },
- },
- },
- },
- expected: []metric.Update{},
- },
- "single node": {
- summaries: []*stats.Summary{
- {
- Node: stats.NodeStats{
- NodeName: "node1",
- CPU: &stats.CPUStats{
- Time: metav1.Time{Time: start1},
- UsageCoreNanoSeconds: util.Ptr(uint64(2000000000)),
- },
- Fs: &stats.FsStats{
- Time: metav1.Time{Time: start1},
- CapacityBytes: util.Ptr(uint64(2 * util.GB)),
- },
- },
- Pods: []stats.PodStats{
- {
- PodRef: stats.PodReference{
- Name: "pod1",
- Namespace: "namespace1",
- UID: "uid1",
- },
- Network: &stats.NetworkStats{
- Time: metav1.Time{Time: start1},
- InterfaceStats: stats.InterfaceStats{
- RxBytes: util.Ptr(uint64(1 * util.MB)),
- TxBytes: util.Ptr(uint64(2 * util.MB)),
- },
- },
- VolumeStats: []stats.VolumeStats{
- {
- Name: "ignoreVol1",
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- {
- Name: "vol1",
- PVCRef: &stats.PVCReference{
- Namespace: "namespace1",
- Name: "pvc1",
- },
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- },
- Containers: []stats.ContainerStats{
- {
- Name: "container1",
- CPU: &stats.CPUStats{
- Time: metav1.Time{Time: start1},
- UsageCoreNanoSeconds: util.Ptr(uint64(1000000000)),
- },
- Memory: &stats.MemoryStats{
- Time: metav1.Time{Time: start1},
- WorkingSetBytes: util.Ptr(uint64(5 * util.MB)),
- },
- Rootfs: &stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- },
- },
- },
- },
- },
- expected: []metric.Update{
- {
- Name: metric.NodeCPUSecondsTotal,
- Labels: map[string]string{
- source.KubernetesNodeLabel: "node1",
- source.ModeLabel: "",
- },
- Value: 2,
- },
- {
- Name: metric.NodeFSCapacityBytes,
- Labels: map[string]string{
- source.InstanceLabel: "node1",
- source.DeviceLabel: "local",
- },
- Value: float64(2 * util.GB),
- },
- {
- Name: metric.ContainerNetworkReceiveBytesTotal,
- Labels: map[string]string{
- source.UIDLabel: "uid1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- },
- Value: float64(1 * util.MB),
- },
- {
- Name: metric.ContainerNetworkTransmitBytesTotal,
- Labels: map[string]string{
- source.UIDLabel: "uid1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- },
- Value: float64(2 * util.MB),
- },
- {
- Name: metric.KubeletVolumeStatsUsedBytes,
- Labels: map[string]string{
- source.PVCLabel: "pvc1",
- source.NamespaceLabel: "namespace1",
- source.UIDLabel: "uid1",
- },
- Value: float64(1 * util.GB),
- },
- {
- Name: metric.ContainerCPUUsageSecondsTotal,
- Labels: map[string]string{
- source.ContainerLabel: "container1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- source.NodeLabel: "node1",
- source.InstanceLabel: "node1",
- source.UIDLabel: "uid1",
- },
- Value: 1,
- },
- {
- Name: metric.ContainerMemoryWorkingSetBytes,
- Labels: map[string]string{
- source.ContainerLabel: "container1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- source.NodeLabel: "node1",
- source.InstanceLabel: "node1",
- source.UIDLabel: "uid1",
- },
- Value: float64(5 * util.MB),
- },
- {
- Name: metric.ContainerFSUsageBytes,
- Labels: map[string]string{
- source.InstanceLabel: "node1",
- source.DeviceLabel: "local",
- source.UIDLabel: "uid1",
- },
- Value: float64(1 * util.GB),
- },
- },
- },
- "single node with error": {
- summaries: []*stats.Summary{
- {
- Node: stats.NodeStats{
- NodeName: "node1",
- CPU: &stats.CPUStats{
- Time: metav1.Time{Time: start1},
- UsageCoreNanoSeconds: util.Ptr(uint64(2000000000)),
- },
- Fs: &stats.FsStats{
- Time: metav1.Time{Time: start1},
- CapacityBytes: util.Ptr(uint64(2 * util.GB)),
- },
- },
- Pods: []stats.PodStats{
- {
- PodRef: stats.PodReference{
- Name: "pod1",
- Namespace: "namespace1",
- UID: "uid1",
- },
- Network: &stats.NetworkStats{
- Time: metav1.Time{Time: start1},
- InterfaceStats: stats.InterfaceStats{
- RxBytes: util.Ptr(uint64(1 * util.MB)),
- TxBytes: util.Ptr(uint64(2 * util.MB)),
- },
- },
- VolumeStats: []stats.VolumeStats{
- {
- Name: "ignoreVol1",
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- {
- Name: "vol1",
- PVCRef: &stats.PVCReference{
- Namespace: "namespace1",
- Name: "pvc1",
- },
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- },
- Containers: []stats.ContainerStats{
- {
- Name: "container1",
- CPU: &stats.CPUStats{
- Time: metav1.Time{Time: start1},
- UsageCoreNanoSeconds: util.Ptr(uint64(1000000000)),
- },
- Memory: &stats.MemoryStats{
- Time: metav1.Time{Time: start1},
- WorkingSetBytes: util.Ptr(uint64(5 * util.MB)),
- },
- Rootfs: &stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- },
- },
- },
- },
- },
- err: fmt.Errorf("failed to retrieve node-XYZ"),
- expected: []metric.Update{
- {
- Name: metric.NodeCPUSecondsTotal,
- Labels: map[string]string{
- source.KubernetesNodeLabel: "node1",
- source.ModeLabel: "",
- },
- Value: 2,
- },
- {
- Name: metric.NodeFSCapacityBytes,
- Labels: map[string]string{
- source.InstanceLabel: "node1",
- source.DeviceLabel: "local",
- },
- Value: float64(2 * util.GB),
- },
- {
- Name: metric.ContainerNetworkReceiveBytesTotal,
- Labels: map[string]string{
- source.UIDLabel: "uid1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- },
- Value: float64(1 * util.MB),
- },
- {
- Name: metric.ContainerNetworkTransmitBytesTotal,
- Labels: map[string]string{
- source.UIDLabel: "uid1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- },
- Value: float64(2 * util.MB),
- },
- {
- Name: metric.KubeletVolumeStatsUsedBytes,
- Labels: map[string]string{
- source.PVCLabel: "pvc1",
- source.NamespaceLabel: "namespace1",
- source.UIDLabel: "uid1",
- },
- Value: float64(1 * util.GB),
- },
- {
- Name: metric.ContainerCPUUsageSecondsTotal,
- Labels: map[string]string{
- source.ContainerLabel: "container1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- source.NodeLabel: "node1",
- source.InstanceLabel: "node1",
- source.UIDLabel: "uid1",
- },
- Value: 1,
- },
- {
- Name: metric.ContainerMemoryWorkingSetBytes,
- Labels: map[string]string{
- source.ContainerLabel: "container1",
- source.PodLabel: "pod1",
- source.NamespaceLabel: "namespace1",
- source.NodeLabel: "node1",
- source.InstanceLabel: "node1",
- source.UIDLabel: "uid1",
- },
- Value: float64(5 * util.MB),
- },
- {
- Name: metric.ContainerFSUsageBytes,
- Labels: map[string]string{
- source.InstanceLabel: "node1",
- source.DeviceLabel: "local",
- source.UIDLabel: "uid1",
- },
- Value: float64(1 * util.GB),
- },
- },
- },
- "repeat pvc": {
- summaries: []*stats.Summary{
- {
- Node: stats.NodeStats{
- NodeName: "node1",
- },
- Pods: []stats.PodStats{
- {
- PodRef: stats.PodReference{
- Name: "pod1",
- Namespace: "namespace1",
- UID: "uid1",
- },
- VolumeStats: []stats.VolumeStats{
- {
- Name: "vol1",
- PVCRef: &stats.PVCReference{
- Namespace: "namespace1",
- Name: "pvc1",
- },
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- },
- },
- {
- PodRef: stats.PodReference{
- Name: "pod2",
- Namespace: "namespace1",
- UID: "uid1",
- },
- VolumeStats: []stats.VolumeStats{
- {
- Name: "vol1",
- PVCRef: &stats.PVCReference{
- Namespace: "namespace1",
- Name: "pvc1",
- },
- FsStats: stats.FsStats{
- Time: metav1.Time{Time: start1},
- UsedBytes: util.Ptr(uint64(1 * util.GB)),
- },
- },
- },
- },
- },
- },
- },
- expected: []metric.Update{
- {
- Name: metric.KubeletVolumeStatsUsedBytes,
- Labels: map[string]string{
- source.PVCLabel: "pvc1",
- source.NamespaceLabel: "namespace1",
- source.UIDLabel: "uid1",
- },
- Value: float64(1 * util.GB),
- },
- },
- },
- }
- for name, tt := range tests {
- t.Run(name, func(t *testing.T) {
- s := &StatSummaryScraper{
- client: &mockStatSummaryClient{results: tt.summaries},
- }
- scrapeResults := s.Scrape()
- if len(scrapeResults) != len(tt.expected) {
- t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
- }
- for i, expected := range tt.expected {
- got := scrapeResults[i]
- if !reflect.DeepEqual(expected, got) {
- t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
- }
- }
- })
- }
- }
|