Repository: containerd/containerd
File: core/mount/mount_linux_test.go (Go)

Code before:
	testCases := []struct {
		name                    string
		lowerDirs               []string
		tmpDir                  string
		callbackFailure         bool
		callbackFailureDuration time.Duration // Duration of 0 means to fail all the time (if callbackFailure is true).
		success                 bool
	}{
		{
			name:      "mount failure",
			lowerDirs: []string{"/non/existent/path"},
		},
		{
			name:      "tmpdir creation failure",
			lowerDirs: []string{"/non/existent/path"},
			tmpDir:    "/non/existent/",
		},
		{
			name:            "cleanup callback failure",
			callbackFailure: true,
			success:         true,
		},
		{
			name:                    "cleanup callback short failure",
			callbackFailure:         true,
			callbackFailureDuration: unmountRetryDelay * 2, // Duration of 2x unmountRetryDelay means it will fail for about two retries.
			success:                 true,
		},
		{
			name:    "all fine",
			success: true,
		},
	}

	usernsFD, err := getUsernsFD(testUIDMaps, testGIDMaps)
	require.NoError(t, err)
	defer usernsFD.Close()

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			tmpDir := tc.tmpDir
			if tmpDir == "" {
				tmpDir = t.TempDir()
			}
			lowerDirs := tc.lowerDirs
			if len(lowerDirs) == 0 {
				// Create a temporary directory with a file to simulate lowerDirs
				dir := t.TempDir()
				require.NoError(t, os.Mkdir(dir+"/l", 0755))
				require.NoError(t, os.WriteFile(dir+"/l/bar", []byte("foo"), 0644))
				lowerDirs = []string{dir + "/l"}

Review comment (suggestion):
based on my experience, the CI env is not stable and the CI provider could be overcommitted to run multiple jobs in one node. Once that node is busy, it's easy to be flaky. I don't know how to handle it. may we can implement specific umountWithRetry for IdMapping (it could have more retry) so that we can verify that retry logic.

Code after:
		name            string
		lowerDirs       []string
		tmpDir          string
		callbackFailure bool
		success         bool
	}{
		{
			name:      "mount failure",
			lowerDirs: []string{"/non/existent/path"},
		},
		{
			name:      "tmpdir creation failure",
			lowerDirs: []string{"/non/existent/path"},
			tmpDir:    "/non/existent/",
		},
		{
			name:            "cleanup callback failure",
			callbackFailure: true,
			success:         true,
		},
		{
			name:    "all fine",
			success: true,
		},
	}

	usernsFD, err := getUsernsFD(testUIDMaps, testGIDMaps)
	require.NoError(t, err)
	defer usernsFD.Close()

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			tmpDir := tc.tmpDir
			if tmpDir == "" {
				tmpDir = t.TempDir()
			}
			lowerDirs := tc.lowerDirs
			if len(lowerDirs) == 0 {
				// Create a temporary directory with a file to simulate lowerDirs
				dir := t.TempDir()
				require.NoError(t, os.Mkdir(dir+"/l", 0755))
				require.NoError(t, os.WriteFile(dir+"/l/bar", []byte("foo"), 0644))
				lowerDirs = []string{dir + "/l"}
			}

			retLowerDirs, cleanup, err := doPrepareIDMappedOverlay(tmpDir, lowerDirs, int(usernsFD.Fd()))
			if tc.success && err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if !tc.success && err == nil {
				t.Fatal("expected error but got none")