list_test.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package service // import "github.com/docker/docker/integration/service"
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/filters"
  7. swarmtypes "github.com/docker/docker/api/types/swarm"
  8. "github.com/docker/docker/integration/internal/swarm"
  9. "gotest.tools/v3/assert"
  10. is "gotest.tools/v3/assert/cmp"
  11. "gotest.tools/v3/poll"
  12. "gotest.tools/v3/skip"
  13. )
  14. // TestServiceListWithStatuses tests that performing a ServiceList operation
  15. // correctly uses the Status parameter, and that the resulting response
  16. // contains correct service statuses.
  17. //
  18. // NOTE(dperny): because it's a pain to elicit the behavior of an unconverged
  19. // service reliably, I'm not testing that an unconverged service returns X
  20. // running and Y desired tasks. Instead, I'm just going to trust that I can
  21. // successfully assign a value to another value without screwing it up. The
  22. // logic for computing service statuses is in swarmkit anyway, not in the
  23. // engine, and is well-tested there, so this test just needs to make sure that
  24. // statuses get correctly associated with the right services.
  25. func TestServiceListWithStatuses(t *testing.T) {
  26. skip.If(t, testEnv.IsRemoteDaemon)
  27. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  28. ctx := setupTest(t)
  29. d := swarm.NewSwarm(ctx, t, testEnv)
  30. defer d.Stop(t)
  31. client := d.NewClientT(t)
  32. defer client.Close()
  33. serviceCount := 3
  34. // create some services.
  35. for i := 0; i < serviceCount; i++ {
  36. spec := fullSwarmServiceSpec(fmt.Sprintf("test-list-%d", i), uint64(i+1))
  37. // for whatever reason, the args "-u root", when included, cause these
  38. // tasks to fail and exit. instead, we'll just pass no args, which
  39. // works.
  40. spec.TaskTemplate.ContainerSpec.Args = []string{}
  41. resp, err := client.ServiceCreate(ctx, spec, types.ServiceCreateOptions{
  42. QueryRegistry: false,
  43. })
  44. assert.NilError(t, err)
  45. id := resp.ID
  46. // we need to wait specifically for the tasks to be running, which the
  47. // serviceContainerCount function does not do. instead, we'll use a
  48. // bespoke closure right here.
  49. poll.WaitOn(t, func(log poll.LogT) poll.Result {
  50. tasks, err := client.TaskList(ctx, types.TaskListOptions{
  51. Filters: filters.NewArgs(filters.Arg("service", id)),
  52. })
  53. running := 0
  54. for _, task := range tasks {
  55. if task.Status.State == swarmtypes.TaskStateRunning {
  56. running++
  57. }
  58. }
  59. switch {
  60. case err != nil:
  61. return poll.Error(err)
  62. case running == i+1:
  63. return poll.Success()
  64. default:
  65. return poll.Continue(
  66. "running task count %d (%d total), waiting for %d",
  67. running, len(tasks), i+1,
  68. )
  69. }
  70. })
  71. }
  72. // now, let's do the list operation with no status arg set.
  73. resp, err := client.ServiceList(ctx, types.ServiceListOptions{})
  74. assert.NilError(t, err)
  75. assert.Check(t, is.Len(resp, serviceCount))
  76. for _, service := range resp {
  77. assert.Check(t, is.Nil(service.ServiceStatus))
  78. }
  79. // now try again, but with Status: true. This time, we should have statuses
  80. resp, err = client.ServiceList(ctx, types.ServiceListOptions{Status: true})
  81. assert.NilError(t, err)
  82. assert.Check(t, is.Len(resp, serviceCount))
  83. for _, service := range resp {
  84. replicas := *service.Spec.Mode.Replicated.Replicas
  85. assert.Assert(t, service.ServiceStatus != nil)
  86. // Use assert.Check to not fail out of the test if this fails
  87. assert.Check(t, is.Equal(service.ServiceStatus.DesiredTasks, replicas))
  88. assert.Check(t, is.Equal(service.ServiceStatus.RunningTasks, replicas))
  89. }
  90. }