Browse code

Merge pull request #382 from thaJeztah/19.03_backport_test_fixes

[19.03 backport] Testing and Jenkinsfile changes [step 1]

Kirill Kolyshkin authored on 2019/09/27 02:43:26
Showing 65 changed files
... ...
@@ -36,7 +36,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/${APT_MIRROR:-deb.debian.org}/g" /etc/
36 36
 FROM base AS criu
37 37
 ARG DEBIAN_FRONTEND
38 38
 # Install CRIU for checkpoint/restore support
39
-ENV CRIU_VERSION 3.11
39
+ENV CRIU_VERSION 3.12
40 40
 # Install dependency packages specific to criu
41 41
 RUN apt-get update && apt-get install -y --no-install-recommends \
42 42
 	libnet-dev \
... ...
@@ -281,8 +281,6 @@ COPY --from=djs55/vpnkit@sha256:e508a17cfacc8fd39261d5b4e397df2b953690da577e2c98
281 281
 
282 282
 ENV PATH=/usr/local/cli:$PATH
283 283
 ENV DOCKER_BUILDTAGS apparmor seccomp selinux
284
-# Options for hack/validate/gometalinter
285
-ENV GOMETALINTER_OPTS="--deadline=2m"
286 284
 WORKDIR /go/src/github.com/docker/docker
287 285
 VOLUME /var/lib/docker
288 286
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
... ...
@@ -214,7 +214,8 @@ RUN `
214 214
   Download-File $location C:\gitsetup.zip; `
215 215
   `
216 216
   Write-Host INFO: Downloading go...; `
217
-  Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; `
217
+  $dlGoVersion=$Env:GO_VERSION -replace '\.0$',''; `
218
+  Download-File "https://golang.org/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; `
218 219
   `
219 220
   Write-Host INFO: Downloading compiler 1 of 3...; `
220 221
   Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip C:\gcc.zip; `
... ...
@@ -22,15 +22,27 @@ pipeline {
22 22
         DOCKER_GRAPHDRIVER  = 'overlay2'
23 23
         APT_MIRROR          = 'cdn-fastly.deb.debian.org'
24 24
         CHECK_CONFIG_COMMIT = '78405559cfe5987174aa2cb6463b9b2c1b917255'
25
+        TESTDEBUG           = '0'
25 26
         TIMEOUT             = '120m'
26 27
     }
27 28
     stages {
29
+        stage('pr-hack') {
30
+            when { changeRequest() }
31
+            steps {
32
+                script {
33
+                    echo "Workaround for PR auto-cancel feature. Borrowed from https://issues.jenkins-ci.org/browse/JENKINS-43353"
34
+                    def buildNumber = env.BUILD_NUMBER as int
35
+                    if (buildNumber > 1) milestone(buildNumber - 1)
36
+                    milestone(buildNumber)
37
+                }
38
+            }
39
+        }
28 40
         stage('DCO-check') {
29 41
             when {
30 42
                 beforeAgent true
31 43
                 expression { !params.skip_dco }
32 44
             }
33
-            agent { label 'linux' }
45
+            agent { label 'amd64 && ubuntu-1804 && overlay2' }
34 46
             steps {
35 47
                 sh '''
36 48
                 docker run --rm \
... ...
@@ -257,13 +269,13 @@ pipeline {
257 257
                                 run_tests() {
258 258
                                         [ -n "$TESTDEBUG" ] && rm= || rm=--rm;
259 259
                                         docker run $rm -t --privileged \
260
-                                          -v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
260
+                                          -v "$WORKSPACE/bundles/${TEST_INTEGRATION_DEST}:/go/src/github.com/docker/docker/bundles" \
261
+                                          -v "$WORKSPACE/bundles/dynbinary-daemon:/go/src/github.com/docker/docker/bundles/dynbinary-daemon" \
261 262
                                           -v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
262 263
                                           --name "$CONTAINER_NAME" \
263 264
                                           -e KEEPBUNDLE=1 \
264 265
                                           -e TESTDEBUG \
265 266
                                           -e TESTFLAGS \
266
-                                          -e TEST_INTEGRATION_DEST \
267 267
                                           -e TEST_SKIP_INTEGRATION \
268 268
                                           -e TEST_SKIP_INTEGRATION_CLI \
269 269
                                           -e DOCKER_GITCOMMIT=${GIT_COMMIT} \
... ...
@@ -308,6 +320,11 @@ pipeline {
308 308
                                 exit $c
309 309
                                 '''
310 310
                             }
311
+                            post {
312
+                                always {
313
+                                    junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
314
+                                }
315
+                            }
311 316
                         }
312 317
                     }
313 318
 
... ...
@@ -315,7 +332,8 @@ pipeline {
315 315
                         always {
316 316
                             sh '''
317 317
                             echo "Ensuring container killed."
318
-                            docker rm -vf docker-pr$BUILD_NUMBER || true
318
+                            cids=$(docker ps -aq -f name=docker-pr${BUILD_NUMBER}-*)
319
+                            [ -n "$cids" ] && docker rm -vf $cids || true
319 320
                             '''
320 321
 
321 322
                             sh '''
... ...
@@ -328,7 +346,7 @@ pipeline {
328 328
                                 bundleName=amd64
329 329
                                 echo "Creating ${bundleName}-bundles.tar.gz"
330 330
                                 # exclude overlay2 directories
331
-                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
331
+                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
332 332
                                 '''
333 333
 
334 334
                                 archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
... ...
@@ -397,6 +415,7 @@ pipeline {
397 397
                                   -e DOCKER_EXPERIMENTAL \
398 398
                                   -e DOCKER_GITCOMMIT=${GIT_COMMIT} \
399 399
                                   -e DOCKER_GRAPHDRIVER \
400
+                                  -e TESTDEBUG \
400 401
                                   -e TEST_SKIP_INTEGRATION_CLI \
401 402
                                   -e TIMEOUT \
402 403
                                   docker:${GIT_COMMIT} \
... ...
@@ -405,6 +424,11 @@ pipeline {
405 405
                                     test-integration
406 406
                                 '''
407 407
                             }
408
+                            post {
409
+                                always {
410
+                                    junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
411
+                                }
412
+                            }
408 413
                         }
409 414
                     }
410 415
 
... ...
@@ -425,7 +449,7 @@ pipeline {
425 425
                                 bundleName=s390x-integration
426 426
                                 echo "Creating ${bundleName}-bundles.tar.gz"
427 427
                                 # exclude overlay2 directories
428
-                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
428
+                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
429 429
                                 '''
430 430
 
431 431
                                 archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
... ...
@@ -483,6 +507,11 @@ pipeline {
483 483
                                     test-integration
484 484
                                 '''
485 485
                             }
486
+                            post {
487
+                                always {
488
+                                    junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
489
+                                }
490
+                            }
486 491
                         }
487 492
                     }
488 493
 
... ...
@@ -503,7 +532,7 @@ pipeline {
503 503
                                 bundleName=s390x-integration-cli
504 504
                                 echo "Creating ${bundleName}-bundles.tar.gz"
505 505
                                 # exclude overlay2 directories
506
-                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
506
+                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
507 507
                                 '''
508 508
 
509 509
                                 archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
... ...
@@ -570,6 +599,7 @@ pipeline {
570 570
                                   -e DOCKER_EXPERIMENTAL \
571 571
                                   -e DOCKER_GITCOMMIT=${GIT_COMMIT} \
572 572
                                   -e DOCKER_GRAPHDRIVER \
573
+                                  -e TESTDEBUG \
573 574
                                   -e TEST_SKIP_INTEGRATION_CLI \
574 575
                                   -e TIMEOUT \
575 576
                                   docker:${GIT_COMMIT} \
... ...
@@ -578,6 +608,11 @@ pipeline {
578 578
                                     test-integration
579 579
                                 '''
580 580
                             }
581
+                            post {
582
+                                always {
583
+                                    junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
584
+                                }
585
+                            }
581 586
                         }
582 587
                     }
583 588
 
... ...
@@ -598,7 +633,7 @@ pipeline {
598 598
                                 bundleName=ppc64le-integration
599 599
                                 echo "Creating ${bundleName}-bundles.tar.gz"
600 600
                                 # exclude overlay2 directories
601
-                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
601
+                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
602 602
                                 '''
603 603
 
604 604
                                 archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
... ...
@@ -654,6 +689,11 @@ pipeline {
654 654
                                     test-integration
655 655
                                 '''
656 656
                             }
657
+                            post {
658
+                                always {
659
+                                    junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
660
+                                }
661
+                            }
657 662
                         }
658 663
                     }
659 664
 
... ...
@@ -662,8 +702,6 @@ pipeline {
662 662
                             sh '''
663 663
                             echo "Ensuring container killed."
664 664
                             docker rm -vf docker-pr$BUILD_NUMBER || true
665
-                            cids=$(docker ps -aq -f name=docker-pr${BUILD_NUMBER}-*)
666
-                            [ -n "$cids" ] && docker rm -vf $cids || true
667 665
                             '''
668 666
 
669 667
                             sh '''
... ...
@@ -676,7 +714,7 @@ pipeline {
676 676
                                 bundleName=ppc64le-integration-cli
677 677
                                 echo "Creating ${bundleName}-bundles.tar.gz"
678 678
                                 # exclude overlay2 directories
679
-                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
679
+                                find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
680 680
                                 '''
681 681
 
682 682
                                 archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
... ...
@@ -699,11 +737,12 @@ pipeline {
699 699
                     }
700 700
                     environment {
701 701
                         DOCKER_BUILDKIT        = '0'
702
+                        DOCKER_DUT_DEBUG       = '1'
702 703
                         SKIP_VALIDATION_TESTS  = '1'
703 704
                         SOURCES_DRIVE          = 'd'
704 705
                         SOURCES_SUBDIR         = 'gopath'
705 706
                         TESTRUN_DRIVE          = 'd'
706
-                        TESTRUN_SUBDIR         = "CI-$BUILD_NUMBER"
707
+                        TESTRUN_SUBDIR         = "CI"
707 708
                         WINDOWS_BASE_IMAGE     = 'mcr.microsoft.com/windows/servercore'
708 709
                         WINDOWS_BASE_IMAGE_TAG = 'ltsc2016'
709 710
                     }
... ...
@@ -732,6 +771,25 @@ pipeline {
732 732
                             }
733 733
                         }
734 734
                     }
735
+                    post {
736
+                        always {
737
+                            catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
738
+                                powershell '''
739
+                                $bundleName="windowsRS1-integration"
740
+                                Write-Host -ForegroundColor Green "Creating ${bundleName}-bundles.zip"
741
+
742
+                                # archiveArtifacts does not support env-vars to , so save the artifacts in a fixed location
743
+                                Compress-Archive -Path "${env:TEMP}/CIDUT.out", "${env:TEMP}/CIDUT.err" -CompressionLevel Optimal -DestinationPath "${bundleName}-bundles.zip"
744
+                                '''
745
+
746
+                                archiveArtifacts artifacts: '*-bundles.zip', allowEmptyArchive: true
747
+                            }
748
+                        }
749
+                        cleanup {
750
+                            sh 'make clean'
751
+                            deleteDir()
752
+                        }
753
+                    }
735 754
                 }
736 755
                 stage('win-RS5') {
737 756
                     when {
... ...
@@ -740,11 +798,12 @@ pipeline {
740 740
                     }
741 741
                     environment {
742 742
                         DOCKER_BUILDKIT        = '0'
743
+                        DOCKER_DUT_DEBUG       = '1'
743 744
                         SKIP_VALIDATION_TESTS  = '1'
744 745
                         SOURCES_DRIVE          = 'd'
745 746
                         SOURCES_SUBDIR         = 'gopath'
746 747
                         TESTRUN_DRIVE          = 'd'
747
-                        TESTRUN_SUBDIR         = "CI-$BUILD_NUMBER"
748
+                        TESTRUN_SUBDIR         = "CI"
748 749
                         WINDOWS_BASE_IMAGE     = 'mcr.microsoft.com/windows/servercore'
749 750
                         WINDOWS_BASE_IMAGE_TAG = 'ltsc2019'
750 751
                     }
... ...
@@ -772,6 +831,25 @@ pipeline {
772 772
                             }
773 773
                         }
774 774
                     }
775
+                    post {
776
+                        always {
777
+                            catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
778
+                                powershell '''
779
+                                $bundleName="windowsRS5-integration"
780
+                                Write-Host -ForegroundColor Green "Creating ${bundleName}-bundles.zip"
781
+
782
+                                # archiveArtifacts does not support env-vars to , so save the artifacts in a fixed location
783
+                                Compress-Archive -Path "${env:TEMP}/CIDUT.out", "${env:TEMP}/CIDUT.err" -CompressionLevel Optimal -DestinationPath "${bundleName}-bundles.zip"
784
+                                '''
785
+
786
+                                archiveArtifacts artifacts: '*-bundles.zip', allowEmptyArchive: true
787
+                            }
788
+                        }
789
+                        cleanup {
790
+                            sh 'make clean'
791
+                            deleteDir()
792
+                        }
793
+                    }
775 794
                 }
776 795
             }
777 796
         }
... ...
@@ -111,7 +111,7 @@
111 111
 			# still stumble into him in our issue tracker, or on IRC.
112 112
 			"erikh",
113 113
 
114
-			# Evan Hazlett is the creator of of the Shipyard and Interlock open source projects,
114
+			# Evan Hazlett is the creator of the Shipyard and Interlock open source projects,
115 115
 			# and the author of "Orca", which became the foundation of Docker Universal Control
116 116
 			# Plane (UCP). As a maintainer, Evan helped integrating SwarmKit (secrets, tasks)
117 117
 			# into the Docker engine.
... ...
@@ -53,7 +53,6 @@ DOCKER_ENVS := \
53 53
 	-e DOCKER_TEST_HOST \
54 54
 	-e DOCKER_USERLANDPROXY \
55 55
 	-e DOCKERD_ARGS \
56
-	-e TEST_INTEGRATION_DEST \
57 56
 	-e TEST_INTEGRATION_DIR \
58 57
 	-e TEST_SKIP_INTEGRATION \
59 58
 	-e TEST_SKIP_INTEGRATION_CLI \
... ...
@@ -3262,7 +3262,7 @@ definitions:
3262 3262
 
3263 3263
           <p><br /></p>
3264 3264
 
3265
-          - "ingress" makes the target port accessible on on every node,
3265
+          - "ingress" makes the target port accessible on every node,
3266 3266
             regardless of whether there is a task for the service running on
3267 3267
             that node or not.
3268 3268
           - "host" bypasses the routing mesh and publish the port directly on
... ...
@@ -24,8 +24,11 @@ func init() {
24 24
 	reexec.Init()
25 25
 }
26 26
 
27
-func initDispatchTestCases() []dispatchTestCase {
28
-	dispatchTestCases := []dispatchTestCase{
27
+func TestDispatch(t *testing.T) {
28
+	if runtime.GOOS != "windows" {
29
+		skip.If(t, os.Getuid() != 0, "skipping test that requires root")
30
+	}
31
+	testCases := []dispatchTestCase{
29 32
 		{
30 33
 			name: "ADD multiple files to file",
31 34
 			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
... ...
@@ -92,56 +95,46 @@ func initDispatchTestCases() []dispatchTestCase {
92 92
 			}},
93 93
 			expectedError: "source can't be a URL for COPY",
94 94
 			files:         nil,
95
-		}}
96
-
97
-	return dispatchTestCases
98
-}
99
-
100
-func TestDispatch(t *testing.T) {
101
-	if runtime.GOOS != "windows" {
102
-		skip.If(t, os.Getuid() != 0, "skipping test that requires root")
95
+		},
103 96
 	}
104
-	testCases := initDispatchTestCases()
105 97
 
106
-	for _, testCase := range testCases {
107
-		executeTestCase(t, testCase)
108
-	}
109
-}
98
+	for _, tc := range testCases {
99
+		t.Run(tc.name, func(t *testing.T) {
100
+			contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
101
+			defer cleanup()
110 102
 
111
-func executeTestCase(t *testing.T, testCase dispatchTestCase) {
112
-	contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
113
-	defer cleanup()
103
+			for filename, content := range tc.files {
104
+				createTestTempFile(t, contextDir, filename, content, 0777)
105
+			}
114 106
 
115
-	for filename, content := range testCase.files {
116
-		createTestTempFile(t, contextDir, filename, content, 0777)
117
-	}
107
+			tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
118 108
 
119
-	tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
109
+			if err != nil {
110
+				t.Fatalf("Error when creating tar stream: %s", err)
111
+			}
120 112
 
121
-	if err != nil {
122
-		t.Fatalf("Error when creating tar stream: %s", err)
123
-	}
124
-
125
-	defer func() {
126
-		if err = tarStream.Close(); err != nil {
127
-			t.Fatalf("Error when closing tar stream: %s", err)
128
-		}
129
-	}()
113
+			defer func() {
114
+				if err = tarStream.Close(); err != nil {
115
+					t.Fatalf("Error when closing tar stream: %s", err)
116
+				}
117
+			}()
130 118
 
131
-	context, err := remotecontext.FromArchive(tarStream)
119
+			context, err := remotecontext.FromArchive(tarStream)
132 120
 
133
-	if err != nil {
134
-		t.Fatalf("Error when creating tar context: %s", err)
135
-	}
121
+			if err != nil {
122
+				t.Fatalf("Error when creating tar context: %s", err)
123
+			}
136 124
 
137
-	defer func() {
138
-		if err = context.Close(); err != nil {
139
-			t.Fatalf("Error when closing tar context: %s", err)
140
-		}
141
-	}()
125
+			defer func() {
126
+				if err = context.Close(); err != nil {
127
+					t.Fatalf("Error when closing tar context: %s", err)
128
+				}
129
+			}()
142 130
 
143
-	b := newBuilderWithMockBackend()
144
-	sb := newDispatchRequest(b, '`', context, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
145
-	err = dispatch(sb, testCase.cmd)
146
-	assert.Check(t, is.ErrorContains(err, testCase.expectedError))
131
+			b := newBuilderWithMockBackend()
132
+			sb := newDispatchRequest(b, '`', context, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
133
+			err = dispatch(sb, tc.cmd)
134
+			assert.Check(t, is.ErrorContains(err, tc.expectedError))
135
+		})
136
+	}
147 137
 }
... ...
@@ -3,8 +3,10 @@ package main
3 3
 import (
4 4
 	"runtime"
5 5
 
6
+	"github.com/docker/docker/daemon"
6 7
 	"github.com/docker/docker/daemon/config"
7 8
 	"github.com/docker/docker/opts"
9
+	"github.com/docker/docker/plugin/executor/containerd"
8 10
 	"github.com/docker/docker/registry"
9 11
 	"github.com/spf13/pflag"
10 12
 )
... ...
@@ -85,7 +87,13 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) error {
85 85
 
86 86
 	conf.MaxConcurrentDownloads = &maxConcurrentDownloads
87 87
 	conf.MaxConcurrentUploads = &maxConcurrentUploads
88
-	return nil
88
+
89
+	flags.StringVar(&conf.ContainerdNamespace, "containerd-namespace", daemon.ContainersNamespace, "Containerd namespace to use")
90
+	if err := flags.MarkHidden("containerd-namespace"); err != nil {
91
+		return err
92
+	}
93
+	flags.StringVar(&conf.ContainerdPluginNamespace, "containerd-plugins-namespace", containerd.PluginNamespace, "Containerd namespace to use for plugins")
94
+	return flags.MarkHidden("containerd-plugins-namespace")
89 95
 }
90 96
 
91 97
 func installRegistryServiceFlags(options *registry.ServiceOptions, flags *pflag.FlagSet) {
... ...
@@ -235,6 +235,9 @@ type CommonConfig struct {
235 235
 	Features map[string]bool `json:"features,omitempty"`
236 236
 
237 237
 	Builder BuilderConfig `json:"builder,omitempty"`
238
+
239
+	ContainerdNamespace       string `json:"containerd-namespace,omitempty"`
240
+	ContainerdPluginNamespace string `json:"containerd-plugin-namespace,omitempty"`
238 241
 }
239 242
 
240 243
 // IsValueSet returns true if a configuration value
... ...
@@ -875,7 +875,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
875 875
 		grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),
876 876
 	}
877 877
 	if config.ContainerdAddr != "" {
878
-		d.containerdCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(ContainersNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second))
878
+		d.containerdCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second))
879 879
 		if err != nil {
880 880
 			return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr)
881 881
 		}
... ...
@@ -887,13 +887,13 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
887 887
 		// Windows is not currently using containerd, keep the
888 888
 		// client as nil
889 889
 		if config.ContainerdAddr != "" {
890
-			pluginCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(pluginexec.PluginNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second))
890
+			pluginCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdPluginNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second))
891 891
 			if err != nil {
892 892
 				return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr)
893 893
 			}
894 894
 		}
895 895
 
896
-		return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, m)
896
+		return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m)
897 897
 	}
898 898
 
899 899
 	// Plugin system initialization should happen before restore. Do not change order.
... ...
@@ -1041,7 +1041,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
1041 1041
 
1042 1042
 	go d.execCommandGC()
1043 1043
 
1044
-	d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), ContainersNamespace, d)
1044
+	d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d)
1045 1045
 	if err != nil {
1046 1046
 		return nil, err
1047 1047
 	}
... ...
@@ -736,6 +736,9 @@ func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error
736 736
 
737 737
 // verifyDaemonSettings performs validation of daemon config struct
738 738
 func verifyDaemonSettings(conf *config.Config) error {
739
+	if conf.ContainerdNamespace == conf.ContainerdPluginNamespace {
740
+		return errors.New("containers namespace and plugins namespace cannot be the same")
741
+	}
739 742
 	// Check for mutually incompatible config options
740 743
 	if conf.BridgeConfig.Iface != "" && conf.BridgeConfig.IP != "" {
741 744
 		return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one")
... ...
@@ -285,6 +285,9 @@ func TestLogClosed(t *testing.T) {
285 285
 	}
286 286
 }
287 287
 
288
+// TestLogBlocking tests that the Log method blocks appropriately when
289
+// non-blocking behavior is not enabled.  Blocking is achieved through an
290
+// internal channel that must be drained for Log to return.
288 291
 func TestLogBlocking(t *testing.T) {
289 292
 	mockClient := newMockClient()
290 293
 	stream := &logStream{
... ...
@@ -299,18 +302,20 @@ func TestLogBlocking(t *testing.T) {
299 299
 		err := stream.Log(&logger.Message{})
300 300
 		errorCh <- err
301 301
 	}()
302
+	// block until the goroutine above has started
302 303
 	<-started
303 304
 	select {
304 305
 	case err := <-errorCh:
305 306
 		t.Fatal("Expected stream.Log to block: ", err)
306 307
 	default:
307
-		break
308 308
 	}
309
+	// assuming it is blocked, we can now try to drain the internal channel and
310
+	// unblock it
309 311
 	select {
310
-	case <-stream.messages:
311
-		break
312
-	default:
312
+	case <-time.After(10 * time.Millisecond):
313
+		// if we're unable to drain the channel within 10ms, something seems broken
313 314
 		t.Fatal("Expected to be able to read from stream.messages but was unable to")
315
+	case <-stream.messages:
314 316
 	}
315 317
 	select {
316 318
 	case err := <-errorCh:
... ...
@@ -925,7 +925,12 @@ func TestFrequency(t *testing.T) {
925 925
 
926 926
 	// 1 to verify connection and 10 to verify that we have sent messages with required frequency,
927 927
 	// but because frequency is too small (to keep test quick), instead of 11, use 9 if context switches will be slow
928
-	if hec.numOfRequests < 9 {
928
+	expectedRequests := 9
929
+	if runtime.GOOS == "windows" {
930
+		// sometimes in Windows, this test fails with number of requests showing 8. So be more conservative.
931
+		expectedRequests = 7
932
+	}
933
+	if hec.numOfRequests < expectedRequests {
929 934
 		t.Fatalf("Unexpected number of requests %d", hec.numOfRequests)
930 935
 	}
931 936
 
... ...
@@ -15,6 +15,11 @@ if ($env:BUILD_TAG -match "-LoW") { $env:LCOW_MODE=1 }
15 15
 if ($env:BUILD_TAG -match "-WoW") { $env:LCOW_MODE="" }
16 16
 
17 17
 
18
+Write-Host -ForegroundColor Red "DEBUG: print all environment variables to check how Jenkins runs this script"
19
+$allArgs = [Environment]::GetCommandLineArgs()
20
+Write-Host -ForegroundColor Red $allArgs
21
+Write-Host -ForegroundColor Red "----------------------------------------------------------------------------"
22
+
18 23
 # -------------------------------------------------------------------------------------------
19 24
 # When executed, we rely on four variables being set in the environment:
20 25
 #
... ...
@@ -46,10 +51,24 @@ if ($env:BUILD_TAG -match "-WoW") { $env:LCOW_MODE="" }
46 46
 #                        TESTRUN_DRIVE\TESTRUN_SUBDIR\CI-<CommitID> or
47 47
 #                        d:\CI\CI-<CommitID>
48 48
 #
49
+# Optional environment variables help in CI:
50
+#
51
+#    BUILD_NUMBER + BRANCH_NAME   are optional variables to be added to the directory below TESTRUN_SUBDIR
52
+#                        to have individual folder per CI build. If some files couldn't be
53
+#                        cleaned up and we want to re-run the build in CI.
54
+#                        Hence, the daemon under test is run under
55
+#                        TESTRUN_DRIVE\TESTRUN_SUBDIR\PR-<PR-Number>\<BuildNumber> or
56
+#                        d:\CI\PR-<PR-Number>\<BuildNumber>
57
+#
49 58
 # In addition, the following variables can control the run configuration:
50 59
 #
51 60
 #    DOCKER_DUT_DEBUG         if defined starts the daemon under test in debug mode.
52 61
 #
62
+#   DOCKER_STORAGE_OPTS       comma-separated list of optional storage driver options for the daemon under test
63
+#                             examples:
64
+#                             DOCKER_STORAGE_OPTS="size=40G"
65
+#                             DOCKER_STORAGE_OPTS="lcow.globalmode=false,lcow.kernel=kernel.efi"
66
+#
53 67
 #    SKIP_VALIDATION_TESTS    if defined skips the validation tests
54 68
 #
55 69
 #    SKIP_UNIT_TESTS          if defined skips the unit tests
... ...
@@ -266,7 +285,7 @@ Try {
266 266
         }
267 267
       }
268 268
     } Catch {}
269
-    if ($defender) { Throw "ERROR: Windows Defender real time protection must be disabled for integration tests" }
269
+    if ($defender) { Write-Host -ForegroundColor Magenta "WARN: Windows Defender real time protection is enabled, which may cause some integration tests to fail" }
270 270
 
271 271
     # Make sure SOURCES_DRIVE is set
272 272
     if ($null -eq $env:SOURCES_DRIVE) { Throw "ERROR: Environment variable SOURCES_DRIVE is not set" }
... ...
@@ -418,7 +437,12 @@ Try {
418 418
 
419 419
     # Redirect to a temporary location. 
420 420
     $TEMPORIG=$env:TEMP
421
-    $env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\CI-$COMMITHASH"
421
+    if ($null -eq $env:BUILD_NUMBER) {
422
+      $env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\CI-$COMMITHASH"
423
+    } else {
424
+      # individual temporary location per CI build that better matches the BUILD_URL
425
+      $env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\$env:BRANCH_NAME\$env:BUILD_NUMBER"
426
+    }
422 427
     $env:LOCALAPPDATA="$env:TEMP\localappdata"
423 428
     $errorActionPreference='Stop'
424 429
     New-Item -ItemType Directory "$env:TEMP" -ErrorAction SilentlyContinue | Out-Null
... ...
@@ -580,6 +604,15 @@ Try {
580 580
         $dutArgs += "--exec-opt isolation=hyperv"
581 581
     }
582 582
 
583
+    # Arguments: Allow setting optional storage-driver options
584
+    # example usage: DOCKER_STORAGE_OPTS="lcow.globalmode=false,lcow.kernel=kernel.efi"
585
+    if (-not ("$env:DOCKER_STORAGE_OPTS" -eq "")) {
586
+        Write-Host -ForegroundColor Green "INFO: Running the daemon under test with storage-driver options ${env:DOCKER_STORAGE_OPTS}"
587
+        $env:DOCKER_STORAGE_OPTS.Split(",") | ForEach {
588
+            $dutArgs += "--storage-opt $_"
589
+        }
590
+    }
591
+
583 592
     # Start the daemon under test, ensuring everything is redirected to folders under $TEMP.
584 593
     # Important - we launch the -$COMMITHASH version so that we can kill it without
585 594
     # killing the control daemon. 
... ...
@@ -608,7 +641,8 @@ Try {
608 608
 
609 609
     # Start tailing the daemon under test if the command is installed
610 610
     if ($null -ne (Get-Command "tail" -ErrorAction SilentlyContinue)) {
611
-        $tail = start-process "tail" -ArgumentList "-f $env:TEMP\dut.out" -ErrorAction SilentlyContinue
611
+        Write-Host -ForegroundColor green "INFO: Start tailing logs of the daemon under tests"
612
+        $tail = Start-Process "tail" -ArgumentList "-f $env:TEMP\dut.out" -PassThru -ErrorAction SilentlyContinue
612 613
     }
613 614
 
614 615
     # Verify we can get the daemon under test to respond 
... ...
@@ -717,7 +751,7 @@ Try {
717 717
     
718 718
         # Inspect the pulled or loaded image to get the version directly
719 719
         $ErrorActionPreference = "SilentlyContinue"
720
-        $dutimgVersion = $(&"$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" inspect  $($env:WINDOWS_BASE_IMAGE) --format "{{.OsVersion}}")
720
+        $dutimgVersion = $(&"$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" inspect "$($env:WINDOWS_BASE_IMAGE):$env:WINDOWS_BASE_IMAGE_TAG" --format "{{.OsVersion}}")
721 721
         $ErrorActionPreference = "Stop"
722 722
         Write-Host -ForegroundColor Green $("INFO: Version of $($env:WINDOWS_BASE_IMAGE):$env:WINDOWS_BASE_IMAGE_TAG is '"+$dutimgVersion+"'")
723 723
     }
... ...
@@ -944,6 +978,12 @@ Try {
944 944
         Remove-Item "$env:TEMP\docker.pid" -force -ErrorAction SilentlyContinue
945 945
     }
946 946
 
947
+    # Stop the tail process (if started)
948
+    if ($null -ne $tail) {
949
+        Write-Host -ForegroundColor green "INFO: Stop tailing logs of the daemon under tests"
950
+        Stop-Process -InputObject $tail -Force
951
+    }
952
+
947 953
     Write-Host -ForegroundColor Green "INFO: executeCI.ps1 Completed successfully at $(Get-Date)."
948 954
 }
949 955
 Catch [Exception] {
... ...
@@ -960,6 +1000,9 @@ Catch [Exception] {
960 960
     Throw $_
961 961
 }
962 962
 Finally {
963
+    # Preserve the LastExitCode of the tests
964
+    $tmpLastExitCode = $LastExitCode
965
+
963 966
     $ErrorActionPreference="SilentlyContinue"
964 967
     $global:ProgressPreference=$origProgressPreference
965 968
     Write-Host  -ForegroundColor Green "INFO: Tidying up at end of run"
... ...
@@ -991,6 +1034,12 @@ Finally {
991 991
 
992 992
     Set-Location "$env:SOURCES_DRIVE\$env:SOURCES_SUBDIR" -ErrorAction SilentlyContinue
993 993
     Nuke-Everything
994
+
995
+    # Restore the TEMP path
996
+    if ($null -ne $TEMPORIG) { $env:TEMP="$TEMPORIG" }
997
+
994 998
     $Dur=New-TimeSpan -Start $StartTime -End $(Get-Date)
995 999
     Write-Host -ForegroundColor $FinallyColour "`nINFO: executeCI.ps1 exiting at $(date). Duration $dur`n"
1000
+
1001
+    exit $tmpLastExitCode
996 1002
 }
... ...
@@ -134,7 +134,7 @@ Function Check-InContainer() {
134 134
 # outside of a container where it may be out of date with master.
135 135
 Function Verify-GoVersion() {
136 136
     Try {
137
-        $goVersionDockerfile=(Select-String -Path ".\Dockerfile" -Pattern "^ARG[\s]+GO_VERSION=(.*)$").Matches.groups[1].Value.TrimEnd(".0")
137
+        $goVersionDockerfile=(Select-String -Path ".\Dockerfile" -Pattern "^ARG[\s]+GO_VERSION=(.*)$").Matches.groups[1].Value -replace '\.0$',''
138 138
         $goVersionInstalled=(go version).ToString().Split(" ")[2].SubString(2)
139 139
     }
140 140
     Catch [Exception] {
... ...
@@ -28,30 +28,6 @@ export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
28 28
 export MAKEDIR="$SCRIPTDIR/make"
29 29
 export PKG_CONFIG=${PKG_CONFIG:-pkg-config}
30 30
 
31
-# We're a nice, sexy, little shell script, and people might try to run us;
32
-# but really, they shouldn't. We want to be in a container!
33
-inContainer="AssumeSoInitially"
34
-if [ "$(go env GOHOSTOS)" = 'windows' ]; then
35
-	if [ -z "$FROM_DOCKERFILE" ]; then
36
-		unset inContainer
37
-	fi
38
-else
39
-	if [ "$PWD" != "/go/src/$DOCKER_PKG" ]; then
40
-		unset inContainer
41
-	fi
42
-fi
43
-
44
-if [ -z "$inContainer" ]; then
45
-	{
46
-		echo "# WARNING! I don't seem to be running in a Docker container."
47
-		echo "# The result of this command might be an incorrect build, and will not be"
48
-		echo "# officially supported."
49
-		echo "#"
50
-		echo "# Try this instead: make all"
51
-		echo "#"
52
-	} >&2
53
-fi
54
-
55 31
 echo
56 32
 
57 33
 # List of bundles to create when no argument is passed
... ...
@@ -72,9 +72,27 @@ run_test_integration_suites() {
72 72
 	for dir in ${integration_api_dirs}; do
73 73
 		if ! (
74 74
 			cd "$dir"
75
-			echo "Running $PWD flags=${flags}"
75
+			# Create a useful package name based on the tests's $dir. We need to take
76
+			# into account that  "$dir" can be either an absolute (/go/src/github.com/docker/docker/integration/foo)
77
+			# or relative (./integration/foo) path. To account for both, first we strip
78
+			# the absolute path, then remove any leading periods and slashes.
79
+			pkgname="${dir}"
80
+			pkgname="${pkgname#*${GOPATH}/src/${DOCKER_PKG}}"
81
+			pkgname="${pkgname#*.}"
82
+			pkgname="${pkgname#*\/}"
83
+
84
+			# Finally, we use periods as separator (instead of slashes) to be more
85
+			# in line with Java package names (which is what junit.xml was designed for)
86
+			pkgname="$(go env GOARCH).${pkgname//\//.}"
87
+			echo "Running $PWD (${pkgname}) flags=${flags}"
88
+			[ -n "$TESTDEBUG" ] && set -x
76 89
 			# shellcheck disable=SC2086
77
-			test_env ./test.main ${flags}
90
+			test_env gotestsum \
91
+				--format=standard-verbose \
92
+				--jsonfile="${ABS_DEST}/${pkgname//./-}-go-test-report.json" \
93
+				--junitfile="${ABS_DEST}/${pkgname//./-}-junit-report.xml" \
94
+				--raw-command \
95
+				-- go tool test2json -p "${pkgname}" -t ./test.main ${flags}
78 96
 		); then exit 1; fi
79 97
 	done
80 98
 }
... ...
@@ -15,16 +15,16 @@ copy_binaries() {
15 15
 	fi
16 16
 	echo "Copying nested executables into $dir"
17 17
 	for file in containerd containerd-shim ctr runc docker-init docker-proxy rootlesskit rootlesskit-docker-proxy dockerd-rootless.sh; do
18
-		cp -f `which "$file"` "$dir/"
19
-		if [ "$hash" == "hash" ]; then
18
+		cp -f "$(command -v "$file")" "$dir/"
19
+		if [ "$hash" = "hash" ]; then
20 20
 			hash_files "$dir/$file"
21 21
 		fi
22 22
 	done
23 23
 
24 24
 	# vpnkit is amd64 only
25
-	if which "vpnkit.$(uname -m)" 2>&1 >/dev/null; then
26
-		cp -f `which "vpnkit.$(uname -m)"` "$dir/vpnkit"
27
-		if [ "$hash" == "hash" ]; then
25
+	if command -v "vpnkit.$(uname -m)" 2>&1 >/dev/null; then
26
+		cp -f "$(command -v "vpnkit.$(uname -m)")" "$dir/vpnkit"
27
+		if [ "$hash" = "hash" ]; then
28 28
 			hash_files "$dir/vpnkit"
29 29
 		fi
30 30
 	fi
... ...
@@ -13,6 +13,7 @@ source hack/make/.integration-test-helpers
13 13
 # TODO remove these skip once we update to a docker-py version that has https://github.com/docker/docker-py/pull/2369, https://github.com/docker/docker-py/pull/2380, https://github.com/docker/docker-py/pull/2382
14 14
 : "${PY_TEST_OPTIONS:=\
15 15
 --deselect=tests/integration/api_swarm_test.py::SwarmTest::test_init_swarm_data_path_addr \
16
+--deselect=tests/integration/api_container_test.py::AttachContainerTest::test_attach_no_stream \
16 17
 --deselect=tests/integration/api_exec_test.py::ExecTest::test_detach_with_arg \
17 18
 --deselect=tests/integration/api_exec_test.py::ExecDemuxTest::test_exec_command_tty_stream_no_demux \
18 19
 --deselect=tests/integration/api_build_test.py::BuildTest::test_build_invalid_platform \
... ...
@@ -1,12 +1,6 @@
1 1
 #!/usr/bin/env bash
2 2
 set -e -o pipefail
3 3
 
4
-if [ -n "$TEST_INTEGRATION_DEST" ]; then
5
-	export DEST="$ABS_DEST/$TEST_INTEGRATION_DEST"
6
-	export DOCKER_INTEGRATION_DAEMON_DEST="$DEST"
7
-	mkdir -p "$DEST"
8
-fi
9
-
10 4
 source hack/make/.integration-test-helpers
11 5
 
12 6
 if [ ! -z "${TEST_SKIP_INTEGRATION}" ] && [ ! -z "${TEST_SKIP_INTEGRATION_CLI}" ]; then
... ...
@@ -4,10 +4,11 @@ set -e -o pipefail
4 4
 SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
5 5
 
6 6
 # CI platforms differ, so per-platform GOMETALINTER_OPTS can be set
7
-# from a platform-specific Dockerfile, otherwise let's just set
7
+# in the Jenkinsfile, otherwise let's just set a
8 8
 # (somewhat pessimistic) default of 10 minutes.
9
-: ${GOMETALINTER_OPTS=--deadline=10m}
9
+: "${GOMETALINTER_OPTS=--deadline=10m}"
10 10
 
11
+# shellcheck disable=SC2086
11 12
 gometalinter \
12 13
 	${GOMETALINTER_OPTS} \
13
-	--config ${SCRIPTDIR}/gometalinter.json ./...
14
+	--config "${SCRIPTDIR}/gometalinter.json" ./...
... ...
@@ -28,7 +28,7 @@ func (s *DockerSuite) BenchmarkConcurrentContainerActions(c *check.C) {
28 28
 			go func() {
29 29
 				defer innerGroup.Done()
30 30
 				for i := 0; i < numIterations; i++ {
31
-					args := []string{"run", "-d", defaultSleepImage}
31
+					args := []string{"run", "-d", "busybox"}
32 32
 					args = append(args, sleepCommandForDaemonPlatform()...)
33 33
 					out, _, err := dockerCmdWithError(args...)
34 34
 					if err != nil {
... ...
@@ -304,8 +304,8 @@ func init() {
304 304
 type DockerSwarmSuite struct {
305 305
 	server      *httptest.Server
306 306
 	ds          *DockerSuite
307
+	daemonsLock sync.Mutex // protect access to daemons and portIndex
307 308
 	daemons     []*daemon.Daemon
308
-	daemonsLock sync.Mutex // protect access to daemons
309 309
 	portIndex   int
310 310
 }
311 311
 
... ...
@@ -333,11 +333,11 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemo
333 333
 			d.StartAndSwarmInit(c)
334 334
 		}
335 335
 	} else {
336
-		d.StartNode(c)
336
+		d.StartNodeWithBusybox(c)
337 337
 	}
338 338
 
339
-	s.portIndex++
340 339
 	s.daemonsLock.Lock()
340
+	s.portIndex++
341 341
 	s.daemons = append(s.daemons, d)
342 342
 	s.daemonsLock.Unlock()
343 343
 
... ...
@@ -354,9 +354,8 @@ func (s *DockerSwarmSuite) TearDownTest(c *check.C) {
354 354
 		}
355 355
 	}
356 356
 	s.daemons = nil
357
-	s.daemonsLock.Unlock()
358
-
359 357
 	s.portIndex = 0
358
+	s.daemonsLock.Unlock()
360 359
 	s.ds.TearDownTest(c)
361 360
 }
362 361
 
... ...
@@ -189,3 +189,25 @@ func (d *Daemon) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
189 189
 	}
190 190
 	return fmt.Errorf("no leader"), check.Commentf("could not find leader")
191 191
 }
192
+
193
+// CmdRetryOutOfSequence tries the specified command against the current daemon
194
+// up to 10 times, retrying if it encounters an "update out of sequence" error.
195
+func (d *Daemon) CmdRetryOutOfSequence(args ...string) (string, error) {
196
+	var (
197
+		output string
198
+		err    error
199
+	)
200
+
201
+	for i := 0; i < 10; i++ {
202
+		output, err = d.Cmd(args...)
203
+		// error, no error, whatever. if we don't have "update out of
204
+		// sequence", we don't retry, we just return.
205
+		if !strings.Contains(output, "update out of sequence") {
206
+			return output, err
207
+		}
208
+	}
209
+
210
+	// otherwise, once all of our attempts have been exhausted, just return
211
+	// whatever the last values were.
212
+	return output, err
213
+}
... ...
@@ -1,5 +1,3 @@
1
-// +build !test_no_exec
2
-
3 1
 package main
4 2
 
5 3
 import (
... ...
@@ -62,8 +62,8 @@ func (s *DockerSuite) TestAPIImagesSaveAndLoad(c *check.C) {
62 62
 		v, err := kernel.GetKernelVersion()
63 63
 		assert.NilError(c, err)
64 64
 		build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
65
-		if build == 16299 {
66
-			c.Skip("Temporarily disabled on RS3 builds")
65
+		if build <= 16299 {
66
+			c.Skip("Temporarily disabled on RS3 and older because they are too slow. See #39909")
67 67
 		}
68 68
 	}
69 69
 
... ...
@@ -4535,17 +4535,17 @@ func (s *DockerSuite) TestBuildBuildTimeArgEnv(c *check.C) {
4535 4535
 		ARG FOO6
4536 4536
 		ARG FO10
4537 4537
 		RUN env
4538
-		RUN [ "$FOO1" == "fromcmd" ]
4539
-		RUN [ "$FOO2" == "" ]
4540
-		RUN [ "$FOO3" == "fromenv" ]
4541
-		RUN [ "$FOO4" == "fromfile" ]
4542
-		RUN [ "$FOO5" == "fromcmd" ]
4538
+		RUN [ "$FOO1" = "fromcmd" ]
4539
+		RUN [ "$FOO2" = "" ]
4540
+		RUN [ "$FOO3" = "fromenv" ]
4541
+		RUN [ "$FOO4" = "fromfile" ]
4542
+		RUN [ "$FOO5" = "fromcmd" ]
4543 4543
 		# The following should not exist at all in the env
4544
-		RUN [ "$(env | grep FOO6)" == "" ]
4545
-		RUN [ "$(env | grep FOO7)" == "" ]
4546
-		RUN [ "$(env | grep FOO8)" == "" ]
4547
-		RUN [ "$(env | grep FOO9)" == "" ]
4548
-		RUN [ "$FO10" == "" ]
4544
+		RUN [ "$(env | grep FOO6)" = "" ]
4545
+		RUN [ "$(env | grep FOO7)" = "" ]
4546
+		RUN [ "$(env | grep FOO8)" = "" ]
4547
+		RUN [ "$(env | grep FOO9)" = "" ]
4548
+		RUN [ "$FO10" = "" ]
4549 4549
 	    `
4550 4550
 	result := buildImage("testbuildtimeargenv",
4551 4551
 		cli.WithFlags(
... ...
@@ -4615,9 +4615,9 @@ func (s *DockerSuite) TestBuildBuildTimeArgEmptyValVariants(c *check.C) {
4615 4615
 		ARG %s=
4616 4616
 		ARG %s=""
4617 4617
 		ARG %s=''
4618
-		RUN [ "$%s" == "$%s" ]
4619
-		RUN [ "$%s" == "$%s" ]
4620
-		RUN [ "$%s" == "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2)
4618
+		RUN [ "$%s" = "$%s" ]
4619
+		RUN [ "$%s" = "$%s" ]
4620
+		RUN [ "$%s" = "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2)
4621 4621
 	buildImageSuccessfully(c, imgName, build.WithDockerfile(dockerfile))
4622 4622
 }
4623 4623
 
... ...
@@ -5952,7 +5952,7 @@ func (s *DockerSuite) TestBuildCopyFromWindowsIsCaseInsensitive(c *check.C) {
5952 5952
 }
5953 5953
 
5954 5954
 // #33176
5955
-func (s *DockerSuite) TestBuildMulitStageResetScratch(c *check.C) {
5955
+func (s *DockerSuite) TestBuildMultiStageResetScratch(c *check.C) {
5956 5956
 	testRequires(c, DaemonIsLinux)
5957 5957
 
5958 5958
 	dockerfile := `
... ...
@@ -309,7 +309,15 @@ func (s *DockerSuite) TestCreateWithWorkdir(c *check.C) {
309 309
 	// Windows does not create the workdir until the container is started
310 310
 	if testEnv.OSType == "windows" {
311 311
 		dockerCmd(c, "start", name)
312
+		if IsolationIsHyperv() {
313
+			// Hyper-V isolated containers do not allow file-operations on a
314
+			// running container. This test currently uses `docker cp` to verify
315
+			// that the WORKDIR was automatically created, which cannot be done
316
+			// while the container is running.
317
+			dockerCmd(c, "stop", name)
318
+		}
312 319
 	}
320
+	// TODO: rewrite this test to not use `docker cp` for verifying that the WORKDIR was created
313 321
 	dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp")
314 322
 }
315 323
 
... ...
@@ -121,7 +121,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C)
121 121
 
122 122
 // TestDaemonShutdownWithPlugins shuts down running plugins.
123 123
 func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
124
-	testRequires(c, IsAmd64, Network, testEnv.IsLocalDaemon)
124
+	testRequires(c, IsAmd64, Network)
125 125
 
126 126
 	s.d.Start(c)
127 127
 	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
... ...
@@ -159,7 +159,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
159 159
 
160 160
 // TestDaemonKillWithPlugins leaves plugins running.
161 161
 func (s *DockerDaemonSuite) TestDaemonKillWithPlugins(c *check.C) {
162
-	testRequires(c, IsAmd64, Network, testEnv.IsLocalDaemon)
162
+	testRequires(c, IsAmd64, Network)
163 163
 
164 164
 	s.d.Start(c)
165 165
 	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
... ...
@@ -232,7 +232,7 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
232 232
 }
233 233
 
234 234
 func (s *DockerDaemonSuite) TestPluginVolumeRemoveOnRestart(c *check.C) {
235
-	testRequires(c, DaemonIsLinux, Network, IsAmd64)
235
+	testRequires(c, IsAmd64, Network)
236 236
 
237 237
 	s.d.Start(c, "--live-restore=true")
238 238
 
... ...
@@ -26,7 +26,6 @@ import (
26 26
 	"github.com/cloudflare/cfssl/helpers"
27 27
 	"github.com/creack/pty"
28 28
 	"github.com/docker/docker/api/types"
29
-	moby_daemon "github.com/docker/docker/daemon"
30 29
 	"github.com/docker/docker/integration-cli/checker"
31 30
 	"github.com/docker/docker/integration-cli/cli"
32 31
 	"github.com/docker/docker/integration-cli/cli/build"
... ...
@@ -826,7 +825,6 @@ func (s *DockerDaemonSuite) TestDaemonDefaultGatewayIPv4ExplicitOutsideContainer
826 826
 }
827 827
 
828 828
 func (s *DockerDaemonSuite) TestDaemonDefaultNetworkInvalidClusterConfig(c *check.C) {
829
-	testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
830 829
 
831 830
 	// Start daemon without docker0 bridge
832 831
 	defaultNetworkBridge := "docker0"
... ...
@@ -967,7 +965,6 @@ func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *che
967 967
 }
968 968
 
969 969
 func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) {
970
-	testRequires(c, DaemonIsLinux)
971 970
 
972 971
 	s.d.StartWithBusybox(c, "--default-ulimit", "nofile=42:42", "--default-ulimit", "nproc=1024:1024")
973 972
 
... ...
@@ -1457,7 +1454,7 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonAndContainerKill(c *chec
1457 1457
 
1458 1458
 	// kill the container
1459 1459
 	icmd.RunCommand(ctrBinary, "--address", containerdSocket,
1460
-		"--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", id).Assert(c, icmd.Success)
1460
+		"--namespace", d.ContainersNamespace(), "tasks", "kill", id).Assert(c, icmd.Success)
1461 1461
 
1462 1462
 	// restart daemon.
1463 1463
 	d.Restart(c)
... ...
@@ -1977,7 +1974,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithKilledRunningContainer(t *check
1977 1977
 
1978 1978
 	// kill the container
1979 1979
 	icmd.RunCommand(ctrBinary, "--address", containerdSocket,
1980
-		"--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", cid).Assert(t, icmd.Success)
1980
+		"--namespace", s.d.ContainersNamespace(), "tasks", "kill", cid).Assert(t, icmd.Success)
1981 1981
 
1982 1982
 	// Give time to containerd to process the command if we don't
1983 1983
 	// the exit event might be received after we do the inspect
... ...
@@ -2080,7 +2077,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *che
2080 2080
 	result := icmd.RunCommand(
2081 2081
 		ctrBinary,
2082 2082
 		"--address", containerdSocket,
2083
-		"--namespace", moby_daemon.ContainersNamespace,
2083
+		"--namespace", s.d.ContainersNamespace(),
2084 2084
 		"tasks", "resume", cid)
2085 2085
 	result.Assert(t, icmd.Success)
2086 2086
 
... ...
@@ -388,7 +388,6 @@ func (s *DockerSuite) TestEventsFilterNetworkID(c *check.C) {
388 388
 }
389 389
 
390 390
 func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) {
391
-	testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux)
392 391
 
393 392
 	// daemon config file
394 393
 	configFilePath := "test.json"
... ...
@@ -457,7 +456,6 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) {
457 457
 }
458 458
 
459 459
 func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) {
460
-	testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux)
461 460
 
462 461
 	// daemon config file
463 462
 	configFilePath := "test.json"
... ...
@@ -1,5 +1,3 @@
1
-// +build !test_no_exec
2
-
3 1
 package main
4 2
 
5 3
 import (
... ...
@@ -81,8 +79,7 @@ func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) {
81 81
 }
82 82
 
83 83
 func (s *DockerDaemonSuite) TestExecAfterDaemonRestart(c *check.C) {
84
-	// TODO Windows CI: Requires a little work to get this ported.
85
-	testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
84
+	// TODO Windows CI: DockerDaemonSuite doesn't run on Windows, and requires a little work to get this ported.
86 85
 	s.d.StartWithBusybox(c)
87 86
 
88 87
 	out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top")
... ...
@@ -1,4 +1,4 @@
1
-// +build !windows,!test_no_exec
1
+// +build !windows
2 2
 
3 3
 package main
4 4
 
... ...
@@ -211,7 +211,6 @@ func (s *DockerSuite) TestInsecureRegistries(c *check.C) {
211 211
 }
212 212
 
213 213
 func (s *DockerDaemonSuite) TestRegistryMirrors(c *check.C) {
214
-	testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux)
215 214
 
216 215
 	registryMirror1 := "https://192.168.1.2"
217 216
 	registryMirror2 := "http://registry.mirror.com:5000"
... ...
@@ -140,7 +140,7 @@ func (s *DockerSuite) TestLinksNotStartedParentNotFail(c *check.C) {
140 140
 
141 141
 func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) {
142 142
 	testRequires(c, DaemonIsLinux)
143
-	testRequires(c, testEnv.IsLocalDaemon, ExecSupport)
143
+	testRequires(c, testEnv.IsLocalDaemon)
144 144
 
145 145
 	out, _ := dockerCmd(c, "run", "-itd", "--name", "one", "busybox", "top")
146 146
 	idOne := strings.TrimSpace(out)
... ...
@@ -158,7 +158,7 @@ func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) {
158 158
 
159 159
 func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) {
160 160
 	testRequires(c, DaemonIsLinux)
161
-	testRequires(c, testEnv.IsLocalDaemon, ExecSupport)
161
+	testRequires(c, testEnv.IsLocalDaemon)
162 162
 	dockerCmd(c, "run", "-d", "--name", "one", "busybox", "top")
163 163
 	out, _ := dockerCmd(c, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top")
164 164
 	id := strings.TrimSpace(string(out))
... ...
@@ -805,7 +805,6 @@ func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) {
805 805
 }
806 806
 
807 807
 func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) {
808
-	testRequires(c, ExecSupport)
809 808
 	// On default bridge network built-in service discovery should not happen
810 809
 	hostsFile := "/etc/hosts"
811 810
 	bridgeName := "external-bridge"
... ...
@@ -863,7 +862,7 @@ func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *
863 863
 }
864 864
 
865 865
 func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) {
866
-	testRequires(c, ExecSupport, NotArm)
866
+	testRequires(c, NotArm)
867 867
 	hostsFile := "/etc/hosts"
868 868
 	cstmBridgeNw := "custom-bridge-nw"
869 869
 	cstmBridgeNw1 := "custom-bridge-nw1"
... ...
@@ -1665,7 +1664,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *c
1665 1665
 }
1666 1666
 
1667 1667
 func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) {
1668
-	testRequires(t, DaemonIsLinux)
1669 1668
 	s.d.StartWithBusybox(t, "--live-restore")
1670 1669
 	defer s.d.Stop(t)
1671 1670
 	oldCon := "old"
... ...
@@ -21,7 +21,6 @@ func (s *DockerSuite) TestCLIProxyDisableProxyUnixSock(c *check.C) {
21 21
 // Can't use localhost here since go has a special case to not use proxy if connecting to localhost
22 22
 // See https://golang.org/pkg/net/http/#ProxyFromEnvironment
23 23
 func (s *DockerDaemonSuite) TestCLIProxyProxyTCPSock(c *check.C) {
24
-	testRequires(c, testEnv.IsLocalDaemon)
25 24
 	// get the IP to use to connect since we can't use localhost
26 25
 	addrs, err := net.InterfaceAddrs()
27 26
 	assert.NilError(c, err)
... ...
@@ -292,7 +292,7 @@ func (s *DockerSuite) TestRestartContainerwithRestartPolicy(c *check.C) {
292 292
 	dockerCmd(c, "start", id1)
293 293
 	dockerCmd(c, "start", id2)
294 294
 
295
-	// Kill the containers, making sure the are stopped at the end of the test
295
+	// Kill the containers, making sure they are stopped at the end of the test
296 296
 	dockerCmd(c, "kill", id1)
297 297
 	dockerCmd(c, "kill", id2)
298 298
 	err = waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout)
... ...
@@ -1792,16 +1792,14 @@ func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) {
1792 1792
 func (s *DockerSuite) TestRunInteractiveWithRestartPolicy(c *check.C) {
1793 1793
 	name := "test-inter-restart"
1794 1794
 
1795
-	result := icmd.StartCmd(icmd.Cmd{
1795
+	result := icmd.RunCmd(icmd.Cmd{
1796 1796
 		Command: []string{dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh"},
1797 1797
 		Stdin:   bytes.NewBufferString("exit 11"),
1798 1798
 	})
1799
-	assert.NilError(c, result.Error)
1800 1799
 	defer func() {
1801
-		dockerCmdWithResult("stop", name).Assert(c, icmd.Success)
1800
+		cli.Docker(cli.Args("stop", name)).Assert(c, icmd.Success)
1802 1801
 	}()
1803 1802
 
1804
-	result = icmd.WaitOnCmd(60*time.Second, result)
1805 1803
 	result.Assert(c, icmd.Expected{ExitCode: 11})
1806 1804
 }
1807 1805
 
... ...
@@ -3430,7 +3428,7 @@ func (s *DockerSuite) TestRunLoopbackWhenNetworkDisabled(c *check.C) {
3430 3430
 
3431 3431
 func (s *DockerSuite) TestRunModeNetContainerHostname(c *check.C) {
3432 3432
 	// Windows does not support --net=container
3433
-	testRequires(c, DaemonIsLinux, ExecSupport)
3433
+	testRequires(c, DaemonIsLinux)
3434 3434
 
3435 3435
 	dockerCmd(c, "run", "-i", "-d", "--name", "parent", "busybox", "top")
3436 3436
 	out, _ := dockerCmd(c, "exec", "parent", "cat", "/etc/hostname")
... ...
@@ -1442,7 +1442,7 @@ func (s *DockerSuite) TestRunUserDeviceAllowed(c *check.C) {
1442 1442
 }
1443 1443
 
1444 1444
 func (s *DockerDaemonSuite) TestRunSeccompJSONNewFormat(c *check.C) {
1445
-	testRequires(c, testEnv.IsLocalDaemon, seccompEnabled)
1445
+	testRequires(c, seccompEnabled)
1446 1446
 
1447 1447
 	s.d.StartWithBusybox(c)
1448 1448
 
... ...
@@ -1467,7 +1467,7 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNewFormat(c *check.C) {
1467 1467
 }
1468 1468
 
1469 1469
 func (s *DockerDaemonSuite) TestRunSeccompJSONNoNameAndNames(c *check.C) {
1470
-	testRequires(c, testEnv.IsLocalDaemon, seccompEnabled)
1470
+	testRequires(c, seccompEnabled)
1471 1471
 
1472 1472
 	s.d.StartWithBusybox(c)
1473 1473
 
... ...
@@ -1493,7 +1493,7 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNoNameAndNames(c *check.C) {
1493 1493
 }
1494 1494
 
1495 1495
 func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) {
1496
-	testRequires(c, testEnv.IsLocalDaemon, seccompEnabled)
1496
+	testRequires(c, seccompEnabled)
1497 1497
 
1498 1498
 	s.d.StartWithBusybox(c)
1499 1499
 
... ...
@@ -1530,7 +1530,7 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) {
1530 1530
 }
1531 1531
 
1532 1532
 func (s *DockerDaemonSuite) TestRunWithDaemonDefaultSeccompProfile(c *check.C) {
1533
-	testRequires(c, testEnv.IsLocalDaemon, seccompEnabled)
1533
+	testRequires(c, seccompEnabled)
1534 1534
 
1535 1535
 	s.d.StartWithBusybox(c)
1536 1536
 
... ...
@@ -28,7 +28,7 @@ func (s *DockerSwarmSuite) TestServiceHealthRun(c *check.C) {
28 28
 	result := cli.BuildCmd(c, imageName, cli.Daemon(d),
29 29
 		build.WithDockerfile(`FROM busybox
30 30
 		RUN touch /status
31
-		HEALTHCHECK --interval=1s --timeout=1s --retries=1\
31
+		HEALTHCHECK --interval=1s --timeout=5s --retries=1\
32 32
 		  CMD cat /status`),
33 33
 	)
34 34
 	result.Assert(c, icmd.Success)
... ...
@@ -14,11 +14,11 @@ func (s *DockerSwarmSuite) TestServiceScale(c *check.C) {
14 14
 	d := s.AddDaemon(c, true, true)
15 15
 
16 16
 	service1Name := "TestService1"
17
-	service1Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service1Name, defaultSleepImage}, sleepCommandForDaemonPlatform()...)
17
+	service1Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service1Name, "busybox"}, sleepCommandForDaemonPlatform()...)
18 18
 
19 19
 	// global mode
20 20
 	service2Name := "TestService2"
21
-	service2Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service2Name, "--mode=global", defaultSleepImage}, sleepCommandForDaemonPlatform()...)
21
+	service2Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service2Name, "--mode=global", "busybox"}, sleepCommandForDaemonPlatform()...)
22 22
 
23 23
 	// Create services
24 24
 	_, err := d.Cmd(service1Args...)
... ...
@@ -277,19 +277,23 @@ func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) {
277 277
 	d := s.AddDaemon(c, true, true)
278 278
 
279 279
 	name := "top"
280
+	// this first command does not have to be retried because service creates
281
+	// don't return out of sequence errors.
280 282
 	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--label", "x=y", "busybox", "top")
281 283
 	assert.NilError(c, err, out)
282 284
 	assert.Assert(c, strings.TrimSpace(out) != "")
283 285
 
284
-	out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name)
286
+	out, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", name)
285 287
 	assert.NilError(c, err, out)
286 288
 
287
-	out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name)
289
+	out, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", name)
288 290
 	assert.NilError(c, err, out)
289 291
 
290
-	_, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name)
292
+	_, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name)
291 293
 	assert.ErrorContains(c, err, "")
292 294
 
295
+	// this last command does not have to be retried because service inspect
296
+	// does not return out of sequence errors.
293 297
 	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name)
294 298
 	assert.NilError(c, err, out)
295 299
 	assert.Equal(c, strings.TrimSpace(out), "[{ tcp 80 80 ingress}]")
... ...
@@ -838,7 +842,7 @@ func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) {
838 838
 
839 839
 	name := "top"
840 840
 
841
-	ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi"
841
+	ttyCheck := "if [ -t 0 ]; then echo TTY > /status; else echo none > /status; fi; exec top"
842 842
 
843 843
 	// Without --tty
844 844
 	expectedOutput := "none"
... ...
@@ -23,7 +23,7 @@ import (
23 23
 // 1. validate uid/gid maps are set properly
24 24
 // 2. verify that files created are owned by remapped root
25 25
 func (s *DockerDaemonSuite) TestDaemonUserNamespaceRootSetting(c *check.C) {
26
-	testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon, UserNamespaceInKernel)
26
+	testRequires(c, UserNamespaceInKernel)
27 27
 
28 28
 	s.d.StartWithBusybox(c, "--userns-remap", "default")
29 29
 
... ...
@@ -63,7 +63,7 @@ func getContainerCount(c *check.C) int {
63 63
 	for _, line := range lines {
64 64
 		if strings.Contains(line, containers) {
65 65
 			output := strings.TrimSpace(line)
66
-			output = strings.TrimLeft(output, containers)
66
+			output = strings.TrimPrefix(output, containers)
67 67
 			output = strings.Trim(output, " ")
68 68
 			containerCount, err := strconv.Atoi(output)
69 69
 			assert.NilError(c, err)
... ...
@@ -347,7 +347,7 @@ func getInspectBody(c *check.C, version, id string) []byte {
347 347
 // Run a long running idle task in a background container using the
348 348
 // system-specific default image and command.
349 349
 func runSleepingContainer(c *check.C, extraArgs ...string) string {
350
-	return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
350
+	return runSleepingContainerInImage(c, "busybox", extraArgs...)
351 351
 }
352 352
 
353 353
 // Run a long running idle task in a background container using the specified
... ...
@@ -80,10 +80,6 @@ func UnixCli() bool {
80 80
 	return isUnixCli
81 81
 }
82 82
 
83
-func ExecSupport() bool {
84
-	return supportsExec
85
-}
86
-
87 83
 func Network() bool {
88 84
 	// Set a timeout on the GET at 15s
89 85
 	var timeout = time.Duration(15 * time.Second)
... ...
@@ -84,20 +84,11 @@ func bridgeNfIptables() bool {
84 84
 	return !SysInfo.BridgeNFCallIPTablesDisabled
85 85
 }
86 86
 
87
-func bridgeNfIP6tables() bool {
88
-	return !SysInfo.BridgeNFCallIP6TablesDisabled
89
-}
90
-
91 87
 func unprivilegedUsernsClone() bool {
92 88
 	content, err := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
93 89
 	return err != nil || !strings.Contains(string(content), "0")
94 90
 }
95 91
 
96
-func ambientCapabilities() bool {
97
-	content, err := ioutil.ReadFile("/proc/self/status")
98
-	return err != nil || strings.Contains(string(content), "CapAmb:")
99
-}
100
-
101 92
 func overlayFSSupported() bool {
102 93
 	cmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "cat /proc/filesystems")
103 94
 	out, err := cmd.CombinedOutput()
... ...
@@ -107,20 +98,6 @@ func overlayFSSupported() bool {
107 107
 	return bytes.Contains(out, []byte("overlay\n"))
108 108
 }
109 109
 
110
-func overlay2Supported() bool {
111
-	if !overlayFSSupported() {
112
-		return false
113
-	}
114
-
115
-	daemonV, err := kernel.ParseRelease(testEnv.DaemonInfo.KernelVersion)
116
-	if err != nil {
117
-		return false
118
-	}
119
-	requiredV := kernel.VersionInfo{Kernel: 4}
120
-	return kernel.CompareKernelVersion(*daemonV, requiredV) > -1
121
-
122
-}
123
-
124 110
 func init() {
125 111
 	if testEnv.IsLocalDaemon() {
126 112
 		SysInfo = sysinfo.New(true)
127 113
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-// +build !test_no_exec
2
-
3
-package main
4
-
5
-const (
6
-	// indicates docker daemon tested supports 'docker exec'
7
-	supportsExec = true
8
-)
9 1
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-// +build test_no_exec
2
-
3
-package main
4
-
5
-const (
6
-	// indicates docker daemon tested supports 'docker exec'
7
-	supportsExec = false
8
-)
... ...
@@ -7,8 +7,4 @@ const (
7 7
 	isUnixCli = true
8 8
 
9 9
 	expectedFileChmod = "-rw-r--r--"
10
-
11
-	// On Unix variants, the busybox image comes with the `top` command which
12
-	// runs indefinitely while still being interruptible by a signal.
13
-	defaultSleepImage = "busybox"
14 10
 )
... ...
@@ -8,8 +8,4 @@ const (
8 8
 
9 9
 	// this is the expected file permission set on windows: gh#11395
10 10
 	expectedFileChmod = "-rwxr-xr-x"
11
-
12
-	// On Windows, the busybox image doesn't have the `top` command, so we rely
13
-	// on `sleep` with a high duration.
14
-	defaultSleepImage = "busybox"
15 11
 )
... ...
@@ -9,8 +9,8 @@ import (
9 9
 	"testing"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/api/types/versions"
12 13
 	dclient "github.com/docker/docker/client"
13
-	"github.com/docker/docker/internal/test/daemon"
14 14
 	"github.com/docker/docker/internal/test/fakecontext"
15 15
 	"github.com/docker/docker/internal/test/request"
16 16
 	"github.com/moby/buildkit/session"
... ...
@@ -23,18 +23,9 @@ import (
23 23
 
24 24
 func TestBuildWithSession(t *testing.T) {
25 25
 	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
26
+	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions")
26 27
 
27
-	var client dclient.APIClient
28
-	if !testEnv.DaemonInfo.ExperimentalBuild {
29
-		skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
30
-
31
-		d := daemon.New(t, daemon.WithExperimental)
32
-		d.StartWithBusybox(t)
33
-		defer d.Stop(t)
34
-		client = d.NewClientT(t)
35
-	} else {
36
-		client = testEnv.APIClient()
37
-	}
28
+	client := testEnv.APIClient()
38 29
 
39 30
 	dockerfile := `
40 31
 		FROM busybox
... ...
@@ -100,7 +100,7 @@ func TestBuildSquashParent(t *testing.T) {
100 100
 	)
101 101
 	container.Run(ctx, t, client,
102 102
 		container.WithImage(name),
103
-		container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" == "world" ]`),
103
+		container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" = "world" ]`),
104 104
 	)
105 105
 
106 106
 	origHistory, err := client.ImageHistory(ctx, origID)
... ...
@@ -1,6 +1,6 @@
1 1
 // +build !windows
2 2
 
3
-package ipvlan
3
+package ipvlan // import "github.com/docker/docker/integration/network/ipvlan"
4 4
 
5 5
 import (
6 6
 	"context"
... ...
@@ -22,11 +22,10 @@ import (
22 22
 
23 23
 func TestDockerNetworkIpvlanPersistance(t *testing.T) {
24 24
 	// verify the driver automatically provisions the 802.1q link (di-dummy0.70)
25
-	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
26 25
 	skip.If(t, testEnv.IsRemoteDaemon)
27 26
 	skip.If(t, !ipvlanKernelSupport(t), "Kernel doesn't support ipvlan")
28 27
 
29
-	d := daemon.New(t, daemon.WithExperimental)
28
+	d := daemon.New(t)
30 29
 	d.StartWithBusybox(t)
31 30
 	defer d.Stop(t)
32 31
 
... ...
@@ -50,7 +49,6 @@ func TestDockerNetworkIpvlanPersistance(t *testing.T) {
50 50
 }
51 51
 
52 52
 func TestDockerNetworkIpvlan(t *testing.T) {
53
-	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
54 53
 	skip.If(t, testEnv.IsRemoteDaemon)
55 54
 	skip.If(t, !ipvlanKernelSupport(t), "Kernel doesn't support ipvlan")
56 55
 
... ...
@@ -87,7 +85,7 @@ func TestDockerNetworkIpvlan(t *testing.T) {
87 87
 			test: testIpvlanAddressing,
88 88
 		},
89 89
 	} {
90
-		d := daemon.New(t, daemon.WithExperimental)
90
+		d := daemon.New(t)
91 91
 		d.StartWithBusybox(t)
92 92
 		c := d.NewClientT(t)
93 93
 
... ...
@@ -1,3 +1,5 @@
1
+// +build !windows
2
+
1 3
 package ipvlan // import "github.com/docker/docker/integration/network/ipvlan"
2 4
 
3 5
 import (
4 6
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+package ipvlan // import "github.com/docker/docker/integration/network/ipvlan"
... ...
@@ -1,6 +1,6 @@
1 1
 // +build !windows
2 2
 
3
-package macvlan
3
+package macvlan // import "github.com/docker/docker/integration/network/macvlan"
4 4
 
5 5
 import (
6 6
 	"context"
... ...
@@ -20,7 +20,6 @@ import (
20 20
 func TestDockerNetworkMacvlanPersistance(t *testing.T) {
21 21
 	// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
22 22
 	skip.If(t, testEnv.IsRemoteDaemon)
23
-	skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan")
24 23
 
25 24
 	d := daemon.New(t)
26 25
 	d.StartWithBusybox(t)
... ...
@@ -43,7 +42,6 @@ func TestDockerNetworkMacvlanPersistance(t *testing.T) {
43 43
 
44 44
 func TestDockerNetworkMacvlan(t *testing.T) {
45 45
 	skip.If(t, testEnv.IsRemoteDaemon)
46
-	skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan")
47 46
 
48 47
 	for _, tc := range []struct {
49 48
 		name string
... ...
@@ -271,8 +269,3 @@ func testMacvlanAddressing(client client.APIClient) func(*testing.T) {
271 271
 		assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abca::254 dev eth0"))
272 272
 	}
273 273
 }
274
-
275
-// ensure Kernel version is >= v3.9 for macvlan support
276
-func macvlanKernelSupport() bool {
277
-	return n.CheckKernelMajorVersionGreaterOrEqualThen(3, 9)
278
-}
... ...
@@ -1,3 +1,5 @@
1
+// +build !windows
2
+
1 3
 package macvlan // import "github.com/docker/docker/integration/network/macvlan"
2 4
 
3 5
 import (
4 6
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+package macvlan // import "github.com/docker/docker/integration/network/macvlan"
... ...
@@ -7,9 +7,7 @@ import (
7 7
 
8 8
 	"github.com/docker/docker/api/types"
9 9
 	"github.com/docker/docker/api/types/container"
10
-	"github.com/docker/docker/api/types/filters"
11 10
 	swarmtypes "github.com/docker/docker/api/types/swarm"
12
-	"github.com/docker/docker/client"
13 11
 	"github.com/docker/docker/integration/internal/swarm"
14 12
 	"github.com/google/go-cmp/cmp"
15 13
 	"gotest.tools/assert"
... ...
@@ -38,7 +36,7 @@ func TestInspect(t *testing.T) {
38 38
 	assert.NilError(t, err)
39 39
 
40 40
 	id := resp.ID
41
-	poll.WaitOn(t, serviceContainerCount(client, id, instances))
41
+	poll.WaitOn(t, swarm.RunningTasksCount(client, id, instances))
42 42
 
43 43
 	service, _, err := client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
44 44
 	assert.NilError(t, err)
... ...
@@ -134,21 +132,3 @@ func fullSwarmServiceSpec(name string, replicas uint64) swarmtypes.ServiceSpec {
134 134
 		},
135 135
 	}
136 136
 }
137
-
138
-func serviceContainerCount(client client.ServiceAPIClient, id string, count uint64) func(log poll.LogT) poll.Result {
139
-	return func(log poll.LogT) poll.Result {
140
-		filter := filters.NewArgs()
141
-		filter.Add("service", id)
142
-		tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
143
-			Filters: filter,
144
-		})
145
-		switch {
146
-		case err != nil:
147
-			return poll.Error(err)
148
-		case len(tasks) == int(count):
149
-			return poll.Success()
150
-		default:
151
-			return poll.Continue("task count at %d waiting for %d", len(tasks), count)
152
-		}
153
-	}
154
-}
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"net/http"
5 5
 	"testing"
6 6
 
7
-	"github.com/docker/docker/internal/test/daemon"
7
+	"github.com/docker/docker/api/types/versions"
8 8
 	req "github.com/docker/docker/internal/test/request"
9 9
 	"gotest.tools/assert"
10 10
 	is "gotest.tools/assert/cmp"
... ...
@@ -13,17 +13,10 @@ import (
13 13
 
14 14
 func TestSessionCreate(t *testing.T) {
15 15
 	skip.If(t, testEnv.OSType == "windows", "FIXME")
16
+	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions")
16 17
 
17 18
 	defer setupTest(t)()
18 19
 	daemonHost := req.DaemonHost()
19
-	if !testEnv.DaemonInfo.ExperimentalBuild {
20
-		skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
21
-
22
-		d := daemon.New(t, daemon.WithExperimental)
23
-		d.StartWithBusybox(t)
24
-		defer d.Stop(t)
25
-		daemonHost = d.Sock()
26
-	}
27 20
 
28 21
 	res, body, err := req.Post("/session",
29 22
 		req.Host(daemonHost),
... ...
@@ -41,17 +34,10 @@ func TestSessionCreate(t *testing.T) {
41 41
 
42 42
 func TestSessionCreateWithBadUpgrade(t *testing.T) {
43 43
 	skip.If(t, testEnv.OSType == "windows", "FIXME")
44
+	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions")
44 45
 
45 46
 	defer setupTest(t)()
46 47
 	daemonHost := req.DaemonHost()
47
-	if !testEnv.DaemonInfo.ExperimentalBuild {
48
-		skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
49
-
50
-		d := daemon.New(t, daemon.WithExperimental)
51
-		d.StartWithBusybox(t)
52
-		defer d.Stop(t)
53
-		daemonHost = d.Sock()
54
-	}
55 48
 
56 49
 	res, body, err := req.Post("/session", req.Host(daemonHost))
57 50
 	assert.NilError(t, err)
... ...
@@ -147,6 +147,11 @@ func New(t testingT, ops ...func(*Daemon)) *Daemon {
147 147
 	return d
148 148
 }
149 149
 
150
+// ContainersNamespace returns the containerd namespace used for containers.
151
+func (d *Daemon) ContainersNamespace() string {
152
+	return d.id
153
+}
154
+
150 155
 // RootDir returns the root directory of the daemon.
151 156
 func (d *Daemon) RootDir() string {
152 157
 	return d.Root
... ...
@@ -231,12 +236,15 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
231 231
 	if err != nil {
232 232
 		return errors.Wrapf(err, "[%s] could not find docker binary in $PATH", d.id)
233 233
 	}
234
+
234 235
 	args := append(d.GlobalFlags,
235 236
 		"--containerd", containerdSocket,
236 237
 		"--data-root", d.Root,
237 238
 		"--exec-root", d.execRoot,
238 239
 		"--pidfile", fmt.Sprintf("%s/docker.pid", d.Folder),
239 240
 		fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
241
+		"--containerd-namespace", d.id,
242
+		"--containerd-plugins-namespace", d.id+"p",
240 243
 	)
241 244
 	if d.experimental {
242 245
 		args = append(args, "--experimental")
... ...
@@ -313,7 +321,7 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
313 313
 	defer cancel()
314 314
 
315 315
 	// make sure daemon is ready to receive requests
316
-	for {
316
+	for i := 0; ; i++ {
317 317
 		d.log.Logf("[%s] waiting for daemon to start", d.id)
318 318
 
319 319
 		select {
... ...
@@ -327,9 +335,14 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
327 327
 
328 328
 			resp, err := client.Do(req.WithContext(rctx))
329 329
 			if err != nil {
330
-				d.log.Logf("[%s] error pinging daemon on start: %v", d.id, err)
331
-
332
-				time.Sleep(500 * time.Millisecond)
330
+				if i > 2 { // don't log the first couple, this ends up just being noise
331
+					d.log.Logf("[%s] error pinging daemon on start: %v", d.id, err)
332
+				}
333
+
334
+				select {
335
+				case <-ctx.Done():
336
+				case <-time.After(500 * time.Millisecond):
337
+				}
333 338
 				continue
334 339
 			}
335 340
 
... ...
@@ -700,8 +713,10 @@ func cleanupRaftDir(t testingT, rootPath string) {
700 700
 	if ht, ok := t.(test.HelperT); ok {
701 701
 		ht.Helper()
702 702
 	}
703
-	walDir := filepath.Join(rootPath, "swarm/raft/wal")
704
-	if err := os.RemoveAll(walDir); err != nil {
705
-		t.Logf("error removing %v: %v", walDir, err)
703
+	for _, p := range []string{"wal", "wal-v3-encrypted", "snap-v3-encrypted"} {
704
+		dir := filepath.Join(rootPath, "swarm/raft", p)
705
+		if err := os.RemoveAll(dir); err != nil {
706
+			t.Logf("error removing %v: %v", dir, err)
707
+		}
706 708
 	}
707 709
 }
... ...
@@ -20,12 +20,19 @@ var (
20 20
 	startArgs = []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
21 21
 )
22 22
 
23
-// StartNode starts daemon to be used as a swarm node
23
+// StartNode (re)starts the daemon
24 24
 func (d *Daemon) StartNode(t testingT) {
25 25
 	if ht, ok := t.(test.HelperT); ok {
26 26
 		ht.Helper()
27 27
 	}
28
-	// avoid networking conflicts
28
+	d.Start(t, startArgs...)
29
+}
30
+
31
+// StartNodeWithBusybox starts daemon to be used as a swarm node, and loads the busybox image
32
+func (d *Daemon) StartNodeWithBusybox(t testingT) {
33
+	if ht, ok := t.(test.HelperT); ok {
34
+		ht.Helper()
35
+	}
29 36
 	d.StartWithBusybox(t, startArgs...)
30 37
 }
31 38
 
... ...
@@ -36,24 +43,28 @@ func (d *Daemon) RestartNode(t testingT) {
36 36
 	}
37 37
 	// avoid networking conflicts
38 38
 	d.Stop(t)
39
-	d.StartWithBusybox(t, startArgs...)
39
+	d.Start(t, startArgs...)
40 40
 }
41 41
 
42 42
 // StartAndSwarmInit starts the daemon (with busybox) and init the swarm
43 43
 func (d *Daemon) StartAndSwarmInit(t testingT) {
44
-	d.StartNode(t)
44
+	d.StartNodeWithBusybox(t)
45 45
 	d.SwarmInit(t, swarm.InitRequest{})
46 46
 }
47 47
 
48 48
 // StartAndSwarmJoin starts the daemon (with busybox) and join the specified swarm as worker or manager
49 49
 func (d *Daemon) StartAndSwarmJoin(t testingT, leader *Daemon, manager bool) {
50
-	d.StartNode(t)
50
+	if th, ok := t.(test.HelperT); ok {
51
+		th.Helper()
52
+	}
53
+	d.StartNodeWithBusybox(t)
51 54
 
52 55
 	tokens := leader.JoinTokens(t)
53 56
 	token := tokens.Worker
54 57
 	if manager {
55 58
 		token = tokens.Manager
56 59
 	}
60
+	t.Logf("[%s] joining swarm manager [%s]@%s, swarm listen addr %s", d.id, leader.id, leader.SwarmListenAddr(), d.SwarmListenAddr())
57 61
 	d.SwarmJoin(t, swarm.JoinRequest{
58 62
 		RemoteAddrs: []string{leader.SwarmListenAddr()},
59 63
 		JoinToken:   token,
... ...
@@ -106,7 +117,7 @@ func (d *Daemon) SwarmJoin(t assert.TestingT, req swarm.JoinRequest) {
106 106
 	cli := d.NewClientT(t)
107 107
 	defer cli.Close()
108 108
 	err := cli.SwarmJoin(context.Background(), req)
109
-	assert.NilError(t, err, "initializing swarm")
109
+	assert.NilError(t, err, "[%s] joining swarm", d.id)
110 110
 	d.CachedInfo = d.Info(t)
111 111
 }
112 112
 
... ...
@@ -2,7 +2,6 @@ package term // import "github.com/docker/docker/pkg/term"
2 2
 
3 3
 import (
4 4
 	"bytes"
5
-	"fmt"
6 5
 	"testing"
7 6
 
8 7
 	"gotest.tools/assert"
... ...
@@ -10,106 +9,143 @@ import (
10 10
 )
11 11
 
12 12
 func TestEscapeProxyRead(t *testing.T) {
13
-	escapeKeys, _ := ToBytes("")
14
-	keys, _ := ToBytes("a")
15
-	reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
16
-	buf := make([]byte, len(keys))
17
-	nr, err := reader.Read(buf)
18
-	assert.NilError(t, err)
19
-	assert.Equal(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys)))
20
-	assert.DeepEqual(t, keys, buf)
21
-
22
-	keys, _ = ToBytes("a,b,c")
23
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
24
-	buf = make([]byte, len(keys))
25
-	nr, err = reader.Read(buf)
26
-	assert.NilError(t, err)
27
-	assert.Equal(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys)))
28
-	assert.DeepEqual(t, keys, buf)
29
-
30
-	keys, _ = ToBytes("")
31
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
32
-	buf = make([]byte, len(keys))
33
-	nr, err = reader.Read(buf)
34
-	assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read")
35
-	assert.Equal(t, nr, 0, "nr should be zero")
36
-	assert.Check(t, is.Len(keys, 0))
37
-	assert.Check(t, is.Len(buf, 0))
38
-
39
-	escapeKeys, _ = ToBytes("DEL")
40
-	keys, _ = ToBytes("a,b,c,+")
41
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
42
-	buf = make([]byte, len(keys))
43
-	nr, err = reader.Read(buf)
44
-	assert.NilError(t, err)
45
-	assert.Equal(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys)))
46
-	assert.DeepEqual(t, keys, buf)
47
-
48
-	keys, _ = ToBytes("")
49
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
50
-	buf = make([]byte, len(keys))
51
-	nr, err = reader.Read(buf)
52
-	assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read")
53
-	assert.Equal(t, nr, 0, "nr should be zero")
54
-	assert.Check(t, is.Len(keys, 0))
55
-	assert.Check(t, is.Len(buf, 0))
56
-
57
-	escapeKeys, _ = ToBytes("ctrl-x,ctrl-@")
58
-	keys, _ = ToBytes("DEL")
59
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
60
-	buf = make([]byte, len(keys))
61
-	nr, err = reader.Read(buf)
62
-	assert.NilError(t, err)
63
-	assert.Equal(t, nr, 1, fmt.Sprintf("nr %d should be equal to the number of 1", nr))
64
-	assert.DeepEqual(t, keys, buf)
65
-
66
-	escapeKeys, _ = ToBytes("ctrl-c")
67
-	keys, _ = ToBytes("ctrl-c")
68
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
69
-	buf = make([]byte, len(keys))
70
-	nr, err = reader.Read(buf)
71
-	assert.Error(t, err, "read escape sequence")
72
-	assert.Equal(t, nr, 0, "nr should be equal to 0")
73
-	assert.DeepEqual(t, keys, buf)
74
-
75
-	escapeKeys, _ = ToBytes("ctrl-c,ctrl-z")
76
-	keys, _ = ToBytes("ctrl-c,ctrl-z")
77
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
78
-	buf = make([]byte, 1)
79
-	nr, err = reader.Read(buf)
80
-	assert.NilError(t, err)
81
-	assert.Equal(t, nr, 0, "nr should be equal to 0")
82
-	assert.DeepEqual(t, keys[0:1], buf)
83
-	nr, err = reader.Read(buf)
84
-	assert.Error(t, err, "read escape sequence")
85
-	assert.Equal(t, nr, 0, "nr should be equal to 0")
86
-	assert.DeepEqual(t, keys[1:], buf)
87
-
88
-	escapeKeys, _ = ToBytes("ctrl-c,ctrl-z")
89
-	keys, _ = ToBytes("ctrl-c,DEL,+")
90
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
91
-	buf = make([]byte, 1)
92
-	nr, err = reader.Read(buf)
93
-	assert.NilError(t, err)
94
-	assert.Equal(t, nr, 0, "nr should be equal to 0")
95
-	assert.DeepEqual(t, keys[0:1], buf)
96
-	buf = make([]byte, len(keys))
97
-	nr, err = reader.Read(buf)
98
-	assert.NilError(t, err)
99
-	assert.Equal(t, nr, len(keys), fmt.Sprintf("nr should be equal to %d", len(keys)))
100
-	assert.DeepEqual(t, keys, buf)
101
-
102
-	escapeKeys, _ = ToBytes("ctrl-c,ctrl-z")
103
-	keys, _ = ToBytes("ctrl-c,DEL")
104
-	reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
105
-	buf = make([]byte, 1)
106
-	nr, err = reader.Read(buf)
107
-	assert.NilError(t, err)
108
-	assert.Equal(t, nr, 0, "nr should be equal to 0")
109
-	assert.DeepEqual(t, keys[0:1], buf)
110
-	buf = make([]byte, len(keys))
111
-	nr, err = reader.Read(buf)
112
-	assert.NilError(t, err)
113
-	assert.Equal(t, nr, len(keys), fmt.Sprintf("nr should be equal to %d", len(keys)))
114
-	assert.DeepEqual(t, keys, buf)
13
+	t.Run("no escape keys, keys a", func(t *testing.T) {
14
+		escapeKeys, _ := ToBytes("")
15
+		keys, _ := ToBytes("a")
16
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
17
+
18
+		buf := make([]byte, len(keys))
19
+		nr, err := reader.Read(buf)
20
+		assert.NilError(t, err)
21
+		assert.Equal(t, nr, len(keys))
22
+		assert.DeepEqual(t, keys, buf)
23
+	})
24
+
25
+	t.Run("no escape keys, keys a,b,c", func(t *testing.T) {
26
+		escapeKeys, _ := ToBytes("")
27
+		keys, _ := ToBytes("a,b,c")
28
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
29
+
30
+		buf := make([]byte, len(keys))
31
+		nr, err := reader.Read(buf)
32
+		assert.NilError(t, err)
33
+		assert.Equal(t, nr, len(keys))
34
+		assert.DeepEqual(t, keys, buf)
35
+	})
36
+
37
+	t.Run("no escape keys, no keys", func(t *testing.T) {
38
+		escapeKeys, _ := ToBytes("")
39
+		keys, _ := ToBytes("")
40
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
41
+
42
+		buf := make([]byte, len(keys))
43
+		nr, err := reader.Read(buf)
44
+		assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read")
45
+		assert.Equal(t, nr, 0)
46
+		assert.Check(t, is.Len(keys, 0))
47
+		assert.Check(t, is.Len(buf, 0))
48
+	})
49
+
50
+	t.Run("DEL escape key, keys a,b,c,+", func(t *testing.T) {
51
+		escapeKeys, _ := ToBytes("DEL")
52
+		keys, _ := ToBytes("a,b,c,+")
53
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
54
+
55
+		buf := make([]byte, len(keys))
56
+		nr, err := reader.Read(buf)
57
+		assert.NilError(t, err)
58
+		assert.Equal(t, nr, len(keys))
59
+		assert.DeepEqual(t, keys, buf)
60
+	})
61
+
62
+	t.Run("DEL escape key, no keys", func(t *testing.T) {
63
+		escapeKeys, _ := ToBytes("DEL")
64
+		keys, _ := ToBytes("")
65
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
66
+
67
+		buf := make([]byte, len(keys))
68
+		nr, err := reader.Read(buf)
69
+		assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read")
70
+		assert.Equal(t, nr, 0)
71
+		assert.Check(t, is.Len(keys, 0))
72
+		assert.Check(t, is.Len(buf, 0))
73
+	})
74
+
75
+	t.Run("ctrl-x,ctrl-@ escape key, keys DEL", func(t *testing.T) {
76
+		escapeKeys, _ := ToBytes("ctrl-x,ctrl-@")
77
+		keys, _ := ToBytes("DEL")
78
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
79
+
80
+		buf := make([]byte, len(keys))
81
+		nr, err := reader.Read(buf)
82
+		assert.NilError(t, err)
83
+		assert.Equal(t, nr, 1)
84
+		assert.DeepEqual(t, keys, buf)
85
+	})
86
+
87
+	t.Run("ctrl-c escape key, keys ctrl-c", func(t *testing.T) {
88
+		escapeKeys, _ := ToBytes("ctrl-c")
89
+		keys, _ := ToBytes("ctrl-c")
90
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
91
+
92
+		buf := make([]byte, len(keys))
93
+		nr, err := reader.Read(buf)
94
+		assert.Error(t, err, "read escape sequence")
95
+		assert.Equal(t, nr, 0)
96
+		assert.DeepEqual(t, keys, buf)
97
+	})
98
+
99
+	t.Run("ctrl-c,ctrl-z escape key, keys ctrl-c,ctrl-z", func(t *testing.T) {
100
+		escapeKeys, _ := ToBytes("ctrl-c,ctrl-z")
101
+		keys, _ := ToBytes("ctrl-c,ctrl-z")
102
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
103
+
104
+		buf := make([]byte, 1)
105
+		nr, err := reader.Read(buf)
106
+		assert.NilError(t, err)
107
+		assert.Equal(t, nr, 0)
108
+		assert.DeepEqual(t, keys[0:1], buf)
109
+
110
+		nr, err = reader.Read(buf)
111
+		assert.Error(t, err, "read escape sequence")
112
+		assert.Equal(t, nr, 0)
113
+		assert.DeepEqual(t, keys[1:], buf)
114
+	})
115
+
116
+	t.Run("ctrl-c,ctrl-z escape key, keys ctrl-c,DEL,+", func(t *testing.T) {
117
+		escapeKeys, _ := ToBytes("ctrl-c,ctrl-z")
118
+		keys, _ := ToBytes("ctrl-c,DEL,+")
119
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
120
+
121
+		buf := make([]byte, 1)
122
+		nr, err := reader.Read(buf)
123
+		assert.NilError(t, err)
124
+		assert.Equal(t, nr, 0)
125
+		assert.DeepEqual(t, keys[0:1], buf)
126
+
127
+		buf = make([]byte, len(keys))
128
+		nr, err = reader.Read(buf)
129
+		assert.NilError(t, err)
130
+		assert.Equal(t, nr, len(keys))
131
+		assert.DeepEqual(t, keys, buf)
132
+	})
133
+
134
+	t.Run("ctrl-c,ctrl-z escape key, keys ctrl-c,DEL", func(t *testing.T) {
135
+		escapeKeys, _ := ToBytes("ctrl-c,ctrl-z")
136
+		keys, _ := ToBytes("ctrl-c,DEL")
137
+		reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
138
+
139
+		buf := make([]byte, 1)
140
+		nr, err := reader.Read(buf)
141
+		assert.NilError(t, err)
142
+		assert.Equal(t, nr, 0)
143
+		assert.DeepEqual(t, keys[0:1], buf)
144
+
145
+		buf = make([]byte, len(keys))
146
+		nr, err = reader.Read(buf)
147
+		assert.NilError(t, err)
148
+		assert.Equal(t, nr, len(keys))
149
+		assert.DeepEqual(t, keys, buf)
150
+	})
151
+
115 152
 }
... ...
@@ -26,13 +26,13 @@ type ExitHandler interface {
26 26
 }
27 27
 
28 28
 // New creates a new containerd plugin executor
29
-func New(ctx context.Context, rootDir string, cli *containerd.Client, exitHandler ExitHandler) (*Executor, error) {
29
+func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler) (*Executor, error) {
30 30
 	e := &Executor{
31 31
 		rootDir:     rootDir,
32 32
 		exitHandler: exitHandler,
33 33
 	}
34 34
 
35
-	client, err := libcontainerd.NewClient(ctx, cli, rootDir, PluginNamespace, e)
35
+	client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e)
36 36
 	if err != nil {
37 37
 		return nil, errors.Wrap(err, "error creating containerd exec client")
38 38
 	}