11package audit
22
33import (
4+ "bufio"
5+ "encoding/json"
6+ "os"
47 "path/filepath"
58 "testing"
69 "time"
7-
8- "github.com/73ai/openbotkit/store"
910)
1011
11- func openTestDB (t * testing.T ) * store.DB {
12- t .Helper ()
13- path := filepath .Join (t .TempDir (), "audit_test.db" )
14- db , err := store .Open (store .SQLiteConfig (path ))
15- if err != nil {
16- t .Fatalf ("open test db: %v" , err )
17- }
18- t .Cleanup (func () { db .Close () })
19- return db
20- }
21-
22- func TestMigrate (t * testing.T ) {
23- db := openTestDB (t )
24- if err := Migrate (db ); err != nil {
25- t .Fatalf ("Migrate: %v" , err )
26- }
27- // Idempotent.
28- if err := Migrate (db ); err != nil {
29- t .Fatalf ("Migrate (2nd call): %v" , err )
30- }
31- }
32-
33- func TestLogger_Log (t * testing.T ) {
34- db := openTestDB (t )
35- if err := Migrate (db ); err != nil {
36- t .Fatalf ("Migrate: %v" , err )
12+ func TestLog (t * testing.T ) {
13+ path := filepath .Join (t .TempDir (), "audit.jsonl" )
14+ l := OpenDefault (path )
15+ if l == nil {
16+ t .Fatal ("OpenDefault returned nil" )
3717 }
18+ defer l .Close ()
3819
39- l := NewLogger (db )
4020 l .Log (Entry {
4121 Timestamp : time .Date (2026 , 1 , 1 , 0 , 0 , 0 , 0 , time .UTC ),
4222 Context : "cli" ,
@@ -46,34 +26,32 @@ func TestLogger_Log(t *testing.T) {
4626 ApprovalStatus : "n/a" ,
4727 })
4828
49- var count int
50- if err := db . QueryRow ( "SELECT COUNT(*) FROM audit_log" ). Scan ( & count ); err != nil {
51- t .Fatalf ("query: %v " , err )
29+ entries := readJSONL ( t , path )
30+ if len ( entries ) != 1 {
31+ t .Fatalf ("got %d entries, want 1 " , len ( entries ) )
5232 }
53- if count != 1 {
54- t .Errorf ("count = %d , want 1 " , count )
33+ if entries [ 0 ]. ToolName != "bash" {
34+ t .Errorf ("tool_name = %q , want %q " , entries [ 0 ]. ToolName , "bash" )
5535 }
56-
57- var toolName , ctx string
58- err := db .QueryRow ("SELECT tool_name, context FROM audit_log WHERE id=1" ).Scan (& toolName , & ctx )
59- if err != nil {
60- t .Fatalf ("query row: %v" , err )
36+ if entries [0 ].Context != "cli" {
37+ t .Errorf ("context = %q, want %q" , entries [0 ].Context , "cli" )
6138 }
62- if toolName != "bash " {
63- t .Errorf ("tool_name = %q, want %q" , toolName , "bash " )
39+ if entries [ 0 ]. Timestamp != "2026-01-01T00:00:00Z " {
40+ t .Errorf ("timestamp = %q, want %q" , entries [ 0 ]. Timestamp , "2026-01-01T00:00:00Z " )
6441 }
65- if ctx != "cli " {
66- t .Errorf ("context = %q, want %q" , ctx , "cli" )
42+ if entries [ 0 ]. Error != "" {
43+ t .Errorf ("error should be omitted, got %q" , entries [ 0 ]. Error )
6744 }
6845}
6946
70- func TestLogger_Truncation (t * testing.T ) {
71- db := openTestDB (t )
72- if err := Migrate (db ); err != nil {
73- t .Fatalf ("Migrate: %v" , err )
47+ func TestTruncation (t * testing.T ) {
48+ path := filepath .Join (t .TempDir (), "audit.jsonl" )
49+ l := OpenDefault (path )
50+ if l == nil {
51+ t .Fatal ("OpenDefault returned nil" )
7452 }
53+ defer l .Close ()
7554
76- l := NewLogger (db )
7755 longInput := make ([]byte , 500 )
7856 for i := range longInput {
7957 longInput [i ] = 'x'
@@ -84,62 +62,96 @@ func TestLogger_Truncation(t *testing.T) {
8462 InputSummary : string (longInput ),
8563 })
8664
87- var inputSum string
88- err := db .QueryRow ("SELECT input_summary FROM audit_log WHERE id=1" ).Scan (& inputSum )
89- if err != nil {
90- t .Fatalf ("query: %v" , err )
65+ entries := readJSONL (t , path )
66+ if len (entries ) != 1 {
67+ t .Fatalf ("got %d entries, want 1" , len (entries ))
9168 }
92- if len (inputSum ) > maxSummaryLen + 10 {
93- t .Errorf ("input_summary len = %d, expected truncated to ~%d" , len (inputSum ), maxSummaryLen )
69+ if len (entries [ 0 ]. InputSummary ) > maxSummaryLen + 10 {
70+ t .Errorf ("input_summary len = %d, expected truncated to ~%d" , len (entries [ 0 ]. InputSummary ), maxSummaryLen )
9471 }
9572}
9673
97- func TestLogger_NilSafe (t * testing.T ) {
74+ func TestNilSafe (t * testing.T ) {
9875 var l * Logger
99- // Should not panic.
10076 l .Log (Entry {ToolName : "bash" })
10177 if err := l .Close (); err != nil {
10278 t .Errorf ("nil Close: %v" , err )
10379 }
10480}
10581
106- func TestOpenDefault (t * testing.T ) {
107- dbPath := filepath .Join (t .TempDir (), "audit" , "data.db " )
108- l := OpenDefault (dbPath )
82+ func TestClose (t * testing.T ) {
83+ path := filepath .Join (t .TempDir (), "audit.jsonl " )
84+ l := OpenDefault (path )
10985 if l == nil {
11086 t .Fatal ("OpenDefault returned nil" )
11187 }
112- defer l .Close ()
113- l .Log (Entry {Context : "test" , ToolName : "bash" , InputSummary : "echo hi" })
88+ if err := l .Close (); err != nil {
89+ t .Fatalf ("Close: %v" , err )
90+ }
91+ // Log after close should not panic.
92+ l .Log (Entry {ToolName : "bash" , Context : "test" })
93+ }
11494
115- var count int
116- if err := l .db .QueryRow ("SELECT COUNT(*) FROM audit_log" ).Scan (& count ); err != nil {
117- t .Fatalf ("query: %v" , err )
95+ func TestOpenDefault_CreatesDir (t * testing.T ) {
96+ path := filepath .Join (t .TempDir (), "sub" , "dir" , "audit.jsonl" )
97+ l := OpenDefault (path )
98+ if l == nil {
99+ t .Fatal ("OpenDefault returned nil" )
118100 }
119- if count != 1 {
120- t .Errorf ("count = %d, want 1" , count )
101+ defer l .Close ()
102+
103+ l .Log (Entry {Context : "test" , ToolName : "bash" , InputSummary : "echo hi" })
104+ entries := readJSONL (t , path )
105+ if len (entries ) != 1 {
106+ t .Fatalf ("got %d entries, want 1" , len (entries ))
121107 }
122108}
123109
124110func TestOpenDefault_BadPath (t * testing.T ) {
125- // A null byte in the path is invalid on all platforms.
126- l := OpenDefault ("/bad\x00 path/data.db" )
111+ l := OpenDefault ("/bad\x00 path/audit.jsonl" )
127112 if l != nil {
128113 l .Close ()
129114 t .Error ("expected nil for bad path" )
130115 }
131116}
132117
133- func TestLogger_Close (t * testing.T ) {
134- path := filepath .Join (t .TempDir (), "close_test.db" )
135- db , err := store .Open (store .SQLiteConfig (path ))
118+ func TestMultipleEntries (t * testing.T ) {
119+ path := filepath .Join (t .TempDir (), "audit.jsonl" )
120+ l := OpenDefault (path )
121+ if l == nil {
122+ t .Fatal ("OpenDefault returned nil" )
123+ }
124+ defer l .Close ()
125+
126+ for i := 0 ; i < 5 ; i ++ {
127+ l .Log (Entry {Context : "cli" , ToolName : "bash" })
128+ }
129+
130+ entries := readJSONL (t , path )
131+ if len (entries ) != 5 {
132+ t .Fatalf ("got %d entries, want 5" , len (entries ))
133+ }
134+ }
135+
136+ func readJSONL (t * testing.T , path string ) []jsonEntry {
137+ t .Helper ()
138+ f , err := os .Open (path )
136139 if err != nil {
137- t .Fatalf ("open db : %v" , err )
140+ t .Fatalf ("open %s : %v" , path , err )
138141 }
139- l := NewLogger (db )
140- if err := l .Close (); err != nil {
141- t .Fatalf ("Close: %v" , err )
142+ defer f .Close ()
143+
144+ var entries []jsonEntry
145+ scanner := bufio .NewScanner (f )
146+ for scanner .Scan () {
147+ var e jsonEntry
148+ if err := json .Unmarshal (scanner .Bytes (), & e ); err != nil {
149+ t .Fatalf ("parse JSON line: %v" , err )
150+ }
151+ entries = append (entries , e )
142152 }
143- // Log after close should not panic (fire-and-forget).
144- l .Log (Entry {ToolName : "bash" , Context : "test" })
153+ if err := scanner .Err (); err != nil {
154+ t .Fatalf ("scan: %v" , err )
155+ }
156+ return entries
145157}
0 commit comments