1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
package docker
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"testing"
)
func TestCreateContainer(t *testing.T) {
t.Parallel()
jsonContainer := `{
"Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
"Warnings": []
}`
var expected Container
err := json.Unmarshal([]byte(jsonContainer), &expected)
if err != nil {
t.Fatal(err)
}
fakeRT := &FakeRoundTripper{message: jsonContainer, status: http.StatusOK}
client := newTestClient(fakeRT)
config := Config{AttachStdout: true, AttachStdin: true}
opts := CreateContainerOptions{Name: "TestCreateContainer", Config: &config}
container, err := client.CreateContainer(opts)
if err != nil {
t.Fatal(err)
}
id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
if container.ID != id {
t.Errorf("CreateContainer: wrong ID. Want %q. Got %q.", id, container.ID)
}
req := fakeRT.requests[0]
if req.Method != http.MethodPost {
t.Errorf("CreateContainer: wrong HTTP method. Want %q. Got %q.", http.MethodPost, req.Method)
}
expectedURL, _ := url.Parse(client.getURL("/containers/create"))
if gotPath := req.URL.Path; gotPath != expectedURL.Path {
t.Errorf("CreateContainer: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
}
var gotBody Config
err = json.NewDecoder(req.Body).Decode(&gotBody)
if err != nil {
t.Fatal(err)
}
}
func TestCreateContainerImageNotFound(t *testing.T) {
t.Parallel()
client := newTestClient(&FakeRoundTripper{message: "No such image: whatever", status: http.StatusNotFound})
config := Config{AttachStdout: true, AttachStdin: true}
container, err := client.CreateContainer(CreateContainerOptions{Config: &config})
if container != nil {
t.Errorf("CreateContainer: expected <nil> container, got %#v.", container)
}
if !errors.Is(err, ErrNoSuchImage) {
t.Errorf("CreateContainer: Wrong error type. Want %#v. Got %#v.", ErrNoSuchImage, err)
}
}
func TestCreateContainerDuplicateName(t *testing.T) {
t.Parallel()
client := newTestClient(&FakeRoundTripper{message: "No such image", status: http.StatusConflict})
config := Config{AttachStdout: true, AttachStdin: true}
container, err := client.CreateContainer(CreateContainerOptions{Config: &config})
if container != nil {
t.Errorf("CreateContainer: expected <nil> container, got %#v.", container)
}
if !errors.Is(err, ErrContainerAlreadyExists) {
t.Errorf("CreateContainer: Wrong error type. Want %#v. Got %#v.", ErrContainerAlreadyExists, err)
}
}
// Workaround for 17.09 bug returning 400 instead of 409.
// See https://github.com/moby/moby/issues/35021
func TestCreateContainerDuplicateNameWorkaroundDocker17_09(t *testing.T) {
t.Parallel()
client := newTestClient(&FakeRoundTripper{message: `{"message":"Conflict. The container name \"/c1\" is already in use by container \"2ce137e165dfca5e087f247b5d05a2311f91ef3da4bb7772168446a1a47e2f68\". You have to remove (or rename) that container to be able to reuse that name."}`, status: http.StatusBadRequest})
config := Config{AttachStdout: true, AttachStdin: true}
container, err := client.CreateContainer(CreateContainerOptions{Config: &config})
if container != nil {
t.Errorf("CreateContainer: expected <nil> container, got %#v.", container)
}
if !errors.Is(err, ErrContainerAlreadyExists) {
t.Errorf("CreateContainer: Wrong error type. Want %#v. Got %#v.", ErrContainerAlreadyExists, err)
}
}
func TestCreateContainerWithHostConfig(t *testing.T) {
t.Parallel()
fakeRT := &FakeRoundTripper{message: "{}", status: http.StatusOK}
client := newTestClient(fakeRT)
config := Config{}
hostConfig := HostConfig{PublishAllPorts: true}
opts := CreateContainerOptions{Name: "TestCreateContainerWithHostConfig", Config: &config, HostConfig: &hostConfig}
_, err := client.CreateContainer(opts)
if err != nil {
t.Fatal(err)
}
req := fakeRT.requests[0]
var gotBody map[string]any
err = json.NewDecoder(req.Body).Decode(&gotBody)
if err != nil {
t.Fatal(err)
}
if _, ok := gotBody["HostConfig"]; !ok {
t.Errorf("CreateContainer: wrong body. HostConfig was not serialized")
}
}
func TestPassingNameOptToCreateContainerReturnsItInContainer(t *testing.T) {
t.Parallel()
jsonContainer := `{
"Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
"Warnings": []
}`
fakeRT := &FakeRoundTripper{message: jsonContainer, status: http.StatusOK}
client := newTestClient(fakeRT)
config := Config{AttachStdout: true, AttachStdin: true}
opts := CreateContainerOptions{Name: "TestCreateContainer", Config: &config}
container, err := client.CreateContainer(opts)
if err != nil {
t.Fatal(err)
}
if container.Name != "TestCreateContainer" {
t.Errorf("Container name expected to be TestCreateContainer, was %s", container.Name)
}
}
func TestPassingPlatformOpt(t *testing.T) {
t.Parallel()
fakeRT := &FakeRoundTripper{message: "{}", status: http.StatusOK}
client := newTestClient(fakeRT)
config := Config{}
opts := CreateContainerOptions{Name: "TestCreateContainerWithPlatform", Platform: "darwin/arm64", Config: &config}
_, err := client.CreateContainer(opts)
if err != nil {
t.Fatal(err)
}
req := fakeRT.requests[0]
gotQs := req.URL.Query().Get("platform")
if gotQs != "darwin/arm64" {
t.Errorf("CreateContainer: missing expected platform query string (%v)", req.URL.RequestURI())
}
}
|