208 lines
8.7 KiB
Go
208 lines
8.7 KiB
Go
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func currentUploadBinding(cmd CurrentExecuteCommand) CurrentRecordingGrant {
|
|
return CurrentRecordingGrant{
|
|
DispatcherID: cmd.DispatcherID, SourceEventID: cmd.EventID,
|
|
UploadID: "upload-" + cmd.EventID, RecordingID: "recording-" + cmd.EventID,
|
|
Bucket: "mock-bucket", ObjectKey: "tenant/1001/" + cmd.EventID + "/rec.wav",
|
|
ChecksumSHA256: strings.Repeat("a", 64), SizeBytes: 128,
|
|
Format: "wav", Channels: 1, SampleRateHz: 16000, DurationMS: 3000,
|
|
}
|
|
}
|
|
|
|
func TestCurrentUploadBoundWhileOriginateAcknowledgmentIsInFlight(t *testing.T) {
|
|
s := preparedCurrentCallStore(t)
|
|
cmd := currentCall("grant-during-dispatch")
|
|
if _, _, err := s.RecordExecute(cmd); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.ReserveExecute(cmd.DispatcherID, cmd.EventID, currentReservation(), time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
binding := currentUploadBinding(cmd)
|
|
if _, created, err := s.BindRecordingUpload(binding); err != nil || !created {
|
|
t.Fatalf("approved Agent could not request a recording token before originate RPC returned: created=%t err=%v", created, err)
|
|
}
|
|
if err := s.MarkExecuteDispatched(cmd.DispatcherID, cmd.EventID); err != nil {
|
|
t.Fatalf("late originate acknowledgment conflicted with original upload: %v", err)
|
|
}
|
|
if _, created, err := s.BindRecordingUpload(binding); err != nil || created {
|
|
t.Fatalf("late acknowledgment replaced the bound asset: created=%t err=%v", created, err)
|
|
}
|
|
}
|
|
|
|
func TestCurrentUploadBindingPersistsOnlyOneOriginalAssetAcrossRestart(t *testing.T) {
|
|
s := preparedCurrentCallStore(t)
|
|
cmd := currentResultCall(t, s, "grant-stable-1", true)
|
|
original := currentUploadBinding(cmd)
|
|
stored, created, err := s.BindRecordingUpload(original)
|
|
if err != nil || !created || !reflect.DeepEqual(stored, original) {
|
|
t.Fatalf("original D-owned bucket/key not bound: stored=%+v created=%t err=%v", stored, created, err)
|
|
}
|
|
stored, created, err = s.BindRecordingUpload(original)
|
|
if err != nil || created || !reflect.DeepEqual(stored, original) {
|
|
t.Fatalf("explicit grant request changed the original target: stored=%+v created=%t err=%v", stored, created, err)
|
|
}
|
|
var version, seq int
|
|
var databaseName, databasePath string
|
|
if err := s.db.QueryRow(`PRAGMA user_version`).Scan(&version); err != nil || version != 2 {
|
|
t.Fatalf("current schema is not the new, reviewed recording layout: version=%d err=%v", version, err)
|
|
}
|
|
if err := s.db.QueryRow(`PRAGMA database_list`).Scan(&seq, &databaseName, &databasePath); err != nil || databasePath == "" {
|
|
t.Fatalf("locate isolated SQLite fixture: %v", err)
|
|
}
|
|
if err := s.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
restarted, err := OpenCurrent(databasePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer restarted.Close()
|
|
loaded, err := restarted.LoadRecordingUpload(cmd.DispatcherID, cmd.EventID)
|
|
if err != nil || !reflect.DeepEqual(loaded, original) {
|
|
t.Fatalf("restart changed the only OSS target: loaded=%+v err=%v", loaded, err)
|
|
}
|
|
var schema string
|
|
if err := restarted.db.QueryRow(`SELECT sql FROM sqlite_master WHERE name='dispatcher_recordings'`).Scan(&schema); err != nil || strings.Contains(strings.ToLower(schema), "token") || strings.Contains(strings.ToLower(schema), "signed_url") || strings.Contains(strings.ToLower(schema), "target_url") {
|
|
t.Fatalf("temporary OSS credential was persisted in grant table: err=%v", err)
|
|
}
|
|
}
|
|
|
|
func TestCurrentUploadBindingRejectsChangedTargetAndUnreservedCalls(t *testing.T) {
|
|
s := preparedCurrentCallStore(t)
|
|
pending := currentCall("grant-not-reserved")
|
|
if _, _, err := s.RecordExecute(pending); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, _, err := s.BindRecordingUpload(currentUploadBinding(pending)); err == nil {
|
|
t.Fatal("unreserved instruction granted an OSS upload")
|
|
}
|
|
cmd := currentResultCall(t, s, "grant-immutable-1", true)
|
|
original := currentUploadBinding(cmd)
|
|
if _, _, err := s.BindRecordingUpload(original); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, change := range []struct {
|
|
name string
|
|
apply func(*CurrentRecordingGrant)
|
|
}{
|
|
{"upload ID", func(x *CurrentRecordingGrant) { x.UploadID = "new-upload" }},
|
|
{"recording ID", func(x *CurrentRecordingGrant) { x.RecordingID = "other-recording" }},
|
|
{"bucket", func(x *CurrentRecordingGrant) { x.Bucket = "changed-bucket" }},
|
|
{"object key", func(x *CurrentRecordingGrant) { x.ObjectKey = "another/key.wav" }},
|
|
{"checksum", func(x *CurrentRecordingGrant) { x.ChecksumSHA256 = strings.Repeat("b", 64) }},
|
|
{"size", func(x *CurrentRecordingGrant) { x.SizeBytes++ }},
|
|
{"channels", func(x *CurrentRecordingGrant) { x.Channels = 2 }},
|
|
} {
|
|
changed := original
|
|
change.apply(&changed)
|
|
if _, _, err := s.BindRecordingUpload(changed); !errors.Is(err, ErrCurrentUploadConflict) {
|
|
t.Fatalf("%s replaced the immutable original: %v", change.name, err)
|
|
}
|
|
}
|
|
if loaded, err := s.LoadRecordingUpload(cmd.DispatcherID, cmd.EventID); err != nil || !reflect.DeepEqual(loaded, original) {
|
|
t.Fatalf("conflicting grant changed durable target: loaded=%+v err=%v", loaded, err)
|
|
}
|
|
}
|
|
|
|
func TestCurrentRecordingSourceMustMatchReservedCallAndNumericTenant(t *testing.T) {
|
|
s := preparedCurrentCallStore(t)
|
|
cmd := currentResultCall(t, s, "grant-auth-source", true)
|
|
if err := s.RequireReservedCall(cmd.DispatcherID, cmd.EventID, cmd.TenantID); err != nil {
|
|
t.Fatalf("approved call identity rejected: %v", err)
|
|
}
|
|
for _, check := range []struct {
|
|
name string
|
|
dispatcherID string
|
|
sourceEventID string
|
|
tenantID int64
|
|
}{
|
|
{"foreign dispatcher", "other-dispatcher", cmd.EventID, cmd.TenantID},
|
|
{"foreign tenant", cmd.DispatcherID, cmd.EventID, cmd.TenantID + 1},
|
|
{"unknown call", cmd.DispatcherID, "unknown-execution", cmd.TenantID},
|
|
} {
|
|
if err := s.RequireReservedCall(check.dispatcherID, check.sourceEventID, check.tenantID); err == nil {
|
|
t.Fatalf("%s was accepted as original approved call", check.name)
|
|
}
|
|
}
|
|
pending := currentCall("grant-not-authorized")
|
|
if _, _, err := s.RecordExecute(pending); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.RequireReservedCall(pending.DispatcherID, pending.EventID, pending.TenantID); err == nil {
|
|
t.Fatal("unreserved instruction was accepted as an approved recording source")
|
|
}
|
|
}
|
|
|
|
func TestCurrentUploadBindingRejectsReusedUploadIDOrOSSObject(t *testing.T) {
|
|
s := preparedCurrentCallStore(t)
|
|
first := currentUploadBinding(currentResultCall(t, s, "grant-unique-1", true))
|
|
second := currentUploadBinding(currentResultCall(t, s, "grant-unique-2", true))
|
|
if _, _, err := s.BindRecordingUpload(first); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second.UploadID = first.UploadID
|
|
if _, _, err := s.BindRecordingUpload(second); err == nil {
|
|
t.Fatal("two calls shared one upload identity")
|
|
}
|
|
second.UploadID = "upload-grant-unique-2"
|
|
second.ObjectKey = first.ObjectKey
|
|
if _, _, err := s.BindRecordingUpload(second); err == nil {
|
|
t.Fatal("two calls shared one original OSS object")
|
|
}
|
|
if _, err := s.LoadRecordingUpload(second.DispatcherID, second.SourceEventID); !errors.Is(err, ErrCurrentUploadNotFound) {
|
|
t.Fatalf("failed uniqueness check left a partial grant: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCurrentSchemaRejectsPreviousCompleteLayoutWithoutErasingOutbox(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "previous-current.db")
|
|
s, err := OpenCurrent(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.db.Exec(`INSERT INTO dispatcher_outbox(dispatcher_id,event_id,event_type,routing_key,body) VALUES(?,?,?,?,?)`, currentDispatcherID, "not-delivered", "call.execute.result", "mock.route", []byte(`{"persisted":true}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.db.Exec(`DROP TABLE dispatcher_recordings`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.db.Exec(`PRAGMA user_version=1`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if reopened, err := OpenCurrent(path); err == nil {
|
|
reopened.Close()
|
|
t.Fatal("incomplete previous SQLite layout was silently modified or admitted")
|
|
}
|
|
old, err := sql.Open("sqlite", path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer old.Close()
|
|
var body []byte
|
|
if err := old.QueryRow(`SELECT body FROM dispatcher_outbox WHERE dispatcher_id=? AND event_id=?`, currentDispatcherID, "not-delivered").Scan(&body); err != nil || string(body) != `{"persisted":true}` {
|
|
t.Fatalf("undelivered result was altered by refused admission: body=%s err=%v", body, err)
|
|
}
|
|
var count, version int
|
|
if err := old.QueryRow(`SELECT COUNT(*) FROM sqlite_master WHERE name='dispatcher_recordings'`).Scan(&count); err != nil || count != 0 {
|
|
t.Fatalf("refused database was automatically migrated: tables=%d err=%v", count, err)
|
|
}
|
|
if err := old.QueryRow(`PRAGMA user_version`).Scan(&version); err != nil || version != 1 {
|
|
t.Fatalf("refused database layout was modified: version=%d err=%v", version, err)
|
|
}
|
|
}
|