testing.NewServer doesn't implement /events endpoint
Summary
The mock server provided by testing.NewServer() doesn't implement the Docker /events endpoint, causing tests that use AddEventListener / AddEventListenerWithOptions to hang forever.
Reproduction
package main
import (
"testing"
"time"
docker "github.com/fsouza/go-dockerclient"
"github.com/fsouza/go-dockerclient/testing"
)
func TestEventsWithMockServer(t *testing.T) {
server, err := testing.NewServer("127.0.0.1:0", nil, nil)
if err != nil {
t.Fatal(err)
}
defer server.Stop()
client, err := docker.NewClient(server.URL())
if err != nil {
t.Fatal(err)
}
events := make(chan *docker.APIEvents, 10)
// This works - listener is added
err = client.AddEventListenerWithOptions(docker.EventsOptions{
Filters: map[string][]string{"type": {"container"}},
}, events)
if err != nil {
t.Fatal(err)
}
// Create a container that the mock server will track
container, err := client.CreateContainer(docker.CreateContainerOptions{
Name: "test",
Config: &docker.Config{Image: "test-image"},
})
if err != nil {
t.Fatal(err)
}
// Start and stop the container
client.StartContainer(container.ID, nil)
server.MutateContainer(container.ID, docker.State{Running: false, ExitCode: 0})
// This will hang forever because the mock server never sends events
select {
case <-events:
t.Log("Received event")
case <-time.After(5 * time.Second):
t.Fatal("Timeout waiting for event - mock server doesn't implement /events")
}
}
Expected Behavior
When container state changes via MutateContainer(), the mock server should send appropriate Docker events (die, stop, etc.) to registered event listeners.
Actual Behavior
The mock server accepts AddEventListener calls but never sends any events. Code that waits for container events hangs indefinitely.
Workaround
We added a polling fallback in our container monitoring code that periodically calls InspectContainer alongside event listening:
pollTicker := time.NewTicker(100 * time.Millisecond)
defer pollTicker.Stop()
for {
select {
case event := <-eventChan:
// Handle event
case <-pollTicker.C:
// Fallback: check container status directly
container, _ := client.InspectContainer(containerID)
if !container.State.Running {
return &container.State, nil
}
}
}
Impact
This limitation makes it difficult to test code that relies on Docker events for container lifecycle monitoring without adding workarounds that also affect production code.
Environment
- go-dockerclient version: v1.12.2
- Go version: 1.23.x