provider_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package stackit
  2. import (
  3. "testing"
  4. )
  5. func newTestProvider(flavors map[string]*pimFlavorPricing, storage map[string]*pimStoragePricing) *STACKIT {
  6. return &STACKIT{
  7. ClusterRegion: "eu01",
  8. pimFlavors: flavors,
  9. pimStorage: storage,
  10. }
  11. }
  12. func TestNodePricing(t *testing.T) {
  13. s := newTestProvider(map[string]*pimFlavorPricing{
  14. "g2i.4": {HourlyCost: "0.201", VCPU: 4, RAMGB: 16.0},
  15. }, nil)
  16. key := &stackitKey{Labels: map[string]string{
  17. "node.kubernetes.io/instance-type": "g2i.4",
  18. "topology.kubernetes.io/zone": "eu01-3",
  19. }}
  20. node, _, err := s.NodePricing(key)
  21. if err != nil {
  22. t.Fatalf("unexpected error: %v", err)
  23. }
  24. if node.Cost != "0.201" {
  25. t.Errorf("Cost = %q, want %q", node.Cost, "0.201")
  26. }
  27. if node.VCPU != "4" {
  28. t.Errorf("VCPU = %q, want %q", node.VCPU, "4")
  29. }
  30. if node.RAM != "16" {
  31. t.Errorf("RAM = %q, want %q", node.RAM, "16")
  32. }
  33. if node.RAMBytes != "17179869184" {
  34. t.Errorf("RAMBytes = %q, want %q", node.RAMBytes, "17179869184")
  35. }
  36. if node.InstanceType != "g2i.4" {
  37. t.Errorf("InstanceType = %q, want %q", node.InstanceType, "g2i.4")
  38. }
  39. if node.Region != "eu01" {
  40. t.Errorf("Region = %q, want %q", node.Region, "eu01")
  41. }
  42. }
  43. func TestNodePricingUnknownType(t *testing.T) {
  44. s := newTestProvider(map[string]*pimFlavorPricing{}, nil)
  45. key := &stackitKey{Labels: map[string]string{
  46. "node.kubernetes.io/instance-type": "unknown.1",
  47. }}
  48. _, _, err := s.NodePricing(key)
  49. if err == nil {
  50. t.Error("expected error for unknown instance type")
  51. }
  52. }
  53. func TestNodePricingGPU(t *testing.T) {
  54. s := newTestProvider(map[string]*pimFlavorPricing{
  55. "n1.14d.g1": {HourlyCost: "3.50", VCPU: 14, RAMGB: 56.0, GPUCount: 1, GPUType: "NVIDIA A100"},
  56. }, nil)
  57. key := &stackitKey{Labels: map[string]string{
  58. "node.kubernetes.io/instance-type": "n1.14d.g1",
  59. }}
  60. node, _, err := s.NodePricing(key)
  61. if err != nil {
  62. t.Fatalf("unexpected error: %v", err)
  63. }
  64. if node.GPU != "1" {
  65. t.Errorf("GPU = %q, want %q", node.GPU, "1")
  66. }
  67. if node.GPUName != "NVIDIA A100" {
  68. t.Errorf("GPUName = %q, want %q", node.GPUName, "NVIDIA A100")
  69. }
  70. }
  71. func TestGpuPricingPerGPU(t *testing.T) {
  72. s := newTestProvider(map[string]*pimFlavorPricing{
  73. "n1.28d.g2": {HourlyCost: "7.00", VCPU: 28, RAMGB: 112.0, GPUCount: 2, GPUType: "NVIDIA A100"},
  74. }, nil)
  75. labels := map[string]string{
  76. "node.kubernetes.io/instance-type": "n1.28d.g2",
  77. }
  78. cost, err := s.GpuPricing(labels)
  79. if err != nil {
  80. t.Fatalf("unexpected error: %v", err)
  81. }
  82. if cost != "3.5" {
  83. t.Errorf("per-GPU cost = %q, want %q", cost, "3.5")
  84. }
  85. }
  86. func TestGpuPricingNoGPU(t *testing.T) {
  87. s := newTestProvider(map[string]*pimFlavorPricing{
  88. "g2i.4": {HourlyCost: "0.201", VCPU: 4, RAMGB: 16.0, GPUCount: 0},
  89. }, nil)
  90. labels := map[string]string{
  91. "node.kubernetes.io/instance-type": "g2i.4",
  92. }
  93. cost, err := s.GpuPricing(labels)
  94. if err != nil {
  95. t.Fatalf("unexpected error: %v", err)
  96. }
  97. if cost != "" {
  98. t.Errorf("expected empty cost for non-GPU instance, got %q", cost)
  99. }
  100. }
  101. func TestGpuPricingUnknownInstance(t *testing.T) {
  102. s := newTestProvider(map[string]*pimFlavorPricing{}, nil)
  103. labels := map[string]string{
  104. "node.kubernetes.io/instance-type": "unknown.1",
  105. }
  106. cost, err := s.GpuPricing(labels)
  107. if err != nil {
  108. t.Fatalf("unexpected error: %v", err)
  109. }
  110. if cost != "" {
  111. t.Errorf("expected empty cost for unknown instance, got %q", cost)
  112. }
  113. }
  114. func TestPVPricingExactMatch(t *testing.T) {
  115. s := newTestProvider(nil, map[string]*pimStoragePricing{
  116. "storage_premium_perf2": {CostPerGBHr: "0.0005"},
  117. "default": {CostPerGBHr: "0.0001"},
  118. })
  119. pvk := &stackitPVKey{StorageClassName: "storage_premium_perf2"}
  120. pv, err := s.PVPricing(pvk)
  121. if err != nil {
  122. t.Fatalf("unexpected error: %v", err)
  123. }
  124. if pv.Cost != "0.0005" {
  125. t.Errorf("Cost = %q, want %q", pv.Cost, "0.0005")
  126. }
  127. }
  128. func TestPVPricingDefaultFallback(t *testing.T) {
  129. s := newTestProvider(nil, map[string]*pimStoragePricing{
  130. "default": {CostPerGBHr: "0.0001"},
  131. })
  132. pvk := &stackitPVKey{StorageClassName: "unknown-class"}
  133. pv, err := s.PVPricing(pvk)
  134. if err != nil {
  135. t.Fatalf("unexpected error: %v", err)
  136. }
  137. if pv.Cost != "0.0001" {
  138. t.Errorf("Cost = %q, want default %q", pv.Cost, "0.0001")
  139. }
  140. if pv.Class != "unknown-class" {
  141. t.Errorf("Class = %q, want %q", pv.Class, "unknown-class")
  142. }
  143. }
  144. func TestPVPricingNoPricing(t *testing.T) {
  145. s := newTestProvider(nil, nil)
  146. pvk := &stackitPVKey{StorageClassName: "some-class"}
  147. pv, err := s.PVPricing(pvk)
  148. if err != nil {
  149. t.Fatalf("unexpected error: %v", err)
  150. }
  151. if pv.Cost != "" {
  152. t.Errorf("expected empty cost when no pricing data, got %q", pv.Cost)
  153. }
  154. }
  155. func TestStackitKeyFeatures(t *testing.T) {
  156. key := &stackitKey{Labels: map[string]string{
  157. "node.kubernetes.io/instance-type": "g2i.4",
  158. "topology.kubernetes.io/zone": "eu01-3",
  159. }}
  160. features := key.Features()
  161. if features != "eu01-3,g2i.4" {
  162. t.Errorf("Features() = %q, want %q", features, "eu01-3,g2i.4")
  163. }
  164. }