1package daemon23import (4 "context"5 "strings"6 "testing"7 "time"89 "github.com/FelineStateMachine/tinyrelay/internal/event"10 "github.com/FelineStateMachine/tinyrelay/internal/storage"11)1213func TestGitPromotionRollsBackVisibilityOnStorageFailure(t *testing.T) {14 _, tenant := testTenant(t)15 ctx := context.Background()16 e := event.Event{Kind: 30618, CreatedAt: time.Now().Unix(), Tags: [][]string{{"d", "repo"}}, Content: ""}17 if err := event.Sign(&e, strings.Repeat("0", 63)+"1"); err != nil {18 t.Fatal(err)19 }20 if _, err := tenant.store.Save(ctx, e, storage.SaveOptions{Now: time.Now().Unix()}); err != nil {21 t.Fatal(err)22 }23 for _, statement := range []string{24 `CREATE TABLE IF NOT EXISTS replication_pending_until(id TEXT PRIMARY KEY,until INTEGER NOT NULL)`,25 `INSERT INTO pending_events(id,reason) VALUES('` + e.ID + `','git objects')`,26 `INSERT INTO replication_pending_until(id,until) VALUES('` + e.ID + `',1)`,27 `CREATE TRIGGER fail_promotion BEFORE DELETE ON replication_pending_until BEGIN SELECT RAISE(ABORT,'injected storage failure'); END`,28 } {29 if _, err := tenant.store.DB().ExecContext(ctx, statement); err != nil {30 t.Fatal(err)31 }32 }33 if err := tenant.releaseGit(ctx, e.ID); err == nil {34 t.Fatal("promotion ignored storage failure")35 }36 var held int37 if err := tenant.store.DB().QueryRowContext(ctx, `SELECT count(*) FROM pending_events WHERE id=?`, e.ID).Scan(&held); err != nil || held != 1 {38 t.Fatalf("failed promotion lost retry marker: %d, %v", held, err)39 }40 if _, err := tenant.store.DB().ExecContext(ctx, `DROP TRIGGER fail_promotion`); err != nil {41 t.Fatal(err)42 }43 if err := tenant.releaseGit(ctx, e.ID); err != nil {44 t.Fatal(err)45 }46 result, err := tenant.store.Query(ctx, event.Filter{IDs: []string{e.ID}}, storage.QueryOptions{Now: time.Now().Unix(), Access: storage.Access{All: true}})47 if err != nil || len(result.Events) != 1 {48 t.Fatalf("retried promotion not visible: %#v, %v", result, err)49 }50}