2026-07-03 16:46:09 +00:00
package diagnostics
import (
"encoding/json"
2026-07-03 18:56:35 +00:00
"fmt"
2026-07-03 16:46:09 +00:00
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
"gitea.maximumdirect.net/eric/notarius/internal/core/artifacts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
)
func TestNewRunDirectoryCreatesRunDirectoryAndRunID ( t * testing . T ) {
workDir := t . TempDir ( )
runDir , err := NewRunDirectory ( workDir , RetentionAuto )
if err != nil {
t . Fatalf ( "NewRunDirectory: %v" , err )
}
if filepath . Dir ( runDir . Path ( ) ) != workDir {
t . Fatalf ( "unexpected run directory parent: %q" , runDir . Path ( ) )
}
if ok := regexp . MustCompile ( ` ^run-\d+$ ` ) . MatchString ( runDir . RunID ( ) ) ; ! ok {
t . Fatalf ( "unexpected run ID: %q" , runDir . RunID ( ) )
}
info , err := os . Stat ( runDir . Path ( ) )
if err != nil {
t . Fatalf ( "stat run directory: %v" , err )
}
if ! info . IsDir ( ) {
t . Fatalf ( "expected run path to be a directory" )
}
}
2026-07-03 18:56:35 +00:00
func TestNewRunDirectoryRetriesOnRunIDCollision ( t * testing . T ) {
workDir := t . TempDir ( )
first := time . Unix ( 0 , 100 ) . UTC ( )
second := first . Add ( time . Nanosecond )
if err := os . Mkdir ( filepath . Join ( workDir , fmt . Sprintf ( "run-%d" , first . UnixNano ( ) ) ) , 0 o755 ) ; err != nil {
t . Fatalf ( "create existing run directory: %v" , err )
}
restoreUTCNow := replaceUTCNow ( func ( ) func ( ) time . Time {
calls := 0
return func ( ) time . Time {
calls ++
if calls == 1 {
return first
}
return second
}
} ( ) )
t . Cleanup ( restoreUTCNow )
runDir , err := NewRunDirectory ( workDir , RetentionAuto )
if err != nil {
t . Fatalf ( "NewRunDirectory: %v" , err )
}
wantRunID := fmt . Sprintf ( "run-%d" , second . UnixNano ( ) )
if runDir . RunID ( ) != wantRunID {
t . Fatalf ( "RunID = %q, want %q" , runDir . RunID ( ) , wantRunID )
}
if _ , err := os . Stat ( runDir . Path ( ) ) ; err != nil {
t . Fatalf ( "stat run directory: %v" , err )
}
}
func TestNewRunDirectoryReturnsErrorAfterRunIDCollisionsExhausted ( t * testing . T ) {
workDir := t . TempDir ( )
collisionTime := time . Unix ( 0 , 200 ) . UTC ( )
collisionPath := filepath . Join ( workDir , fmt . Sprintf ( "run-%d" , collisionTime . UnixNano ( ) ) )
if err := os . Mkdir ( collisionPath , 0 o755 ) ; err != nil {
t . Fatalf ( "create existing run directory: %v" , err )
}
restoreUTCNow := replaceUTCNow ( func ( ) time . Time {
return collisionTime
} )
t . Cleanup ( restoreUTCNow )
_ , err := NewRunDirectory ( workDir , RetentionAuto )
if err == nil || ! strings . Contains ( err . Error ( ) , "exhausted unique run ID attempts" ) {
t . Fatalf ( "expected exhausted collision error, got %v" , err )
}
}
2026-07-03 16:46:09 +00:00
func TestNewRunDirectoryUsesDefaultWorkDirectory ( t * testing . T ) {
runDir , err := NewRunDirectory ( "" , RetentionAuto )
if err != nil {
t . Fatalf ( "NewRunDirectory: %v" , err )
}
t . Cleanup ( func ( ) {
_ = os . RemoveAll ( runDir . Path ( ) )
_ = os . Remove ( defaultWorkDir )
} )
if filepath . Dir ( runDir . Path ( ) ) != defaultWorkDir {
t . Fatalf ( "expected default work directory %q, got %q" , defaultWorkDir , filepath . Dir ( runDir . Path ( ) ) )
}
}
func TestWriteJSONArtifactWritesIndentedNewlineTerminatedJSON ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
if err := runDir . WriteJSONArtifact ( "artifact.json" , map [ string ] any { "value" : "ok" } ) ; err != nil {
t . Fatalf ( "WriteJSONArtifact: %v" , err )
}
data := readArtifact ( t , runDir , "artifact.json" )
if ! strings . HasSuffix ( string ( data ) , "\n" ) {
t . Fatalf ( "expected trailing newline, got %q" , data )
}
if ! strings . Contains ( string ( data ) , "\n \"value\": \"ok\"\n" ) {
t . Fatalf ( "expected indented JSON, got %s" , data )
}
}
2026-07-04 01:11:57 +00:00
func TestWriteJSONArtifactLeavesNoTemporaryFiles ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
if err := runDir . WriteJSONArtifact ( "artifact.json" , map [ string ] any { "value" : "ok" } ) ; err != nil {
t . Fatalf ( "WriteJSONArtifact: %v" , err )
}
entries , err := os . ReadDir ( runDir . Path ( ) )
if err != nil {
t . Fatalf ( "read run directory: %v" , err )
}
for _ , entry := range entries {
if strings . Contains ( entry . Name ( ) , ".tmp-" ) {
t . Fatalf ( "temporary diagnostics file remains after success: %s" , entry . Name ( ) )
}
}
}
2026-07-03 16:46:09 +00:00
func TestWriteInvocationMetadataFillsMissingRunIDAndStartTime ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
if err := runDir . WriteInvocationMetadata ( InvocationMetadata { Operation : "validate" } ) ; err != nil {
t . Fatalf ( "WriteInvocationMetadata: %v" , err )
}
var got InvocationMetadata
if err := json . Unmarshal ( readArtifact ( t , runDir , ArtifactInvocationMetadata ) , & got ) ; err != nil {
t . Fatalf ( "unmarshal invocation metadata: %v" , err )
}
if got . RunID != runDir . RunID ( ) {
t . Fatalf ( "unexpected run ID: got %q want %q" , got . RunID , runDir . RunID ( ) )
}
if got . StartedAt . IsZero ( ) {
t . Fatalf ( "expected started_at to be filled" )
}
if got . Operation != "validate" {
t . Fatalf ( "unexpected operation: %q" , got . Operation )
}
}
func TestWriteInvocationMetadataPreservesProvidedRunIDAndStartTime ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
startedAt := time . Date ( 2026 , 7 , 3 , 12 , 0 , 0 , 0 , time . UTC )
if err := runDir . WriteInvocationMetadata ( InvocationMetadata {
Operation : "validate" ,
RunID : "provided" ,
StartedAt : startedAt ,
} ) ; err != nil {
t . Fatalf ( "WriteInvocationMetadata: %v" , err )
}
var got InvocationMetadata
if err := json . Unmarshal ( readArtifact ( t , runDir , ArtifactInvocationMetadata ) , & got ) ; err != nil {
t . Fatalf ( "unmarshal invocation metadata: %v" , err )
}
if got . RunID != "provided" {
t . Fatalf ( "unexpected run ID: %q" , got . RunID )
}
if ! got . StartedAt . Equal ( startedAt ) {
t . Fatalf ( "unexpected started_at: %s" , got . StartedAt )
}
}
func TestWriteTypedArtifacts ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
2026-07-03 20:54:22 +00:00
if err := runDir . WriteRedactedEffectiveConfig ( fakeRedactedEffectiveConfig { payload : map [ string ] any { "redacted" : true } } ) ; err != nil {
2026-07-03 16:46:09 +00:00
t . Fatalf ( "WriteRedactedEffectiveConfig: %v" , err )
}
if err := runDir . WriteResolvedPipeline ( map [ string ] any { "pipeline" : "test" } ) ; err != nil {
t . Fatalf ( "WriteResolvedPipeline: %v" , err )
}
2026-07-05 14:44:44 +00:00
if err := runDir . WriteResolvedReferences ( [ ] artifacts . ReferenceProvenance { { LaneID : "events" , SlotName : "roster" } } ) ; err != nil {
t . Fatalf ( "WriteResolvedReferences: %v" , err )
}
2026-07-03 16:46:09 +00:00
if err := runDir . WriteSourceDocument ( map [ string ] any { "source_id" : "source-1" } ) ; err != nil {
t . Fatalf ( "WriteSourceDocument: %v" , err )
}
if err := runDir . WriteRunManifest ( artifacts . RunManifest { RunID : "run-1" } ) ; err != nil {
t . Fatalf ( "WriteRunManifest: %v" , err )
}
if err := runDir . WriteRunReport ( map [ string ] any { "ok" : true } ) ; err != nil {
t . Fatalf ( "WriteRunReport: %v" , err )
}
if err := runDir . WriteWarnings ( [ ] contracts . Warning { { ReasonCode : "test" , Message : "warning" } } ) ; err != nil {
t . Fatalf ( "WriteWarnings: %v" , err )
}
for _ , name := range [ ] string {
ArtifactEffectiveConfig ,
ArtifactResolvedPipeline ,
2026-07-05 14:44:44 +00:00
ArtifactResolvedReferences ,
2026-07-03 16:46:09 +00:00
ArtifactSourceDocument ,
ArtifactRunManifest ,
ArtifactRunReport ,
ArtifactWarnings ,
} {
if _ , err := os . Stat ( filepath . Join ( runDir . Path ( ) , name ) ) ; err != nil {
t . Fatalf ( "expected artifact %q: %v" , name , err )
}
}
}
2026-07-03 20:54:22 +00:00
func TestWriteRedactedEffectiveConfigWritesPayloadReturnedByProvider ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
if err := runDir . WriteRedactedEffectiveConfig ( fakeRedactedEffectiveConfig {
payload : map [ string ] any {
"api_key" : "[REDACTED]" ,
"model" : "test-model" ,
} ,
} ) ; err != nil {
t . Fatalf ( "WriteRedactedEffectiveConfig: %v" , err )
}
data := string ( readArtifact ( t , runDir , ArtifactEffectiveConfig ) )
if ! strings . Contains ( data , ` "api_key": "[REDACTED]" ` ) || ! strings . Contains ( data , ` "model": "test-model" ` ) {
t . Fatalf ( "unexpected effective config artifact: %s" , data )
}
}
2026-07-03 16:46:09 +00:00
func TestWriteErrorLogWritesPlainTextWithTrailingNewline ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
if err := runDir . WriteErrorLog ( "something failed" ) ; err != nil {
t . Fatalf ( "WriteErrorLog: %v" , err )
}
if got := string ( readArtifact ( t , runDir , ArtifactErrorLog ) ) ; got != "something failed\n" {
t . Fatalf ( "unexpected error log: %q" , got )
}
}
func TestArtifactPathRejectsUnsafeNames ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
tests := [ ] string {
"" ,
" " ,
"/absolute.json" ,
"nested/artifact.json" ,
` nested\artifact.json ` ,
"../escape.json" ,
}
for _ , name := range tests {
t . Run ( name , func ( t * testing . T ) {
if err := runDir . WriteJSONArtifact ( name , map [ string ] any { } ) ; err == nil {
t . Fatalf ( "expected unsafe artifact name %q to be rejected" , name )
}
} )
}
}
func TestShouldRetainRunDirectoryDecisions ( t * testing . T ) {
tests := [ ] struct {
name string
input RetentionDecisionInput
want bool
} {
{ name : "failed auto retained" , input : RetentionDecisionInput { RetentionMode : RetentionAuto , RunSucceeded : false } , want : true } ,
{ name : "failed always retained" , input : RetentionDecisionInput { RetentionMode : RetentionAlways , RunSucceeded : false } , want : true } ,
{ name : "failed never retained" , input : RetentionDecisionInput { RetentionMode : RetentionNever , RunSucceeded : false } , want : true } ,
{ name : "successful always retained" , input : RetentionDecisionInput { RetentionMode : RetentionAlways , RunSucceeded : true } , want : true } ,
{ name : "successful never removed" , input : RetentionDecisionInput { RetentionMode : RetentionNever , RunSucceeded : true } , want : false } ,
{ name : "successful auto without warnings removed" , input : RetentionDecisionInput { RetentionMode : RetentionAuto , RunSucceeded : true } , want : false } ,
{ name : "successful auto with warnings retained" , input : RetentionDecisionInput { RetentionMode : RetentionAuto , RunSucceeded : true , HasWarnings : true } , want : true } ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
if got := ShouldRetainRunDirectory ( tc . input ) ; got != tc . want {
t . Fatalf ( "ShouldRetainRunDirectory() = %v, want %v" , got , tc . want )
}
} )
}
}
func TestApplyRetentionRemovesOnlyRunDirectory ( t * testing . T ) {
workDir := t . TempDir ( )
runDir , err := NewRunDirectory ( workDir , RetentionNever )
if err != nil {
t . Fatalf ( "NewRunDirectory: %v" , err )
}
siblingPath := filepath . Join ( workDir , "sibling" )
if err := os . WriteFile ( siblingPath , [ ] byte ( "keep" ) , 0 o644 ) ; err != nil {
t . Fatalf ( "write sibling: %v" , err )
}
if err := runDir . ApplyRetention ( RetentionDecisionInput { RunSucceeded : true } ) ; err != nil {
t . Fatalf ( "ApplyRetention: %v" , err )
}
if _ , err := os . Stat ( runDir . Path ( ) ) ; ! os . IsNotExist ( err ) {
t . Fatalf ( "expected run directory removed, stat err=%v" , err )
}
if _ , err := os . Stat ( workDir ) ; err != nil {
t . Fatalf ( "expected work directory retained: %v" , err )
}
if _ , err := os . Stat ( siblingPath ) ; err != nil {
t . Fatalf ( "expected sibling retained: %v" , err )
}
}
func TestApplyRetentionKeepsRetainedRunDirectory ( t * testing . T ) {
runDir := newTestRunDirectory ( t )
if err := runDir . ApplyRetention ( RetentionDecisionInput { RunSucceeded : true , HasWarnings : true } ) ; err != nil {
t . Fatalf ( "ApplyRetention: %v" , err )
}
if _ , err := os . Stat ( runDir . Path ( ) ) ; err != nil {
t . Fatalf ( "expected run directory retained: %v" , err )
}
}
func newTestRunDirectory ( t * testing . T ) * RunDirectory {
t . Helper ( )
runDir , err := NewRunDirectory ( t . TempDir ( ) , RetentionAuto )
if err != nil {
t . Fatalf ( "NewRunDirectory: %v" , err )
}
return runDir
}
2026-07-03 18:56:35 +00:00
func replaceUTCNow ( replacement func ( ) time . Time ) func ( ) {
original := utcNow
utcNow = replacement
return func ( ) {
utcNow = original
}
}
2026-07-03 16:46:09 +00:00
func readArtifact ( t * testing . T , runDir * RunDirectory , name string ) [ ] byte {
t . Helper ( )
data , err := os . ReadFile ( filepath . Join ( runDir . Path ( ) , name ) )
if err != nil {
t . Fatalf ( "read artifact %q: %v" , name , err )
}
return data
}
2026-07-03 20:54:22 +00:00
type fakeRedactedEffectiveConfig struct {
payload any
}
func ( f fakeRedactedEffectiveConfig ) RedactedDiagnosticsPayload ( ) any {
return f . payload
}