Files
2026-07-27 18:10:12 +01:00

166 lines
6.0 KiB
Go

package github
import (
"context"
"errors"
"testing"
"time"
)
func newCopyTestService(t *testing.T) *Service {
t.Helper()
client := NewMockClient()
store := newTestStore(t)
return NewService(client, AuthMethodPAT, nil, store, nil, testLogger(t))
}
func TestCopyWorkspaceSettingsToWorkspace_CopiesSettings(t *testing.T) {
svc := newCopyTestService(t)
ctx := context.Background()
const src, dst = "ws-src", "ws-dst"
if err := svc.UpsertWorkspaceSettings(ctx, &WorkspaceSettings{
WorkspaceID: src,
TaskGitCredentialsMode: TaskGitCredentialsModeExecutor,
RepoScopeMode: RepoScopeModeRepos,
RepoScopeRepos: []RepoFilter{{Owner: "kdlbs", Name: "kandev"}},
SavedPresets: []byte(`[{"id":"p1","kind":"pr","label":"Mine"}]`),
DefaultQueryPresets: []byte(`{"pr":[],"issue":[]}`),
}); err != nil {
t.Fatalf("seed source: %v", err)
}
if _, err := svc.UpdateActionPresets(ctx, &UpdateActionPresetsRequest{
WorkspaceID: src,
PR: &[]ActionPreset{{ID: "custom", Label: "Custom", PromptTemplate: "do {{url}}"}},
}); err != nil {
t.Fatalf("seed source action presets: %v", err)
}
got, err := svc.CopyWorkspaceSettingsToWorkspace(ctx, src, dst)
if err != nil {
t.Fatalf("copy: %v", err)
}
if got.WorkspaceID != dst || got.RepoScopeMode != RepoScopeModeRepos {
t.Errorf("copied settings identity/scope mismatch: %+v", got)
}
if got.TaskGitCredentialsMode != TaskGitCredentialsModeExecutor {
t.Errorf("task Git credential mode not copied: %q", got.TaskGitCredentialsMode)
}
if len(got.RepoScopeRepos) != 1 || got.RepoScopeRepos[0].Owner != "kdlbs" ||
got.RepoScopeRepos[0].Name != "kandev" {
t.Errorf("repo scope not copied: %+v", got.RepoScopeRepos)
}
if string(got.SavedPresets) != `[{"id":"p1","kind":"pr","label":"Mine"}]` {
t.Errorf("saved presets not copied: %s", got.SavedPresets)
}
if string(got.DefaultQueryPresets) != `{"pr":[],"issue":[]}` {
t.Errorf("default query presets not copied: %s", got.DefaultQueryPresets)
}
presets, err := svc.GetActionPresets(ctx, dst)
if err != nil {
t.Fatalf("get copied action presets: %v", err)
}
if len(presets.PR) != 1 || presets.PR[0].ID != "custom" {
t.Errorf("action presets not copied: %+v", presets.PR)
}
}
func TestCopyWorkspaceSettingsToWorkspace_DoesNotCopyAuthentication(t *testing.T) {
svc := newCopyTestService(t)
ctx := context.Background()
const src, dst = "ws-src", "ws-dst"
seedConnectionWorkspaces(t, svc.store, src, dst)
seedStoreAppRegistration(t, svc.store)
now := time.Now().UTC()
installationID := int64(42)
if err := svc.store.UpsertWorkspaceConnection(ctx, &WorkspaceConnection{
WorkspaceID: src, Source: ConnectionSourceGitHubAppInstallation, GitHubHost: "github.com",
InstallationID: &installationID, InstallationAccountLogin: "acme",
InstallationAccountType: "Organization", AppRegistrationID: "registration-store-test",
Status: ConnectionStatusActive, CreatedAt: now, UpdatedAt: now,
}); err != nil {
t.Fatalf("seed source connection: %v", err)
}
if err := svc.store.UpsertUserConnection(ctx, &UserConnection{
WorkspaceID: src, UserID: "default-user", AppRegistrationID: "registration-store-test",
GitHubUserID: 42, Login: "octocat",
Status: ConnectionStatusActive, AccessExpiresAt: now.Add(time.Hour), CreatedAt: now, UpdatedAt: now,
}); err != nil {
t.Fatalf("seed source user connection: %v", err)
}
if _, err := svc.CopyWorkspaceSettingsToWorkspace(ctx, src, dst); err != nil {
t.Fatalf("copy: %v", err)
}
connection, err := svc.store.GetWorkspaceConnection(ctx, dst)
if err != nil {
t.Fatalf("get target connection: %v", err)
}
if connection != nil {
t.Fatalf("target inherited workspace auth: %+v", connection)
}
user, err := svc.store.GetUserConnection(ctx, dst, "default-user")
if err != nil {
t.Fatalf("get target user connection: %v", err)
}
if user != nil {
t.Fatalf("target inherited personal auth: %+v", user)
}
}
// When the source relies on default presets (no stored row), the copy must
// clear the target's customised presets so both fall back to the same defaults —
// otherwise the copy silently leaves the target diverged from the source.
func TestCopyWorkspaceSettingsToWorkspace_ClearsTargetPresetsWhenSourceHasNone(t *testing.T) {
svc := newCopyTestService(t)
ctx := context.Background()
const src, dst = "ws-src", "ws-dst"
// Target has customised presets; source has none stored.
if _, err := svc.UpdateActionPresets(ctx, &UpdateActionPresetsRequest{
WorkspaceID: dst,
PR: &[]ActionPreset{{ID: "target-custom", Label: "Target", PromptTemplate: "x {{url}}"}},
}); err != nil {
t.Fatalf("seed target action presets: %v", err)
}
if _, err := svc.CopyWorkspaceSettingsToWorkspace(ctx, src, dst); err != nil {
t.Fatalf("copy: %v", err)
}
defaults, err := svc.GetActionPresets(ctx, "ws-fresh")
if err != nil {
t.Fatalf("get default presets: %v", err)
}
got, err := svc.GetActionPresets(ctx, dst)
if err != nil {
t.Fatalf("get target presets: %v", err)
}
if len(got.PR) != len(defaults.PR) {
t.Errorf("target presets not reset to defaults: got %d, want %d", len(got.PR), len(defaults.PR))
}
for _, p := range got.PR {
if p.ID == "target-custom" {
t.Errorf("target retained its customised preset after copy from a source with none")
}
}
}
func TestCopyWorkspaceSettingsToWorkspace_SameWorkspace(t *testing.T) {
svc := newCopyTestService(t)
if _, err := svc.CopyWorkspaceSettingsToWorkspace(context.Background(), "ws-1", "ws-1"); !errors.Is(err, ErrSameWorkspace) {
t.Fatalf("expected ErrSameWorkspace, got %v", err)
}
}
func TestCopyWorkspaceSettingsToWorkspace_MissingIDs(t *testing.T) {
svc := newCopyTestService(t)
if _, err := svc.CopyWorkspaceSettingsToWorkspace(context.Background(), "", "ws-dst"); !errors.Is(err, ErrWorkspaceSettingsValidation) {
t.Fatalf("expected ErrWorkspaceSettingsValidation for empty source, got %v", err)
}
if _, err := svc.CopyWorkspaceSettingsToWorkspace(context.Background(), "ws-src", ""); !errors.Is(err, ErrWorkspaceSettingsValidation) {
t.Fatalf("expected ErrWorkspaceSettingsValidation for empty destination, got %v", err)
}
}