mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-20 10:52:08 +00:00
fc5aaef391
Add external_probe to the licensing feature enumeration, Pro tier membership, self-hosted feature catalog, feature map, upgrade matrix and pricing handoff, with the entitlement contract goldens updated. The capability is served by the community binary - the entitlement alone gates it, like relay. No existing free functionality changes: local availability checks stay ungated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
165 lines
5.3 KiB
Go
165 lines
5.3 KiB
Go
package licensing
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestResolveProTrialSignupURL_DefaultWhenUnset(t *testing.T) {
|
|
if got := ResolveProTrialSignupURL(""); got != DefaultProTrialSignupURL {
|
|
t.Fatalf("ResolveProTrialSignupURL(\"\") = %q, want %q", got, DefaultProTrialSignupURL)
|
|
}
|
|
}
|
|
|
|
func TestResolveProTrialSignupURL_DefaultIsHostedCommercialBase(t *testing.T) {
|
|
if strings.Contains(DefaultProTrialSignupURL, "start-pro-trial") {
|
|
t.Fatalf("DefaultProTrialSignupURL=%q must not point at retired trial signup route", DefaultProTrialSignupURL)
|
|
}
|
|
}
|
|
|
|
func TestResolveProTrialSignupURL_UsesValidOverride(t *testing.T) {
|
|
const override = "https://example.com/commercial-base?src=test"
|
|
|
|
if got := ResolveProTrialSignupURL(override); got != override {
|
|
t.Fatalf("ResolveProTrialSignupURL() = %q, want %q", got, override)
|
|
}
|
|
}
|
|
|
|
func TestResolveProTrialSignupURL_AllowsLoopbackHTTPOverride(t *testing.T) {
|
|
const override = "http://127.0.0.1:8080/commercial-base?src=test"
|
|
|
|
if got := ResolveProTrialSignupURL(override); got != override {
|
|
t.Fatalf("ResolveProTrialSignupURL() = %q, want %q", got, override)
|
|
}
|
|
}
|
|
|
|
func TestResolveProTrialSignupURL_RejectsInvalidOverrides(t *testing.T) {
|
|
testCases := []string{
|
|
"relative/path",
|
|
"javascript:alert(1)",
|
|
"https://",
|
|
"http://192.168.1.20/commercial-base",
|
|
"ftp://example.com/commercial-base",
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc, func(t *testing.T) {
|
|
if got := ResolveProTrialSignupURL(tc); got != DefaultProTrialSignupURL {
|
|
t.Fatalf("ResolveProTrialSignupURL() = %q, want default %q", got, DefaultProTrialSignupURL)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolvePulseAccountPortalURL_DefaultWhenUnset(t *testing.T) {
|
|
if got := ResolvePulseAccountPortalURL(""); got != DefaultPulseAccountPortalURL {
|
|
t.Fatalf("ResolvePulseAccountPortalURL(\"\") = %q, want %q", got, DefaultPulseAccountPortalURL)
|
|
}
|
|
}
|
|
|
|
func TestResolvePulseAccountPortalURL_UsesValidOverride(t *testing.T) {
|
|
const override = "https://example.com/portal?src=test"
|
|
|
|
if got := ResolvePulseAccountPortalURL(override); got != override {
|
|
t.Fatalf("ResolvePulseAccountPortalURL() = %q, want %q", got, override)
|
|
}
|
|
}
|
|
|
|
func TestResolvePulseAccountPortalURL_AllowsLoopbackHTTPOverride(t *testing.T) {
|
|
const override = "http://localhost:8080/portal?src=test"
|
|
|
|
if got := ResolvePulseAccountPortalURL(override); got != override {
|
|
t.Fatalf("ResolvePulseAccountPortalURL() = %q, want %q", got, override)
|
|
}
|
|
}
|
|
|
|
func TestResolvePulseAccountPortalURL_RejectsInvalidOverrides(t *testing.T) {
|
|
testCases := []string{
|
|
"relative/path",
|
|
"javascript:alert(1)",
|
|
"https://",
|
|
"http://10.0.0.25/portal",
|
|
"ftp://example.com/portal",
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc, func(t *testing.T) {
|
|
if got := ResolvePulseAccountPortalURL(tc); got != DefaultPulseAccountPortalURL {
|
|
t.Fatalf("ResolvePulseAccountPortalURL() = %q, want default %q", got, DefaultPulseAccountPortalURL)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOperatorOutcomeUpgradeReasonsRemainCanonical(t *testing.T) {
|
|
expected := map[string]string{
|
|
FeatureRelay: "Get Relay so Pulse stays reachable securely from anywhere instead of only on the local dashboard.",
|
|
FeatureLongTermMetrics: "Get Relay for 14 days of history, or Pro for 90 days, so you can see what changed before and after an incident.",
|
|
FeatureAIAlerts: "Upgrade to Pro so Patrol can investigate issues instead of handing you a stack of symptoms.",
|
|
FeatureAIAutoFix: "Upgrade to Pro so Patrol can investigate issues, apply safe fixes within Patrol mode, and verify the result.",
|
|
}
|
|
|
|
for _, entry := range UpgradeReasonMatrix {
|
|
want, ok := expected[entry.Feature]
|
|
if !ok {
|
|
continue
|
|
}
|
|
if entry.Reason != want {
|
|
t.Fatalf("reason for %q = %q, want %q", entry.Feature, entry.Reason, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCompatibilityOnlyFeaturesStayOutOfGenericUpgradeReasons(t *testing.T) {
|
|
reasons := GenerateUpgradeReasons(nil)
|
|
for _, entry := range reasons {
|
|
if entry.Feature == FeatureKubernetesAI {
|
|
t.Fatalf("compatibility-only feature %q should not produce a generic upgrade reason", entry.Feature)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCompatibilityOnlyFeatureUpgradeURLsFallBackToGenericPricing(t *testing.T) {
|
|
foundCompatibilityOnlyFeature := false
|
|
|
|
for _, entry := range AllFeatureMetadata() {
|
|
if !IsCompatibilityOnlyFeature(entry.Key) {
|
|
continue
|
|
}
|
|
foundCompatibilityOnlyFeature = true
|
|
if got := UpgradeURLForFeature(entry.Key); got != DefaultUpgradeURL {
|
|
t.Fatalf("UpgradeURLForFeature(%q) = %q, want generic pricing URL %q", entry.Key, got, DefaultUpgradeURL)
|
|
}
|
|
}
|
|
|
|
if !foundCompatibilityOnlyFeature {
|
|
t.Fatal("expected at least one compatibility-only feature in metadata")
|
|
}
|
|
}
|
|
|
|
func TestUpgradeReasonMatrixDerivesFromCanonicalFeatureMetadata(t *testing.T) {
|
|
expectedOrder := []string{
|
|
FeatureMobileApp,
|
|
FeaturePushNotifications,
|
|
FeatureRelay,
|
|
FeatureLongTermMetrics,
|
|
FeatureAIAutoFix,
|
|
FeatureAIAlerts,
|
|
FeatureRBAC,
|
|
FeatureAgentProfiles,
|
|
FeatureExternalProbe,
|
|
FeatureAuditLogging,
|
|
FeatureAdvancedReporting,
|
|
}
|
|
|
|
if len(UpgradeReasonMatrix) != len(expectedOrder) {
|
|
t.Fatalf("UpgradeReasonMatrix length = %d, want %d", len(UpgradeReasonMatrix), len(expectedOrder))
|
|
}
|
|
|
|
for idx, feature := range expectedOrder {
|
|
if UpgradeReasonMatrix[idx].Feature != feature {
|
|
t.Fatalf("UpgradeReasonMatrix[%d].Feature = %q, want %q", idx, UpgradeReasonMatrix[idx].Feature, feature)
|
|
}
|
|
}
|
|
}
|