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