123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- package containerd
- import (
- "context"
- "io/ioutil"
- "os"
- "sync"
- "testing"
- "time"
- "github.com/docker/docker/libcontainerd"
- "github.com/gotestyourself/gotestyourself/assert"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- )
- func TestLifeCycle(t *testing.T) {
- t.Parallel()
- mock := newMockClient()
- exec, cleanup := setupTest(t, mock, mock)
- defer cleanup()
- id := "test-create"
- mock.simulateStartError(true, id)
- err := exec.Create(id, specs.Spec{}, nil, nil)
- assert.Assert(t, err != nil)
- mock.simulateStartError(false, id)
- err = exec.Create(id, specs.Spec{}, nil, nil)
- assert.Assert(t, err)
- running, _ := exec.IsRunning(id)
- assert.Assert(t, running)
- // create with the same ID
- err = exec.Create(id, specs.Spec{}, nil, nil)
- assert.Assert(t, err != nil)
- mock.HandleExitEvent(id) // simulate a plugin that exits
- err = exec.Create(id, specs.Spec{}, nil, nil)
- assert.Assert(t, err)
- }
- func setupTest(t *testing.T, client Client, eh ExitHandler) (*Executor, func()) {
- rootDir, err := ioutil.TempDir("", "test-daemon")
- assert.Assert(t, err)
- assert.Assert(t, client != nil)
- assert.Assert(t, eh != nil)
- return &Executor{
- rootDir: rootDir,
- client: client,
- exitHandler: eh,
- }, func() {
- assert.Assert(t, os.RemoveAll(rootDir))
- }
- }
- type mockClient struct {
- mu sync.Mutex
- containers map[string]bool
- errorOnStart map[string]bool
- }
- func newMockClient() *mockClient {
- return &mockClient{
- containers: make(map[string]bool),
- errorOnStart: make(map[string]bool),
- }
- }
- func (c *mockClient) Create(ctx context.Context, id string, _ *specs.Spec, _ interface{}) error {
- c.mu.Lock()
- defer c.mu.Unlock()
- if _, ok := c.containers[id]; ok {
- return errors.New("exists")
- }
- c.containers[id] = false
- return nil
- }
- func (c *mockClient) Restore(ctx context.Context, id string, attachStdio libcontainerd.StdioCallback) (alive bool, pid int, err error) {
- return false, 0, nil
- }
- func (c *mockClient) Status(ctx context.Context, id string) (libcontainerd.Status, error) {
- c.mu.Lock()
- defer c.mu.Unlock()
- running, ok := c.containers[id]
- if !ok {
- return libcontainerd.StatusUnknown, errors.New("not found")
- }
- if running {
- return libcontainerd.StatusRunning, nil
- }
- return libcontainerd.StatusStopped, nil
- }
- func (c *mockClient) Delete(ctx context.Context, id string) error {
- c.mu.Lock()
- defer c.mu.Unlock()
- delete(c.containers, id)
- return nil
- }
- func (c *mockClient) DeleteTask(ctx context.Context, id string) (uint32, time.Time, error) {
- return 0, time.Time{}, nil
- }
- func (c *mockClient) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio libcontainerd.StdioCallback) (pid int, err error) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if _, ok := c.containers[id]; !ok {
- return 0, errors.New("not found")
- }
- if c.errorOnStart[id] {
- return 0, errors.New("some startup error")
- }
- c.containers[id] = true
- return 1, nil
- }
- func (c *mockClient) SignalProcess(ctx context.Context, containerID, processID string, signal int) error {
- return nil
- }
- func (c *mockClient) simulateStartError(sim bool, id string) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if sim {
- c.errorOnStart[id] = sim
- return
- }
- delete(c.errorOnStart, id)
- }
- func (c *mockClient) HandleExitEvent(id string) error {
- c.mu.Lock()
- defer c.mu.Unlock()
- delete(c.containers, id)
- return nil
- }
|