inspect_test.go 4.4 KB

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