Files
kandev/apps/backend/internal/gitlab/controller_watch_reset_test.go
T
2026-07-21 23:24:22 +01:00

79 lines
3.0 KiB
Go

package gitlab
import (
"context"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
func TestReviewWatchMutationGuardHidesCrossWorkspaceWatch(t *testing.T) {
gin.SetMode(gin.TestMode)
store := newTestStore(t)
watch := &ReviewWatch{
WorkspaceID: "workspace-a", WorkflowID: "wf", WorkflowStepID: "step",
AgentProfileID: "agent", ExecutorProfileID: "executor", Enabled: true,
}
if err := store.CreateReviewWatch(context.Background(), watch); err != nil {
t.Fatalf("create watch: %v", err)
}
svc := NewService("", nil, "none", nil, newTestLogger(t))
svc.SetStore(store)
controller := NewController(svc, newTestLogger(t))
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest("PATCH", "/api/v1/gitlab/watches/review/"+watch.ID+"?workspace_id=workspace-b", nil)
ctx.Params = gin.Params{{Key: "id", Value: watch.ID}}
if controller.requireReviewWatchInWorkspace(ctx, watch.ID) {
t.Fatal("cross-workspace watch unexpectedly authorized")
}
if recorder.Code != 404 {
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
}
}
func TestWatchDeleteGuardsAllowOwnedTombstoneRetries(t *testing.T) {
gin.SetMode(gin.TestMode)
store := newTestStore(t)
review := &ReviewWatch{WorkspaceID: "workspace-a", WorkflowID: "wf", WorkflowStepID: "step", AgentProfileID: "agent", ExecutorProfileID: "executor", Enabled: true}
issue := &IssueWatch{WorkspaceID: "workspace-a", WorkflowID: "wf", WorkflowStepID: "step", AgentProfileID: "agent", ExecutorProfileID: "executor", Enabled: true}
if err := store.CreateReviewWatch(t.Context(), review); err != nil {
t.Fatal(err)
}
if err := store.CreateIssueWatch(t.Context(), issue); err != nil {
t.Fatal(err)
}
if _, err := store.BeginReviewWatchDelete(t.Context(), review.ID); err != nil {
t.Fatal(err)
}
if _, err := store.BeginIssueWatchDelete(t.Context(), issue.ID); err != nil {
t.Fatal(err)
}
service := NewService("", nil, AuthMethodNone, nil, newTestLogger(t))
service.SetStore(store)
controller := NewController(service, newTestLogger(t))
for _, test := range []struct {
name string
id string
guard func(*gin.Context, string) bool
}{{"review", review.ID, controller.requireReviewWatchDeleteInWorkspace}, {"issue", issue.ID, controller.requireIssueWatchDeleteInWorkspace}} {
t.Run(test.name, func(t *testing.T) {
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest("DELETE", "/?workspace_id=workspace-a", nil)
if !test.guard(ctx, test.id) {
t.Fatalf("owned tombstone retry rejected: status=%d body=%s", recorder.Code, recorder.Body.String())
}
foreignRecorder := httptest.NewRecorder()
foreign, _ := gin.CreateTestContext(foreignRecorder)
foreign.Request = httptest.NewRequest("DELETE", "/?workspace_id=workspace-b", nil)
if test.guard(foreign, test.id) || foreignRecorder.Code != 404 {
t.Fatalf("foreign tombstone disclosed: status=%d body=%s", foreignRecorder.Code, foreignRecorder.Body.String())
}
})
}
}