|
|
@@ -9,7 +9,6 @@ import (
|
|
|
|
|
|
"github.com/opencost/opencost/core/pkg/model/kubemodel"
|
|
|
"github.com/opencost/opencost/core/pkg/source"
|
|
|
- "github.com/opencost/opencost/core/pkg/util"
|
|
|
)
|
|
|
|
|
|
const testClusterUID = "cluster-uid-1"
|
|
|
@@ -19,15 +18,6 @@ func newTestWindow() (time.Time, time.Time) {
|
|
|
return start, start.Add(time.Hour)
|
|
|
}
|
|
|
|
|
|
-func newTestKubeModel(t *testing.T) (*KubeModel, *source.MockOpenCostDataSource) {
|
|
|
- t.Helper()
|
|
|
- ds := source.NewMockOpenCostDataSource()
|
|
|
- ds.ResolutionValue = 5 * time.Minute
|
|
|
- km, err := NewKubeModel(testClusterUID, ds)
|
|
|
- require.NoError(t, err)
|
|
|
- return km, ds
|
|
|
-}
|
|
|
-
|
|
|
// seedCluster sets the minimum overrides needed for computeCluster to succeed.
|
|
|
func seedCluster(ds *source.MockOpenCostDataSource, start, end time.Time) {
|
|
|
ds.Querier.SetOverride(source.QueryClusterInfo, []*source.ClusterInfoResult{
|
|
|
@@ -45,327 +35,179 @@ func TestNewKubeModel_NilDataSource(t *testing.T) {
|
|
|
require.Error(t, err)
|
|
|
}
|
|
|
|
|
|
-// ---- computeCluster ----
|
|
|
-
|
|
|
-func TestComputeCluster_HappyPath(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
- require.NotNil(t, kms.Cluster)
|
|
|
- assert.Equal(t, testClusterUID, kms.Cluster.UID)
|
|
|
- assert.Equal(t, "my-cluster", kms.Cluster.Name)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeCluster_UIDNotFound(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryClusterInfo, []*source.ClusterInfoResult{
|
|
|
- {UID: "other-uid", Cluster: "other-cluster"},
|
|
|
- })
|
|
|
-
|
|
|
- _, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.Error(t, err)
|
|
|
- assert.Contains(t, err.Error(), testClusterUID)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeCluster_NoUptime(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryClusterInfo, []*source.ClusterInfoResult{
|
|
|
- {UID: testClusterUID, Cluster: "my-cluster"},
|
|
|
- })
|
|
|
- // QueryClusterUptime left at NoOp — cluster Start/End stay zero, fail window
|
|
|
- // validation inside RegisterCluster, so kms.Cluster is not set.
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
- assert.Nil(t, kms.Cluster)
|
|
|
-}
|
|
|
-
|
|
|
-// ---- computeNodes ----
|
|
|
-
|
|
|
-func TestComputeNodes_HappyPath(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryNodeInfo, []*source.NodeInfoResult{
|
|
|
- {UID: "node-1", Node: "node-a", ProviderID: "aws:///us-east-1a/i-abc"},
|
|
|
- {UID: "node-2", Node: "node-b", ProviderID: "aws:///us-east-1b/i-def"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryNodeUptime, []*source.UptimeResult{
|
|
|
- {UID: "node-1", First: start, Last: end},
|
|
|
- {UID: "node-2", First: start, Last: end},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryNodeLabels, []*source.NodeLabelsResult{
|
|
|
- {UID: "node-1", Labels: map[string]string{"zone": "us-east-1a"}},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- assert.Len(t, kms.Nodes, 2)
|
|
|
- n1 := kms.Nodes["node-1"]
|
|
|
- require.NotNil(t, n1)
|
|
|
- assert.Equal(t, "node-a", n1.Name)
|
|
|
- assert.Equal(t, "aws:///us-east-1a/i-abc", n1.ProviderID)
|
|
|
- assert.Equal(t, map[string]string{"zone": "us-east-1a"}, n1.Labels)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeNodes_ResourceCapacities(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryNodeInfo, []*source.NodeInfoResult{
|
|
|
- {UID: "node-1", Node: "node-a"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryNodeUptime, []*source.UptimeResult{
|
|
|
- {UID: "node-1", First: start, Last: end},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryNodeResourceCapacities, []*source.ResourceResult{
|
|
|
- {UID: "node-1", Resource: "cpu", Unit: "cores", Value: 4.0},
|
|
|
- {UID: "node-1", Resource: "memory", Unit: "bytes", Value: 16 * 1024 * 1024 * 1024},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryNodeResourcesAllocatable, []*source.ResourceResult{
|
|
|
- {UID: "node-1", Resource: "cpu", Unit: "cores", Value: 3.9},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- n := kms.Nodes["node-1"]
|
|
|
- require.NotNil(t, n)
|
|
|
- assert.NotEmpty(t, n.ResourceCapacities)
|
|
|
- assert.NotEmpty(t, n.ResourcesAllocatable)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeNodes_LocalStorage(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryNodeInfo, []*source.NodeInfoResult{
|
|
|
- {UID: "node-1", Node: "node-a"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryNodeUptime, []*source.UptimeResult{
|
|
|
- {UID: "node-1", First: start, Last: end},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryKMLocalStorageBytes, []*source.UIDValueResult{
|
|
|
- {UID: "node-1", Value: 500 * 1024 * 1024 * 1024},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryKMLocalStorageUsedAvg, []*source.NodeUIDValueResult{
|
|
|
- {UID: "node-1", Value: 100 * 1024 * 1024 * 1024},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryKMLocalStorageUsedMax, []*source.NodeUIDValueResult{
|
|
|
- {UID: "node-1", Value: 200 * 1024 * 1024 * 1024},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- n := kms.Nodes["node-1"]
|
|
|
- require.NotNil(t, n)
|
|
|
- assert.Equal(t, float64(500*1024*1024*1024), n.FileSystem.CapacityBytes)
|
|
|
- assert.Equal(t, float64(100*1024*1024*1024), n.FileSystem.UsageByteAvg)
|
|
|
- assert.Equal(t, float64(200*1024*1024*1024), n.FileSystem.UsageByteMax)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeNodes_EmptyResults(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
- assert.Empty(t, kms.Nodes)
|
|
|
-}
|
|
|
-
|
|
|
-// ---- computePods ----
|
|
|
-
|
|
|
-func TestComputePods_HappyPath(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryPodInfo, []*source.PodInfoResult{
|
|
|
- {UID: "pod-1", Pod: "my-pod", NamespaceUID: "ns-1", NodeUID: "node-1"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodUptime, []*source.UptimeResult{
|
|
|
- {UID: "pod-1", First: start, Last: end},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodLabels, []*source.PodLabelsResult{
|
|
|
- {UID: "pod-1", Labels: map[string]string{"app": "my-app"}},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodAnnotations, []*source.PodAnnotationsResult{
|
|
|
- {UID: "pod-1", Annotations: map[string]string{"note": "val"}},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- pod := kms.Pods["pod-1"]
|
|
|
- require.NotNil(t, pod)
|
|
|
- assert.Equal(t, "my-pod", pod.Name)
|
|
|
- assert.Equal(t, "ns-1", pod.NamespaceUID)
|
|
|
- assert.Equal(t, "node-1", pod.NodeUID)
|
|
|
- assert.Equal(t, map[string]string{"app": "my-app"}, pod.Labels)
|
|
|
- assert.Equal(t, map[string]string{"note": "val"}, pod.Annotations)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputePods_Owners(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryPodInfo, []*source.PodInfoResult{
|
|
|
- {UID: "pod-1", Pod: "my-pod", NamespaceUID: "ns-1"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodUptime, []*source.UptimeResult{
|
|
|
- {UID: "pod-1", First: start, Last: end},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodOwners, []*source.OwnerResult{
|
|
|
- {UID: "pod-1", OwnerUID: "rs-1", OwnerKind: "ReplicaSet", Controller: true},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- pod := kms.Pods["pod-1"]
|
|
|
- require.NotNil(t, pod)
|
|
|
- require.Len(t, pod.Owners, 1)
|
|
|
- assert.Equal(t, "rs-1", pod.Owners[0].UID)
|
|
|
- assert.True(t, pod.Owners[0].Controller)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputePods_PVCVolumes(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryPodInfo, []*source.PodInfoResult{
|
|
|
- {UID: "pod-1", Pod: "my-pod", NamespaceUID: "ns-1"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodUptime, []*source.UptimeResult{
|
|
|
- {UID: "pod-1", First: start, Last: end},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryPodPVCVolumes, []*source.PodPVCVolumeResult{
|
|
|
- {UID: "pod-1", PVCUID: "pvc-1", PodVolumeName: "data"},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- pod := kms.Pods["pod-1"]
|
|
|
- require.NotNil(t, pod)
|
|
|
- require.Len(t, pod.PVCVolumes, 1)
|
|
|
- assert.Equal(t, "pvc-1", pod.PVCVolumes[0].PersistentVolumeClaimUID)
|
|
|
- assert.Equal(t, "data", pod.PVCVolumes[0].Name)
|
|
|
-}
|
|
|
-
|
|
|
-// ---- computeContainers ----
|
|
|
-
|
|
|
-func TestComputeContainers_HappyPath(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- ds.Querier.SetOverride(source.QueryContainerUptime, []*source.ContainerUptimeResult{
|
|
|
- {UptimeResult: source.UptimeResult{UID: "pod-1", First: start, Last: end}, Container: "app"},
|
|
|
- {UptimeResult: source.UptimeResult{UID: "pod-1", First: start, Last: end}, Container: "sidecar"},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
- assert.Len(t, kms.Containers, 2)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeContainers_ResourceRequestsAndLimits(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
+// ---- ComputeKubeModelSet orchestration ----
|
|
|
|
|
|
- ds.Querier.SetOverride(source.QueryContainerUptime, []*source.ContainerUptimeResult{
|
|
|
- {UptimeResult: source.UptimeResult{UID: "pod-1", First: start, Last: end}, Container: "app"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryContainerResourceRequests, []*source.ContainerResourceResult{
|
|
|
- {ResourceResult: source.ResourceResult{UID: "pod-1", Resource: "cpu", Unit: "cores", Value: 0.5}, Container: "app"},
|
|
|
- {ResourceResult: source.ResourceResult{UID: "pod-1", Resource: "memory", Unit: "bytes", Value: 128 * 1024 * 1024}, Container: "app"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryContainerResourceLimits, []*source.ContainerResourceResult{
|
|
|
- {ResourceResult: source.ResourceResult{UID: "pod-1", Resource: "cpu", Unit: "cores", Value: 1.0}, Container: "app"},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- c := findContainer(kms, "pod-1", "app")
|
|
|
- require.NotNil(t, c)
|
|
|
- assert.NotEmpty(t, c.ResourceRequests)
|
|
|
- assert.NotEmpty(t, c.ResourceLimits)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeContainers_CPUAndRAMUsage(t *testing.T) {
|
|
|
+func TestComputeKubeModelSet(t *testing.T) {
|
|
|
start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
|
|
|
- ts := float64(start.Unix())
|
|
|
- ds.Querier.SetOverride(source.QueryContainerUptime, []*source.ContainerUptimeResult{
|
|
|
- {UptimeResult: source.UptimeResult{UID: "pod-1", First: start, Last: end}, Container: "app"},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryCPUCoresAllocated, []*source.CPUCoresAllocatedResult{
|
|
|
- {UID: "pod-1", Container: "app", Data: []*util.Vector{{Timestamp: ts, Value: 0.25}}},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryCPUUsageAvg, []*source.CPUUsageAvgResult{
|
|
|
- {UID: "pod-1", Container: "app", Data: []*util.Vector{{Timestamp: ts, Value: 0.1}}},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryCPUUsageMax, []*source.CPUUsageMaxResult{
|
|
|
- {UID: "pod-1", Container: "app", Data: []*util.Vector{{Timestamp: ts, Value: 0.2}}},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryRAMBytesAllocated, []*source.RAMBytesAllocatedResult{
|
|
|
- {UID: "pod-1", Container: "app", Data: []*util.Vector{{Timestamp: ts, Value: 256 * 1024 * 1024}}},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryRAMUsageAvg, []*source.RAMUsageAvgResult{
|
|
|
- {UID: "pod-1", Container: "app", Data: []*util.Vector{{Timestamp: ts, Value: 100 * 1024 * 1024}}},
|
|
|
- })
|
|
|
- ds.Querier.SetOverride(source.QueryRAMUsageMax, []*source.RAMUsageMaxResult{
|
|
|
- {UID: "pod-1", Container: "app", Data: []*util.Vector{{Timestamp: ts, Value: 200 * 1024 * 1024}}},
|
|
|
- })
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
-
|
|
|
- c := findContainer(kms, "pod-1", "app")
|
|
|
- require.NotNil(t, c)
|
|
|
- assert.Equal(t, 0.25, c.CPUCoresAllocated)
|
|
|
- assert.Equal(t, 0.1, c.CPUCoreUsageAvg)
|
|
|
- assert.Equal(t, 0.2, c.CPUCoreUsageMax)
|
|
|
- assert.Equal(t, float64(256*1024*1024), c.RAMBytesAllocated)
|
|
|
- assert.Equal(t, float64(100*1024*1024), c.RAMBytesUsageAvg)
|
|
|
- assert.Equal(t, float64(200*1024*1024), c.RAMBytesUsageMax)
|
|
|
-}
|
|
|
-
|
|
|
-func TestComputeContainers_EmptyResults(t *testing.T) {
|
|
|
- start, end := newTestWindow()
|
|
|
- km, ds := newTestKubeModel(t)
|
|
|
- seedCluster(ds, start, end)
|
|
|
-
|
|
|
- kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
- require.NoError(t, err)
|
|
|
- assert.Empty(t, kms.Containers)
|
|
|
-}
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ setup func(ds *source.MockOpenCostDataSource)
|
|
|
+ wantErr bool
|
|
|
+ check func(t *testing.T, kms *kubemodel.KubeModelSet)
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "cluster UID not found returns error",
|
|
|
+ setup: func(ds *source.MockOpenCostDataSource) {
|
|
|
+ ds.Querier.SetOverride(source.QueryClusterInfo, []*source.ClusterInfoResult{
|
|
|
+ {UID: "wrong-uid", Cluster: "other"},
|
|
|
+ })
|
|
|
+ },
|
|
|
+ wantErr: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "cluster uptime missing: cluster nil but other compute functions still run",
|
|
|
+ setup: func(ds *source.MockOpenCostDataSource) {
|
|
|
+ // cluster info present but no uptime — cluster won't register, but no error
|
|
|
+ ds.Querier.SetOverride(source.QueryClusterInfo, []*source.ClusterInfoResult{
|
|
|
+ {UID: testClusterUID, Cluster: "my-cluster"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryNamespaceInfo, []*source.NamespaceInfoResult{
|
|
|
+ {UID: "ns-1", Namespace: "default"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryNamespaceUptime, []*source.UptimeResult{
|
|
|
+ {UID: "ns-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ },
|
|
|
+ check: func(t *testing.T, kms *kubemodel.KubeModelSet) {
|
|
|
+ assert.Nil(t, kms.Cluster, "cluster with no uptime should not be registered")
|
|
|
+ assert.NotEmpty(t, kms.Namespaces, "namespace compute should still run after cluster registration fails")
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "all compute functions produce results when given data",
|
|
|
+ setup: func(ds *source.MockOpenCostDataSource) {
|
|
|
+ seedCluster(ds, start, end)
|
|
|
+ ds.Querier.SetOverride(source.QueryNodeInfo, []*source.NodeInfoResult{
|
|
|
+ {UID: "node-1", Node: "node-a"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryNodeUptime, []*source.UptimeResult{
|
|
|
+ {UID: "node-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryNamespaceInfo, []*source.NamespaceInfoResult{
|
|
|
+ {UID: "ns-1", Namespace: "default"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryNamespaceUptime, []*source.UptimeResult{
|
|
|
+ {UID: "ns-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryPodInfo, []*source.PodInfoResult{
|
|
|
+ {UID: "pod-1", Pod: "my-pod", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryPodUptime, []*source.UptimeResult{
|
|
|
+ {UID: "pod-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryContainerUptime, []*source.ContainerUptimeResult{
|
|
|
+ {UptimeResult: source.UptimeResult{UID: "pod-1", First: start, Last: end}, Container: "app"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryDeploymentInfo, []*source.DeploymentInfoResult{
|
|
|
+ {UID: "dep-1", Deployment: "my-dep", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryDeploymentUptime, []*source.UptimeResult{
|
|
|
+ {UID: "dep-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryStatefulSetInfo, []*source.StatefulSetInfoResult{
|
|
|
+ {UID: "sts-1", StatefulSet: "my-sts", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryStatefulSetUptime, []*source.UptimeResult{
|
|
|
+ {UID: "sts-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryDaemonSetInfo, []*source.DaemonSetInfoResult{
|
|
|
+ {UID: "ds-1", DaemonSet: "my-ds", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryDaemonSetUptime, []*source.UptimeResult{
|
|
|
+ {UID: "ds-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryJobInfo, []*source.JobInfoResult{
|
|
|
+ {UID: "job-1", Job: "my-job", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryJobUptime, []*source.UptimeResult{
|
|
|
+ {UID: "job-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryCronJobInfo, []*source.CronJobInfoResult{
|
|
|
+ {UID: "cj-1", CronJob: "my-cj", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryCronJobUptime, []*source.UptimeResult{
|
|
|
+ {UID: "cj-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryReplicaSetInfo, []*source.ReplicaSetInfoResult{
|
|
|
+ {UID: "rs-1", ReplicaSet: "my-rs", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryReplicaSetUptime, []*source.UptimeResult{
|
|
|
+ {UID: "rs-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryResourceQuotaInfo, []*source.ResourceQuotaInfoResult{
|
|
|
+ {UID: "rq-1", ResourceQuota: "default-quota", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryResourceQuotaUptime, []*source.UptimeResult{
|
|
|
+ {UID: "rq-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryServiceInfo, []*source.ServiceInfoResult{
|
|
|
+ {UID: "svc-1", Service: "my-svc", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryServiceUptime, []*source.UptimeResult{
|
|
|
+ {UID: "svc-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryKMPVInfo, []*source.PVInfoResult{
|
|
|
+ {UID: "pv-1", PersistentVolume: "my-pv"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryPVUptime, []*source.UptimeResult{
|
|
|
+ {UID: "pv-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryPVBytes, []*source.PVBytesResult{
|
|
|
+ {UID: "pv-1", Value: 10 * 1024 * 1024 * 1024},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryKMPVCInfo, []*source.PVCInfoResult{
|
|
|
+ {UID: "pvc-1", PersistentVolumeClaim: "data-claim", NamespaceUID: "ns-1"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryPVCUptime, []*source.UptimeResult{
|
|
|
+ {UID: "pvc-1", First: start, Last: end},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryDCGMDeviceInfo, []*source.DCGMDeviceInfoResult{
|
|
|
+ {UUID: "GPU-abc123", Device: "nvidia0", ModelName: "A100"},
|
|
|
+ })
|
|
|
+ ds.Querier.SetOverride(source.QueryDCGMDeviceUptime, []*source.DCGMDeviceUptimeResult{
|
|
|
+ {UUID: "GPU-abc123", First: start, Last: end},
|
|
|
+ })
|
|
|
+ },
|
|
|
+ check: func(t *testing.T, kms *kubemodel.KubeModelSet) {
|
|
|
+ assert.NotNil(t, kms.Cluster)
|
|
|
+ assert.NotEmpty(t, kms.Nodes)
|
|
|
+ assert.NotEmpty(t, kms.Namespaces)
|
|
|
+ assert.NotEmpty(t, kms.Pods)
|
|
|
+ assert.NotEmpty(t, kms.Containers)
|
|
|
+ assert.NotEmpty(t, kms.Deployments)
|
|
|
+ assert.NotEmpty(t, kms.StatefulSets)
|
|
|
+ assert.NotEmpty(t, kms.DaemonSets)
|
|
|
+ assert.NotEmpty(t, kms.Jobs)
|
|
|
+ assert.NotEmpty(t, kms.CronJobs)
|
|
|
+ assert.NotEmpty(t, kms.ReplicaSets)
|
|
|
+ assert.NotEmpty(t, kms.ResourceQuotas)
|
|
|
+ assert.NotEmpty(t, kms.Services)
|
|
|
+ assert.NotEmpty(t, kms.PersistentVolumes)
|
|
|
+ assert.NotEmpty(t, kms.PersistentVolumeClaims)
|
|
|
+ assert.NotEmpty(t, kms.DCGMDevices)
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
|
|
|
-func findContainer(kms *kubemodel.KubeModelSet, podUID, name string) *kubemodel.Container {
|
|
|
- for _, c := range kms.Containers {
|
|
|
- if c.PodUID == podUID && c.Name == name {
|
|
|
- return c
|
|
|
- }
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ ds := source.NewMockOpenCostDataSource()
|
|
|
+ ds.ResolutionValue = 5 * time.Minute
|
|
|
+ tt.setup(ds)
|
|
|
+
|
|
|
+ km, err := NewKubeModel(testClusterUID, ds)
|
|
|
+ require.NoError(t, err)
|
|
|
+
|
|
|
+ kms, err := km.ComputeKubeModelSet(start, end)
|
|
|
+ if tt.wantErr {
|
|
|
+ require.Error(t, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ require.NoError(t, err)
|
|
|
+ if tt.check != nil {
|
|
|
+ tt.check(t, kms)
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
- return nil
|
|
|
}
|