package daemon import ( "sync/atomic" "testing" "time" "github.com/docker/docker/daemon/execdriver" ) func TestStateRunStop(t *testing.T) { s := NewState() for i := 1; i < 3; i++ { // full lifecycle two times started := make(chan struct{}) var pid int64 go func() { runPid, _ := s.waitRunning(-1 * time.Second) atomic.StoreInt64(&pid, int64(runPid)) close(started) }() s.Lock() s.setRunning(i + 100) s.Unlock() if !s.IsRunning() { t.Fatal("State not running") } if s.Pid != i+100 { t.Fatalf("Pid %v, expected %v", s.Pid, i+100) } if s.ExitCode != 0 { t.Fatalf("ExitCode %v, expected 0", s.ExitCode) } select { case <-time.After(100 * time.Millisecond): t.Fatal("Start callback doesn't fire in 100 milliseconds") case <-started: t.Log("Start callback fired") } runPid := int(atomic.LoadInt64(&pid)) if runPid != i+100 { t.Fatalf("Pid %v, expected %v", runPid, i+100) } if pid, err := s.waitRunning(-1 * time.Second); err != nil || pid != i+100 { t.Fatalf("waitRunning returned pid: %v, err: %v, expected pid: %v, err: %v", pid, err, i+100, nil) } stopped := make(chan struct{}) var exit int64 go func() { exitCode, _ := s.WaitStop(-1 * time.Second) atomic.StoreInt64(&exit, int64(exitCode)) close(stopped) }() s.setStoppedLocking(&execdriver.ExitStatus{ExitCode: i}) if s.IsRunning() { t.Fatal("State is running") } if s.ExitCode != i { t.Fatalf("ExitCode %v, expected %v", s.ExitCode, i) } if s.Pid != 0 { t.Fatalf("Pid %v, expected 0", s.Pid) } select { case <-time.After(100 * time.Millisecond): t.Fatal("Stop callback doesn't fire in 100 milliseconds") case <-stopped: t.Log("Stop callback fired") } exitCode := int(atomic.LoadInt64(&exit)) if exitCode != i { t.Fatalf("ExitCode %v, expected %v", exitCode, i) } if exitCode, err := s.WaitStop(-1 * time.Second); err != nil || exitCode != i { t.Fatalf("WaitStop returned exitCode: %v, err: %v, expected exitCode: %v, err: %v", exitCode, err, i, nil) } } } func TestStateTimeoutWait(t *testing.T) { s := NewState() started := make(chan struct{}) go func() { s.waitRunning(100 * time.Millisecond) close(started) }() select { case <-time.After(200 * time.Millisecond): t.Fatal("Start callback doesn't fire in 100 milliseconds") case <-started: t.Log("Start callback fired") } s.Lock() s.setRunning(49) s.Unlock() stopped := make(chan struct{}) go func() { s.waitRunning(100 * time.Millisecond) close(stopped) }() select { case <-time.After(200 * time.Millisecond): t.Fatal("Start callback doesn't fire in 100 milliseconds") case <-stopped: t.Log("Start callback fired") } }