@@ -308,6 +308,87 @@ func TestLoadConfig_RoundTrip(t *testing.T) {
308308 assert .True (t , cfg .LastVersionCheckAt .Equal (loaded .LastVersionCheckAt ))
309309}
310310
311+ func TestRun_CIFlagSetInRequest (t * testing.T ) {
312+ now := time .Date (2026 , 5 , 4 , 12 , 0 , 0 , 0 , time .UTC )
313+ cfg := & Config {
314+ InstanceID : "2ed05245-10d7-4d21-a8e8-7c4e8a9851b4" ,
315+ StartCount : 1 ,
316+ }
317+ var gotReq * http.Request
318+
319+ result , err := run (context .Background (), options {
320+ Config : cfg ,
321+ Version : "v0.18.0" ,
322+ URL : "https://updates.example/check" ,
323+ CI : true ,
324+ Client : & http.Client {Transport : roundTripFunc (func (req * http.Request ) (* http.Response , error ) {
325+ gotReq = req
326+ return & http.Response {
327+ StatusCode : http .StatusNoContent ,
328+ Body : io .NopCloser (strings .NewReader ("" )),
329+ }, nil
330+ })},
331+ Now : func () time.Time { return now },
332+ SaveConfig : func (* Config ) error { return nil },
333+ Env : func (string ) string { return "" },
334+ })
335+
336+ require .NoError (t , err )
337+ assert .Nil (t , result )
338+ require .NotNil (t , gotReq )
339+ assert .Equal (t , "true" , gotReq .URL .Query ().Get ("ci" ))
340+ }
341+
342+ func TestRun_NonCIOmitsCIParam (t * testing.T ) {
343+ cfg := & Config {InstanceID : "2ed05245-10d7-4d21-a8e8-7c4e8a9851b4" , StartCount : 1 }
344+ var gotReq * http.Request
345+
346+ _ , err := run (context .Background (), options {
347+ Config : cfg ,
348+ Version : "v0.18.0" ,
349+ URL : "https://updates.example/check" ,
350+ Client : & http.Client {Transport : roundTripFunc (func (req * http.Request ) (* http.Response , error ) {
351+ gotReq = req
352+ return & http.Response {
353+ StatusCode : http .StatusNoContent ,
354+ Body : io .NopCloser (strings .NewReader ("" )),
355+ }, nil
356+ })},
357+ SaveConfig : func (* Config ) error { return nil },
358+ Env : func (string ) string { return "" },
359+ })
360+
361+ require .NoError (t , err )
362+ require .NotNil (t , gotReq )
363+ _ , hasCI := gotReq .URL .Query ()["ci" ]
364+ assert .False (t , hasCI , "ci param should be absent when not running in CI" )
365+ }
366+
367+ func TestRun_CISkipsPersistentState (t * testing.T ) {
368+ dir := t .TempDir ()
369+ t .Setenv ("POUTINE_CONFIG_DIR" , dir )
370+ t .Setenv (DisableEnv , "" )
371+ t .Setenv (CIEnv , "true" )
372+ t .Setenv (URLEnv , "https://override.example/check" )
373+
374+ // Stub the HTTP transport via the default client used by Run. Because Run
375+ // constructs its own client, we can't intercept the request here; what we
376+ // care about is that no state file is written on disk after the call.
377+ _ = Run (context .Background (), "v0.18.0" , false )
378+
379+ _ , err := os .Stat (filepath .Join (dir , "config.yaml" ))
380+ assert .True (t , os .IsNotExist (err ), "no state file should be written in CI mode" )
381+ }
382+
383+ func TestIsCIEnv (t * testing.T ) {
384+ for _ , value := range []string {"1" , "true" , "TRUE" , "yes" , "on" } {
385+ assert .True (t , isCIEnv (value ), value )
386+ }
387+ for _ , value := range []string {"" , "0" , "false" , "no" , "off" , "anything" } {
388+ assert .False (t , isCIEnv (value ), value )
389+ }
390+ }
391+
311392func TestRun_DisabledShortCircuitsBeforeAnyDiskWrite (t * testing.T ) {
312393 dir := t .TempDir ()
313394 t .Setenv ("POUTINE_CONFIG_DIR" , dir )
0 commit comments