@@ -37,12 +37,14 @@ import (
37
37
"gotest.tools/v3/icmd"
38
38
39
39
"github.com/containerd/containerd/v2/defaults"
40
+ "github.com/containerd/log"
40
41
41
42
"github.com/containerd/nerdctl/v2/pkg/buildkitutil"
42
43
"github.com/containerd/nerdctl/v2/pkg/imgutil"
43
44
"github.com/containerd/nerdctl/v2/pkg/infoutil"
44
45
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
45
46
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/native"
47
+ "github.com/containerd/nerdctl/v2/pkg/lockutil"
46
48
"github.com/containerd/nerdctl/v2/pkg/platformutil"
47
49
"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
48
50
)
@@ -549,14 +551,63 @@ var (
549
551
flagTestKube bool
550
552
)
551
553
554
+ var (
555
+ testLockFile = filepath .Join (os .TempDir (), "nerdctl-test-prevent-concurrency" , ".lock" )
556
+ )
557
+
552
558
func M (m * testing.M ) {
553
559
flag .StringVar (& flagTestTarget , "test.target" , Nerdctl , "target to test" )
554
560
flag .BoolVar (& flagTestKillDaemon , "test.allow-kill-daemon" , false , "enable tests that kill the daemon" )
555
561
flag .BoolVar (& flagTestIPv6 , "test.only-ipv6" , false , "enable tests on IPv6" )
556
562
flag .BoolVar (& flagTestKube , "test.only-kubernetes" , false , "enable tests on Kubernetes" )
557
563
flag .Parse ()
558
- fmt .Fprintf (os .Stderr , "test target: %q\n " , flagTestTarget )
559
- os .Exit (m .Run ())
564
+
565
+ os .Exit (func () int {
566
+ // If there is a lockfile (no err), or if we error-ed stating it (permission), another test run is currently going.
567
+ // Note that this could be racy. The .lock file COULD get acquired after this and before we hit the lock section.
568
+ // This is not a big deal then: we will just wait for the lock to free.
569
+ if _ , err := os .Stat (testLockFile ); err == nil || ! errors .Is (err , os .ErrNotExist ) {
570
+ log .L .Errorf ("Another test binary is already running. If you think this is an error, manually remove %s" , testLockFile )
571
+ return 1
572
+ }
573
+
574
+ err := os .MkdirAll (filepath .Dir (testLockFile ), 0o777 )
575
+ if err != nil {
576
+ log .L .WithError (err ).Errorf ("failed creating testing lock directory %q" , filepath .Dir (testLockFile ))
577
+ return 1
578
+ }
579
+
580
+ // Ensure that permissions are set to 777 (regardless of umask value), so that we do not lock people out when
581
+ // switching between rootful and rootless locking
582
+ os .Chmod (filepath .Dir (testLockFile ), 0o777 )
583
+
584
+ // Acquire lock
585
+ lock , err := lockutil .Lock (filepath .Dir (testLockFile ))
586
+ if err != nil {
587
+ log .L .WithError (err ).Errorf ("failed acquiring testing lock %q" , filepath .Dir (testLockFile ))
588
+ return 1
589
+ }
590
+
591
+ // Release...
592
+ defer lockutil .Unlock (lock )
593
+
594
+ // Create marker file
595
+ err = os .WriteFile (testLockFile , []byte ("prevent testing from running in parallel for subpackages integration tests" ), 0o666 )
596
+ if err != nil {
597
+ log .L .WithError (err ).Errorf ("failed writing lock file %q" , testLockFile )
598
+ return 1
599
+ }
600
+
601
+ // Ensure cleanup
602
+ defer func () {
603
+ os .Remove (testLockFile )
604
+ }()
605
+
606
+ // Now, run the tests
607
+ fmt .Fprintf (os .Stderr , "test target: %q\n " , flagTestTarget )
608
+
609
+ return m .Run ()
610
+ }())
560
611
}
561
612
562
613
func GetTarget () string {
0 commit comments