@@ -25,17 +25,18 @@ import {
2525 storeUpdateSession ,
2626 storeGetEnvironment ,
2727 storeGetSession ,
28- storeListActiveEnvironments ,
2928} from "../store" ;
29+ import { getEventBus , getAllEventBuses , removeEventBus } from "../transport/event-bus" ;
30+ import { runDisconnectMonitorSweep } from "../services/disconnect-monitor" ;
3031
3132describe ( "Disconnect Monitor Logic" , ( ) => {
3233 beforeEach ( ( ) => {
3334 storeReset ( ) ;
35+ for ( const [ key ] of getAllEventBuses ( ) ) {
36+ removeEventBus ( key ) ;
37+ }
3438 } ) ;
3539
36- // Test the logic directly rather than the interval-based monitor
37- // to avoid long-running tests with timers
38-
3940 test ( "environment times out when lastPollAt is too old" , ( ) => {
4041 const env = storeCreateEnvironment ( { secret : "s" } ) ;
4142 const timeoutMs = 300 * 1000 ; // 5 minutes
@@ -44,31 +45,15 @@ describe("Disconnect Monitor Logic", () => {
4445 const oldDate = new Date ( Date . now ( ) - timeoutMs - 60000 ) ;
4546 storeUpdateEnvironment ( env . id , { lastPollAt : oldDate } ) ;
4647
47- // Check the timeout logic (same as in disconnect-monitor.ts)
48- const now = Date . now ( ) ;
49- const envs = storeListActiveEnvironments ( ) ;
50- for ( const e of envs ) {
51- if ( e . lastPollAt && now - e . lastPollAt . getTime ( ) > timeoutMs ) {
52- storeUpdateEnvironment ( e . id , { status : "disconnected" } ) ;
53- }
54- }
48+ runDisconnectMonitorSweep ( ) ;
5549
5650 const updated = storeGetEnvironment ( env . id ) ;
5751 expect ( updated ?. status ) . toBe ( "disconnected" ) ;
5852 } ) ;
5953
6054 test ( "environment stays active when lastPollAt is recent" , ( ) => {
6155 const env = storeCreateEnvironment ( { secret : "s" } ) ;
62- const timeoutMs = 300 * 1000 ;
63-
64- // lastPollAt is recent (just created)
65- const now = Date . now ( ) ;
66- const envs = storeListActiveEnvironments ( ) ;
67- for ( const e of envs ) {
68- if ( e . lastPollAt && now - e . lastPollAt . getTime ( ) > timeoutMs ) {
69- storeUpdateEnvironment ( e . id , { status : "disconnected" } ) ;
70- }
71- }
56+ runDisconnectMonitorSweep ( ) ;
7257
7358 const updated = storeGetEnvironment ( env . id ) ;
7459 expect ( updated ?. status ) . toBe ( "active" ) ;
@@ -77,25 +62,47 @@ describe("Disconnect Monitor Logic", () => {
7762 test ( "session becomes inactive when updatedAt is too old" , ( ) => {
7863 const session = storeCreateSession ( { } ) ;
7964 storeUpdateSession ( session . id , { status : "running" } ) ;
80- const timeoutMs = 300 * 1000 * 2 ; // 2x disconnect timeout
81-
82- // Simulate updatedAt being older than 2x timeout
83- // We can't directly set updatedAt, but we can verify the logic
84- // by checking that recently updated sessions are not marked inactive
85- const now = Date . now ( ) ;
8665 const rec = storeGetSession ( session . id ) ;
87- // Session was just updated, should not be inactive
88- expect ( rec ?. status ) . toBe ( "running" ) ;
89- expect ( now - rec ! . updatedAt . getTime ( ) ) . toBeLessThan ( timeoutMs ) ;
66+ expect ( rec ) . toBeTruthy ( ) ;
67+ if ( ! rec ) return ;
68+
69+ rec . updatedAt = new Date ( Date . now ( ) - 300 * 1000 * 2 - 60000 ) ;
70+
71+ runDisconnectMonitorSweep ( ) ;
72+
73+ const updated = storeGetSession ( session . id ) ;
74+ expect ( updated ?. status ) . toBe ( "inactive" ) ;
9075 } ) ;
9176
9277 test ( "session stays running when recently updated" , ( ) => {
9378 const session = storeCreateSession ( { } ) ;
9479 storeUpdateSession ( session . id , { status : "running" } ) ;
9580
96- const timeoutMs = 300 * 1000 * 2 ;
81+ runDisconnectMonitorSweep ( ) ;
82+
83+ const updated = storeGetSession ( session . id ) ;
84+ expect ( updated ?. status ) . toBe ( "running" ) ;
85+ } ) ;
86+
87+ test ( "session timeout publishes an inactive session_status event" , ( ) => {
88+ const session = storeCreateSession ( { } ) ;
89+ storeUpdateSession ( session . id , { status : "idle" } ) ;
9790 const rec = storeGetSession ( session . id ) ;
98- expect ( rec ?. status ) . toBe ( "running" ) ;
99- expect ( Date . now ( ) - rec ! . updatedAt . getTime ( ) ) . toBeLessThan ( timeoutMs ) ;
91+ expect ( rec ) . toBeTruthy ( ) ;
92+ if ( ! rec ) return ;
93+ rec . updatedAt = new Date ( Date . now ( ) - 300 * 1000 * 2 - 60000 ) ;
94+
95+ const bus = getEventBus ( session . id ) ;
96+ const events : Array < { type : string ; payload : { status ?: string } } > = [ ] ;
97+ bus . subscribe ( ( event ) => {
98+ events . push ( { type : event . type , payload : event . payload as { status ?: string } } ) ;
99+ } ) ;
100+
101+ runDisconnectMonitorSweep ( ) ;
102+
103+ expect ( events ) . toContainEqual ( {
104+ type : "session_status" ,
105+ payload : { status : "inactive" } ,
106+ } ) ;
100107 } ) ;
101108} ) ;
0 commit comments