|
@@ -0,0 +1,108 @@
|
|
|
+package service // import "github.com/docker/docker/integration/service"
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "fmt"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "github.com/docker/docker/api/types"
|
|
|
+ "github.com/docker/docker/api/types/filters"
|
|
|
+ swarmtypes "github.com/docker/docker/api/types/swarm"
|
|
|
+ "github.com/docker/docker/api/types/versions"
|
|
|
+ "github.com/docker/docker/integration/internal/swarm"
|
|
|
+ "gotest.tools/assert"
|
|
|
+ is "gotest.tools/assert/cmp"
|
|
|
+ "gotest.tools/poll"
|
|
|
+ "gotest.tools/skip"
|
|
|
+)
|
|
|
+
|
|
|
+// TestServiceListWithStatuses tests that performing a ServiceList operation
|
|
|
+// correctly uses the Status parameter, and that the resulting response
|
|
|
+// contains correct service statuses.
|
|
|
+//
|
|
|
+// NOTE(dperny): because it's a pain to elicit the behavior of an unconverged
|
|
|
+// service reliably, I'm not testing that an unconverged service returns X
|
|
|
+// running and Y desired tasks. Instead, I'm just going to trust that I can
|
|
|
+// successfully assign a value to another value without screwing it up. The
|
|
|
+// logic for computing service statuses is in swarmkit anyway, not in the
|
|
|
+// engine, and is well-tested there, so this test just needs to make sure that
|
|
|
+// statuses get correctly associated with the right services.
|
|
|
+func TestServiceListWithStatuses(t *testing.T) {
|
|
|
+ skip.If(t, testEnv.IsRemoteDaemon)
|
|
|
+ skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
|
+ // statuses were added in API version 1.41
|
|
|
+ skip.If(t, versions.LessThan(testEnv.DaemonInfo.ServerVersion, "1.41"))
|
|
|
+ defer setupTest(t)()
|
|
|
+ d := swarm.NewSwarm(t, testEnv)
|
|
|
+ defer d.Stop(t)
|
|
|
+ client := d.NewClientT(t)
|
|
|
+ defer client.Close()
|
|
|
+
|
|
|
+ ctx := context.Background()
|
|
|
+
|
|
|
+ serviceCount := 3
|
|
|
+ // create some services.
|
|
|
+ for i := 0; i < serviceCount; i++ {
|
|
|
+ spec := fullSwarmServiceSpec(fmt.Sprintf("test-list-%d", i), uint64(i+1))
|
|
|
+ // for whatever reason, the args "-u root", when included, cause these
|
|
|
+ // tasks to fail and exit. instead, we'll just pass no args, which
|
|
|
+ // works.
|
|
|
+ spec.TaskTemplate.ContainerSpec.Args = []string{}
|
|
|
+ resp, err := client.ServiceCreate(ctx, spec, types.ServiceCreateOptions{
|
|
|
+ QueryRegistry: false,
|
|
|
+ })
|
|
|
+ assert.NilError(t, err)
|
|
|
+ id := resp.ID
|
|
|
+ // we need to wait specifically for the tasks to be running, which the
|
|
|
+ // serviceContainerCount function does not do. instead, we'll use a
|
|
|
+ // bespoke closure right here.
|
|
|
+ poll.WaitOn(t, func(log poll.LogT) poll.Result {
|
|
|
+ filter := filters.NewArgs()
|
|
|
+ filter.Add("service", id)
|
|
|
+ tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
|
|
+ Filters: filter,
|
|
|
+ })
|
|
|
+
|
|
|
+ running := 0
|
|
|
+ for _, task := range tasks {
|
|
|
+ if task.Status.State == swarmtypes.TaskStateRunning {
|
|
|
+ running++
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ switch {
|
|
|
+ case err != nil:
|
|
|
+ return poll.Error(err)
|
|
|
+ case running == i+1:
|
|
|
+ return poll.Success()
|
|
|
+ default:
|
|
|
+ return poll.Continue(
|
|
|
+ "running task count %d (%d total), waiting for %d",
|
|
|
+ running, len(tasks), i+1,
|
|
|
+ )
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // now, let's do the list operation with no status arg set.
|
|
|
+ resp, err := client.ServiceList(ctx, types.ServiceListOptions{})
|
|
|
+ assert.NilError(t, err)
|
|
|
+ assert.Check(t, is.Len(resp, serviceCount))
|
|
|
+ for _, service := range resp {
|
|
|
+ assert.Check(t, is.Nil(service.ServiceStatus))
|
|
|
+ }
|
|
|
+
|
|
|
+ // now try again, but with Status: true. This time, we should have statuses
|
|
|
+ resp, err = client.ServiceList(ctx, types.ServiceListOptions{Status: true})
|
|
|
+ assert.NilError(t, err)
|
|
|
+ assert.Check(t, is.Len(resp, serviceCount))
|
|
|
+ for _, service := range resp {
|
|
|
+ replicas := *service.Spec.Mode.Replicated.Replicas
|
|
|
+
|
|
|
+ assert.Assert(t, service.ServiceStatus != nil)
|
|
|
+ // Use assert.Check to not fail out of the test if this fails
|
|
|
+ assert.Check(t, is.Equal(service.ServiceStatus.DesiredTasks, replicas))
|
|
|
+ assert.Check(t, is.Equal(service.ServiceStatus.RunningTasks, replicas))
|
|
|
+ }
|
|
|
+
|
|
|
+}
|