@@ -184,6 +184,69 @@ fn named_sessions_use_separate_servers_and_workspace_state() {
184184 cleanup_test_base ( & base) ;
185185}
186186
187+ #[ test]
188+ fn dead_server_cli_reports_one_session_aware_json_line ( ) {
189+ fn assert_server_not_running (
190+ output : std:: process:: Output ,
191+ socket_path : & Path ,
192+ attach_command : & str ,
193+ ) {
194+ assert_eq ! (
195+ output. status. code( ) ,
196+ Some ( 1 ) ,
197+ "stdout={} stderr={}" ,
198+ String :: from_utf8_lossy( & output. stdout) ,
199+ String :: from_utf8_lossy( & output. stderr)
200+ ) ;
201+ assert ! ( output. stdout. is_empty( ) , "server errors belong on stderr" ) ;
202+
203+ let stderr = String :: from_utf8 ( output. stderr ) . unwrap ( ) ;
204+ let lines: Vec < _ > = stderr. lines ( ) . collect ( ) ;
205+ assert_eq ! ( lines. len( ) , 1 , "expected exactly one JSON line: {stderr:?}" ) ;
206+
207+ let response: serde_json:: Value = serde_json:: from_str ( lines[ 0 ] ) . unwrap ( ) ;
208+ assert_eq ! ( response[ "id" ] , "cli:workspace:create" ) ;
209+ assert_eq ! ( response[ "error" ] [ "code" ] , "server_not_running" ) ;
210+ assert_eq ! (
211+ response[ "error" ] [ "message" ] ,
212+ format!(
213+ "no herdr server is running at {}; run `{attach_command}` to start or attach it" ,
214+ socket_path. display( )
215+ )
216+ ) ;
217+ }
218+
219+ let base = unique_test_dir ( ) ;
220+ let config_home = base. join ( "config" ) ;
221+ let runtime_dir = base. join ( "runtime" ) ;
222+ fs:: create_dir_all ( & runtime_dir) . unwrap ( ) ;
223+ register_runtime_dir ( & runtime_dir) ;
224+
225+ let named_socket = named_session_socket ( & config_home, "foo" ) ;
226+ let missing = run_named_cli (
227+ & config_home,
228+ & runtime_dir,
229+ & [ "--session" , "foo" , "workspace" , "create" ] ,
230+ ) ;
231+ assert_server_not_running ( missing, & named_socket, "herdr session attach foo" ) ;
232+
233+ let stale_socket = runtime_dir. join ( "stale.sock" ) ;
234+ drop ( UnixListener :: bind ( & stale_socket) . unwrap ( ) ) ;
235+ let stale = Command :: new ( env ! ( "CARGO_BIN_EXE_herdr" ) )
236+ . args ( [ "workspace" , "create" ] )
237+ . env ( "XDG_CONFIG_HOME" , & config_home)
238+ . env ( "XDG_RUNTIME_DIR" , & runtime_dir)
239+ . env ( "HERDR_SOCKET_PATH" , & stale_socket)
240+ . env ( "HERDR_SESSION" , "unrelated" )
241+ . env_remove ( "HERDR_CLIENT_SOCKET_PATH" )
242+ . env_remove ( "HERDR_ENV" )
243+ . output ( )
244+ . unwrap ( ) ;
245+ assert_server_not_running ( stale, & stale_socket, "herdr" ) ;
246+
247+ cleanup_test_base ( & base) ;
248+ }
249+
187250#[ test]
188251fn integration_commands_run_locally_when_server_is_missing ( ) {
189252 let base = unique_test_dir ( ) ;
0 commit comments