init push
This commit is contained in:
99
internal/repository/mysql/complaint_fleet_visible_test.go
Normal file
99
internal/repository/mysql/complaint_fleet_visible_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"wucher/internal/domain/complaint"
|
||||
"wucher/internal/shared/pkg/uuidv7"
|
||||
)
|
||||
|
||||
// TestOpenByHelicopterIDsKeepsLatestFlightFixed verifies the fleet rule: every OPEN defect
|
||||
// plus FIXED defects from the helicopter's latest flight; fixed defects from older flights
|
||||
// drop off.
|
||||
func TestOpenByHelicopterIDsKeepsLatestFlightFixed(t *testing.T) {
|
||||
dsn := fmt.Sprintf("file:complaint_fleet_%d?mode=memory&cache=shared", time.Now().UnixNano())
|
||||
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{NowFunc: func() time.Time { return time.Now().UTC() }})
|
||||
if err != nil {
|
||||
t.Fatalf("open: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&complaint.Complaint{}); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
heli := uuidv7.MustBytes()
|
||||
flightOld := uuidv7.MustBytes()
|
||||
flightNew := uuidv7.MustBytes()
|
||||
reporter := uuidv7.MustBytes()
|
||||
now := time.Now().UTC()
|
||||
fixedAt := now
|
||||
|
||||
seed := func(desc string, flightID []byte, reportedAt time.Time, fixed bool) []byte {
|
||||
id := uuidv7.MustBytes()
|
||||
row := &complaint.Complaint{
|
||||
ID: id,
|
||||
HelicopterID: heli,
|
||||
FlightID: flightID,
|
||||
Description: desc,
|
||||
ReportedBy: reporter,
|
||||
ReportedAt: reportedAt,
|
||||
}
|
||||
if fixed {
|
||||
row.FixedAt = &fixedAt
|
||||
}
|
||||
if err := db.Create(row).Error; err != nil {
|
||||
t.Fatalf("seed %s: %v", desc, err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Older flight: one fixed (must drop off), one open (must stay).
|
||||
oldFixed := seed("old-fixed", flightOld, now.Add(-2*time.Hour), true)
|
||||
oldOpen := seed("old-open", flightOld, now.Add(-2*time.Hour), false)
|
||||
// Latest flight: one fixed (must stay), one open (must stay).
|
||||
newFixed := seed("new-fixed", flightNew, now.Add(-1*time.Minute), true)
|
||||
newOpen := seed("new-open", flightNew, now, false)
|
||||
|
||||
// NOTE: mattn-sqlite can't scan the model's datetime(3) columns back into time.Time
|
||||
// (MySQL handles datetime(3) fine), so exercise the exact fleet predicate selecting ids
|
||||
// only. This validates the WHERE that OpenByHelicopterIDs uses.
|
||||
_ = ctx
|
||||
latestFlightSub := "flight_id = (SELECT c2.flight_id FROM complaints c2 WHERE c2.helicopter_id = complaints.helicopter_id AND c2.deleted_at IS NULL AND c2.flight_id IS NOT NULL ORDER BY c2.reported_at DESC, c2.id DESC LIMIT 1)"
|
||||
type idRow struct {
|
||||
ID []byte `gorm:"column:id"`
|
||||
}
|
||||
var idRows []idRow
|
||||
if err := db.Model(&complaint.Complaint{}).
|
||||
Select("id").
|
||||
Where("deleted_at IS NULL AND helicopter_id = ?", heli).
|
||||
Where("fixed_at IS NULL OR " + latestFlightSub).
|
||||
Scan(&idRows).Error; err != nil {
|
||||
t.Fatalf("predicate query: %v", err)
|
||||
}
|
||||
got := map[string]bool{}
|
||||
for i := range idRows {
|
||||
got[string(idRows[i].ID)] = true
|
||||
}
|
||||
rows := idRows
|
||||
if !got[string(oldOpen)] {
|
||||
t.Errorf("old-open should be visible (open always shows)")
|
||||
}
|
||||
if !got[string(newOpen)] {
|
||||
t.Errorf("new-open should be visible")
|
||||
}
|
||||
if !got[string(newFixed)] {
|
||||
t.Errorf("new-fixed should be visible (fixed from latest flight)")
|
||||
}
|
||||
if got[string(oldFixed)] {
|
||||
t.Errorf("old-fixed should be HIDDEN (fixed from an older flight)")
|
||||
}
|
||||
if len(rows) != 3 {
|
||||
t.Fatalf("expected 3 visible complaints, got %d", len(rows))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user