package runconfig // import "github.com/docker/docker/runconfig" import ( "bytes" "encoding/json" "fmt" "os" "runtime" "strings" "testing" "github.com/docker/docker/api/types/container" networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/pkg/sysinfo" ) type f struct { file string entrypoint strslice.StrSlice } func TestDecodeContainerConfig(t *testing.T) { var ( fixtures []f imgName string ) // FIXME (thaJeztah): update fixtures for more current versions. if runtime.GOOS != "windows" { imgName = "ubuntu" fixtures = []f{ {"fixtures/unix/container_config_1_19.json", strslice.StrSlice{"bash"}}, } } else { imgName = "windows" fixtures = []f{ {"fixtures/windows/container_config_1_19.json", strslice.StrSlice{"cmd"}}, } } for _, f := range fixtures { f := f t.Run(f.file, func(t *testing.T) { b, err := os.ReadFile(f.file) if err != nil { t.Fatal(err) } c, h, _, err := decodeContainerConfig(bytes.NewReader(b), sysinfo.New()) if err != nil { t.Fatal(err) } if c.Image != imgName { t.Fatalf("Expected %s image, found %s", imgName, c.Image) } if len(c.Entrypoint) != len(f.entrypoint) { t.Fatalf("Expected %v, found %v", f.entrypoint, c.Entrypoint) } if h != nil && h.Memory != 1000 { t.Fatalf("Expected memory to be 1000, found %d", h.Memory) } }) } } // TestDecodeContainerConfigIsolation validates isolation passed // to the daemon in the hostConfig structure. Note this is platform specific // as to what level of container isolation is supported. func TestDecodeContainerConfigIsolation(t *testing.T) { // An Invalid isolation level if _, _, _, err := callDecodeContainerConfigIsolation("invalid"); err != nil { if !strings.Contains(err.Error(), `Invalid isolation: "invalid"`) { t.Fatal(err) } } // Blank isolation (== default) if _, _, _, err := callDecodeContainerConfigIsolation(""); err != nil { t.Fatal("Blank isolation should have succeeded") } // Default isolation if _, _, _, err := callDecodeContainerConfigIsolation("default"); err != nil { t.Fatal("default isolation should have succeeded") } // Process isolation (Valid on Windows only) if runtime.GOOS == "windows" { if _, _, _, err := callDecodeContainerConfigIsolation("process"); err != nil { t.Fatal("process isolation should have succeeded") } } else { if _, _, _, err := callDecodeContainerConfigIsolation("process"); err != nil { if !strings.Contains(err.Error(), `Invalid isolation: "process"`) { t.Fatal(err) } } } // Hyper-V Containers isolation (Valid on Windows only) if runtime.GOOS == "windows" { if _, _, _, err := callDecodeContainerConfigIsolation("hyperv"); err != nil { t.Fatal("hyperv isolation should have succeeded") } } else { if _, _, _, err := callDecodeContainerConfigIsolation("hyperv"); err != nil { if !strings.Contains(err.Error(), `Invalid isolation: "hyperv"`) { t.Fatal(err) } } } } // callDecodeContainerConfigIsolation is a utility function to call // DecodeContainerConfig for validating isolation func callDecodeContainerConfigIsolation(isolation string) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { var ( b []byte err error ) w := ContainerConfigWrapper{ Config: &container.Config{}, HostConfig: &container.HostConfig{ NetworkMode: "none", Isolation: container.Isolation(isolation), }, } if b, err = json.Marshal(w); err != nil { return nil, nil, nil, fmt.Errorf("Error on marshal %s", err.Error()) } return decodeContainerConfig(bytes.NewReader(b), sysinfo.New()) }