| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- package pricing
- import (
- "sync"
- "testing"
- "github.com/opencost/opencost/core/pkg/unit"
- )
- // TestMemoryGetEmpty verifies that a fresh store returns a non-nil, empty set.
- func TestMemoryGetEmpty(t *testing.T) {
- mps := NewMemoryPricingStore()
- ps, err := mps.GetPricingSet(t.Context())
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if ps == nil {
- t.Fatal("expected non-nil pricing set")
- }
- if !ps.IsEmpty() {
- t.Errorf("expected empty pricing set, got %+v", ps)
- }
- }
- // TestMemoryRoundTrip verifies that a set survives a Set/Get round trip while
- // being returned as a distinct copy, not the stored pointer.
- func TestMemoryRoundTrip(t *testing.T) {
- mps := NewMemoryPricingStore()
- in := fullPricingSet()
- if err := mps.SetPricingSet(t.Context(), in); err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- out, err := mps.GetPricingSet(t.Context())
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- csIn, err := in.Checksum()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- csOut, err := out.Checksum()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if csIn != csOut {
- t.Errorf("round-trip changed contents: %q -> %q", csIn, csOut)
- }
- if out == in {
- t.Error("expected Get to return a copy, not the set pointer")
- }
- }
- // TestMemorySetIsolation verifies that mutating the value passed to Set after
- // the call does not affect what the store returns.
- func TestMemorySetIsolation(t *testing.T) {
- mps := NewMemoryPricingStore()
- in := fullPricingSet()
- if err := mps.SetPricingSet(t.Context(), in); err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- before, err := mps.GetPricingSet(t.Context())
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- csBefore, err := before.Checksum()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- // Mutate the caller's copy after setting it.
- in.NodePricing[0].Properties.Labels["team"] = "mutated"
- in.NodePricing[0].Prices[ResourceNode] = Price{Unit: unit.Hour, Price: 99}
- in.NodePricing = append(in.NodePricing, nodePricing("m5.xlarge", 0.192))
- after, err := mps.GetPricingSet(t.Context())
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- csAfter, err := after.Checksum()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if csBefore != csAfter {
- t.Errorf("mutating the set argument changed store contents: %q -> %q", csBefore, csAfter)
- }
- }
- // TestMemoryGetIsolation verifies that mutating a value returned by Get does not
- // affect what subsequent Get calls return.
- func TestMemoryGetIsolation(t *testing.T) {
- mps := NewMemoryPricingStore()
- if err := mps.SetPricingSet(t.Context(), fullPricingSet()); err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- got, err := mps.GetPricingSet(t.Context())
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- csBefore, err := got.Checksum()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- // Mutate the returned copy.
- got.NodePricing[0].Properties.Labels["team"] = "mutated"
- got.NodePricing[0].Prices[ResourceNode] = Price{Unit: unit.Hour, Price: 99}
- again, err := mps.GetPricingSet(t.Context())
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- csAfter, err := again.Checksum()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if csBefore != csAfter {
- t.Errorf("mutating a returned set changed store contents: %q -> %q", csBefore, csAfter)
- }
- }
- // TestMemorySetNil verifies that Set rejects a nil pricing set.
- func TestMemorySetNil(t *testing.T) {
- mps := NewMemoryPricingStore()
- if err := mps.SetPricingSet(t.Context(), nil); err == nil {
- t.Error("expected error for nil pricing set")
- }
- }
- // TestMemoryConcurrentAccess exercises the store under concurrent readers and
- // writers; run with -race to catch data races.
- func TestMemoryConcurrentAccess(t *testing.T) {
- mps := NewMemoryPricingStore()
- var wg sync.WaitGroup
- for i := 0; i < 50; i++ {
- wg.Add(2)
- go func() {
- defer wg.Done()
- _ = mps.SetPricingSet(t.Context(), fullPricingSet())
- }()
- go func() {
- defer wg.Done()
- if _, err := mps.GetPricingSet(t.Context()); err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- }()
- }
- wg.Wait()
- }
|