package service import ( "context" "testing" "github.com/docker/docker/api/types" swarmtypes "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/integration/internal/swarm" "gotest.tools/v3/assert" "gotest.tools/v3/poll" "gotest.tools/v3/skip" ) // The file jobs_test.go contains tests that verify that services which are in // the mode ReplicatedJob or GlobalJob. // TestCreateJob tests that a Service can be created and run with // mode ReplicatedJob func TestCreateJob(t *testing.T) { skip.If(t, testEnv.IsRemoteDaemon) skip.If(t, testEnv.DaemonInfo.OSType == "windows") defer setupTest(t) d := swarm.NewSwarm(t, testEnv) defer d.Stop(t) client := d.NewClientT(t) defer client.Close() for _, mode := range []swarmtypes.ServiceMode{ {ReplicatedJob: &swarmtypes.ReplicatedJob{}}, {GlobalJob: &swarmtypes.GlobalJob{}}, } { id := swarm.CreateService(t, d, swarm.ServiceWithMode(mode)) poll.WaitOn(t, swarm.RunningTasksCount(client, id, 1), swarm.ServicePoll) } } // TestReplicatedJob tests that running a replicated job starts the requisite // number of tasks, func TestReplicatedJob(t *testing.T) { skip.If(t, testEnv.IsRemoteDaemon) skip.If(t, testEnv.DaemonInfo.OSType == "windows") // we need variables, because the replicas field takes a pointer maxConcurrent := uint64(2) // there is overhead, especially in the test environment, associated with // starting tasks. if total is set too high, then the time needed to // complete the test, even if everything is proceeding ideally, may exceed // the time the test has to execute // // in CI,the test has been seen to time out with as few as 7 completions // after 15 seconds. this means 7 completions ought not be too many. total := uint64(7) defer setupTest(t) d := swarm.NewSwarm(t, testEnv) defer d.Stop(t) client := d.NewClientT(t) defer client.Close() id := swarm.CreateService(t, d, swarm.ServiceWithMode(swarmtypes.ServiceMode{ ReplicatedJob: &swarmtypes.ReplicatedJob{ MaxConcurrent: &maxConcurrent, TotalCompletions: &total, }, }), // just run a command to execute and exit peacefully. swarm.ServiceWithCommand([]string{"true"}), ) service, _, err := client.ServiceInspectWithRaw( context.Background(), id, types.ServiceInspectOptions{}, ) assert.NilError(t, err) poll.WaitOn(t, swarm.JobComplete(client, service), swarm.ServicePoll) } // TestUpdateJob tests that a job can be updated, and that it runs with the // correct parameters. func TestUpdateReplicatedJob(t *testing.T) { skip.If(t, testEnv.IsRemoteDaemon) skip.If(t, testEnv.DaemonInfo.OSType == "windows") defer setupTest(t)() d := swarm.NewSwarm(t, testEnv) defer d.Stop(t) client := d.NewClientT(t) defer client.Close() // avoid writing "context.Background()" over and over again ctx := context.Background() // Create the job service id := swarm.CreateService(t, d, swarm.ServiceWithMode(swarmtypes.ServiceMode{ ReplicatedJob: &swarmtypes.ReplicatedJob{ // use the default, empty values. }, }), // run "true" so the task exits with 0 swarm.ServiceWithCommand([]string{"true"}), ) service, _, err := client.ServiceInspectWithRaw( ctx, id, types.ServiceInspectOptions{}, ) assert.NilError(t, err) // wait for the job to completed poll.WaitOn(t, swarm.JobComplete(client, service), swarm.ServicePoll) // update the job. spec := service.Spec spec.TaskTemplate.ForceUpdate++ _, err = client.ServiceUpdate( ctx, id, service.Version, spec, types.ServiceUpdateOptions{}, ) assert.NilError(t, err) service2, _, err := client.ServiceInspectWithRaw( ctx, id, types.ServiceInspectOptions{}, ) assert.NilError(t, err) // assert that the job iteration has increased assert.Assert(t, service.JobStatus.JobIteration.Index < service2.JobStatus.JobIteration.Index, ) // now wait for the service to complete a second time. poll.WaitOn(t, swarm.JobComplete(client, service2), swarm.ServicePoll) }