48 lines
2.0 KiB
Go
48 lines
2.0 KiB
Go
package dispatcher
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.ipao.vip/rogee/go-sip/internal/mq"
|
|
)
|
|
|
|
// A deterministic SQLite write failure models the admission boundary under
|
|
// disk exhaustion without filling the developer's filesystem. The MQ handler
|
|
// must leave the original command available for redelivery, not ACK a refusal.
|
|
func TestLocalSQLiteWriteFailureKeepsOriginalCommandUnaccepted(t *testing.T) {
|
|
at := time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC)
|
|
d, st, configServer := newLocalV01TestDispatcher(t, at)
|
|
defer configServer.Close()
|
|
defer st.Close()
|
|
const commandID = "command-sqlite-full"
|
|
route := "d." + localTestDispatcherID + ".task." + localTestTaskID + ".in"
|
|
body := localExecuteCommandBody(t, commandID, at.Add(2*time.Hour))
|
|
if _, err := st.DB().Exec(`CREATE TRIGGER injected_sqlite_full BEFORE INSERT ON tasks BEGIN SELECT RAISE(ABORT, 'database or disk is full'); END`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.AcceptLocalV01Command(context.Background(), route, body); err == nil || mq.IsPermanent(err) {
|
|
t.Fatalf("SQLite write failure was ACKable or classified as a permanent command error: %v", err)
|
|
}
|
|
var tasks, reservations int
|
|
if err := st.DB().QueryRow(`SELECT COUNT(*) FROM tasks WHERE task_item_id=?`, commandID).Scan(&tasks); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.DB().QueryRow(`SELECT COUNT(*) FROM reservations`).Scan(&reservations); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if tasks != 0 || reservations != 0 {
|
|
t.Fatalf("failed SQLite admission persisted a partial command: tasks=%d reservations=%d", tasks, reservations)
|
|
}
|
|
if _, err := st.DB().Exec(`DROP TRIGGER injected_sqlite_full`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.AcceptLocalV01Command(context.Background(), route, body); err != nil {
|
|
t.Fatalf("original command was not accepted after storage recovered: %v", err)
|
|
}
|
|
if err := st.DB().QueryRow(`SELECT COUNT(*) FROM tasks WHERE task_item_id=?`, commandID).Scan(&tasks); err != nil || tasks != 1 {
|
|
t.Fatalf("recovered command identity changed or duplicated: tasks=%d err=%v", tasks, err)
|
|
}
|
|
}
|