Files
Assistant/cmd/commit-runtime/execution_test.go
2026-08-31 16:28:57 +03:00

88 lines
3.8 KiB
Go

package main
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"git.cin.su/m/Assistant/adapters/postgres"
commitcontract "git.cin.su/m/Assistant/contracts/commit"
"git.cin.su/m/Assistant/modules/commit/ports"
)
type fakeExecutionRepository struct {
action commitcontract.AuthorizedAction
attempts []commitcontract.ActionAttempt
receipt commitcontract.ExecutionReceipt
}
func (f *fakeExecutionRepository) SaveExecutionReceipt(_ context.Context, receipt commitcontract.ExecutionReceipt) error {
f.receipt = receipt
return nil
}
func (f *fakeExecutionRepository) LoadAuthorized(context.Context, commitcontract.AuthorizedActionID) (commitcontract.AuthorizedAction, error) {
return f.action, nil
}
func (f *fakeExecutionRepository) LoadLatestAttempt(context.Context, commitcontract.AuthorizedActionID) (commitcontract.ActionAttempt, error) {
if len(f.attempts) == 0 {
return commitcontract.ActionAttempt{}, postgres.ErrActionAttemptNotFound
}
return f.attempts[len(f.attempts)-1], nil
}
func (f *fakeExecutionRepository) BeginAttempt(_ context.Context, attempt commitcontract.ActionAttempt) error {
f.attempts = append(f.attempts, attempt)
return nil
}
func (f *fakeExecutionRepository) FinishAttempt(_ context.Context, attempt commitcontract.ActionAttempt) error {
if len(f.attempts) == 0 || f.attempts[len(f.attempts)-1].ID != attempt.ID {
return errors.New("attempt not begun")
}
f.attempts[len(f.attempts)-1] = attempt
return nil
}
func (f *fakeExecutionRepository) SaveAuthorized(_ context.Context, action commitcontract.AuthorizedAction) error {
f.action = action
return nil
}
type knownExecutor struct{ calls int }
func (e *knownExecutor) Execute(commitcontract.AuthorizedAction) ports.ExecutionResult {
e.calls++
completed := int64(1)
return ports.ExecutionResult{Known: true, Succeeded: true, Receipt: &commitcontract.ExecutionReceipt{ID: "receipt-1", ExecutorImplementationRef: "test-executor", ExternalOperationRef: "SHADOW_CAPTURED", RequestDigest: "request", ExecutorResult: commitcontract.ExecutorReportedSuccess, ReconciliationKey: "receipt-1", DispatchAtUnixMillis: 1, CompletedAtUnixMillis: &completed}}
}
func (e *knownExecutor) Reconcile(commitcontract.AuthorizedAction) ports.ExecutionResult {
return ports.ExecutionResult{Known: true, Succeeded: true}
}
func TestExecutionIsDurablyBegunAndCannotBeBlindlyRepeated(t *testing.T) {
repository := &fakeExecutionRepository{action: commitcontract.AuthorizedAction{ID: "authorized-1", State: commitcontract.ActionAuthorized, Proposal: commitcontract.ActionProposal{IntentID: "intent-1"}}}
executor := &knownExecutor{}
mux := http.NewServeMux()
registerExecutionRoutes(mux, repository, executor, executor, "secret")
request := httptest.NewRequest(http.MethodPost, "/v1/internal/authorized-actions/authorized-1/execute", strings.NewReader(`{"AttemptID":"attempt-1"}`))
request.Header.Set("Authorization", "Bearer secret")
result := httptest.NewRecorder()
mux.ServeHTTP(result, request)
if result.Code != http.StatusOK || executor.calls != 1 || repository.attempts[0].State != commitcontract.ActionSucceeded {
t.Fatalf("status=%d calls=%d attempts=%#v", result.Code, executor.calls, repository.attempts)
}
if repository.receipt.ActionAttemptRef != repository.attempts[0].ID {
t.Fatalf("receipt attempt reference=%q want %q", repository.receipt.ActionAttemptRef, repository.attempts[0].ID)
}
repeated := httptest.NewRequest(http.MethodPost, "/v1/internal/authorized-actions/authorized-1/execute", strings.NewReader(`{"AttemptID":"attempt-2"}`))
repeated.Header.Set("Authorization", "Bearer secret")
repeatedResult := httptest.NewRecorder()
mux.ServeHTTP(repeatedResult, repeated)
if repeatedResult.Code != http.StatusConflict || executor.calls != 1 {
t.Fatalf("repeat status=%d calls=%d", repeatedResult.Code, executor.calls)
}
}