set_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package pricing
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "github.com/opencost/opencost/core/pkg/unit"
  6. )
  7. func TestPricingSetSort(t *testing.T) {
  8. // Create a pricing set with items in non-deterministic order
  9. ps1 := &PricingSet{
  10. Nodes: []*NodePricing{
  11. {
  12. Properties: NodePricingProperties{
  13. Provider: AzureProvider,
  14. Region: "eastus",
  15. InstanceType: "Standard_D2s_v3",
  16. },
  17. Prices: Prices{
  18. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.096}},
  19. },
  20. },
  21. {
  22. Properties: NodePricingProperties{
  23. Provider: AWSProvider,
  24. Region: "us-east-1",
  25. InstanceType: "t3.medium",
  26. },
  27. Prices: Prices{
  28. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.0416}},
  29. },
  30. },
  31. {
  32. Properties: NodePricingProperties{
  33. Provider: AWSProvider,
  34. Region: "us-east-1",
  35. InstanceType: "t3.large",
  36. },
  37. Prices: Prices{
  38. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.0832}},
  39. },
  40. },
  41. },
  42. Volumes: []*VolumePricing{
  43. {
  44. Properties: VolumePricingProperties{
  45. Provider: AzureProvider,
  46. Region: "eastus",
  47. VolumeType: VolumeTypePremiumLRS,
  48. },
  49. Prices: Prices{
  50. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.15}},
  51. },
  52. },
  53. {
  54. Properties: VolumePricingProperties{
  55. Provider: AWSProvider,
  56. Region: "us-east-1",
  57. VolumeType: VolumeTypeGP3,
  58. },
  59. Prices: Prices{
  60. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.08}},
  61. },
  62. },
  63. },
  64. }
  65. // Create a second pricing set with the same items in different order
  66. ps2 := &PricingSet{
  67. Nodes: []*NodePricing{
  68. {
  69. Properties: NodePricingProperties{
  70. Provider: AWSProvider,
  71. Region: "us-east-1",
  72. InstanceType: "t3.large",
  73. },
  74. Prices: Prices{
  75. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.0832}},
  76. },
  77. },
  78. {
  79. Properties: NodePricingProperties{
  80. Provider: AWSProvider,
  81. Region: "us-east-1",
  82. InstanceType: "t3.medium",
  83. },
  84. Prices: Prices{
  85. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.0416}},
  86. },
  87. },
  88. {
  89. Properties: NodePricingProperties{
  90. Provider: AzureProvider,
  91. Region: "eastus",
  92. InstanceType: "Standard_D2s_v3",
  93. },
  94. Prices: Prices{
  95. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.096}},
  96. },
  97. },
  98. },
  99. Volumes: []*VolumePricing{
  100. {
  101. Properties: VolumePricingProperties{
  102. Provider: AWSProvider,
  103. Region: "us-east-1",
  104. VolumeType: VolumeTypeGP3,
  105. },
  106. Prices: Prices{
  107. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.08}},
  108. },
  109. },
  110. {
  111. Properties: VolumePricingProperties{
  112. Provider: AzureProvider,
  113. Region: "eastus",
  114. VolumeType: VolumeTypePremiumLRS,
  115. },
  116. Prices: Prices{
  117. unit.USD: []Price{{Currency: unit.USD, Unit: unit.Hour, Price: 0.15}},
  118. },
  119. },
  120. },
  121. }
  122. // Sort both pricing sets
  123. ps1.Sort()
  124. ps2.Sort()
  125. // Serialize both to JSON
  126. json1, err := json.Marshal(ps1)
  127. if err != nil {
  128. t.Fatalf("Failed to marshal ps1: %v", err)
  129. }
  130. json2, err := json.Marshal(ps2)
  131. if err != nil {
  132. t.Fatalf("Failed to marshal ps2: %v", err)
  133. }
  134. // They should produce identical JSON
  135. if string(json1) != string(json2) {
  136. t.Errorf("Sorted pricing sets produced different JSON output.\nps1: %s\nps2: %s", string(json1), string(json2))
  137. }
  138. // Verify the sort order is correct (AWS before Azure alphabetically)
  139. if ps1.Nodes[0].Properties.Provider != AWSProvider {
  140. t.Errorf("Expected first node to be AWS, got %s", ps1.Nodes[0].Properties.Provider)
  141. }
  142. if ps1.Nodes[2].Properties.Provider != AzureProvider {
  143. t.Errorf("Expected third node to be Azure, got %s", ps1.Nodes[2].Properties.Provider)
  144. }
  145. // Verify instance types are sorted within same provider/region
  146. if ps1.Nodes[0].Properties.InstanceType != "t3.large" {
  147. t.Errorf("Expected first AWS node to be t3.large, got %s", ps1.Nodes[0].Properties.InstanceType)
  148. }
  149. if ps1.Nodes[1].Properties.InstanceType != "t3.medium" {
  150. t.Errorf("Expected second AWS node to be t3.medium, got %s", ps1.Nodes[1].Properties.InstanceType)
  151. }
  152. }
  153. func TestPricingSetSortNil(t *testing.T) {
  154. var ps *PricingSet
  155. // Should not panic
  156. ps.Sort()
  157. }
  158. func TestPricingSetSortEmpty(t *testing.T) {
  159. ps := &PricingSet{
  160. Nodes: []*NodePricing{},
  161. Volumes: []*VolumePricing{},
  162. }
  163. // Should not panic
  164. ps.Sort()
  165. }
  166. // Made with Bob