78 lines
3.1 KiB
Go
78 lines
3.1 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
|
|
}
|
|
|
|
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++
|
|
return ports.ExecutionResult{Known: true, Succeeded: true}
|
|
}
|
|
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)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|