github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/plugin/executor/containerd/containerd_test.go (about) 1 package containerd 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/docker/docker/libcontainerd" 12 "github.com/gotestyourself/gotestyourself/assert" 13 specs "github.com/opencontainers/runtime-spec/specs-go" 14 "github.com/pkg/errors" 15 ) 16 17 func TestLifeCycle(t *testing.T) { 18 t.Parallel() 19 20 mock := newMockClient() 21 exec, cleanup := setupTest(t, mock, mock) 22 defer cleanup() 23 24 id := "test-create" 25 mock.simulateStartError(true, id) 26 err := exec.Create(id, specs.Spec{}, nil, nil) 27 assert.Assert(t, err != nil) 28 mock.simulateStartError(false, id) 29 30 err = exec.Create(id, specs.Spec{}, nil, nil) 31 assert.Assert(t, err) 32 running, _ := exec.IsRunning(id) 33 assert.Assert(t, running) 34 35 // create with the same ID 36 err = exec.Create(id, specs.Spec{}, nil, nil) 37 assert.Assert(t, err != nil) 38 39 mock.HandleExitEvent(id) // simulate a plugin that exits 40 41 err = exec.Create(id, specs.Spec{}, nil, nil) 42 assert.Assert(t, err) 43 } 44 45 func setupTest(t *testing.T, client Client, eh ExitHandler) (*Executor, func()) { 46 rootDir, err := ioutil.TempDir("", "test-daemon") 47 assert.Assert(t, err) 48 assert.Assert(t, client != nil) 49 assert.Assert(t, eh != nil) 50 51 return &Executor{ 52 rootDir: rootDir, 53 client: client, 54 exitHandler: eh, 55 }, func() { 56 assert.Assert(t, os.RemoveAll(rootDir)) 57 } 58 } 59 60 type mockClient struct { 61 mu sync.Mutex 62 containers map[string]bool 63 errorOnStart map[string]bool 64 } 65 66 func newMockClient() *mockClient { 67 return &mockClient{ 68 containers: make(map[string]bool), 69 errorOnStart: make(map[string]bool), 70 } 71 } 72 73 func (c *mockClient) Create(ctx context.Context, id string, _ *specs.Spec, _ interface{}) error { 74 c.mu.Lock() 75 defer c.mu.Unlock() 76 77 if _, ok := c.containers[id]; ok { 78 return errors.New("exists") 79 } 80 81 c.containers[id] = false 82 return nil 83 } 84 85 func (c *mockClient) Restore(ctx context.Context, id string, attachStdio libcontainerd.StdioCallback) (alive bool, pid int, err error) { 86 return false, 0, nil 87 } 88 89 func (c *mockClient) Status(ctx context.Context, id string) (libcontainerd.Status, error) { 90 c.mu.Lock() 91 defer c.mu.Unlock() 92 93 running, ok := c.containers[id] 94 if !ok { 95 return libcontainerd.StatusUnknown, errors.New("not found") 96 } 97 if running { 98 return libcontainerd.StatusRunning, nil 99 } 100 return libcontainerd.StatusStopped, nil 101 } 102 103 func (c *mockClient) Delete(ctx context.Context, id string) error { 104 c.mu.Lock() 105 defer c.mu.Unlock() 106 delete(c.containers, id) 107 return nil 108 } 109 110 func (c *mockClient) DeleteTask(ctx context.Context, id string) (uint32, time.Time, error) { 111 return 0, time.Time{}, nil 112 } 113 114 func (c *mockClient) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio libcontainerd.StdioCallback) (pid int, err error) { 115 c.mu.Lock() 116 defer c.mu.Unlock() 117 118 if _, ok := c.containers[id]; !ok { 119 return 0, errors.New("not found") 120 } 121 122 if c.errorOnStart[id] { 123 return 0, errors.New("some startup error") 124 } 125 c.containers[id] = true 126 return 1, nil 127 } 128 129 func (c *mockClient) SignalProcess(ctx context.Context, containerID, processID string, signal int) error { 130 return nil 131 } 132 133 func (c *mockClient) simulateStartError(sim bool, id string) { 134 c.mu.Lock() 135 defer c.mu.Unlock() 136 if sim { 137 c.errorOnStart[id] = sim 138 return 139 } 140 delete(c.errorOnStart, id) 141 } 142 143 func (c *mockClient) HandleExitEvent(id string) error { 144 c.mu.Lock() 145 defer c.mu.Unlock() 146 delete(c.containers, id) 147 return nil 148 }