Просмотр исходного кода

Added basic cost change tracking and test cases

Signed-off-by: nickcurie <ncurie@kubecost.com>
nickcurie 3 лет назад
Родитель
Сommit
c19b4b9fd1
2 измененных файлов с 87 добавлено и 65 удалено
  1. 12 8
      pkg/kubecost/asset.go
  2. 75 57
      pkg/kubecost/diff_test.go

+ 12 - 8
pkg/kubecost/asset.go

@@ -2893,6 +2893,7 @@ type DiffKind string
 const (
 const (
 	DiffAdded   DiffKind = "added"
 	DiffAdded   DiffKind = "added"
 	DiffRemoved          = "removed"
 	DiffRemoved          = "removed"
+	DiffChanged          = "changed"
 )
 )
 
 
 // Diff stores an object and a string that denotes whether that object was
 // Diff stores an object and a string that denotes whether that object was
@@ -2902,23 +2903,26 @@ type Diff[T any] struct {
 	Kind   DiffKind
 	Kind   DiffKind
 }
 }
 
 
-// DiffAsset takes two AssetSets and returns a slice of Diffs by checking
-// the keys of each AssetSet. If a key is not found, a Diff is generated
-// and added to the slice.
-func DiffAsset(before, after *AssetSet) []Diff[Asset] {
-	changedItems := []Diff[Asset]{}
+// DiffAsset takes two AssetSets and returns a map of keys to Diffs by checking
+// the keys of each AssetSet. If a key is not found or is found with a different total cost,
+// a Diff is generated and added to the map.
+func DiffAsset(before, after *AssetSet) map[string]Diff[Asset] {
+	changedItems := map[string]Diff[Asset]{}
 
 
 	for assetKey1, asset1 := range before.assets {
 	for assetKey1, asset1 := range before.assets {
-		if _, ok := after.assets[assetKey1]; !ok {
+		if asset2, ok := after.assets[assetKey1]; !ok {
 			d := Diff[Asset]{asset1, DiffRemoved}
 			d := Diff[Asset]{asset1, DiffRemoved}
-			changedItems = append(changedItems, d)
+			changedItems[assetKey1] = d
+		} else if asset1.TotalCost() != asset2.TotalCost() {
+			d := Diff[Asset]{asset1, DiffChanged}
+			changedItems[assetKey1] = d
 		}
 		}
 	}
 	}
 
 
 	for assetKey2, asset2 := range after.assets {
 	for assetKey2, asset2 := range after.assets {
 		if _, ok := before.assets[assetKey2]; !ok {
 		if _, ok := before.assets[assetKey2]; !ok {
 			d := Diff[Asset]{asset2, DiffAdded}
 			d := Diff[Asset]{asset2, DiffAdded}
-			changedItems = append(changedItems, d)
+			changedItems[assetKey2] = d
 		}
 		}
 	}
 	}
 
 

+ 75 - 57
pkg/kubecost/diff_test.go

@@ -4,105 +4,123 @@ import (
 	"reflect"
 	"reflect"
 	"testing"
 	"testing"
 	"time"
 	"time"
-
-	"golang.org/x/exp/slices"
 )
 )
 
 
 func TestDiff(t *testing.T) {
 func TestDiff(t *testing.T) {
 
 
 	start := time.Now().AddDate(0, 0, -1)
 	start := time.Now().AddDate(0, 0, -1)
-	end :=  time.Now()
+	end := time.Now()
 	window1 := NewWindow(&start, &end)
 	window1 := NewWindow(&start, &end)
 
 
 	node1 := NewNode("node1", "cluster1", "123abc", start, end, window1)
 	node1 := NewNode("node1", "cluster1", "123abc", start, end, window1)
+	node1.CPUCost = 10
+	node1b := node1.Clone().(*Node)
+	node1b.CPUCost = 20
+	node1Key, _ := key(node1, nil)
 	node2 := NewNode("node2", "cluster1", "123abc", start, end, window1)
 	node2 := NewNode("node2", "cluster1", "123abc", start, end, window1)
+	node2Key, _ := key(node2, nil)
 	node3 := NewNode("node3", "cluster1", "123abc", start, end, window1)
 	node3 := NewNode("node3", "cluster1", "123abc", start, end, window1)
+	node3Key, _ := key(node3, nil)
 	node4 := NewNode("node4", "cluster1", "123abc", start, end, window1)
 	node4 := NewNode("node4", "cluster1", "123abc", start, end, window1)
+	node4Key, _ := key(node4, nil)
 	disk1 := NewDisk("disk1", "cluster1", "123abc", start, end, window1)
 	disk1 := NewDisk("disk1", "cluster1", "123abc", start, end, window1)
+	disk1Key, _ := key(disk1, nil)
 	disk2 := NewDisk("disk2", "cluster1", "123abc", start, end, window1)
 	disk2 := NewDisk("disk2", "cluster1", "123abc", start, end, window1)
+	disk2Key, _ := key(disk2, nil)
 
 
 	cases := map[string]struct {
 	cases := map[string]struct {
 		inputAssetsBefore []Asset
 		inputAssetsBefore []Asset
 		inputAssetsAfter  []Asset
 		inputAssetsAfter  []Asset
-		expected          []Diff[Asset]
+		test              []Node
+		costChange        []int
+		expected          map[string]Diff[Asset]
 	}{
 	}{
-		"added node":            {
-			inputAssetsBefore: []Asset{node1, node2}, 
-			inputAssetsAfter:  []Asset{node1, node2, node3}, 
-			expected:          []Diff[Asset]{{node3, DiffAdded}},
+		"added node": {
+			inputAssetsBefore: []Asset{node1, node2},
+			inputAssetsAfter:  []Asset{node1, node2, node3},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{node3Key: {node3, DiffAdded}},
 		},
 		},
-		"multiple adds":         {
-			inputAssetsBefore: []Asset{node1, node2}, 
-			inputAssetsAfter:  []Asset{node1, node2, node3, node4}, 
-			expected:          []Diff[Asset]{{node3, DiffAdded}, {node4, DiffAdded}},
+		"multiple adds": {
+			inputAssetsBefore: []Asset{node1, node2},
+			inputAssetsAfter:  []Asset{node1, node2, node3, node4},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{node3Key: {node3, DiffAdded}, node4Key: {node4, DiffAdded}},
 		},
 		},
-		"removed node":          {
-			inputAssetsBefore: []Asset{node1, node2}, 
-			inputAssetsAfter:  []Asset{node2}, 
-			expected:          []Diff[Asset]{{node1, DiffRemoved}},
+		"removed node": {
+			inputAssetsBefore: []Asset{node1, node2},
+			inputAssetsAfter:  []Asset{node2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{node1Key: {node1, DiffRemoved}},
 		},
 		},
-		"multiple removes":      {
-			inputAssetsBefore: []Asset{node1, node2, node3}, 
-			inputAssetsAfter:  []Asset{node2}, 
-			expected:          []Diff[Asset]{{node1, DiffRemoved}, {node3, DiffRemoved}},
+		"multiple removes": {
+			inputAssetsBefore: []Asset{node1, node2, node3},
+			inputAssetsAfter:  []Asset{node2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{node1Key: {node1, DiffRemoved}, node3Key: {node3, DiffRemoved}},
 		},
 		},
-		"remove all":            {
-			inputAssetsBefore: []Asset{node1, node2}, 
-			inputAssetsAfter:  []Asset{}, 
-			expected:          []Diff[Asset]{{node1, DiffRemoved}, {node2, DiffRemoved}},
+		"remove all": {
+			inputAssetsBefore: []Asset{node1, node2},
+			inputAssetsAfter:  []Asset{},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{node1Key: {node1, DiffRemoved}, node2Key: {node2, DiffRemoved}},
 		},
 		},
-		"add and remove":        {
-			inputAssetsBefore: []Asset{node1, node2}, 
-			inputAssetsAfter:  []Asset{node2, node3}, 
-			expected:          []Diff[Asset]{{node1, DiffRemoved}, {node3, DiffAdded}},
+		"add and remove": {
+			inputAssetsBefore: []Asset{node1, node2},
+			inputAssetsAfter:  []Asset{node2, node3},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{node1Key: {node1, DiffRemoved}, node3Key: {node3, DiffAdded}},
 		},
 		},
-		"no change":             {
-			inputAssetsBefore: []Asset{node1, node2}, 
-			inputAssetsAfter:  []Asset{node1, node2}, 
-			expected:          []Diff[Asset]{},
+		"no change": {
+			inputAssetsBefore: []Asset{node1, node2},
+			inputAssetsAfter:  []Asset{node1, node2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{},
 		},
 		},
-		"order switch":          {
-			inputAssetsBefore: []Asset{node2, node1}, 
-			inputAssetsAfter:  []Asset{node1, node2}, 
-			expected:          []Diff[Asset]{},
+		"order switch": {
+			inputAssetsBefore: []Asset{node2, node1},
+			inputAssetsAfter:  []Asset{node1, node2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{},
 		},
 		},
-		"disk add":              {
-			inputAssetsBefore: []Asset{disk1, node1}, 
-			inputAssetsAfter:  []Asset{disk1, node1, disk2}, 
-			expected:          []Diff[Asset]{{disk2, DiffAdded}},
+		"disk add": {
+			inputAssetsBefore: []Asset{disk1, node1},
+			inputAssetsAfter:  []Asset{disk1, node1, disk2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{disk2Key: {disk2, DiffAdded}},
 		},
 		},
-		"disk and node add":     {
-			inputAssetsBefore: []Asset{disk1, node1}, 
-			inputAssetsAfter:  []Asset{disk1, node1, disk2, node2}, 
-			expected:          []Diff[Asset]{{disk2, DiffAdded}, {node2, DiffAdded}},
+		"disk and node add": {
+			inputAssetsBefore: []Asset{disk1, node1},
+			inputAssetsAfter:  []Asset{disk1, node1, disk2, node2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{disk2Key: {disk2, DiffAdded}, node2Key: {node2, DiffAdded}},
 		},
 		},
 		"disk and node removed": {
 		"disk and node removed": {
-			inputAssetsBefore: []Asset{disk1, node1, disk2, node2}, 
-			inputAssetsAfter:  []Asset{disk2, node2}, 
-			expected:          []Diff[Asset]{{disk1, DiffRemoved}, {node1, DiffRemoved}},
+			inputAssetsBefore: []Asset{disk1, node1, disk2, node2},
+			inputAssetsAfter:  []Asset{disk2, node2},
+			costChange:        []int{},
+			expected:          map[string]Diff[Asset]{disk1Key: {disk1, DiffRemoved}, node1Key: {node1, DiffRemoved}},
+		},
+		"cost change": {
+			inputAssetsBefore: []Asset{node1},
+			inputAssetsAfter:  []Asset{node1b},
+			expected:          map[string]Diff[Asset]{node1Key: {node1, DiffChanged}},
 		},
 		},
 	}
 	}
 
 
 	for name, tc := range cases {
 	for name, tc := range cases {
 		t.Run(name, func(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			as1 := NewAssetSet(start, end, tc.inputAssetsBefore...)
 			as1 := NewAssetSet(start, end, tc.inputAssetsBefore...)
+
 			as2 := NewAssetSet(start, end, tc.inputAssetsAfter...)
 			as2 := NewAssetSet(start, end, tc.inputAssetsAfter...)
 
 
 			result := DiffAsset(as1.Clone(), as2.Clone())
 			result := DiffAsset(as1.Clone(), as2.Clone())
 
 
-			slices.SortFunc(result, func(a, b Diff[Asset]) bool {
-				return a.Entity.Properties().Name < b.Entity.Properties().Name
-			})
-
-			slices.SortFunc(tc.expected, func(a, b Diff[Asset]) bool {
-				return a.Entity.Properties().Name < b.Entity.Properties().Name
-			})
-	
 			if !reflect.DeepEqual(result, tc.expected) {
 			if !reflect.DeepEqual(result, tc.expected) {
 				t.Fatalf("expected %+v; got %+v", tc.expected, result)
 				t.Fatalf("expected %+v; got %+v", tc.expected, result)
 			}
 			}
-			
+
 		})
 		})
 	}
 	}
 
 
-}
+}