package resources_test import ( "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "cloud.o-forge.io/core/oc-lib/models/common/pricing" "cloud.o-forge.io/core/oc-lib/models/resources" "cloud.o-forge.io/core/oc-lib/tools" ) // ---- Mock PricingProfile ---- type MockPricingProfile struct { pricing.PricingProfileITF Purchased bool ReturnErr bool ReturnCost float64 } func (m *MockPricingProfile) IsPurchased() bool { return m.Purchased } func (m *MockPricingProfile) GetPrice(amount float64, explicitDuration float64, start time.Time, end time.Time, _ ...string) (float64, error) { if m.ReturnErr { return 0, errors.New("mock error") } return m.ReturnCost, nil } // ---- Tests ---- func TestGetIDAndCreatorAndType(t *testing.T) { r := resources.PricedResource{ ResourceID: "res-123", CreatorID: "user-abc", ResourceType: tools.DATA_RESOURCE, } assert.Equal(t, "res-123", r.GetID()) assert.Equal(t, "user-abc", r.GetCreatorID()) assert.Equal(t, tools.DATA_RESOURCE, r.GetType()) } func TestIsPurchased(t *testing.T) { t.Run("nil selected pricing returns false", func(t *testing.T) { r := &resources.PricedResource{} assert.False(t, r.IsPurchased()) }) t.Run("returns true if pricing profile is purchased", func(t *testing.T) { mock := &MockPricingProfile{Purchased: true} r := &resources.PricedResource{SelectedPricing: mock} assert.True(t, r.IsPurchased()) }) } func TestGetAndSetLocationStartEnd(t *testing.T) { r := &resources.PricedResource{} now := time.Now() r.SetLocationStart(now) r.SetLocationEnd(now.Add(2 * time.Hour)) assert.Equal(t, now, *r.GetLocationStart()) assert.Equal(t, now.Add(2*time.Hour), *r.GetLocationEnd()) } func TestGetExplicitDurationInS(t *testing.T) { t.Run("uses explicit duration if set", func(t *testing.T) { r := &resources.PricedResource{ExplicitBookingDurationS: 3600} assert.Equal(t, 3600.0, r.GetExplicitDurationInS()) }) t.Run("computes duration from start and end", func(t *testing.T) { start := time.Now() end := start.Add(2 * time.Hour) r := &resources.PricedResource{UsageStart: &start, UsageEnd: &end} assert.InDelta(t, 7200.0, r.GetExplicitDurationInS(), 0.1) }) t.Run("defaults to 1 hour when times not set", func(t *testing.T) { r := &resources.PricedResource{} assert.InDelta(t, 3600.0, r.GetExplicitDurationInS(), 0.1) }) } func TestGetPrice(t *testing.T) { t.Run("returns error if no pricing profile", func(t *testing.T) { r := &resources.PricedResource{ResourceID: "no-profile"} price, err := r.GetPrice() require.Error(t, err) assert.Contains(t, err.Error(), "pricing profile must be set") assert.Equal(t, 0.0, price) }) t.Run("uses first profile if selected is nil", func(t *testing.T) { start := time.Now() end := start.Add(30 * time.Minute) mock := &MockPricingProfile{ReturnCost: 42.0} r := &resources.PricedResource{ PricingProfiles: []pricing.PricingProfileITF{mock}, UsageStart: &start, UsageEnd: &end, } price, err := r.GetPrice() require.NoError(t, err) assert.Equal(t, 42.0, price) }) t.Run("returns error if profile GetPrice fails", func(t *testing.T) { start := time.Now() end := start.Add(1 * time.Hour) mock := &MockPricingProfile{ReturnErr: true} r := &resources.PricedResource{ SelectedPricing: mock, UsageStart: &start, UsageEnd: &end, } price, err := r.GetPrice() require.Error(t, err) assert.Equal(t, 0.0, price) }) t.Run("uses SelectedPricing if set", func(t *testing.T) { start := time.Now() end := start.Add(1 * time.Hour) mock := &MockPricingProfile{ReturnCost: 10.0} r := &resources.PricedResource{ SelectedPricing: mock, UsageStart: &start, UsageEnd: &end, } price, err := r.GetPrice() require.NoError(t, err) assert.Equal(t, 10.0, price) }) }