okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
61c43ca
main
1// The HTTP adapter must preserve date units across metadata and stream consumers. 2// A controlled peer supplies subsecond dates that ordinary daemon timestamps 3// cannot deterministically place relative to the presentation clock. 4package daemon 5 6import ( 7"albedo/cli/internal/presentation" 8"encoding/json" 9"net/http" 10"testing" 11"time" 12) 13 14func TestMetadataDatesProduceCorrectAges (t * testing.T ) { 15activity := time .Date (2026 ,9 ,20 ,12 ,30 ,0 ,123456789 ,time .UTC ) 16conn := controlledConnection (t ,func (w http.ResponseWriter ,r * http.Request ) { 17switch r .URL .Path { 18case "/sessions/s" : 19session := canonicalSession ("s" ,generationA ,0 ) 20session ["activity_at" ]= activity .Format (time .RFC3339Nano ) 21if r .Header .Get ("Accept" )== "text/event-stream" { 22session ["usage" ].(map [string ]any )["observed_at" ]= activity .Format (time .RFC3339Nano ) 23w .Header ().Set ("Content-Type" ,"text/event-stream" ) 24writeBatch (w ,map [string ]any {"generation" :generationA ,"cursor" :0 ,"snapshot" :session ,"events" : []any {map [string ]any {"type" :"reset" ,"data" :map [string ]any {"reason" :"initial" }}}}) 25return 26 } 27_ = json .NewEncoder (w ).Encode (session ) 28case "/workspaces" : 29_ = json .NewEncoder (w ).Encode (map [string ]any { 30"directory" :"/work" ,"parent" :"/" ,"home" :"/home" ,"host" :nil ,"next" :nil , 31"items" : []any {map [string ]any {"name" :"project" ,"location" :"/work/project" ,"vcs" :"git" ,"modified_at" :activity .Format (time .RFC3339Nano ),"hidden" :false }}, 32"preview" :map [string ]any { 33"repository" :map [string ]any {"kind" :"git" ,"root" :"/work" ,"branch" :"main" ,"revision" :"revision" ,"dirty" :false ,"added" :0 ,"modified" :0 ,"removed" :0 ,"changed" :0 ,"touched_at" :activity .Format (time .RFC3339Nano )}, 34"repository_diagnostic" :nil ,"languages" : []any {},"tree" : []any {},"more" :0 , 35 }, 36 }) 37default : 38t .Errorf ("unexpected request: %s" ,r .URL ) 39 } 40 }) 41session ,err := GetSession (t .Context (),conn ,"s" ) 42if err != nil { 43t .Fatal (err ) 44 } 45folders ,err := ListFolders (t .Context (),conn ,"/work" ) 46if err != nil { 47t .Fatal (err ) 48 } 49repo ,err := FolderRepo (t .Context (),conn ,"/work" ) 50if err != nil || repo == nil { 51t .Fatalf ("repository: %v, %v" ,repo ,err ) 52 } 53if len (folders .Entries )!= 1 { 54t .Fatalf ("folders: %v" ,folders .Entries ) 55 } 56now := activity .Add (72 * time .Hour ) 57for name ,timestamp := range map [string ]* int64 {"session" :session .LastAssistantAt ,"folder" :& folders .Entries [0 ].Modified ,"repository" :repo .Touched } { 58if age := presentation .AssistantAge (timestamp ,now );age != "3d ago" { 59t .Errorf ("%s date produced %q" ,name ,age ) 60 } 61 } 62var recordedAt * int64 63if err := NewChatClient (conn ,"s" ).Stream (t .Context (),0 ,func (event StreamEvent )error { 64if event .Type == EventUsage { 65recordedAt = event .Usage .RecordedAt 66 } 67return nil 68 });err != nil { 69t .Fatal (err ) 70 } 71if recordedAt == nil || * recordedAt != activity .UnixMilli () { 72t .Fatalf ("usage lost its millisecond timestamp: %v" ,recordedAt ) 73 } 74}