package handlers import ( "context" "sync" "time" "github.com/orchard9/rdev/internal/domain" ) // mockOperationRepo is a mock implementation of port.OperationRepository for testing. type mockOperationRepo struct { mu sync.Mutex operations map[string]*domain.Operation } func newMockOperationRepo() *mockOperationRepo { return &mockOperationRepo{ operations: make(map[string]*domain.Operation), } } func (m *mockOperationRepo) Create(_ context.Context, op *domain.Operation) error { m.mu.Lock() defer m.mu.Unlock() m.operations[op.ID] = op return nil } func (m *mockOperationRepo) Update(_ context.Context, op *domain.Operation) error { m.mu.Lock() defer m.mu.Unlock() m.operations[op.ID] = op return nil } func (m *mockOperationRepo) Get(_ context.Context, id string) (*domain.Operation, error) { m.mu.Lock() defer m.mu.Unlock() op, ok := m.operations[id] if !ok { return nil, domain.ErrOperationNotFound } return op, nil } func (m *mockOperationRepo) GetByCommitSHA(_ context.Context, projectID, sha string) (*domain.Operation, error) { m.mu.Lock() defer m.mu.Unlock() for _, op := range m.operations { if op.ProjectID == projectID && op.CommitSHA == sha { return op, nil } } return nil, domain.ErrOperationNotFound } func (m *mockOperationRepo) List(_ context.Context, filter domain.OperationFilters) ([]*domain.Operation, error) { m.mu.Lock() defer m.mu.Unlock() var result []*domain.Operation for _, op := range m.operations { if filter.ProjectID != "" && op.ProjectID != filter.ProjectID { continue } result = append(result, op) } return result, nil } func (m *mockOperationRepo) AddStep(_ context.Context, operationID string, step domain.OperationStep) error { m.mu.Lock() defer m.mu.Unlock() op, ok := m.operations[operationID] if !ok { return domain.ErrOperationNotFound } op.Steps = append(op.Steps, step) return nil } func (m *mockOperationRepo) UpdateStep(_ context.Context, operationID string, step domain.OperationStep) error { m.mu.Lock() defer m.mu.Unlock() op, ok := m.operations[operationID] if !ok { return domain.ErrOperationNotFound } for i, s := range op.Steps { if s.Name == step.Name { op.Steps[i] = step return nil } } return nil } func (m *mockOperationRepo) Complete(_ context.Context, operationID string, status domain.OperationStatus, output map[string]any, errMsg, errDetail string) error { m.mu.Lock() defer m.mu.Unlock() op, ok := m.operations[operationID] if !ok { return domain.ErrOperationNotFound } op.Status = status now := time.Now() op.CompletedAt = &now op.DurationMs = now.Sub(op.StartedAt).Milliseconds() op.Output = output op.Error = errMsg op.ErrorDetail = errDetail return nil } func (m *mockOperationRepo) SetCommitSHA(_ context.Context, operationID, sha string) error { m.mu.Lock() defer m.mu.Unlock() op, ok := m.operations[operationID] if !ok { return domain.ErrOperationNotFound } op.CommitSHA = sha return nil } func (m *mockOperationRepo) SetTriggeredBy(_ context.Context, operationID, parentID string) error { m.mu.Lock() defer m.mu.Unlock() op, ok := m.operations[operationID] if !ok { return domain.ErrOperationNotFound } op.TriggeredBy = parentID return nil } func (m *mockOperationRepo) DeleteOlderThan(_ context.Context, _ time.Time) (int64, error) { return 0, nil } // count returns the number of operations stored. func (m *mockOperationRepo) count() int { m.mu.Lock() defer m.mu.Unlock() return len(m.operations) }