Files
moby/daemon/image_store_choice_test.go
Paweł Gronowski 391247ce96 daemon: Fix image store choice priority for prior graphdriver state
The priority order for determining image store choice was incorrect when
a prior graphdriver existed.

The issue occurred because the prior graphdriver check happened after
processing explicit driver configuration, effectively ignoring user
intent when prior state existed.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 10:05:49 +01:00

270 lines
6.8 KiB
Go

package daemon
import (
"slices"
"testing"
"github.com/moby/moby/v2/daemon/config"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestDetermineImageStoreChoice(t *testing.T) {
str := func(s string) *string {
return &s
}
type testCase struct {
name string
envDockerDriver *string
envTestUseGraphDriver *string
priorGraphDriver bool
cfg *config.Config
expectedChoice imageStoreChoice
expectError bool
skipPlatform string
onlyPlatform string
}
tests := []testCase{
{
name: "containerd-snapshotter feature enabled",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{
"containerd-snapshotter": true,
},
},
},
expectedChoice: imageStoreChoiceContainerdExplicit,
},
{
name: "containerd-snapshotter feature disabled",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{
"containerd-snapshotter": false,
},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
},
{
name: "TEST_INTEGRATION_USE_GRAPHDRIVER env var set",
envTestUseGraphDriver: str("1"),
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
},
{
name: "TEST_INTEGRATION_USE_GRAPHDRIVER takes precedence over feature flag",
envTestUseGraphDriver: str("1"),
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{
"containerd-snapshotter": true,
},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
},
{
name: "native driver in config",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: "native",
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceContainerdExplicit,
},
{
name: "vfs driver in config",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: "vfs",
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
},
{
name: "custom snapshotter",
envDockerDriver: str("my-custom-snapshotter"),
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceContainerdExplicit,
},
}
nonWindows := []testCase{
{
name: "default containerd on non-Windows",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceContainerd,
},
}
for _, gd := range []string{"fuse-overlayfs", "overlay2", "btrfs", "zfs"} {
nonWindows = append(nonWindows, testCase{
name: gd + " driver in config",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: gd,
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
})
nonWindows = append(nonWindows, testCase{
name: gd + " driver in config with prior data",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: gd,
Features: map[string]bool{},
},
},
priorGraphDriver: true,
expectedChoice: imageStoreChoiceGraphdriverPrior,
})
nonWindows = append(nonWindows, testCase{
name: gd + " driver in config with containerd snapshotter feature enabled",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: gd,
Features: map[string]bool{
"containerd-snapshotter": true,
},
},
},
expectedChoice: imageStoreChoiceContainerdExplicit,
})
nonWindows = append(nonWindows, testCase{
name: gd + " driver in config with containerd snapshotter feature disabled",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: gd,
Features: map[string]bool{
"containerd-snapshotter": false,
},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
})
nonWindows = append(nonWindows, testCase{
name: gd + " driver in config with TEST_INTEGRATION_USE_GRAPHDRIVER env var set",
envTestUseGraphDriver: str("1"),
cfg: &config.Config{
CommonConfig: config.CommonConfig{
GraphDriver: gd,
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
})
}
windows := []testCase{
{
name: "default graphdriver on Windows",
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceGraphdriver,
},
{
name: "windows driver on Windows",
envDockerDriver: str("windows"),
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceContainerdExplicit,
},
{
name: "windowsfilter driver on Windows",
envDockerDriver: str("windowsfilter"),
cfg: &config.Config{
CommonConfig: config.CommonConfig{
Features: map[string]bool{},
},
},
expectedChoice: imageStoreChoiceGraphdriverExplicit,
},
}
for i := range nonWindows {
nonWindows[i].skipPlatform = "windows"
}
tests = append(tests, nonWindows...)
for i := range windows {
windows[i].onlyPlatform = "windows"
}
tests = append(tests, windows...)
registeredDrivers := []string{"fuse-overlayfs", "overlay2", "btrfs", "zfs", "vfs"}
windowsRegisteredDrivers := []string{"vfs", "windowsfilter"}
for _, os := range []string{"linux", "windows"} {
for _, tc := range tests {
if tc.skipPlatform != "" && os == tc.skipPlatform {
continue
}
if tc.onlyPlatform != "" && os != tc.onlyPlatform {
continue
}
t.Run(os+"/"+tc.name, func(t *testing.T) {
if tc.envDockerDriver != nil {
t.Setenv("DOCKER_DRIVER", *tc.envDockerDriver)
} else {
t.Setenv("DOCKER_DRIVER", "")
}
if tc.envTestUseGraphDriver != nil {
t.Setenv("TEST_INTEGRATION_USE_GRAPHDRIVER", *tc.envTestUseGraphDriver)
} else {
t.Setenv("TEST_INTEGRATION_USE_GRAPHDRIVER", "")
}
choice, err := determineImageStoreChoice(tc.cfg, determineImageStoreChoiceOptions{
runtimeOS: os,
hasPriorDriver: func(root string) bool {
return tc.priorGraphDriver
},
isRegisteredGraphdriver: func(driverName string) bool {
if os == "windows" {
return slices.Contains(windowsRegisteredDrivers, driverName)
}
return slices.Contains(registeredDrivers, driverName)
},
})
if tc.expectError {
assert.Error(t, err, "expected an error but got none")
} else {
assert.NilError(t, err)
}
assert.Check(t, is.Equal(tc.expectedChoice, choice))
})
}
}
}