package handlers import ( "context" "fmt" "time" "github.com/orchard9/rdev/internal/domain" "github.com/orchard9/rdev/internal/port" ) // mockGitRepository implements port.GitRepository for testing. type mockGitRepository struct { repos map[string]*domain.Repo err error } func newMockGitRepository() *mockGitRepository { return &mockGitRepository{repos: make(map[string]*domain.Repo)} } func (m *mockGitRepository) CreateRepo(_ context.Context, name, description string, private bool) (*domain.Repo, error) { if m.err != nil { return nil, m.err } repo := &domain.Repo{ ID: 1, Owner: "threesix", Name: name, FullName: "threesix/" + name, Description: description, Private: private, CloneSSH: fmt.Sprintf("git@git.threesix.ai:threesix/%s.git", name), CloneHTTP: fmt.Sprintf("https://git.threesix.ai/threesix/%s.git", name), HTMLURL: fmt.Sprintf("https://git.threesix.ai/threesix/%s", name), CreatedAt: time.Now(), UpdatedAt: time.Now(), } m.repos[name] = repo return repo, nil } func (m *mockGitRepository) DeleteRepo(_ context.Context, _, name string) error { if m.err != nil { return m.err } delete(m.repos, name) return nil } func (m *mockGitRepository) ListRepos(_ context.Context, _ string) ([]*domain.Repo, error) { if m.err != nil { return nil, m.err } var repos []*domain.Repo for _, r := range m.repos { repos = append(repos, r) } return repos, nil } func (m *mockGitRepository) GetRepo(_ context.Context, _, name string) (*domain.Repo, error) { if m.err != nil { return nil, m.err } r, ok := m.repos[name] if !ok { return nil, fmt.Errorf("repo not found: %s", name) } return r, nil } func (m *mockGitRepository) AddCollaborator(context.Context, string, string, string, string) error { return m.err } func (m *mockGitRepository) RemoveCollaborator(context.Context, string, string, string) error { return m.err } func (m *mockGitRepository) AddDeployKey(context.Context, string, string, string, string, bool) (*domain.DeployKey, error) { return nil, m.err } func (m *mockGitRepository) DeleteDeployKey(context.Context, string, string, int64) error { return m.err } func (m *mockGitRepository) CreateWebhook(context.Context, string, string, string, string, []string) (*domain.RepoWebhook, error) { return nil, m.err } func (m *mockGitRepository) DeleteWebhook(context.Context, string, string, int64) error { return m.err } func (m *mockGitRepository) ListBranches(_ context.Context, _, _ string) ([]*domain.GitBranch, error) { if m.err != nil { return nil, m.err } return []*domain.GitBranch{ {Name: "main", CommitSHA: "abc123", Protected: true}, {Name: "develop", CommitSHA: "def456", Protected: false}, }, nil } func (m *mockGitRepository) CreateBranch(_ context.Context, _, _, branchName, _ string) (*domain.GitBranch, error) { if m.err != nil { return nil, m.err } return &domain.GitBranch{ Name: branchName, CommitSHA: "newcommit123", Protected: false, }, nil } func (m *mockGitRepository) CreateAccessToken(_ context.Context, name string, _ []string, _ *time.Time) (*domain.GitAccessToken, error) { if m.err != nil { return nil, m.err } return &domain.GitAccessToken{ ID: 12345, Name: name, Token: "test-token-12345", Scopes: []string{"write:repository"}, }, nil } func (m *mockGitRepository) DeleteAccessToken(_ context.Context, _ int64) error { return m.err } // mockDNSProvider implements port.DNSProvider for testing. type mockDNSProvider struct { records map[string]*domain.DNSRecord err error } func newMockDNSProvider() *mockDNSProvider { return &mockDNSProvider{records: make(map[string]*domain.DNSRecord)} } func (m *mockDNSProvider) CreateRecord(_ context.Context, record domain.DNSRecord) (*domain.DNSRecord, error) { if m.err != nil { return nil, m.err } record.ID = "rec-" + record.Name m.records[record.Name] = &record return &record, nil } func (m *mockDNSProvider) UpdateRecord(_ context.Context, recordID string, record domain.DNSRecord) (*domain.DNSRecord, error) { if m.err != nil { return nil, m.err } record.ID = recordID m.records[recordID] = &record return &record, nil } func (m *mockDNSProvider) DeleteRecord(_ context.Context, recordID string) error { if m.err != nil { return m.err } delete(m.records, recordID) return nil } func (m *mockDNSProvider) DeleteRecordByName(_ context.Context, _, name string) error { if m.err != nil { return m.err } delete(m.records, name) return nil } func (m *mockDNSProvider) GetRecord(_ context.Context, recordID string) (*domain.DNSRecord, error) { if m.err != nil { return nil, m.err } r, ok := m.records[recordID] if !ok { return nil, fmt.Errorf("record not found") } return r, nil } func (m *mockDNSProvider) ListRecords(_ context.Context, recordType string) ([]*domain.DNSRecord, error) { if m.err != nil { return nil, m.err } var result []*domain.DNSRecord for _, r := range m.records { if recordType == "" || r.Type == recordType { result = append(result, r) } } return result, nil } func (m *mockDNSProvider) FindRecord(_ context.Context, _, name string) (*domain.DNSRecord, error) { if m.err != nil { return nil, m.err } r, ok := m.records[name] if !ok { return nil, nil } return r, nil } func (m *mockDNSProvider) UpsertRecord(ctx context.Context, record domain.DNSRecord) (*domain.DNSRecord, error) { if m.err != nil { return nil, m.err } // Check if record exists, then update or create existing, _ := m.FindRecord(ctx, record.Type, record.Name) if existing != nil { return m.UpdateRecord(ctx, existing.ID, record) } return m.CreateRecord(ctx, record) } // mockDeployer implements port.Deployer for testing. type mockDeployer struct { deployments map[string]*domain.DeployStatus logs string err error } func newMockDeployer() *mockDeployer { return &mockDeployer{deployments: make(map[string]*domain.DeployStatus)} } func (m *mockDeployer) Deploy(_ context.Context, spec domain.DeploySpec) error { if m.err != nil { return m.err } m.deployments[spec.ProjectName] = &domain.DeployStatus{ ProjectName: spec.ProjectName, Image: spec.Image, Replicas: spec.Replicas, ReadyReplicas: 0, URL: "https://" + spec.Domain, Status: domain.DeploymentStatusPending, CreatedAt: time.Now(), UpdatedAt: time.Now(), } return nil } func (m *mockDeployer) Undeploy(_ context.Context, projectName string) error { if m.err != nil { return m.err } delete(m.deployments, projectName) return nil } func (m *mockDeployer) UndeployAll(_ context.Context, projectName string) error { if m.err != nil { return m.err } delete(m.deployments, projectName) return nil } func (m *mockDeployer) GetStatus(_ context.Context, projectName string) (*domain.DeployStatus, error) { if m.err != nil { return nil, m.err } s, ok := m.deployments[projectName] if !ok { return nil, nil } return s, nil } func (m *mockDeployer) Restart(_ context.Context, _ string) error { return m.err } func (m *mockDeployer) Scale(_ context.Context, projectName string, replicas int) error { if m.err != nil { return m.err } if s, ok := m.deployments[projectName]; ok { s.Replicas = replicas } return nil } func (m *mockDeployer) GetLogs(_ context.Context, _ string, _ int) (string, error) { if m.err != nil { return "", m.err } return m.logs, nil } func (m *mockDeployer) AddIngressHost(_ context.Context, _, _ string) error { return m.err } func (m *mockDeployer) RemoveIngressHost(_ context.Context, _, _ string) error { return m.err } func (m *mockDeployer) UndeployComponent(_ context.Context, _, _ string) error { return m.err } func (m *mockDeployer) GetComponentStatus(_ context.Context, _, _ string) (*domain.DeployStatus, error) { if m.err != nil { return nil, m.err } return nil, nil } func (m *mockDeployer) ListComponentStatuses(_ context.Context, _ string) (*domain.ProjectDeployStatus, error) { if m.err != nil { return nil, m.err } return &domain.ProjectDeployStatus{}, nil } func (m *mockDeployer) RestartComponent(_ context.Context, _, _ string) error { return m.err } func (m *mockDeployer) ScaleComponent(_ context.Context, _, _ string, _ int) error { return m.err } func (m *mockDeployer) GetComponentLogs(_ context.Context, _, _ string, _ int) (string, error) { if m.err != nil { return "", m.err } return m.logs, nil } func (m *mockDeployer) AddIngressPath(_ context.Context, _, _, _, _ string, _ int) error { return m.err } func (m *mockDeployer) RemoveIngressPath(_ context.Context, _, _, _ string) error { return m.err } // mockPreviewManager implements port.PreviewManager for testing. type mockPreviewManager struct { previews map[string]bool err error } func newMockPreviewManager() *mockPreviewManager { return &mockPreviewManager{previews: make(map[string]bool)} } func (m *mockPreviewManager) CreatePreview(_ context.Context, opts port.PreviewOptions) error { if m.err != nil { return m.err } m.previews[opts.SessionID] = true return nil } func (m *mockPreviewManager) DeletePreview(_ context.Context, sessionID string) error { if m.err != nil { return m.err } delete(m.previews, sessionID) return nil }