2026-08-04 19:42:35 +08:00
package evidence
import (
"bytes"
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"errors"
"image"
"image/color"
"image/png"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"
"time"
2026-08-04 20:57:33 +08:00
"cmbuyer/admin/internal/deviceauth"
2026-08-04 19:42:35 +08:00
core "cmbuyer/admin/internal/evidence"
"cmbuyer/admin/internal/migrations"
"cmbuyer/admin/internal/storage/sqlite"
)
const (
testTaskID = "13c9f507-7473-4fa6-8d71-8786c34c6301"
testAuthID = "23c9f507-7473-4fa6-8d71-8786c34c6301"
testAttemptID = "33c9f507-7473-4fa6-8d71-8786c34c6301"
testUploadKey = "43c9f507-7473-4fa6-8d71-8786c34c6301"
2026-08-04 20:57:33 +08:00
testDeviceID = "53c9f507-7473-4fa6-8d71-8786c34c6301"
2026-08-04 19:42:35 +08:00
)
func TestStageCommitReplayAndOpen ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 8 , 6 )
hash := sha256Hex ( pngBytes )
metadata := core . UploadMetadata { UploadKey : testUploadKey , TaskID : testTaskID , AttemptID : testAttemptID , Kind : core . KindSKUPanelGate1 , PrivacyTier : core . PrivacyInternalRaw , SHA256 : hash , CapturedAt : time . Date ( 2026 , 8 , 4 , 1 , 2 , 3 , 0 , time . UTC )}
2026-08-04 20:57:33 +08:00
principal := deviceauth . Principal { ID : testDeviceID }
2026-08-04 19:42:35 +08:00
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
asset , replayed , err := store . Commit ( context . Background (), principal , metadata , staged )
if err != nil || replayed {
t . Fatalf ( "Commit = replayed %t, err %v" , replayed , err )
}
if asset . SHA256 != hash || asset . ByteSize != int64 ( len ( pngBytes )) || asset . Width != 8 || asset . Height != 6 || asset . StorageKey != hash [: 2 ] + "/" + hash + ".png" {
t . Fatalf ( "asset = %#v" , asset )
}
opened , reader , err := store . Open ( context . Background (), asset . ID )
if err != nil {
t . Fatalf ( "Open: %v" , err )
}
got , err := io . ReadAll ( reader )
_ = reader . Close ()
if err != nil || ! bytes . Equal ( got , pngBytes ) || opened . ID != asset . ID {
t . Fatalf ( "opened asset changed: bytes=%t asset=%#v err=%v" , bytes . Equal ( got , pngBytes ), opened , err )
}
replayStage , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "stage replay: %v" , err )
}
replayedAsset , replayed , err := store . Commit ( context . Background (), principal , metadata , replayStage )
if err != nil || ! replayed || replayedAsset . ID != asset . ID {
t . Fatalf ( "replay = %#v, %t, %v" , replayedAsset , replayed , err )
}
conflictStage , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "stage conflict: %v" , err )
}
conflicting := metadata
conflicting . CapturedAt = conflicting . CapturedAt . Add ( time . Second )
if _ , _ , err := store . Commit ( context . Background (), principal , conflicting , conflictStage ); ! errors . Is ( err , core . ErrConflict ) {
t . Fatalf ( "conflicting replay error = %v" , err )
}
}
2026-08-04 22:33:16 +08:00
func TestCommitRequiresCurrentClaimOwnerButClosedClaimKeepsHistoricalReplay ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 4 , 3 )
metadata := testMetadata ( sha256Hex ( pngBytes ))
stage := func () core . StagedFile {
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
return staged
}
otherDevice := deviceauth . Principal { ID : "73c9f507-7473-4fa6-8d71-8786c34c6301" }
if _ , _ , err := store . Commit ( context . Background (), otherDevice , metadata , stage ()); ! errors . Is ( err , core . ErrInvalid ) {
t . Fatalf ( "device B upload to device A attempt error = %v" , err )
}
principal := deviceauth . Principal { ID : testDeviceID }
asset , replayed , err := store . Commit ( context . Background (), principal , metadata , stage ())
if err != nil || replayed {
t . Fatalf ( "owner first Commit = replayed %v, err %v" , replayed , err )
}
if _ , err := database . Exec ( "UPDATE purchase_attempt_claims SET closed_at='2026-08-04T03:00:00Z' WHERE attempt_id=?" , testAttemptID ); err != nil {
t . Fatalf ( "close claim: %v" , err )
}
replayedAsset , replayed , err := store . Commit ( context . Background (), principal , metadata , stage ())
if err != nil || ! replayed || replayedAsset . ID != asset . ID {
t . Fatalf ( "closed claim historical replay = %#v replayed %v err %v" , replayedAsset , replayed , err )
}
newMetadata := metadata
newMetadata . UploadKey = "83c9f507-7473-4fa6-8d71-8786c34c6301"
if _ , _ , err := store . Commit ( context . Background (), principal , newMetadata , stage ()); ! errors . Is ( err , core . ErrInvalid ) {
t . Fatalf ( "closed claim new upload error = %v" , err )
}
}
2026-08-04 19:42:35 +08:00
func TestConcurrentReplayCreatesOneAsset ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 3 , 2 )
metadata := core . UploadMetadata { UploadKey : testUploadKey , TaskID : testTaskID , AttemptID : testAttemptID , Kind : core . KindSKUPanelGate1 , PrivacyTier : core . PrivacyInternalRaw , SHA256 : sha256Hex ( pngBytes ), CapturedAt : time . Date ( 2026 , 8 , 4 , 1 , 2 , 3 , 0 , time . UTC )}
staged := make ([] core . StagedFile , 2 )
for index := range staged {
var err error
staged [ index ], err = store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage %d: %v" , index , err )
}
}
var wait sync . WaitGroup
wait . Add ( 2 )
assets := make ([] core . Asset , 2 )
replays := make ([] bool , 2 )
errorsSeen := make ([] error , 2 )
for index := range staged {
go func ( index int ) {
defer wait . Done ()
2026-08-04 20:57:33 +08:00
assets [ index ], replays [ index ], errorsSeen [ index ] = store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, metadata , staged [ index ])
2026-08-04 19:42:35 +08:00
}( index )
}
wait . Wait ()
if errorsSeen [ 0 ] != nil || errorsSeen [ 1 ] != nil || assets [ 0 ]. ID != assets [ 1 ]. ID || replays [ 0 ] == replays [ 1 ] {
t . Fatalf ( "concurrent commits assets=%#v replays=%#v errors=%#v" , assets , replays , errorsSeen )
}
var count int
if err := database . QueryRow ( "SELECT COUNT(*) FROM evidence_assets" ). Scan ( & count ); err != nil || count != 1 {
t . Fatalf ( "asset count = %d, err %v" , count , err )
}
}
func TestPlatformDirectorySync ( t * testing . T ) {
if err := syncDirectory ( t . TempDir ()); err != nil {
t . Fatalf ( "syncDirectory must either establish the durability boundary or fail closed: %v" , err )
}
}
func TestNewStoreRetriesRootParentSyncWhenRootAlreadyExists ( t * testing . T ) {
database , _ := newTestStore ( t )
parent := t . TempDir ()
root := filepath . Join ( parent , "retry-root" )
injected := errors . New ( "injected root parent sync failure" )
if _ , err := newStore ( database , root , func ( string ) error { return injected }); ! errors . Is ( err , injected ) {
t . Fatalf ( "first newStore error = %v, want injected root sync failure" , err )
}
if info , err := os . Stat ( root ); err != nil || ! info . IsDir () {
t . Fatalf ( "failed parent sync must leave root for retry: info=%v err=%v" , info , err )
}
var paths [] string
store , err := newStore ( database , root , func ( path string ) error {
paths = append ( paths , path )
return syncDirectory ( path )
})
if err != nil {
t . Fatalf ( "retry newStore: %v" , err )
}
if store == nil || len ( paths ) == 0 || paths [ 0 ] != parent {
t . Fatalf ( "retry sync paths = %#v, want root parent %q first" , paths , parent )
}
}
func TestCommitSyncsShardAndRenameBeforeDatabaseWrite ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 4 , 3 )
hash := sha256Hex ( pngBytes )
metadata := testMetadata ( hash )
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
finalPath , err := store . pathForKey ( storageKey ( hash ))
if err != nil {
t . Fatalf ( "final path: %v" , err )
}
finalDirectory := filepath . Dir ( finalPath )
var events [] string
store . syncDirectory = func ( path string ) error {
var count int
if err := database . QueryRow ( "SELECT COUNT(*) FROM evidence_assets" ). Scan ( & count ); err != nil {
t . Fatalf ( "count evidence before directory sync: %v" , err )
}
if count != 0 {
t . Fatalf ( "database row became visible before directory sync: %d" , count )
}
switch path {
case store . root :
events = append ( events , "sync-root" )
if path != store . root {
t . Fatalf ( "shard parent sync path = %q, want evidence root %q" , path , store . root )
}
if info , err := os . Stat ( finalDirectory ); err != nil || ! info . IsDir () {
t . Fatalf ( "shard directory must exist before parent sync: info=%v err=%v" , info , err )
}
if _ , err := os . Stat ( finalPath ); ! errors . Is ( err , os . ErrNotExist ) {
t . Fatalf ( "final file exists before publication: %v" , err )
}
case finalDirectory :
events = append ( events , "sync-shard" )
if info , err := os . Stat ( finalPath ); err != nil || ! info . Mode (). IsRegular () {
t . Fatalf ( "renamed file must exist before shard sync: info=%v err=%v" , info , err )
}
default :
t . Fatalf ( "unexpected extra directory sync: %q" , path )
}
return syncDirectory ( path )
}
store . syncFile = func ( file * os . File ) error {
if filepath . Dir ( file . Name ()) != finalDirectory || ! strings . HasPrefix ( filepath . Base ( file . Name ()), ".publish-" ) {
t . Fatalf ( "publication temp is not inside shard: %q" , file . Name ())
}
events = append ( events , "sync-file" )
return file . Sync ()
}
store . renameFile = func ( oldPath , newPath string ) error {
if filepath . Dir ( oldPath ) != filepath . Dir ( newPath ) || newPath != finalPath {
t . Fatalf ( "rename is not same-directory publication: %q -> %q" , oldPath , newPath )
}
events = append ( events , "rename" )
return os . Rename ( oldPath , newPath )
}
2026-08-04 20:57:33 +08:00
if _ , replayed , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, metadata , staged ); err != nil || replayed {
2026-08-04 19:42:35 +08:00
t . Fatalf ( "Commit = replayed %t, err %v" , replayed , err )
}
if got , want := strings . Join ( events , "," ), "sync-root,sync-root,sync-file,rename,sync-shard" ; got != want {
t . Fatalf ( "durability order = %q, want %q" , got , want )
}
assertEvidenceCount ( t , database , 1 )
assertNoPublishTemps ( t , finalDirectory )
}
func TestCommitDirectorySyncFailuresNeverWriteDatabase ( t * testing . T ) {
for _ , failAt := range [] int { 1 , 2 , 3 } {
t . Run ( map [ int ] string { 1 : "new shard parent" , 2 : "unconditional shard parent" , 3 : "rename target" }[ failAt ], func ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 4 , 3 )
hash := sha256Hex ( pngBytes )
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
finalPath , err := store . pathForKey ( storageKey ( hash ))
if err != nil {
t . Fatalf ( "final path: %v" , err )
}
injected := errors . New ( "injected directory sync failure" )
calls := 0
store . syncDirectory = func ( path string ) error {
calls ++
if calls == failAt {
return injected
}
return syncDirectory ( path )
}
2026-08-04 20:57:33 +08:00
if _ , _ , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, testMetadata ( hash ), staged ); ! errors . Is ( err , injected ) {
2026-08-04 19:42:35 +08:00
t . Fatalf ( "Commit error = %v, want injected sync failure" , err )
}
if calls != failAt {
t . Fatalf ( "sync calls = %d, want %d" , calls , failAt )
}
assertEvidenceCount ( t , database , 0 )
_ , statErr := os . Stat ( finalPath )
if failAt < 3 && ! errors . Is ( statErr , os . ErrNotExist ) {
t . Fatalf ( "file exists before rename durability boundary: %v" , statErr )
}
if failAt == 3 && statErr != nil {
t . Fatalf ( "post-rename sync failure may leave an orphan file, stat error = %v" , statErr )
}
assertNoPublishTemps ( t , filepath . Dir ( finalPath ))
})
}
}
func TestCommitRetriesShardParentSyncAfterPriorFailure ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 4 , 3 )
hash := sha256Hex ( pngBytes )
finalPath , err := store . pathForKey ( storageKey ( hash ))
if err != nil {
t . Fatalf ( "final path: %v" , err )
}
firstStage , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "first Stage: %v" , err )
}
injected := errors . New ( "injected first shard parent sync failure" )
store . syncDirectory = func ( string ) error { return injected }
2026-08-04 20:57:33 +08:00
if _ , _ , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, testMetadata ( hash ), firstStage ); ! errors . Is ( err , injected ) {
2026-08-04 19:42:35 +08:00
t . Fatalf ( "first Commit error = %v" , err )
}
if info , err := os . Stat ( filepath . Dir ( finalPath )); err != nil || ! info . IsDir () {
t . Fatalf ( "failed first sync must leave the created shard for retry: info=%v err=%v" , info , err )
}
assertEvidenceCount ( t , database , 0 )
secondStage , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "second Stage: %v" , err )
}
var paths [] string
store . syncDirectory = func ( path string ) error {
paths = append ( paths , path )
return syncDirectory ( path )
}
2026-08-04 20:57:33 +08:00
if _ , replayed , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, testMetadata ( hash ), secondStage ); err != nil || replayed {
2026-08-04 19:42:35 +08:00
t . Fatalf ( "retry Commit = replayed %t, err %v" , replayed , err )
}
if len ( paths ) != 2 || paths [ 0 ] != store . root || paths [ 1 ] != filepath . Dir ( finalPath ) {
t . Fatalf ( "retry sync paths = %#v, want root then shard" , paths )
}
assertEvidenceCount ( t , database , 1 )
assertNoPublishTemps ( t , filepath . Dir ( finalPath ))
}
func TestCommitPublicationFailuresCleanTempAndNeverWriteDatabase ( t * testing . T ) {
for _ , name := range [] string { "file sync" , "rename" } {
t . Run ( name , func ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 4 , 3 )
hash := sha256Hex ( pngBytes )
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
finalPath , err := store . pathForKey ( storageKey ( hash ))
if err != nil {
t . Fatalf ( "final path: %v" , err )
}
injected := errors . New ( "injected publication failure" )
if name == "file sync" {
store . syncFile = func ( * os . File ) error { return injected }
} else {
store . renameFile = func ( string , string ) error { return injected }
}
2026-08-04 20:57:33 +08:00
if _ , _ , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, testMetadata ( hash ), staged ); ! errors . Is ( err , injected ) {
2026-08-04 19:42:35 +08:00
t . Fatalf ( "Commit error = %v, want injected publication failure" , err )
}
if _ , err := os . Stat ( finalPath ); ! errors . Is ( err , os . ErrNotExist ) {
t . Fatalf ( "final file exists after failed publication: %v" , err )
}
assertNoPublishTemps ( t , filepath . Dir ( finalPath ))
assertEvidenceCount ( t , database , 0 )
})
}
}
func TestCommitDatabaseFailuresAfterDurableRenameLeaveOnlyOrphan ( t * testing . T ) {
for _ , test := range [] struct {
name string
inject func ( * testing . T , * sql . DB , * Store , error )
}{
{
name : "insert" ,
inject : func ( t * testing . T , database * sql . DB , _ * Store , _ error ) {
t . Helper ()
if _ , err := database . Exec ( `CREATE TRIGGER fail_evidence_insert BEFORE INSERT ON evidence_assets BEGIN SELECT RAISE(ABORT, 'injected insert failure'); END` ); err != nil {
t . Fatalf ( "create insert failure trigger: %v" , err )
}
},
},
{
name : "commit" ,
inject : func ( _ * testing . T , _ * sql . DB , store * Store , injected error ) {
store . commitTx = func ( * sql . Tx ) error { return injected }
},
},
} {
t . Run ( test . name , func ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 4 , 3 )
hash := sha256Hex ( pngBytes )
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
finalPath , err := store . pathForKey ( storageKey ( hash ))
if err != nil {
t . Fatalf ( "final path: %v" , err )
}
injected := errors . New ( "injected database failure" )
test . inject ( t , database , store , injected )
syncCalls := 0
store . syncDirectory = func ( path string ) error {
syncCalls ++
return syncDirectory ( path )
}
2026-08-04 20:57:33 +08:00
if _ , _ , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, testMetadata ( hash ), staged ); err == nil {
2026-08-04 19:42:35 +08:00
t . Fatal ( "Commit unexpectedly succeeded" )
}
if syncCalls != 3 {
t . Fatalf ( "database failure occurred before both durability syncs: sync calls = %d" , syncCalls )
}
if info , err := os . Stat ( finalPath ); err != nil || ! info . Mode (). IsRegular () {
t . Fatalf ( "durable rename may leave only an orphan file: info=%v err=%v" , info , err )
}
assertNoPublishTemps ( t , filepath . Dir ( finalPath ))
assertEvidenceCount ( t , database , 0 )
})
}
}
func TestStageRejectsUnsafeContent ( t * testing . T ) {
_ , store := newTestStore ( t )
largePNG := makePNG ( t , core . MaxImageSide + 1 , 1 )
pngWithXML := append ( makePNG ( t , 1 , 1 ), [] byte ( "<hierarchy/>" ) ... )
for name , test := range map [ string ] struct {
reader io . Reader
contentType string
}{
"wrong content type" : { reader : bytes . NewReader ( makePNG ( t , 1 , 1 )), contentType : "application/octet-stream" },
"xml" : { reader : bytes . NewBufferString ( "<hierarchy/>" ), contentType : core . PNGContentType },
"png with xml tail" : { reader : bytes . NewReader ( pngWithXML ), contentType : core . PNGContentType },
"truncated png" : { reader : bytes . NewReader ( pngSignature ), contentType : core . PNGContentType },
"too wide" : { reader : bytes . NewReader ( largePNG ), contentType : core . PNGContentType },
"too many bytes" : { reader : io . LimitReader ( zeroReader {}, core . MaxFileBytes + 1 ), contentType : core . PNGContentType },
} {
t . Run ( name , func ( t * testing . T ) {
staged , err := store . Stage ( test . reader , test . contentType )
if ! errors . Is ( err , core . ErrInvalid ) && ! errors . Is ( err , core . ErrTooLarge ) {
store . Discard ( staged )
t . Fatalf ( "Stage error = %v" , err )
}
})
}
}
func TestCommitRequiresAttemptOwnedByTaskAndLowercaseHash ( t * testing . T ) {
database , store := newTestStore ( t )
insertAttemptFixture ( t , database )
pngBytes := makePNG ( t , 2 , 2 )
base := core . UploadMetadata { UploadKey : testUploadKey , TaskID : testTaskID , AttemptID : testAttemptID , Kind : core . KindSKUPanelGate1 , PrivacyTier : core . PrivacyInternalRaw , SHA256 : sha256Hex ( pngBytes ), CapturedAt : time . Date ( 2026 , 8 , 4 , 1 , 2 , 3 , 0 , time . UTC )}
for name , mutate := range map [ string ] func ( * core . UploadMetadata ){
"unknown attempt" : func ( value * core . UploadMetadata ) { value . AttemptID = "53c9f507-7473-4fa6-8d71-8786c34c6301" },
"uppercase hash" : func ( value * core . UploadMetadata ) {
value . SHA256 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
},
"wrong kind" : func ( value * core . UploadMetadata ) { value . Kind = "ORDER_CONFIRM" },
} {
t . Run ( name , func ( t * testing . T ) {
staged , err := store . Stage ( bytes . NewReader ( pngBytes ), core . PNGContentType )
if err != nil {
t . Fatalf ( "Stage: %v" , err )
}
metadata := base
mutate ( & metadata )
2026-08-04 20:57:33 +08:00
if _ , _ , err := store . Commit ( context . Background (), deviceauth . Principal { ID : testDeviceID }, metadata , staged ); ! errors . Is ( err , core . ErrInvalid ) {
2026-08-04 19:42:35 +08:00
t . Fatalf ( "Commit error = %v" , err )
}
})
}
var count int
if err := database . QueryRow ( "SELECT COUNT(*) FROM evidence_assets" ). Scan ( & count ); err != nil || count != 0 {
t . Fatalf ( "invalid commits created %d assets, err %v" , count , err )
}
}
func TestNewStoreRejectsRelativeAndFilesystemRootPaths ( t * testing . T ) {
database , _ := newTestStore ( t )
if _ , err := NewStore ( database , "relative-evidence" ); err == nil {
t . Fatal ( "relative evidence root succeeded" )
}
volumeRoot := filepath . VolumeName ( t . TempDir ()) + string ( filepath . Separator )
if _ , err := NewStore ( database , volumeRoot ); err == nil {
t . Fatal ( "filesystem root succeeded" )
}
}
type zeroReader struct {}
func ( zeroReader ) Read ( buffer [] byte ) ( int , error ) {
for index := range buffer {
buffer [ index ] = 0
}
return len ( buffer ), nil
}
func newTestStore ( t * testing . T ) ( * sql . DB , * Store ) {
t . Helper ()
database , err := sqlite . Open ( filepath . Join ( t . TempDir (), "evidence.db" ))
if err != nil {
t . Fatalf ( "open database: %v" , err )
}
t . Cleanup ( func () { _ = database . Close () })
_ , file , _ , ok := runtime . Caller ( 0 )
if ! ok {
t . Fatal ( "locate test" )
}
directory := filepath . Join ( filepath . Dir ( file ), ".." , ".." , ".." , "migrations" )
if err := migrations . Up ( context . Background (), database , directory ); err != nil {
t . Fatalf ( "migrate database: %v" , err )
}
store , err := NewStore ( database , filepath . Join ( t . TempDir (), "assets" ))
if err != nil {
t . Fatalf ( "NewStore: %v" , err )
}
return database , store
}
func insertAttemptFixture ( t * testing . T , database * sql . DB ) {
t . Helper ()
timestamp := "2026-08-04T00:00:00Z"
2026-08-04 22:33:16 +08:00
tokenHash := sha256 . Sum256 ([] byte ( "evidence-device-token" ))
if _ , err := database . Exec ( `INSERT INTO device_credentials
(device_id,display_name,token_sha256,status,created_at,revoked_at)
VALUES (?, 'evidence device', ?, 'ACTIVE', ?, NULL)` , testDeviceID , tokenHash [:], timestamp ); err != nil {
t . Fatalf ( "insert device: %v" , err )
}
2026-08-04 19:42:35 +08:00
if _ , err := database . Exec ( `INSERT INTO tasks (id, source, title, goods_id, sku_color, sku_size, quantity, max_total_price, status, version, created_at, updated_at) VALUES (?, 'MANUAL', 'task', '123', 'black', 'M', 1, '1.00', 'DRAFT', 1, ?, ?)` , testTaskID , timestamp , timestamp ); err != nil {
t . Fatalf ( "insert task: %v" , err )
}
if _ , err := database . Exec ( `INSERT INTO order_authorizations (id, task_id, task_version, start_key, goods_id, sku_color, sku_size, quantity, total_price_cap, status, created_by, created_at, expires_at) VALUES (?, ?, 1, 'start', '123', 'black', 'M', 1, '1.00', 'ACTIVE', 'admin', ?, ?)` , testAuthID , testTaskID , timestamp , timestamp ); err != nil {
t . Fatalf ( "insert authorization: %v" , err )
}
if _ , err := database . Exec ( `INSERT INTO purchase_attempts (id, task_id, authorization_id, claim_generation, status, started_at) VALUES (?, ?, ?, 1, 'CLAIMED', ?)` , testAttemptID , testTaskID , testAuthID , timestamp ); err != nil {
t . Fatalf ( "insert attempt: %v" , err )
}
2026-08-04 22:33:16 +08:00
if _ , err := database . Exec ( `INSERT INTO purchase_attempt_claims
(attempt_id,task_id,authorization_id,claimed_by_device_id,session_id,claim_generation,
task_version,task_title,authorization_task_version,goods_id,sku_color,sku_size,quantity,
total_price_cap,authorization_expires_at,claim_nonce,claim_token_sha256,lease_expires_at,claimed_at,closed_at)
VALUES (?, ?, ?, ?, '63c9f507-7473-4fa6-8d71-8786c34c6301', 1, 1, 'task',
1, '123', 'black', 'M', 1, '1.00', ?, ?, ?, '2026-08-04T02:00:00Z', ?, NULL)` ,
testAttemptID , testTaskID , testAuthID , testDeviceID , timestamp , bytes . Repeat ([] byte { 1 }, 32 ), bytes . Repeat ([] byte { 2 }, 32 ), timestamp ); err != nil {
t . Fatalf ( "insert claim: %v" , err )
}
2026-08-04 19:42:35 +08:00
}
func testMetadata ( hash string ) core . UploadMetadata {
return core . UploadMetadata {
UploadKey : testUploadKey , TaskID : testTaskID , AttemptID : testAttemptID ,
Kind : core . KindSKUPanelGate1 , PrivacyTier : core . PrivacyInternalRaw , SHA256 : hash ,
CapturedAt : time . Date ( 2026 , 8 , 4 , 1 , 2 , 3 , 0 , time . UTC ),
}
}
func assertEvidenceCount ( t * testing . T , database * sql . DB , want int ) {
t . Helper ()
var count int
if err := database . QueryRow ( "SELECT COUNT(*) FROM evidence_assets" ). Scan ( & count ); err != nil {
t . Fatalf ( "count evidence assets: %v" , err )
}
if count != want {
t . Fatalf ( "evidence asset count = %d, want %d" , count , want )
}
}
func assertNoPublishTemps ( t * testing . T , directory string ) {
t . Helper ()
entries , err := os . ReadDir ( directory )
if err != nil {
t . Fatalf ( "read shard directory: %v" , err )
}
for _ , entry := range entries {
if strings . HasPrefix ( entry . Name (), ".publish-" ) {
t . Fatalf ( "publication temp leaked: %q" , entry . Name ())
}
}
}
func makePNG ( t * testing . T , width , height int ) [] byte {
t . Helper ()
imageData := image . NewNRGBA ( image . Rect ( 0 , 0 , width , height ))
imageData . Set ( 0 , 0 , color . NRGBA { R : 12 , G : 34 , B : 56 , A : 255 })
var buffer bytes . Buffer
if err := png . Encode ( & buffer , imageData ); err != nil {
t . Fatalf ( "encode PNG: %v" , err )
}
return buffer . Bytes ()
}
func sha256Hex ( value [] byte ) string {
hash := sha256 . Sum256 ( value )
return hex . EncodeToString ( hash [:])
}