Skip to content

Commit

Permalink
testing: add method to notify containers through a channel
Browse files Browse the repository at this point in the history
Related to issue #105.
  • Loading branch information
fsouza committed Jun 29, 2014
1 parent bbdc472 commit 8b40158
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 8 deletions.
29 changes: 25 additions & 4 deletions testing/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type DockerServer struct {
mux *mux.Router
hook func(*http.Request)
failures map[string]FailureSpec
cChan chan<- *docker.Container
}

// FailureSpec is used with PrepareFailure and describes in which situations
Expand All @@ -58,19 +59,36 @@ type FailureSpec struct {
// the method URL to get the URL of the server.
//
// It receives the bind address (use 127.0.0.1:0 for getting an available port
// on the host) and a hook function, that will be called on every request.
func NewServer(bind string, hook func(*http.Request)) (*DockerServer, error) {
// on the host), a channel of containers and a hook function, that will be
// called on every request.
//
// The fake server will send containers in the channel whenever the container
// changes its state, via the HTTP API (i.e.: create, start and stop). This
// channel may be nil, which means that the server won't notify on state
// changes.
func NewServer(bind string, containerChan chan<- *docker.Container, hook func(*http.Request)) (*DockerServer, error) {
listener, err := net.Listen("tcp", bind)
if err != nil {
return nil, err
}
server := DockerServer{listener: listener, imgIDs: make(map[string]string), hook: hook,
failures: make(map[string]FailureSpec)}
server := DockerServer{
listener: listener,
imgIDs: make(map[string]string),
hook: hook,
failures: make(map[string]FailureSpec),
cChan: containerChan,
}
server.buildMuxer()
go http.Serve(listener, &server)
return &server, nil
}

func (s *DockerServer) notify(container *docker.Container) {
if s.cChan != nil {
s.cChan <- container
}
}

func (s *DockerServer) buildMuxer() {
s.mux = mux.NewRouter()
s.mux.Path("/commit").Methods("POST").HandlerFunc(s.handlerWrapper(s.commitContainer))
Expand Down Expand Up @@ -284,6 +302,7 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
s.cMut.Lock()
s.containers = append(s.containers, &container)
s.cMut.Unlock()
s.notify(&container)
var c = struct{ ID string }{ID: container.ID}
json.NewEncoder(w).Encode(c)
}
Expand Down Expand Up @@ -320,6 +339,7 @@ func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {
return
}
container.State.Running = true
s.notify(container)
}

func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
Expand All @@ -337,6 +357,7 @@ func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
}
w.WriteHeader(http.StatusNoContent)
container.State.Running = false
s.notify(container)
}

func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {
Expand Down
66 changes: 62 additions & 4 deletions testing/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

func TestNewServer(t *testing.T) {
server, err := NewServer("127.0.0.1:0", nil)
server, err := NewServer("127.0.0.1:0", nil, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -33,7 +33,7 @@ func TestNewServer(t *testing.T) {
}

func TestServerStop(t *testing.T) {
server, err := NewServer("127.0.0.1:0", nil)
server, err := NewServer("127.0.0.1:0", nil, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -50,7 +50,7 @@ func TestServerStopNoListener(t *testing.T) {
}

func TestServerURL(t *testing.T) {
server, err := NewServer("127.0.0.1:0", nil)
server, err := NewServer("127.0.0.1:0", nil, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -71,7 +71,7 @@ func TestServerURLNoListener(t *testing.T) {

func TestHandleWithHook(t *testing.T) {
var called bool
server, _ := NewServer("127.0.0.1:0", func(*http.Request) { called = true })
server, _ := NewServer("127.0.0.1:0", nil, func(*http.Request) { called = true })
defer server.Stop()
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
Expand Down Expand Up @@ -158,6 +158,25 @@ func TestCreateContainer(t *testing.T) {
}
}

func TestCreateContainerWithNotifyChannel(t *testing.T) {
ch := make(chan *docker.Container, 1)
server := DockerServer{}
server.imgIDs = map[string]string{"base": "a1234"}
server.cChan = ch
server.buildMuxer()
recorder := httptest.NewRecorder()
body := `{"Hostname":"", "User":"", "Memory":0, "MemorySwap":0, "AttachStdin":false, "AttachStdout":true, "AttachStderr":true,
"PortSpecs":null, "Tty":false, "OpenStdin":false, "StdinOnce":false, "Env":null, "Cmd":["date"], "Image":"base", "Volumes":{}, "VolumesFrom":""}`
request, _ := http.NewRequest("POST", "/containers/create", strings.NewReader(body))
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusCreated {
t.Errorf("CreateContainer: wrong status. Want %d. Got %d.", http.StatusCreated, recorder.Code)
}
if notified := <-ch; notified != server.containers[0] {
t.Errorf("CreateContainer: did not notify the proper container. Want %q. Got %q.", server.containers[0].ID, notified.ID)
}
}

func TestCreateContainerInvalidBody(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
Expand Down Expand Up @@ -320,6 +339,25 @@ func TestStartContainer(t *testing.T) {
}
}

func TestStartContainerWithNotifyChannel(t *testing.T) {
ch := make(chan *docker.Container, 1)
server := DockerServer{}
server.cChan = ch
addContainers(&server, 1)
addContainers(&server, 1)
server.buildMuxer()
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s/start", server.containers[1].ID)
request, _ := http.NewRequest("POST", path, nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusOK, recorder.Code)
}
if notified := <-ch; notified != server.containers[1] {
t.Errorf("StartContainer: did not notify the proper container. Want %q. Got %q.", server.containers[1].ID, notified.ID)
}
}

func TestStartContainerNotFound(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
Expand Down Expand Up @@ -363,6 +401,26 @@ func TestStopContainer(t *testing.T) {
}
}

func TestStopContainerWithNotifyChannel(t *testing.T) {
ch := make(chan *docker.Container, 1)
server := DockerServer{}
server.cChan = ch
addContainers(&server, 1)
addContainers(&server, 1)
server.containers[1].State.Running = true
server.buildMuxer()
recorder := httptest.NewRecorder()
path := fmt.Sprintf("/containers/%s/stop", server.containers[1].ID)
request, _ := http.NewRequest("POST", path, nil)
server.ServeHTTP(recorder, request)
if recorder.Code != http.StatusNoContent {
t.Errorf("StopContainer: wrong status code. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
}
if notified := <-ch; notified != server.containers[1] {
t.Errorf("StopContainer: did not notify the proper container. Want %q. Got %q.", server.containers[1].ID, notified.ID)
}
}

func TestStopContainerNotFound(t *testing.T) {
server := DockerServer{}
server.buildMuxer()
Expand Down

0 comments on commit 8b40158

Please sign in to comment.