@@ -32,6 +32,7 @@ import (
3232 "github.com/containerd/nerdctl/mod/tigron/tig"
3333
3434 "github.com/containerd/nerdctl/v2/pkg/healthcheck"
35+ "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
3536 "github.com/containerd/nerdctl/v2/pkg/rootlessutil"
3637 "github.com/containerd/nerdctl/v2/pkg/testutil"
3738 "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
@@ -309,7 +310,7 @@ func TestContainerHealthCheckAdvance(t *testing.T) {
309310 debug , _ := json .MarshalIndent (h , "" , " " )
310311 t .Log (string (debug ))
311312 assert .Assert (t , h != nil , "expected health state" )
312- assert .Equal (t , h .FailingStreak , 1 )
313+ assert .Assert (t , h .FailingStreak >= 1 , "expected at least one failing streak" )
313314 assert .Assert (t , len (inspect .State .Health .Log ) > 0 , "expected health log to have entries" )
314315 last := inspect .State .Health .Log [0 ]
315316 assert .Equal (t , - 1 , last .ExitCode )
@@ -348,7 +349,7 @@ func TestContainerHealthCheckAdvance(t *testing.T) {
348349 t .Log (string (debug ))
349350 assert .Assert (t , h != nil , "expected health state" )
350351 assert .Equal (t , h .Status , healthcheck .Unhealthy )
351- assert .Equal (t , h .FailingStreak , 2 )
352+ assert .Assert (t , h .FailingStreak >= 1 , "expected atleast one FailingStreak" )
352353 }),
353354 }
354355 },
@@ -411,7 +412,7 @@ func TestContainerHealthCheckAdvance(t *testing.T) {
411412 t .Log (string (debug ))
412413 assert .Assert (t , h != nil , "expected health state" )
413414 assert .Equal (t , h .Status , healthcheck .Unhealthy )
414- assert .Equal (t , h .FailingStreak , 1 )
415+ assert .Assert (t , h .FailingStreak >= 1 , "expected at least one failing streak" )
415416 }),
416417 }
417418 },
@@ -633,7 +634,7 @@ func TestContainerHealthCheckAdvance(t *testing.T) {
633634 assert .Assert (t , h != nil , "expected health state" )
634635 assert .Equal (t , h .Status , healthcheck .Healthy )
635636 assert .Equal (t , h .FailingStreak , 0 )
636- assert .Assert (t , len (h .Log ) == 1 , "expected one log entry" )
637+ assert .Assert (t , len (h .Log ) >= 1 , "expected at least one log entry" )
637638 output := h .Log [0 ].Output
638639 assert .Assert (t , strings .HasSuffix (output , "[truncated]" ), "expected output to be truncated with '[truncated]'" )
639640 }),
@@ -931,6 +932,107 @@ func TestHealthCheck_SystemdIntegration_Basic(t *testing.T) {
931932 testCase .Run (t )
932933}
933934
935+ func TestHealthCheck_GlobalFlags (t * testing.T ) {
936+ testCase := nerdtest .Setup ()
937+ testCase .Require = require .Not (nerdtest .Docker )
938+ // Skip systemd tests in rootless environment to bypass dbus permission issues
939+ if rootlessutil .IsRootless () {
940+ t .Skip ("systemd healthcheck tests are skipped in rootless environment" )
941+ }
942+
943+ testCase .SubTests = []* test.Case {
944+ {
945+ Description : "Healthcheck works with custom namespace flag" ,
946+ Setup : func (data test.Data , helpers test.Helpers ) {
947+ // Create container in custom namespace with healthcheck
948+ helpers .Ensure ("--namespace=healthcheck-test" , "run" , "-d" , "--name" , data .Identifier (),
949+ "--health-cmd" , "echo healthy" ,
950+ "--health-interval" , "2s" ,
951+ testutil .CommonImage , "sleep" , "30" )
952+ // Wait a bit to ensure container is running (can't use EnsureContainerStarted with custom namespace)
953+ time .Sleep (1 * time .Second )
954+ },
955+ Cleanup : func (data test.Data , helpers test.Helpers ) {
956+ helpers .Anyhow ("--namespace=healthcheck-test" , "rm" , "-f" , data .Identifier ())
957+ },
958+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
959+ // Wait a bit for healthcheck to run
960+ time .Sleep (3 * time .Second )
961+ // Verify container is accessible in the custom namespace
962+ return helpers .Command ("--namespace=healthcheck-test" , "inspect" , data .Identifier ())
963+ },
964+ Expected : func (data test.Data , helpers test.Helpers ) * test.Expected {
965+ return & test.Expected {
966+ ExitCode : 0 ,
967+ Output : func (stdout string , t tig.T ) {
968+ var inspectResults []dockercompat.Container
969+ err := json .Unmarshal ([]byte (stdout ), & inspectResults )
970+ assert .NilError (t , err , "failed to parse inspect output" )
971+ assert .Assert (t , len (inspectResults ) > 0 , "expected at least one container in inspect results" )
972+
973+ inspect := inspectResults [0 ]
974+ h := inspect .State .Health
975+ assert .Assert (t , h != nil , "expected health state to be present" )
976+ assert .Assert (t , h .Status == healthcheck .Healthy || h .Status == healthcheck .Starting ,
977+ "expected health status to be healthy or starting, got: %s" , h .Status )
978+ assert .Assert (t , len (h .Log ) > 0 , "expected at least one health check log entry" )
979+ },
980+ }
981+ },
982+ },
983+ {
984+ Description : "Healthcheck works correctly with namespace after container restart" ,
985+ Setup : func (data test.Data , helpers test.Helpers ) {
986+ // Create container in custom namespace
987+ helpers .Ensure ("--namespace=restart-test" , "run" , "-d" , "--name" , data .Identifier (),
988+ "--health-cmd" , "echo healthy" ,
989+ "--health-interval" , "2s" ,
990+ testutil .CommonImage , "sleep" , "60" )
991+ // Wait a bit to ensure container is running (can't use EnsureContainerStarted with custom namespace)
992+ time .Sleep (1 * time .Second )
993+ },
994+ Cleanup : func (data test.Data , helpers test.Helpers ) {
995+ helpers .Anyhow ("--namespace=restart-test" , "rm" , "-f" , data .Identifier ())
996+ },
997+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
998+ // Wait for initial healthcheck
999+ time .Sleep (3 * time .Second )
1000+
1001+ // Stop and restart the container
1002+ helpers .Ensure ("--namespace=restart-test" , "stop" , data .Identifier ())
1003+ helpers .Ensure ("--namespace=restart-test" , "start" , data .Identifier ())
1004+ // Wait a bit to ensure container is running after restart
1005+ time .Sleep (1 * time .Second )
1006+
1007+ // Wait for healthcheck to run after restart
1008+ time .Sleep (3 * time .Second )
1009+
1010+ return helpers .Command ("--namespace=restart-test" , "inspect" , data .Identifier ())
1011+ },
1012+ Expected : func (data test.Data , helpers test.Helpers ) * test.Expected {
1013+ return & test.Expected {
1014+ ExitCode : 0 ,
1015+ Output : func (stdout string , t tig.T ) {
1016+ // Parse the inspect JSON output directly since we're in a custom namespace
1017+ var inspectResults []dockercompat.Container
1018+ err := json .Unmarshal ([]byte (stdout ), & inspectResults )
1019+ assert .NilError (t , err , "failed to parse inspect output" )
1020+ assert .Assert (t , len (inspectResults ) > 0 , "expected at least one container in inspect results" )
1021+
1022+ inspect := inspectResults [0 ]
1023+ h := inspect .State .Health
1024+ assert .Assert (t , h != nil , "expected health state after restart" )
1025+ assert .Assert (t , h .Status == healthcheck .Healthy || h .Status == healthcheck .Starting ,
1026+ "expected health status to be healthy or starting after restart, got: %s" , h .Status )
1027+ assert .Assert (t , len (h .Log ) > 0 , "expected health check logs after restart" )
1028+ },
1029+ }
1030+ },
1031+ },
1032+ }
1033+ testCase .Run (t )
1034+ }
1035+
9341036func TestHealthCheck_SystemdIntegration_Advanced (t * testing.T ) {
9351037 testCase := nerdtest .Setup ()
9361038 testCase .Require = require .Not (nerdtest .Docker )
0 commit comments