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