containerd_test.go 3.3 KB

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