bump(github.com/fsouza/go-dockerclient): 17d39bcb22e8103ba6d1c0cb2530c6434cb870a3

This commit is contained in:
Paul Weil
2015-04-10 16:05:43 -04:00
parent 1db1894850
commit fb63370451
20 changed files with 864 additions and 131 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2014 go-dockerclient authors. All rights reserved.
// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -35,6 +35,7 @@ import (
type DockerServer struct {
containers []*docker.Container
execs []*docker.ExecInspect
execMut sync.RWMutex
cMut sync.RWMutex
images []docker.Image
iMut sync.RWMutex
@@ -43,6 +44,8 @@ type DockerServer struct {
mux *mux.Router
hook func(*http.Request)
failures map[string]string
multiFailures []map[string]string
execCallbacks map[string]func()
customHandlers map[string]http.Handler
handlerMutex sync.RWMutex
cChan chan<- *docker.Container
@@ -69,6 +72,7 @@ func NewServer(bind string, containerChan chan<- *docker.Container, hook func(*h
imgIDs: make(map[string]string),
hook: hook,
failures: make(map[string]string),
execCallbacks: make(map[string]func()),
customHandlers: make(map[string]http.Handler),
cChan: containerChan,
}
@@ -89,6 +93,7 @@ func (s *DockerServer) buildMuxer() {
s.mux.Path("/containers/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.listContainers))
s.mux.Path("/containers/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.createContainer))
s.mux.Path("/containers/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectContainer))
s.mux.Path("/containers/{id:.*}/rename").Methods("POST").HandlerFunc(s.handlerWrapper(s.renameContainer))
s.mux.Path("/containers/{id:.*}/top").Methods("GET").HandlerFunc(s.handlerWrapper(s.topContainer))
s.mux.Path("/containers/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startContainer))
s.mux.Path("/containers/{id:.*}/kill").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer))
@@ -115,17 +120,59 @@ func (s *DockerServer) buildMuxer() {
s.mux.Path("/images/{id:.*}/get").Methods("GET").HandlerFunc(s.handlerWrapper(s.getImage))
}
// SetHook changes the hook function used by the server.
//
// The hook function is a function called on every request.
func (s *DockerServer) SetHook(hook func(*http.Request)) {
s.hook = hook
}
// PrepareExec adds a callback to a container exec in the fake server.
//
// This function will be called whenever the given exec id is started, and the
// given exec id will remain in the "Running" start while the function is
// running, so it's useful for emulating an exec that runs for two seconds, for
// example:
//
// opts := docker.CreateExecOptions{
// AttachStdin: true,
// AttachStdout: true,
// AttachStderr: true,
// Tty: true,
// Cmd: []string{"/bin/bash", "-l"},
// }
// // Client points to a fake server.
// exec, err := client.CreateExec(opts)
// // handle error
// server.PrepareExec(exec.ID, func() {time.Sleep(2 * time.Second)})
// err = client.StartExec(exec.ID, docker.StartExecOptions{Tty: true}) // will block for 2 seconds
// // handle error
func (s *DockerServer) PrepareExec(id string, callback func()) {
s.execCallbacks[id] = callback
}
// PrepareFailure adds a new expected failure based on a URL regexp it receives
// an id for the failure.
func (s *DockerServer) PrepareFailure(id string, urlRegexp string) {
s.failures[id] = urlRegexp
}
// PrepareMultiFailures enqueues a new expected failure based on a URL regexp
// it receives an id for the failure.
func (s *DockerServer) PrepareMultiFailures(id string, urlRegexp string) {
s.multiFailures = append(s.multiFailures, map[string]string{"error": id, "url": urlRegexp})
}
// ResetFailure removes an expected failure identified by the given id.
func (s *DockerServer) ResetFailure(id string) {
delete(s.failures, id)
}
// ResetMultiFailures removes all enqueued failures.
func (s *DockerServer) ResetMultiFailures() {
s.multiFailures = []map[string]string{}
}
// CustomHandler registers a custom handler for a specific path.
//
// For example:
@@ -170,9 +217,11 @@ func (s *DockerServer) URL() string {
func (s *DockerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.handlerMutex.RLock()
defer s.handlerMutex.RUnlock()
if handler, ok := s.customHandlers[r.URL.Path]; ok {
handler.ServeHTTP(w, r)
return
for re, handler := range s.customHandlers {
if m, _ := regexp.MatchString(re, r.URL.Path); m {
handler.ServeHTTP(w, r)
return
}
}
s.mux.ServeHTTP(w, r)
if s.hook != nil {
@@ -200,6 +249,19 @@ func (s *DockerServer) handlerWrapper(f func(http.ResponseWriter, *http.Request)
http.Error(w, errorID, http.StatusBadRequest)
return
}
for i, failure := range s.multiFailures {
matched, err := regexp.MatchString(failure["url"], r.URL.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if !matched {
continue
}
http.Error(w, failure["error"], http.StatusBadRequest)
s.multiFailures = append(s.multiFailures[:i], s.multiFailures[i+1:]...)
return
}
f(w, r)
}
}
@@ -336,6 +398,23 @@ func (s *DockerServer) generateID() string {
return fmt.Sprintf("%x", buf)
}
func (s *DockerServer) renameContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, index, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
copy := *container
copy.Name = r.URL.Query().Get("name")
s.cMut.Lock()
defer s.cMut.Unlock()
if s.containers[index].ID == copy.ID {
s.containers[index] = &copy
}
w.WriteHeader(http.StatusNoContent)
}
func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
@@ -524,9 +603,13 @@ func (s *DockerServer) commitContainer(w http.ResponseWriter, r *http.Request) {
Config: config,
}
repository := r.URL.Query().Get("repo")
tag := r.URL.Query().Get("tag")
s.iMut.Lock()
s.images = append(s.images, image)
if repository != "" {
if tag != "" {
repository += ":" + tag
}
s.imgIDs[repository] = image.ID
}
s.iMut.Unlock()
@@ -582,20 +665,28 @@ func (s *DockerServer) buildImage(w http.ResponseWriter, r *http.Request) {
}
func (s *DockerServer) pullImage(w http.ResponseWriter, r *http.Request) {
repository := r.URL.Query().Get("fromImage")
fromImageName := r.URL.Query().Get("fromImage")
tag := r.URL.Query().Get("tag")
image := docker.Image{
ID: s.generateID(),
}
s.iMut.Lock()
s.images = append(s.images, image)
if repository != "" {
s.imgIDs[repository] = image.ID
if fromImageName != "" {
if tag != "" {
fromImageName = fmt.Sprintf("%s:%s", fromImageName, tag)
}
s.imgIDs[fromImageName] = image.ID
}
s.iMut.Unlock()
}
func (s *DockerServer) pushImage(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
tag := r.URL.Query().Get("tag")
if tag != "" {
name += ":" + tag
}
s.iMut.RLock()
if _, ok := s.imgIDs[name]; !ok {
s.iMut.RUnlock()
@@ -619,6 +710,10 @@ func (s *DockerServer) tagImage(w http.ResponseWriter, r *http.Request) {
s.iMut.Lock()
defer s.iMut.Unlock()
newRepo := r.URL.Query().Get("repo")
newTag := r.URL.Query().Get("tag")
if newTag != "" {
newRepo += ":" + newTag
}
s.imgIDs[newRepo] = s.imgIDs[name]
w.WriteHeader(http.StatusCreated)
}
@@ -722,7 +817,6 @@ func (s *DockerServer) loadImage(w http.ResponseWriter, r *http.Request) {
func (s *DockerServer) getImage(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/tar")
}
func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Request) {
@@ -733,7 +827,7 @@ func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Reques
return
}
exec := docker.ExecInspect{
ID: "id-exec-created-by-test",
ID: s.generateID(),
Container: *container,
}
var params docker.CreateExecOptions
@@ -748,44 +842,63 @@ func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Reques
exec.ProcessConfig.Arguments = params.Cmd[1:]
}
}
s.execMut.Lock()
s.execs = append(s.execs, &exec)
s.execMut.Unlock()
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"Id": exec.ID})
}
func (s *DockerServer) startExecContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
for _, exec := range s.execs {
if exec.ID == id {
w.WriteHeader(http.StatusOK)
return
if exec, err := s.getExec(id); err == nil {
s.execMut.Lock()
exec.Running = true
s.execMut.Unlock()
if callback, ok := s.execCallbacks[id]; ok {
callback()
delete(s.execCallbacks, id)
} else if callback, ok := s.execCallbacks["*"]; ok {
callback()
delete(s.execCallbacks, "*")
}
s.execMut.Lock()
exec.Running = false
s.execMut.Unlock()
w.WriteHeader(http.StatusOK)
return
}
w.WriteHeader(http.StatusNotFound)
}
func (s *DockerServer) resizeExecContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
for _, exec := range s.execs {
if exec.ID == id {
w.WriteHeader(http.StatusOK)
return
}
if _, err := s.getExec(id); err == nil {
w.WriteHeader(http.StatusOK)
return
}
w.WriteHeader(http.StatusNotFound)
}
func (s *DockerServer) inspectExecContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
for _, exec := range s.execs {
if exec.ID == id {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(exec)
return
}
if exec, err := s.getExec(id); err == nil {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(exec)
return
}
w.WriteHeader(http.StatusNotFound)
}
func (s *DockerServer) getExec(id string) (*docker.ExecInspect, error) {
s.execMut.RLock()
defer s.execMut.RUnlock()
for _, exec := range s.execs {
if exec.ID == id {
return exec, nil
}
}
return nil, errors.New("exec not found")
}

View File

@@ -1,4 +1,4 @@
// Copyright 2014 go-dockerclient authors. All rights reserved.
// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -82,6 +82,19 @@ func TestHandleWithHook(t *testing.T) {
}
}
func TestSetHook(t *testing.T) {
var called bool
server, _ := NewServer("127.0.0.1:0", nil, nil)
defer server.Stop()
server.SetHook(func(*http.Request) { called = true })
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
server.ServeHTTP(recorder, request)
if !called {
t.Error("ServeHTTP did not call the hook function.")
}
}
func TestCustomHandler(t *testing.T) {
var called bool
server, _ := NewServer("127.0.0.1:0", nil, nil)
@@ -101,6 +114,25 @@ func TestCustomHandler(t *testing.T) {
}
}
func TestCustomHandlerRegexp(t *testing.T) {
var called bool
server, _ := NewServer("127.0.0.1:0", nil, nil)
addContainers(server, 2)
server.CustomHandler("/containers/.*/json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
called = true
fmt.Fprint(w, "Hello world")
}))
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("GET", "/containers/.*/json?all=1", nil)
server.ServeHTTP(recorder, request)
if !called {
t.Error("Did not call the custom handler")
}
if got := recorder.Body.String(); got != "Hello world" {
t.Errorf("Wrong output for custom handler: want %q. Got %q.", "Hello world", got)
}
}
func TestListContainers(t *testing.T) {
server := DockerServer{}
addContainers(&server, 2)
@@ -223,6 +255,35 @@ func TestCreateContainerImageNotFound(t *testing.T) {
}
}
func TestRenameContainer(t *testing.T) {
server := DockerServer{}
addContainers(&server, 2)
server.buildMuxer()
recorder := httptest.NewRecorder()
newName := server.containers[0].Name + "abc"
path := fmt.Sprintf("/containers/%s/rename?name=%s", server.containers[0].ID, newName)
request, _ := http.NewRequest("POST", path, nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusNoContent {
t.Errorf("RenameContainer: wrong status. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
}
container := server.containers[0]
if container.Name != newName {
t.Errorf("RenameContainer: did not rename the container. Want %q. Got %q.", newName, container.Name)
}
}
func TestRenameContainerNotFound(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("POST", "/containers/blabla/rename?name=something", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusNotFound {
t.Errorf("RenameContainer: wrong status. Want %d. Got %d.", http.StatusNotFound, recorder.Code)
}
}
func TestCommitContainer(t *testing.T) {
server := DockerServer{}
addContainers(&server, 2)
@@ -277,6 +338,27 @@ func TestCommitContainerComplete(t *testing.T) {
}
}
func TestCommitContainerWithTag(t *testing.T) {
server := DockerServer{}
server.imgIDs = make(map[string]string)
addContainers(&server, 2)
server.buildMuxer()
recorder := httptest.NewRecorder()
queryString := "container=" + server.containers[0].ID + "&repo=tsuru/python&tag=v1"
request, _ := http.NewRequest("POST", "/commit?"+queryString, nil)
server.ServeHTTP(recorder, request)
image := server.images[0]
if image.Parent != server.containers[0].Image {
t.Errorf("CommitContainer: wrong parent image. Want %q. Got %q.", server.containers[0].Image, image.Parent)
}
if image.Container != server.containers[0].ID {
t.Errorf("CommitContainer: wrong container. Want %q. Got %q.", server.containers[0].ID, image.Container)
}
if id := server.imgIDs["tsuru/python:v1"]; id != image.ID {
t.Errorf("CommitContainer: wrong ID saved for repository. Want %q. Got %q.", image.ID, id)
}
}
func TestCommitContainerInvalidRun(t *testing.T) {
server := DockerServer{}
addContainers(&server, 1)
@@ -767,6 +849,23 @@ func TestPullImage(t *testing.T) {
}
}
func TestPullImageWithTag(t *testing.T) {
server := DockerServer{imgIDs: make(map[string]string)}
server.buildMuxer()
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("POST", "/images/create?fromImage=base&tag=tag", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("PullImage: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
if len(server.images) != 1 {
t.Errorf("PullImage: Want 1 image. Got %d.", len(server.images))
}
if _, ok := server.imgIDs["base:tag"]; !ok {
t.Error("PullImage: Repository should not be empty.")
}
}
func TestPushImage(t *testing.T) {
server := DockerServer{imgIDs: map[string]string{"tsuru/python": "a123"}}
server.buildMuxer()
@@ -778,6 +877,17 @@ func TestPushImage(t *testing.T) {
}
}
func TestPushImageWithTag(t *testing.T) {
server := DockerServer{imgIDs: map[string]string{"tsuru/python:v1": "a123"}}
server.buildMuxer()
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("POST", "/images/tsuru/python/push?tag=v1", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("PushImage: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
}
func TestPushImageNotFound(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
@@ -803,6 +913,20 @@ func TestTagImage(t *testing.T) {
}
}
func TestTagImageWithRepoAndTag(t *testing.T) {
server := DockerServer{imgIDs: map[string]string{"tsuru/python": "a123"}}
server.buildMuxer()
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("POST", "/images/tsuru/python/tag?repo=tsuru/new-python&tag=v1", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusCreated {
t.Errorf("TagImage: wrong status. Want %d. Got %d.", http.StatusCreated, recorder.Code)
}
if server.imgIDs["tsuru/python"] != server.imgIDs["tsuru/new-python:v1"] {
t.Errorf("TagImage: did not tag the image")
}
}
func TestTagImageNotFound(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
@@ -986,6 +1110,41 @@ func TestPrepareFailure(t *testing.T) {
}
}
func TestPrepareMultiFailures(t *testing.T) {
server := DockerServer{multiFailures: []map[string]string{}}
server.buildMuxer()
errorID := "multi error"
server.PrepareMultiFailures(errorID, "containers/json")
server.PrepareMultiFailures(errorID, "containers/json")
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusBadRequest {
t.Errorf("PrepareFailure: wrong status. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
}
if recorder.Body.String() != errorID+"\n" {
t.Errorf("PrepareFailure: wrong message. Want %s. Got %s.", errorID, recorder.Body.String())
}
recorder = httptest.NewRecorder()
request, _ = http.NewRequest("GET", "/containers/json?all=1", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusBadRequest {
t.Errorf("PrepareFailure: wrong status. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
}
if recorder.Body.String() != errorID+"\n" {
t.Errorf("PrepareFailure: wrong message. Want %s. Got %s.", errorID, recorder.Body.String())
}
recorder = httptest.NewRecorder()
request, _ = http.NewRequest("GET", "/containers/json?all=1", nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("PrepareFailure: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
if recorder.Body.String() == errorID+"\n" {
t.Errorf("PrepareFailure: wrong message. Want %s. Got %s.", errorID, recorder.Body.String())
}
}
func TestRemoveFailure(t *testing.T) {
server := DockerServer{failures: make(map[string]string)}
server.buildMuxer()
@@ -1006,6 +1165,21 @@ func TestRemoveFailure(t *testing.T) {
}
}
func TestResetMultiFailures(t *testing.T) {
server := DockerServer{multiFailures: []map[string]string{}}
server.buildMuxer()
errorID := "multi error"
server.PrepareMultiFailures(errorID, "containers/json")
server.PrepareMultiFailures(errorID, "containers/json")
if len(server.multiFailures) != 2 {
t.Errorf("PrepareMultiFailures: error adding multi failures.")
}
server.ResetMultiFailures()
if len(server.multiFailures) != 0 {
t.Errorf("ResetMultiFailures: error reseting multi failures.")
}
}
func TestMutateContainer(t *testing.T) {
server := DockerServer{failures: make(map[string]string)}
server.buildMuxer()
@@ -1169,3 +1343,132 @@ func TestInspectExecContainer(t *testing.T) {
t.Errorf("InspectContainer: wrong value. Want:\n%#v\nGot:\n%#v\n", expected, got2)
}
}
func TestStartExecContainer(t *testing.T) {
server, _ := NewServer("127.0.0.1:0", nil, nil)
addContainers(server, 1)
server.buildMuxer()
recorder := httptest.NewRecorder()
body := `{"Cmd": ["bash", "-c", "ls"]}`
path := fmt.Sprintf("/containers/%s/exec", server.containers[0].ID)
request, _ := http.NewRequest("POST", path, strings.NewReader(body))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("CreateExec: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
var exec docker.Exec
err := json.NewDecoder(recorder.Body).Decode(&exec)
if err != nil {
t.Fatal(err)
}
unleash := make(chan bool)
server.PrepareExec(exec.ID, func() {
<-unleash
})
codes := make(chan int, 1)
sent := make(chan bool)
go func() {
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/exec/%s/start", exec.ID)
body := `{"Tty":true}`
request, _ := http.NewRequest("POST", path, strings.NewReader(body))
close(sent)
server.ServeHTTP(recorder, request)
codes <- recorder.Code
}()
<-sent
execInfo, err := waitExec(server.URL(), exec.ID, true, 5)
if err != nil {
t.Fatal(err)
}
if !execInfo.Running {
t.Error("StartExec: expected exec to be running, but it's not running")
}
close(unleash)
if code := <-codes; code != http.StatusOK {
t.Errorf("StartExec: wrong status. Want %d. Got %d.", http.StatusOK, code)
}
execInfo, err = waitExec(server.URL(), exec.ID, false, 5)
if err != nil {
t.Fatal(err)
}
if execInfo.Running {
t.Error("StartExec: expected exec to be not running after start returns, but it's running")
}
}
func TestStartExecContainerWildcardCallback(t *testing.T) {
server, _ := NewServer("127.0.0.1:0", nil, nil)
addContainers(server, 1)
server.buildMuxer()
recorder := httptest.NewRecorder()
body := `{"Cmd": ["bash", "-c", "ls"]}`
path := fmt.Sprintf("/containers/%s/exec", server.containers[0].ID)
request, _ := http.NewRequest("POST", path, strings.NewReader(body))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("CreateExec: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
unleash := make(chan bool)
server.PrepareExec("*", func() {
<-unleash
})
var exec docker.Exec
err := json.NewDecoder(recorder.Body).Decode(&exec)
if err != nil {
t.Fatal(err)
}
codes := make(chan int, 1)
sent := make(chan bool)
go func() {
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/exec/%s/start", exec.ID)
body := `{"Tty":true}`
request, _ := http.NewRequest("POST", path, strings.NewReader(body))
close(sent)
server.ServeHTTP(recorder, request)
codes <- recorder.Code
}()
<-sent
execInfo, err := waitExec(server.URL(), exec.ID, true, 5)
if err != nil {
t.Fatal(err)
}
if !execInfo.Running {
t.Error("StartExec: expected exec to be running, but it's not running")
}
close(unleash)
if code := <-codes; code != http.StatusOK {
t.Errorf("StartExec: wrong status. Want %d. Got %d.", http.StatusOK, code)
}
execInfo, err = waitExec(server.URL(), exec.ID, false, 5)
if err != nil {
t.Fatal(err)
}
if execInfo.Running {
t.Error("StartExec: expected exec to be not running after start returns, but it's running")
}
}
func TestStartExecContainerNotFound(t *testing.T) {
server, _ := NewServer("127.0.0.1:0", nil, nil)
addContainers(server, 1)
server.buildMuxer()
recorder := httptest.NewRecorder()
body := `{"Tty":true}`
request, _ := http.NewRequest("POST", "/exec/something-wat/start", strings.NewReader(body))
server.ServeHTTP(recorder, request)
}
func waitExec(url, execID string, running bool, maxTry int) (*docker.ExecInspect, error) {
client, err := docker.NewClient(url)
if err != nil {
return nil, err
}
exec, err := client.InspectExec(execID)
for i := 0; i < maxTry && exec.Running != running && err == nil; i++ {
time.Sleep(100e6)
exec, err = client.InspectExec(exec.ID)
}
return exec, err
}