Why: Account disable could be followed by late Backend business writes, API key creation could implicitly create users, account bootstrap locks could invert, and directory cursors were process-local or leaked out-of-scope changes. Evidence: Local go test ./... and isolated PostgreSQL package suites passed on the staged candidate; exact committed-head SELF replay and stage 6 human review remain pending. Impact: Adds final account transactions and external-effect checks across HTTP, Host, Bus and run manager; tightens API key issuance and persists versioned cursor signing. Delegated RDM rename still needs the separately proposed real-operator contract, so A1 and stage 6 are not complete. Refs: Documents U3 r1, approved A1-A4 amendment fb3a821, pending delegated-projection amendment 5783940, Dev feature/iam-u3-account-directory-recovery.
61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package store
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestPGSameOwnerBootstrapAndCreateSerialize(t *testing.T) {
|
|
baseDSN := os.Getenv("AGENT_PG_TEST_DSN")
|
|
if baseDSN == "" {
|
|
t.Skip("isolated PostgreSQL test DSN required")
|
|
}
|
|
first := openTestStore(t)
|
|
if err := first.EnsureSystemIdentity("same-owner-admission", "pg"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var schema string
|
|
if err := first.DB().QueryRow(`SELECT current_schema()`).Scan(&schema); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := OpenExistingPostgres(withTestSearchPath(baseDSN, schema), filepath.Join(t.TempDir(), "artifacts"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer second.Close()
|
|
start := make(chan struct{})
|
|
results := make(chan error, 2)
|
|
go func() {
|
|
<-start
|
|
_, err := first.CreateActivatedAccount(AccountWrite{Owner: "same", Name: "Same", Purpose: LoginKeyPurposeActivate, Actor: "fixture", CreatedBy: "fixture"})
|
|
results <- err
|
|
}()
|
|
go func() {
|
|
<-start
|
|
_, err := second.BootstrapFirstAdminWrite(AccountWrite{Owner: "same", Name: "Same", Actor: "fixture", CreatedBy: "fixture"})
|
|
results <- err
|
|
}()
|
|
close(start)
|
|
wins, conflicts := 0, 0
|
|
for range 2 {
|
|
select {
|
|
case err := <-results:
|
|
if err == nil {
|
|
wins++
|
|
} else if errors.Is(err, ErrConflict) {
|
|
conflicts++
|
|
} else {
|
|
t.Fatalf("same-owner admission returned %v", err)
|
|
}
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("account/bootstrap lock ordering did not make progress")
|
|
}
|
|
}
|
|
if wins != 1 || conflicts != 1 {
|
|
t.Fatalf("wins=%d conflicts=%d, want 1/1", wins, conflicts)
|
|
}
|
|
}
|