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