Browse Source

Fixes #505 - Make sure all output is send on the network before closing

Guillaume J. Charmes 12 years ago
parent
commit
fd9ad1a194
4 changed files with 33 additions and 14 deletions
  1. 7 1
      api_test.go
  2. 7 6
      container.go
  3. 13 6
      runtime_test.go
  4. 6 1
      z_final_test.go

+ 7 - 1
api_test.go

@@ -895,6 +895,12 @@ func TestPostContainersAttach(t *testing.T) {
 	stdin, stdinPipe := io.Pipe()
 	stdin, stdinPipe := io.Pipe()
 	stdout, stdoutPipe := io.Pipe()
 	stdout, stdoutPipe := io.Pipe()
 
 
+	// Try to avoid the timeoout in destroy. Best effort, don't check error
+	defer func() {
+		closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
+		container.Kill()
+	}()
+
 	// Attach to it
 	// Attach to it
 	c1 := make(chan struct{})
 	c1 := make(chan struct{})
 	go func() {
 	go func() {
@@ -934,7 +940,7 @@ func TestPostContainersAttach(t *testing.T) {
 	}
 	}
 
 
 	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
 	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
-	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
+	setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
 		<-c1
 		<-c1
 	})
 	})
 
 

+ 7 - 6
container.go

@@ -379,14 +379,15 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
 				utils.Debugf("[start] attach stdin\n")
 				utils.Debugf("[start] attach stdin\n")
 				defer utils.Debugf("[end] attach stdin\n")
 				defer utils.Debugf("[end] attach stdin\n")
 				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
 				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
-				if cStdout != nil {
-					defer cStdout.Close()
-				}
-				if cStderr != nil {
-					defer cStderr.Close()
-				}
 				if container.Config.StdinOnce && !container.Config.Tty {
 				if container.Config.StdinOnce && !container.Config.Tty {
 					defer cStdin.Close()
 					defer cStdin.Close()
+				} else {
+					if cStdout != nil {
+						defer cStdout.Close()
+					}
+					if cStderr != nil {
+						defer cStderr.Close()
+					}
 				}
 				}
 				if container.Config.Tty {
 				if container.Config.Tty {
 					_, err = utils.CopyEscapable(cStdin, stdin)
 					_, err = utils.CopyEscapable(cStdin, stdin)

+ 13 - 6
runtime_test.go

@@ -8,6 +8,7 @@ import (
 	"log"
 	"log"
 	"net"
 	"net"
 	"os"
 	"os"
+	"runtime"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
@@ -25,7 +26,11 @@ const (
 	testDaemonProto       = "tcp"
 	testDaemonProto       = "tcp"
 )
 )
 
 
-var globalRuntime *Runtime
+var (
+	globalRuntime   *Runtime
+	startFds        int
+	startGoroutines int
+)
 
 
 func nuke(runtime *Runtime) error {
 func nuke(runtime *Runtime) error {
 	var wg sync.WaitGroup
 	var wg sync.WaitGroup
@@ -80,21 +85,21 @@ func init() {
 	NetworkBridgeIface = unitTestNetworkBridge
 	NetworkBridgeIface = unitTestNetworkBridge
 
 
 	// Make it our Store root
 	// Make it our Store root
-	runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false)
-	if err != nil {
+	if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil {
 		panic(err)
 		panic(err)
+	} else {
+		globalRuntime = runtime
 	}
 	}
-	globalRuntime = runtime
 
 
 	// Create the "Server"
 	// Create the "Server"
 	srv := &Server{
 	srv := &Server{
-		runtime:     runtime,
+		runtime:     globalRuntime,
 		enableCors:  false,
 		enableCors:  false,
 		pullingPool: make(map[string]struct{}),
 		pullingPool: make(map[string]struct{}),
 		pushingPool: make(map[string]struct{}),
 		pushingPool: make(map[string]struct{}),
 	}
 	}
 	// If the unit test is not found, try to download it.
 	// If the unit test is not found, try to download it.
-	if img, err := runtime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
+	if img, err := globalRuntime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
 		// Retrieve the Image
 		// Retrieve the Image
 		if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
 		if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
 			panic(err)
 			panic(err)
@@ -109,6 +114,8 @@ func init() {
 
 
 	// Give some time to ListenAndServer to actually start
 	// Give some time to ListenAndServer to actually start
 	time.Sleep(time.Second)
 	time.Sleep(time.Second)
+
+	startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
 }
 }
 
 
 // FIXME: test that ImagePull(json=true) send correct json output
 // FIXME: test that ImagePull(json=true) send correct json output

+ 6 - 1
z_final_test.go

@@ -6,7 +6,12 @@ import (
 	"testing"
 	"testing"
 )
 )
 
 
+func displayFdGoroutines(t *testing.T) {
+	t.Logf("Fds: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
+}
+
 func TestFinal(t *testing.T) {
 func TestFinal(t *testing.T) {
 	cleanup(globalRuntime)
 	cleanup(globalRuntime)
-	t.Logf("Fds: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
+	t.Logf("Start Fds: %d, Start Goroutines: %d", startFds, startGoroutines)
+	displayFdGoroutines(t)
 }
 }