Browse Source

Fix wait on stopped container (after docker restart) + add Unit test for that case

Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume.charmes@docker.com> (github: creack)
Guillaume J. Charmes 11 years ago
parent
commit
0376a69cb1
2 changed files with 67 additions and 0 deletions
  1. 61 0
      integration/server_test.go
  2. 6 0
      runtime.go

+ 61 - 0
integration/server_test.go

@@ -2,8 +2,10 @@ package docker
 
 import (
 	"github.com/dotcloud/docker"
+	"github.com/dotcloud/docker/engine"
 	"strings"
 	"testing"
+	"time"
 )
 
 func TestImageTagImageDelete(t *testing.T) {
@@ -154,6 +156,65 @@ func TestCommit(t *testing.T) {
 	}
 }
 
+func TestRestartKillWait(t *testing.T) {
+	eng := NewTestEngine(t)
+	srv := mkServerFromEngine(eng, t)
+	runtime := mkRuntimeFromEngine(eng, t)
+	defer runtime.Nuke()
+
+	config, hostConfig, _, err := docker.ParseRun([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	id := createTestContainer(eng, config, t)
+
+	if c := srv.Containers(true, false, -1, "", ""); len(c) != 1 {
+		t.Errorf("Expected 1 container, %v found", len(c))
+	}
+
+	job := eng.Job("start", id)
+	if err := job.ImportEnv(hostConfig); err != nil {
+		t.Fatal(err)
+	}
+	if err := job.Run(); err != nil {
+		t.Fatal(err)
+	}
+	job = eng.Job("kill", id)
+	if err := job.Run(); err != nil {
+		t.Fatal(err)
+	}
+
+	eng, err = engine.New(eng.Root())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	job = eng.Job("initapi")
+	job.Setenv("Root", eng.Root())
+	job.SetenvBool("AutoRestart", false)
+	// TestGetEnabledCors and TestOptionsRoute require EnableCors=true
+	job.SetenvBool("EnableCors", true)
+	if err := job.Run(); err != nil {
+		t.Fatal(err)
+	}
+
+	srv = mkServerFromEngine(eng, t)
+	c := srv.Containers(true, false, -1, "", "")
+	if len(c) != 1 {
+		t.Errorf("Expected 1 container, %v found", len(c))
+	}
+
+	setTimeout(t, "Waiting on stopped container timedout", 5*time.Second, func() {
+		job = srv.Eng.Job("wait", c[0].ID)
+		var statusStr string
+		job.Stdout.AddString(&statusStr)
+		if err := job.Run(); err != nil {
+			t.Fatal(err)
+		}
+	})
+}
+
 func TestCreateStartRestartStopStartKillRm(t *testing.T) {
 	eng := NewTestEngine(t)
 	srv := mkServerFromEngine(eng, t)

+ 6 - 0
runtime.go

@@ -183,6 +183,12 @@ func (runtime *Runtime) Register(container *Container) error {
 			container.waitLock = make(chan struct{})
 			go container.monitor(nil)
 		}
+	} else {
+		// When the container is not running, we still initialize the waitLock
+		// chan and close it. Receiving on nil chan blocks whereas receiving on a
+		// closed chan does not. In this case we do not want to block.
+		container.waitLock = make(chan struct{})
+		close(container.waitLock)
 	}
 	return nil
 }