6bb0d181 |
package container |
47065b90 |
import ( |
cfdf84d5 |
"context" |
47065b90 |
"testing"
"time" |
1a149a0e |
"github.com/docker/docker/api/types" |
47065b90 |
)
|
1a149a0e |
func TestIsValidHealthString(t *testing.T) {
contexts := []struct {
Health string
Expected bool
}{
{types.Healthy, true},
{types.Unhealthy, true},
{types.Starting, true},
{types.NoHealthcheck, true},
{"fail", false},
}
for _, c := range contexts {
v := IsValidHealthString(c.Health)
if v != c.Expected {
t.Fatalf("Expected %t, but got %t", c.Expected, v)
}
}
}
|
47065b90 |
func TestStateRunStop(t *testing.T) {
s := NewState() |
cfdf84d5 |
|
49211715 |
// Begin another wait with WaitConditionRemoved. It should complete |
cfdf84d5 |
// within 200 milliseconds. |
49211715 |
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) |
cfdf84d5 |
defer cancel() |
49211715 |
removalWait := s.Wait(ctx, WaitConditionRemoved) |
cfdf84d5 |
// Full lifecycle two times.
for i := 1; i <= 2; i++ { |
49211715 |
// A wait with WaitConditionNotRunning should return
// immediately since the state is now either "created" (on the
// first iteration) or "exited" (on the second iteration). It
// shouldn't take more than 50 milliseconds.
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
// Expectx exit code to be i-1 since it should be the exit
// code from the previous loop or 0 for the created state.
if status := <-s.Wait(ctx, WaitConditionNotRunning); status.ExitCode() != i-1 {
t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i-1, status.Err())
}
// A wait with WaitConditionNextExit should block until the
// container has started and exited. It shouldn't take more
// than 100 milliseconds.
ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
initialWait := s.Wait(ctx, WaitConditionNextExit)
|
cfdf84d5 |
// Set the state to "Running". |
eff253df |
s.Lock() |
cfdf84d5 |
s.SetRunning(i, true) |
eff253df |
s.Unlock() |
abd72d40 |
|
cfdf84d5 |
// Assert desired state. |
47065b90 |
if !s.IsRunning() {
t.Fatal("State not running")
} |
cfdf84d5 |
if s.Pid != i {
t.Fatalf("Pid %v, expected %v", s.Pid, i) |
47065b90 |
} |
dcfe9927 |
if s.ExitCode() != 0 {
t.Fatalf("ExitCode %v, expected 0", s.ExitCode()) |
47065b90 |
}
|
49211715 |
// Now that it's running, a wait with WaitConditionNotRunning
// should block until we stop the container. It shouldn't take
// more than 100 milliseconds.
ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond) |
cfdf84d5 |
defer cancel() |
49211715 |
exitWait := s.Wait(ctx, WaitConditionNotRunning) |
cfdf84d5 |
// Set the state to "Exited". |
a28c389d |
s.Lock()
s.SetStopped(&ExitStatus{ExitCode: i})
s.Unlock() |
cfdf84d5 |
// Assert desired state. |
47065b90 |
if s.IsRunning() {
t.Fatal("State is running")
} |
dcfe9927 |
if s.ExitCode() != i {
t.Fatalf("ExitCode %v, expected %v", s.ExitCode(), i) |
47065b90 |
}
if s.Pid != 0 {
t.Fatalf("Pid %v, expected 0", s.Pid)
} |
cfdf84d5 |
|
49211715 |
// Receive the initialWait result.
if status := <-initialWait; status.ExitCode() != i { |
cfdf84d5 |
t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i, status.Err()) |
47065b90 |
} |
cfdf84d5 |
|
49211715 |
// Receive the exitWait result.
if status := <-exitWait; status.ExitCode() != i { |
cfdf84d5 |
t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i, status.Err()) |
47065b90 |
}
} |
cfdf84d5 |
// Set the state to dead and removed.
s.SetDead()
s.SetRemoved()
// Wait for removed status or timeout. |
49211715 |
if status := <-removalWait; status.ExitCode() != 2 { |
cfdf84d5 |
// Should have the final exit code from the loop.
t.Fatalf("Removal wait exitCode %v, expected %v, err %q", status.ExitCode(), 2, status.Err())
} |
47065b90 |
}
func TestStateTimeoutWait(t *testing.T) {
s := NewState() |
cfdf84d5 |
|
49211715 |
s.Lock()
s.SetRunning(0, true)
s.Unlock()
|
cfdf84d5 |
// Start a wait with a timeout.
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel() |
49211715 |
waitC := s.Wait(ctx, WaitConditionNotRunning) |
cfdf84d5 |
// It should timeout *before* this 200ms timer does. |
47065b90 |
select {
case <-time.After(200 * time.Millisecond): |
51f927d4 |
t.Fatal("Stop callback doesn't fire in 200 milliseconds") |
cfdf84d5 |
case status := <-waitC: |
a0191a23 |
t.Log("Stop callback fired") |
cfdf84d5 |
// Should be a timeout error.
if status.Err() == nil {
t.Fatal("expected timeout error, got nil")
}
if status.ExitCode() != -1 {
t.Fatalf("expected exit code %v, got %v", -1, status.ExitCode())
} |
47065b90 |
} |
abd72d40 |
|
a28c389d |
s.Lock() |
cfdf84d5 |
s.SetStopped(&ExitStatus{ExitCode: 0}) |
a28c389d |
s.Unlock() |
abd72d40 |
|
cfdf84d5 |
// Start another wait with a timeout. This one should return
// immediately.
ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel() |
49211715 |
waitC = s.Wait(ctx, WaitConditionNotRunning) |
cfdf84d5 |
|
47065b90 |
select {
case <-time.After(200 * time.Millisecond): |
92ee5a5d |
t.Fatal("Stop callback doesn't fire in 200 milliseconds") |
cfdf84d5 |
case status := <-waitC: |
a0191a23 |
t.Log("Stop callback fired") |
cfdf84d5 |
if status.ExitCode() != 0 {
t.Fatalf("expected exit code %v, got %v, err %q", 0, status.ExitCode(), status.Err())
} |
47065b90 |
}
} |
675ac374 |
func TestIsValidStateString(t *testing.T) {
states := []struct {
state string
expected bool
}{
{"paused", true},
{"restarting", true},
{"running", true},
{"dead", true},
{"start", false},
{"created", true},
{"exited", true},
{"removing", true},
{"stop", false},
}
for _, s := range states {
v := IsValidStateString(s.state)
if v != s.expected {
t.Fatalf("Expected %t, but got %t", s.expected, v)
}
}
} |