package deployer import ( "testing" "github.com/alexei/tinyforge/internal/notify" "github.com/alexei/tinyforge/internal/store" ) // TestResolveDeployTarget locks the stage→project→global precedence. The // most-specific tier with a non-empty URL wins, and the secret travels // with the URL that sourced it (so a stage can sign even when project and // global are unsigned). A regression here misroutes notifications and // silently leaks events to the wrong receiver — worth catching. func TestResolveDeployTarget(t *testing.T) { cases := []struct { name string stage store.Stage project store.Project settings store.Settings wantURL string wantSec string wantTier notify.Tier }{ { name: "stage wins when set", stage: store.Stage{NotificationURL: "https://stage.example/wh", NotificationSecret: "stage-key"}, project: store.Project{NotificationURL: "https://project.example/wh", NotificationSecret: "project-key"}, settings: store.Settings{NotificationURL: "https://global.example/wh", NotificationSecret: "global-key"}, wantURL: "https://stage.example/wh", wantSec: "stage-key", wantTier: notify.TierStage, }, { name: "stage URL empty → project wins", stage: store.Stage{NotificationURL: "", NotificationSecret: "stage-key"}, // secret without URL ignored project: store.Project{NotificationURL: "https://project.example/wh", NotificationSecret: "project-key"}, settings: store.Settings{NotificationURL: "https://global.example/wh", NotificationSecret: "global-key"}, wantURL: "https://project.example/wh", wantSec: "project-key", wantTier: notify.TierProject, }, { name: "stage and project empty → global wins", stage: store.Stage{}, project: store.Project{}, settings: store.Settings{NotificationURL: "https://global.example/wh", NotificationSecret: "global-key"}, wantURL: "https://global.example/wh", wantSec: "global-key", wantTier: notify.TierSettings, }, { name: "all empty → returns settings tier with empty URL (caller skips)", stage: store.Stage{}, project: store.Project{}, settings: store.Settings{}, wantURL: "", wantSec: "", wantTier: notify.TierSettings, }, { name: "stage signs even when global is unsigned", stage: store.Stage{ NotificationURL: "https://stage.example/wh", NotificationSecret: "stage-only-key", }, project: store.Project{}, settings: store.Settings{NotificationURL: "https://global.example/wh"}, wantURL: "https://stage.example/wh", wantSec: "stage-only-key", wantTier: notify.TierStage, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { gotURL, gotSec, gotTier := resolveDeployTarget(tc.stage, tc.project, tc.settings) if gotURL != tc.wantURL { t.Errorf("url = %q, want %q", gotURL, tc.wantURL) } if gotSec != tc.wantSec { t.Errorf("secret = %q, want %q", gotSec, tc.wantSec) } if gotTier != tc.wantTier { t.Errorf("tier = %q, want %q", gotTier, tc.wantTier) } }) } }