Pulse/pkg/licensing/trial_start_test.go

243 lines
7.6 KiB
Go

package licensing
import (
"testing"
"time"
)
func TestEvaluateTrialStartEligibility(t *testing.T) {
now := time.Unix(1700000000, 0)
started := now.Add(-24 * time.Hour).Unix()
tests := []struct {
name string
hasActiveLicense bool
existing *BillingState
wantAllowed bool
wantReason TrialStartDenialReason
}{
{
name: "denied when license active",
hasActiveLicense: true,
existing: nil,
wantAllowed: false,
wantReason: TrialStartDeniedLicense,
},
{
name: "allowed with no state",
hasActiveLicense: false,
existing: nil,
wantAllowed: true,
wantReason: TrialStartAllowed,
},
{
name: "denied when trial already used",
hasActiveLicense: false,
existing: &BillingState{TrialStartedAt: &started},
wantAllowed: false,
wantReason: TrialStartDeniedAlreadyUsed,
},
{
name: "denied on active subscription",
hasActiveLicense: false,
existing: &BillingState{SubscriptionState: SubStateActive},
wantAllowed: false,
wantReason: TrialStartDeniedSubscription,
},
{
name: "denied on grace subscription",
hasActiveLicense: false,
existing: &BillingState{SubscriptionState: SubStateGrace},
wantAllowed: false,
wantReason: TrialStartDeniedSubscription,
},
{
name: "denied on suspended subscription",
hasActiveLicense: false,
existing: &BillingState{SubscriptionState: SubStateSuspended},
wantAllowed: false,
wantReason: TrialStartDeniedSubscription,
},
{
name: "denied when v5 migration is pending",
hasActiveLicense: false,
existing: &BillingState{CommercialMigration: &CommercialMigrationStatus{
Source: CommercialMigrationSourceV5License,
State: CommercialMigrationStatePending,
}},
wantAllowed: false,
wantReason: TrialStartDeniedMigrationPending,
},
{
name: "denied when v5 migration failed",
hasActiveLicense: false,
existing: &BillingState{CommercialMigration: &CommercialMigrationStatus{
Source: CommercialMigrationSourceV5License,
State: CommercialMigrationStateFailed,
}},
wantAllowed: false,
wantReason: TrialStartDeniedMigrationFailed,
},
{
name: "allowed on expired subscription",
hasActiveLicense: false,
existing: &BillingState{SubscriptionState: SubStateExpired},
wantAllowed: true,
wantReason: TrialStartAllowed,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := EvaluateTrialStartEligibility(tt.hasActiveLicense, tt.existing)
if got.Allowed != tt.wantAllowed {
t.Fatalf("allowed=%t, want %t", got.Allowed, tt.wantAllowed)
}
if got.Reason != tt.wantReason {
t.Fatalf("reason=%q, want %q", got.Reason, tt.wantReason)
}
})
}
}
func TestTrialStartError(t *testing.T) {
tests := []struct {
name string
reason TrialStartDenialReason
wantCode string
wantMessage string
wantIncludeOrgID bool
}{
{
name: "license active",
reason: TrialStartDeniedLicense,
wantCode: "trial_not_available",
wantMessage: "Trial cannot be started while a license is active",
wantIncludeOrgID: false,
},
{
name: "already used",
reason: TrialStartDeniedAlreadyUsed,
wantCode: "trial_already_used",
wantMessage: "Trial has already been used for this organization",
wantIncludeOrgID: true,
},
{
name: "subscription active",
reason: TrialStartDeniedSubscription,
wantCode: "trial_not_available",
wantMessage: "Trial cannot be started while a subscription is active",
wantIncludeOrgID: true,
},
{
name: "migration pending",
reason: TrialStartDeniedMigrationPending,
wantCode: "trial_not_available",
wantMessage: "Trial cannot be started while a paid v5 license migration is pending",
wantIncludeOrgID: false,
},
{
name: "migration failed",
reason: TrialStartDeniedMigrationFailed,
wantCode: "trial_not_available",
wantMessage: "Trial cannot be started until the paid v5 license migration is resolved",
wantIncludeOrgID: false,
},
{
name: "unknown",
reason: TrialStartAllowed,
wantCode: "",
wantMessage: "",
wantIncludeOrgID: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
code, message, includeOrgID := TrialStartError(tt.reason)
if code != tt.wantCode {
t.Fatalf("code=%q, want %q", code, tt.wantCode)
}
if message != tt.wantMessage {
t.Fatalf("message=%q, want %q", message, tt.wantMessage)
}
if includeOrgID != tt.wantIncludeOrgID {
t.Fatalf("includeOrgID=%t, want %t", includeOrgID, tt.wantIncludeOrgID)
}
})
}
}
func TestTrialWindow(t *testing.T) {
now := time.Unix(1700000000, 0)
startedAt, endsAt := TrialWindow(now, 48*time.Hour)
if startedAt != now.Unix() {
t.Fatalf("startedAt=%d, want %d", startedAt, now.Unix())
}
if endsAt != now.Add(48*time.Hour).Unix() {
t.Fatalf("endsAt=%d, want %d", endsAt, now.Add(48*time.Hour).Unix())
}
}
func TestBuildTrialBillingState(t *testing.T) {
now := time.Unix(1700000000, 0)
capsInput := []string{"a", "b"}
state := BuildTrialBillingState(now, capsInput)
if state == nil {
t.Fatal("expected non-nil state")
}
if state.SubscriptionState != SubStateTrial {
t.Fatalf("subscription state=%q, want %q", state.SubscriptionState, SubStateTrial)
}
if state.PlanVersion != string(SubStateTrial) {
t.Fatalf("plan version=%q, want %q", state.PlanVersion, string(SubStateTrial))
}
if state.TrialStartedAt == nil || state.TrialEndsAt == nil {
t.Fatalf("expected trial timestamps to be set, got started=%v ends=%v", state.TrialStartedAt, state.TrialEndsAt)
}
if *state.TrialStartedAt != now.Unix() {
t.Fatalf("trial_started_at=%d, want %d", *state.TrialStartedAt, now.Unix())
}
if *state.TrialEndsAt != now.Add(DefaultTrialDuration).Unix() {
t.Fatalf("trial_ends_at=%d, want %d", *state.TrialEndsAt, now.Add(DefaultTrialDuration).Unix())
}
if len(state.Limits) != 0 {
t.Fatalf("expected empty limits, got %#v", state.Limits)
}
if len(state.MetersEnabled) != 0 {
t.Fatalf("expected empty meters, got %#v", state.MetersEnabled)
}
if len(state.Capabilities) != 2 {
t.Fatalf("capabilities length=%d, want 2", len(state.Capabilities))
}
capsInput[0] = "changed"
if state.Capabilities[0] != "a" {
t.Fatalf("expected capability copy to be immutable from caller changes")
}
}
func TestBuildTrialBillingStateWithPlan(t *testing.T) {
now := time.Unix(1700000000, 0)
state := BuildTrialBillingStateWithPlan(now, []string{"cloud_feature"}, " cloud_trial ", 72*time.Hour)
if state.PlanVersion != "cloud_trial" {
t.Fatalf("plan_version=%q, want %q", state.PlanVersion, "cloud_trial")
}
if state.SubscriptionState != SubStateTrial {
t.Fatalf("subscription_state=%q, want %q", state.SubscriptionState, SubStateTrial)
}
if *state.TrialStartedAt != now.Unix() {
t.Fatalf("trial_started_at=%d, want %d", *state.TrialStartedAt, now.Unix())
}
if *state.TrialEndsAt != now.Add(72*time.Hour).Unix() {
t.Fatalf("trial_ends_at=%d, want %d", *state.TrialEndsAt, now.Add(72*time.Hour).Unix())
}
if !state.QuickstartCreditsGranted {
t.Fatal("expected quickstart credits to be granted for new trial workspaces")
}
if state.QuickstartCreditsGrantedAt == nil {
t.Fatal("expected quickstart credits grant timestamp to be populated")
}
}