| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- package opencost
- import (
- "testing"
- "time"
- )
- // TestComputeAssetTotals_ProviderID_ByNode verifies that when computing
- // AssetTotals by node (byAsset=true), the ProviderID field is correctly
- // populated from the node's ProviderID.
- func TestComputeAssetTotals_ProviderID_ByNode(t *testing.T) {
- // Create test window
- start := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
- end := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC)
- window := NewClosedWindow(start, end)
- // Create AssetSet with nodes that have ProviderIDs
- as := NewAssetSet(start, end)
- // Node 1: AWS EC2 instance
- node1 := NewNode("node1", "cluster1", "aws:///us-east-1a/i-0abc123def456789", start, end, window)
- node1.CPUCost = 10.0
- node1.RAMCost = 5.0
- // Node 2: GCP instance
- node2 := NewNode("node2", "cluster1", "gce://my-project/us-central1-a/instance-456", start, end, window)
- node2.CPUCost = 8.0
- node2.RAMCost = 4.0
- // Node 3: Azure VM
- node3 := NewNode("node3", "cluster1", "azure:///subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/vm-789", start, end, window)
- node3.CPUCost = 12.0
- node3.RAMCost = 6.0
- as.Insert(node1, nil)
- as.Insert(node2, nil)
- as.Insert(node3, nil)
- // Compute AssetTotals by node (byAsset=true)
- totals := ComputeAssetTotals(as, true)
- // Verify that each node's totals includes the correct ProviderID
- expectedProviderIDs := map[string]string{
- "cluster1/node1": "aws:///us-east-1a/i-0abc123def456789",
- "cluster1/node2": "gce://my-project/us-central1-a/instance-456",
- "cluster1/node3": "azure:///subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/vm-789",
- }
- for key, expectedProviderID := range expectedProviderIDs {
- total, ok := totals[key]
- if !ok {
- t.Errorf("Expected to find totals for key %s", key)
- continue
- }
- if total.ProviderID != expectedProviderID {
- t.Errorf("For key %s: expected ProviderID %q, got %q", key, expectedProviderID, total.ProviderID)
- }
- // Verify Node field is also set correctly
- expectedNodeName := key[len("cluster1/"):]
- if total.Node != expectedNodeName {
- t.Errorf("For key %s: expected Node %q, got %q", key, expectedNodeName, total.Node)
- }
- }
- }
- // TestComputeAssetTotals_ProviderID_ByCluster verifies that when computing
- // AssetTotals by cluster (byAsset=false), the ProviderID field is empty
- // because there's no single instance ID that represents all nodes.
- func TestComputeAssetTotals_ProviderID_ByCluster(t *testing.T) {
- // Create test window
- start := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
- end := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC)
- window := NewClosedWindow(start, end)
- // Create AssetSet with nodes that have ProviderIDs
- as := NewAssetSet(start, end)
- node1 := NewNode("node1", "cluster1", "aws:///us-east-1a/i-0abc123def456789", start, end, window)
- node1.CPUCost = 10.0
- node1.RAMCost = 5.0
- node2 := NewNode("node2", "cluster1", "gce://my-project/us-central1-a/instance-456", start, end, window)
- node2.CPUCost = 8.0
- node2.RAMCost = 4.0
- as.Insert(node1, nil)
- as.Insert(node2, nil)
- // Compute AssetTotals by cluster (byAsset=false)
- totals := ComputeAssetTotals(as, false)
- // Verify that cluster-level totals have an empty ProviderID
- total, ok := totals["cluster1"]
- if !ok {
- t.Fatal("Expected to find totals for cluster1")
- }
- if total.ProviderID != "" {
- t.Errorf("Expected empty ProviderID for cluster-level totals, got %q", total.ProviderID)
- }
- // Verify Node field is also empty at cluster level
- if total.Node != "" {
- t.Errorf("Expected empty Node for cluster-level totals, got %q", total.Node)
- }
- // Verify costs are aggregated correctly
- expectedCPUCost := 18.0 // 10.0 + 8.0
- expectedRAMCost := 9.0 // 5.0 + 4.0
- if total.CPUCost != expectedCPUCost {
- t.Errorf("Expected CPUCost %f, got %f", expectedCPUCost, total.CPUCost)
- }
- if total.RAMCost != expectedRAMCost {
- t.Errorf("Expected RAMCost %f, got %f", expectedRAMCost, total.RAMCost)
- }
- }
- // TestComputeAssetTotals_ProviderID_EmptyProviderID verifies that nodes
- // without a ProviderID still work correctly and result in an empty string
- // in the AssetTotals.
- func TestComputeAssetTotals_ProviderID_EmptyProviderID(t *testing.T) {
- // Create test window
- start := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
- end := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC)
- window := NewClosedWindow(start, end)
- // Create AssetSet with a node that has no ProviderID
- as := NewAssetSet(start, end)
- // Node without ProviderID (e.g., local/bare-metal cluster)
- node := NewNode("node1", "cluster1", "", start, end, window)
- node.CPUCost = 10.0
- node.RAMCost = 5.0
- as.Insert(node, nil)
- // Compute AssetTotals by node (byAsset=true)
- totals := ComputeAssetTotals(as, true)
- // Verify that the node's totals has an empty ProviderID
- total, ok := totals["cluster1/node1"]
- if !ok {
- t.Fatal("Expected to find totals for cluster1/node1")
- }
- if total.ProviderID != "" {
- t.Errorf("Expected empty ProviderID for node without ProviderID, got %q", total.ProviderID)
- }
- // Verify other fields are still populated correctly
- if total.Node != "node1" {
- t.Errorf("Expected Node %q, got %q", "node1", total.Node)
- }
- if total.CPUCost != 10.0 {
- t.Errorf("Expected CPUCost %f, got %f", 10.0, total.CPUCost)
- }
- }
- // TestComputeAssetTotals_ProviderID_MultipleNodesAggregation tests that
- // when multiple nodes with different ProviderIDs are aggregated at the
- // cluster level, the ProviderID remains empty.
- func TestComputeAssetTotals_ProviderID_MultipleNodesAggregation(t *testing.T) {
- // Create test window
- start := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
- end := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC)
- window := NewClosedWindow(start, end)
- // Create AssetSet with multiple nodes across different clusters
- as := NewAssetSet(start, end)
- // Cluster 1 nodes
- node1 := NewNode("node1", "cluster1", "aws:///us-east-1a/i-0abc123", start, end, window)
- node1.CPUCost = 10.0
- node1.RAMCost = 5.0
- node2 := NewNode("node2", "cluster1", "aws:///us-east-1b/i-0def456", start, end, window)
- node2.CPUCost = 8.0
- node2.RAMCost = 4.0
- // Cluster 2 node
- node3 := NewNode("node3", "cluster2", "gce://project/zone/instance", start, end, window)
- node3.CPUCost = 12.0
- node3.RAMCost = 6.0
- as.Insert(node1, nil)
- as.Insert(node2, nil)
- as.Insert(node3, nil)
- // Compute AssetTotals by node (byAsset=true)
- nodeTotal := ComputeAssetTotals(as, true)
- // Verify each node has its own ProviderID
- if nodeTotal["cluster1/node1"].ProviderID != "aws:///us-east-1a/i-0abc123" {
- t.Errorf("Node1 ProviderID mismatch")
- }
- if nodeTotal["cluster1/node2"].ProviderID != "aws:///us-east-1b/i-0def456" {
- t.Errorf("Node2 ProviderID mismatch")
- }
- if nodeTotal["cluster2/node3"].ProviderID != "gce://project/zone/instance" {
- t.Errorf("Node3 ProviderID mismatch")
- }
- // Compute AssetTotals by cluster (byAsset=false)
- clusterTotals := ComputeAssetTotals(as, false)
- // Verify cluster-level totals have empty ProviderID
- for clusterKey, total := range clusterTotals {
- if total.ProviderID != "" {
- t.Errorf("Cluster %s should have empty ProviderID, got %q", clusterKey, total.ProviderID)
- }
- }
- // Verify cluster1 aggregates both nodes correctly
- cluster1Total := clusterTotals["cluster1"]
- expectedCPU := 18.0 // 10.0 + 8.0
- expectedRAM := 9.0 // 5.0 + 4.0
- if cluster1Total.CPUCost != expectedCPU {
- t.Errorf("Cluster1 CPUCost: expected %f, got %f", expectedCPU, cluster1Total.CPUCost)
- }
- if cluster1Total.RAMCost != expectedRAM {
- t.Errorf("Cluster1 RAMCost: expected %f, got %f", expectedRAM, cluster1Total.RAMCost)
- }
- }
|