66 lines
2.4 KiB
Go
66 lines
2.4 KiB
Go
package local_event
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
|
|
"git.ilapage.cn/ila/yovision/Sense/server/app/sense/integration/bell_connector"
|
|
"git.ilapage.cn/ila/yovision/Sense/server/app/sense/outbox"
|
|
)
|
|
|
|
func TestCreateWithOutboxCommitsAndRollsBackAtomically(t *testing.T) {
|
|
db, err := gorm.Open(sqlite.Open("file:"+uuid.NewString()+"?mode=memory&cache=shared"), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB, _ := db.DB()
|
|
sqlDB.SetMaxOpenConns(1)
|
|
if err = db.AutoMigrate(&EventCandidate{}, &outbox.Message{}, &outbox.DeliveryRecord{}, &outbox.Attempt{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
now := time.Date(2026, 8, 28, 10, 0, 0, 0, time.UTC)
|
|
candidate := EventCandidate{ID: uuid.NewString(), OccurredAt: now, SourceRef: "SEN-CAM-01", RuleRef: "rule-1", RuleName: "区域闯入", CandidateState: CandidateStateCandidate, EvidenceState: EvidenceStatePending, RetainUntil: now.Add(24 * time.Hour)}
|
|
fixturePath := filepath.Join("..", "..", "..", "..", "..", "contracts", "events", "v1", "examples", "dangerous-area.json")
|
|
fixture, err := os.ReadFile(fixturePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var payload map[string]interface{}
|
|
if err = json.Unmarshal(fixture, &payload); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
payload["producer_id"] = "sense-local"
|
|
payload["source_event_id"] = candidate.ID
|
|
if err = CreateWithOutbox(context.Background(), db, candidate, payload, now); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var candidates, messages int64
|
|
db.Model(&EventCandidate{}).Count(&candidates)
|
|
db.Model(&outbox.Message{}).Count(&messages)
|
|
if candidates != 1 || messages != 1 {
|
|
t.Fatalf("candidates=%d messages=%d", candidates, messages)
|
|
}
|
|
var message outbox.Message
|
|
if err = db.First(&message).Error; err != nil || message.InternalType != bell_connector.OutboxType {
|
|
t.Fatalf("local event did not enqueue Bell contract delivery: type=%s err=%v", message.InternalType, err)
|
|
}
|
|
duplicate := candidate
|
|
duplicate.ID = candidate.ID
|
|
if err = CreateWithOutbox(context.Background(), db, duplicate, payload, now); err == nil {
|
|
t.Fatal("expected duplicate transaction failure")
|
|
}
|
|
db.Model(&EventCandidate{}).Count(&candidates)
|
|
db.Model(&outbox.Message{}).Count(&messages)
|
|
if candidates != 1 || messages != 1 {
|
|
t.Fatalf("atomic rollback failed candidates=%d messages=%d", candidates, messages)
|
|
}
|
|
}
|