github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/container/state_test.go (about)

     1  package container
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/docker/docker/api/types"
     9  )
    10  
    11  func TestIsValidHealthString(t *testing.T) {
    12  	contexts := []struct {
    13  		Health   string
    14  		Expected bool
    15  	}{
    16  		{types.Healthy, true},
    17  		{types.Unhealthy, true},
    18  		{types.Starting, true},
    19  		{types.NoHealthcheck, true},
    20  		{"fail", false},
    21  	}
    22  
    23  	for _, c := range contexts {
    24  		v := IsValidHealthString(c.Health)
    25  		if v != c.Expected {
    26  			t.Fatalf("Expected %t, but got %t", c.Expected, v)
    27  		}
    28  	}
    29  }
    30  
    31  func TestStateRunStop(t *testing.T) {
    32  	s := NewState()
    33  
    34  	// Begin another wait with WaitConditionRemoved. It should complete
    35  	// within 200 milliseconds.
    36  	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
    37  	defer cancel()
    38  	removalWait := s.Wait(ctx, WaitConditionRemoved)
    39  
    40  	// Full lifecycle two times.
    41  	for i := 1; i <= 2; i++ {
    42  		// A wait with WaitConditionNotRunning should return
    43  		// immediately since the state is now either "created" (on the
    44  		// first iteration) or "exited" (on the second iteration). It
    45  		// shouldn't take more than 50 milliseconds.
    46  		ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
    47  		defer cancel()
    48  		// Expectx exit code to be i-1 since it should be the exit
    49  		// code from the previous loop or 0 for the created state.
    50  		if status := <-s.Wait(ctx, WaitConditionNotRunning); status.ExitCode() != i-1 {
    51  			t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i-1, status.Err())
    52  		}
    53  
    54  		// A wait with WaitConditionNextExit should block until the
    55  		// container has started and exited. It shouldn't take more
    56  		// than 100 milliseconds.
    57  		ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
    58  		defer cancel()
    59  		initialWait := s.Wait(ctx, WaitConditionNextExit)
    60  
    61  		// Set the state to "Running".
    62  		s.Lock()
    63  		s.SetRunning(i, true)
    64  		s.Unlock()
    65  
    66  		// Assert desired state.
    67  		if !s.IsRunning() {
    68  			t.Fatal("State not running")
    69  		}
    70  		if s.Pid != i {
    71  			t.Fatalf("Pid %v, expected %v", s.Pid, i)
    72  		}
    73  		if s.ExitCode() != 0 {
    74  			t.Fatalf("ExitCode %v, expected 0", s.ExitCode())
    75  		}
    76  
    77  		// Now that it's running, a wait with WaitConditionNotRunning
    78  		// should block until we stop the container. It shouldn't take
    79  		// more than 100 milliseconds.
    80  		ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
    81  		defer cancel()
    82  		exitWait := s.Wait(ctx, WaitConditionNotRunning)
    83  
    84  		// Set the state to "Exited".
    85  		s.Lock()
    86  		s.SetStopped(&ExitStatus{ExitCode: i})
    87  		s.Unlock()
    88  
    89  		// Assert desired state.
    90  		if s.IsRunning() {
    91  			t.Fatal("State is running")
    92  		}
    93  		if s.ExitCode() != i {
    94  			t.Fatalf("ExitCode %v, expected %v", s.ExitCode(), i)
    95  		}
    96  		if s.Pid != 0 {
    97  			t.Fatalf("Pid %v, expected 0", s.Pid)
    98  		}
    99  
   100  		// Receive the initialWait result.
   101  		if status := <-initialWait; status.ExitCode() != i {
   102  			t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i, status.Err())
   103  		}
   104  
   105  		// Receive the exitWait result.
   106  		if status := <-exitWait; status.ExitCode() != i {
   107  			t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i, status.Err())
   108  		}
   109  	}
   110  
   111  	// Set the state to dead and removed.
   112  	s.SetDead()
   113  	s.SetRemoved()
   114  
   115  	// Wait for removed status or timeout.
   116  	if status := <-removalWait; status.ExitCode() != 2 {
   117  		// Should have the final exit code from the loop.
   118  		t.Fatalf("Removal wait exitCode %v, expected %v, err %q", status.ExitCode(), 2, status.Err())
   119  	}
   120  }
   121  
   122  func TestStateTimeoutWait(t *testing.T) {
   123  	s := NewState()
   124  
   125  	s.Lock()
   126  	s.SetRunning(0, true)
   127  	s.Unlock()
   128  
   129  	// Start a wait with a timeout.
   130  	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   131  	defer cancel()
   132  	waitC := s.Wait(ctx, WaitConditionNotRunning)
   133  
   134  	// It should timeout *before* this 200ms timer does.
   135  	select {
   136  	case <-time.After(200 * time.Millisecond):
   137  		t.Fatal("Stop callback doesn't fire in 200 milliseconds")
   138  	case status := <-waitC:
   139  		t.Log("Stop callback fired")
   140  		// Should be a timeout error.
   141  		if status.Err() == nil {
   142  			t.Fatal("expected timeout error, got nil")
   143  		}
   144  		if status.ExitCode() != -1 {
   145  			t.Fatalf("expected exit code %v, got %v", -1, status.ExitCode())
   146  		}
   147  	}
   148  
   149  	s.Lock()
   150  	s.SetStopped(&ExitStatus{ExitCode: 0})
   151  	s.Unlock()
   152  
   153  	// Start another wait with a timeout. This one should return
   154  	// immediately.
   155  	ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
   156  	defer cancel()
   157  	waitC = s.Wait(ctx, WaitConditionNotRunning)
   158  
   159  	select {
   160  	case <-time.After(200 * time.Millisecond):
   161  		t.Fatal("Stop callback doesn't fire in 200 milliseconds")
   162  	case status := <-waitC:
   163  		t.Log("Stop callback fired")
   164  		if status.ExitCode() != 0 {
   165  			t.Fatalf("expected exit code %v, got %v, err %q", 0, status.ExitCode(), status.Err())
   166  		}
   167  	}
   168  }
   169  
   170  func TestIsValidStateString(t *testing.T) {
   171  	states := []struct {
   172  		state    string
   173  		expected bool
   174  	}{
   175  		{"paused", true},
   176  		{"restarting", true},
   177  		{"running", true},
   178  		{"dead", true},
   179  		{"start", false},
   180  		{"created", true},
   181  		{"exited", true},
   182  		{"removing", true},
   183  		{"stop", false},
   184  	}
   185  
   186  	for _, s := range states {
   187  		v := IsValidStateString(s.state)
   188  		if v != s.expected {
   189  			t.Fatalf("Expected %t, but got %t", s.expected, v)
   190  		}
   191  	}
   192  }