inspect_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package service // import "github.com/docker/docker/integration/service"
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/container"
  7. "github.com/docker/docker/api/types/filters"
  8. swarmtypes "github.com/docker/docker/api/types/swarm"
  9. "github.com/docker/docker/client"
  10. "github.com/docker/docker/integration/internal/swarm"
  11. "github.com/google/go-cmp/cmp"
  12. "github.com/gotestyourself/gotestyourself/assert"
  13. is "github.com/gotestyourself/gotestyourself/assert/cmp"
  14. "github.com/gotestyourself/gotestyourself/poll"
  15. "github.com/gotestyourself/gotestyourself/skip"
  16. "golang.org/x/net/context"
  17. )
  18. func TestInspect(t *testing.T) {
  19. skip.If(t, testEnv.IsRemoteDaemon())
  20. defer setupTest(t)()
  21. d := swarm.NewSwarm(t, testEnv)
  22. defer d.Stop(t)
  23. client := d.NewClientT(t)
  24. defer client.Close()
  25. var now = time.Now()
  26. var instances uint64 = 2
  27. serviceSpec := fullSwarmServiceSpec("test-service-inspect", instances)
  28. ctx := context.Background()
  29. resp, err := client.ServiceCreate(ctx, serviceSpec, types.ServiceCreateOptions{
  30. QueryRegistry: false,
  31. })
  32. assert.NilError(t, err)
  33. id := resp.ID
  34. poll.WaitOn(t, serviceContainerCount(client, id, instances))
  35. service, _, err := client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
  36. assert.NilError(t, err)
  37. expected := swarmtypes.Service{
  38. ID: id,
  39. Spec: serviceSpec,
  40. Meta: swarmtypes.Meta{
  41. Version: swarmtypes.Version{Index: uint64(11)},
  42. CreatedAt: now,
  43. UpdatedAt: now,
  44. },
  45. }
  46. assert.Check(t, is.DeepEqual(service, expected, cmpServiceOpts()))
  47. }
  48. // TODO: use helpers from gotestyourself/assert/opt when available
  49. func cmpServiceOpts() cmp.Option {
  50. const threshold = 20 * time.Second
  51. metaTimeFields := func(path cmp.Path) bool {
  52. switch path.String() {
  53. case "Meta.CreatedAt", "Meta.UpdatedAt":
  54. return true
  55. }
  56. return false
  57. }
  58. withinThreshold := cmp.Comparer(func(x, y time.Time) bool {
  59. delta := x.Sub(y)
  60. return delta < threshold && delta > -threshold
  61. })
  62. return cmp.FilterPath(metaTimeFields, withinThreshold)
  63. }
  64. func fullSwarmServiceSpec(name string, replicas uint64) swarmtypes.ServiceSpec {
  65. restartDelay := 100 * time.Millisecond
  66. maxAttempts := uint64(4)
  67. return swarmtypes.ServiceSpec{
  68. Annotations: swarmtypes.Annotations{
  69. Name: name,
  70. Labels: map[string]string{
  71. "service-label": "service-label-value",
  72. },
  73. },
  74. TaskTemplate: swarmtypes.TaskSpec{
  75. ContainerSpec: &swarmtypes.ContainerSpec{
  76. Image: "busybox:latest",
  77. Labels: map[string]string{"container-label": "container-value"},
  78. Command: []string{"/bin/top"},
  79. Args: []string{"-u", "root"},
  80. Hostname: "hostname",
  81. Env: []string{"envvar=envvalue"},
  82. Dir: "/work",
  83. User: "root",
  84. StopSignal: "SIGINT",
  85. StopGracePeriod: &restartDelay,
  86. Hosts: []string{"8.8.8.8 google"},
  87. DNSConfig: &swarmtypes.DNSConfig{
  88. Nameservers: []string{"8.8.8.8"},
  89. Search: []string{"somedomain"},
  90. },
  91. Isolation: container.IsolationDefault,
  92. },
  93. RestartPolicy: &swarmtypes.RestartPolicy{
  94. Delay: &restartDelay,
  95. Condition: swarmtypes.RestartPolicyConditionOnFailure,
  96. MaxAttempts: &maxAttempts,
  97. },
  98. Runtime: swarmtypes.RuntimeContainer,
  99. },
  100. Mode: swarmtypes.ServiceMode{
  101. Replicated: &swarmtypes.ReplicatedService{
  102. Replicas: &replicas,
  103. },
  104. },
  105. UpdateConfig: &swarmtypes.UpdateConfig{
  106. Parallelism: 2,
  107. Delay: 200 * time.Second,
  108. FailureAction: swarmtypes.UpdateFailureActionContinue,
  109. Monitor: 2 * time.Second,
  110. MaxFailureRatio: 0.2,
  111. Order: swarmtypes.UpdateOrderStopFirst,
  112. },
  113. RollbackConfig: &swarmtypes.UpdateConfig{
  114. Parallelism: 3,
  115. Delay: 300 * time.Second,
  116. FailureAction: swarmtypes.UpdateFailureActionPause,
  117. Monitor: 3 * time.Second,
  118. MaxFailureRatio: 0.3,
  119. Order: swarmtypes.UpdateOrderStartFirst,
  120. },
  121. }
  122. }
  123. func serviceContainerCount(client client.ServiceAPIClient, id string, count uint64) func(log poll.LogT) poll.Result {
  124. return func(log poll.LogT) poll.Result {
  125. filter := filters.NewArgs()
  126. filter.Add("service", id)
  127. tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
  128. Filters: filter,
  129. })
  130. switch {
  131. case err != nil:
  132. return poll.Error(err)
  133. case len(tasks) == int(count):
  134. return poll.Success()
  135. default:
  136. return poll.Continue("task count at %d waiting for %d", len(tasks), count)
  137. }
  138. }
  139. }