containerd_test.go 3.3 KB

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