1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
20 "git.curoverse.com/arvados.git/sdk/go/arvados"
21 "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
22 "git.curoverse.com/arvados.git/sdk/go/arvadostest"
23 "git.curoverse.com/arvados.git/sdk/go/dispatch"
27 // Gocheck boilerplate
28 func Test(t *testing.T) {
32 var _ = Suite(&TestSuite{})
33 var _ = Suite(&MockArvadosServerSuite{})
35 type TestSuite struct{}
36 type MockArvadosServerSuite struct{}
38 var initialArgs []string
40 func (s *TestSuite) SetUpSuite(c *C) {
42 arvadostest.StartAPI()
43 runningCmds = make(map[string]*exec.Cmd)
46 func (s *TestSuite) TearDownSuite(c *C) {
50 func (s *TestSuite) SetUpTest(c *C) {
51 args := []string{"crunch-dispatch-local"}
55 func (s *TestSuite) TearDownTest(c *C) {
56 arvadostest.ResetEnv()
60 func (s *MockArvadosServerSuite) TearDownTest(c *C) {
61 arvadostest.ResetEnv()
64 func (s *TestSuite) TestIntegration(c *C) {
65 arv, err := arvadosclient.MakeArvadosClient()
69 crunchRunCommand = &echo
71 ctx, cancel := context.WithCancel(context.Background())
72 dispatcher := dispatch.Dispatcher{
74 PollPeriod: time.Second,
75 RunContainer: func(d *dispatch.Dispatcher, c arvados.Container, s <-chan arvados.Container) {
81 startCmd = func(container arvados.Container, cmd *exec.Cmd) error {
82 dispatcher.UpdateState(container.UUID, "Running")
83 dispatcher.UpdateState(container.UUID, "Complete")
87 err = dispatcher.Run(ctx)
88 c.Assert(err, Equals, context.Canceled)
90 // Wait for all running crunch jobs to complete / terminate
93 // There should be no queued containers now
94 params := arvadosclient.Dict{
95 "filters": [][]string{{"state", "=", "Queued"}},
97 var containers arvados.ContainerList
98 err = arv.List("containers", params, &containers)
100 c.Assert(len(containers.Items), Equals, 0)
102 // Previously "Queued" container should now be in "Complete" state
103 var container arvados.Container
104 err = arv.Get("containers", "zzzzz-dz642-queuedcontainer", nil, &container)
106 c.Check(string(container.State), Equals, "Complete")
109 func (s *MockArvadosServerSuite) Test_APIErrorGettingContainers(c *C) {
110 apiStubResponses := make(map[string]arvadostest.StubResponse)
111 apiStubResponses["/arvados/v1/containers"] = arvadostest.StubResponse{500, string(`{}`)}
113 testWithServerStub(c, apiStubResponses, "echo", "Error getting list of containers")
116 func (s *MockArvadosServerSuite) Test_APIErrorUpdatingContainerState(c *C) {
117 apiStubResponses := make(map[string]arvadostest.StubResponse)
118 apiStubResponses["/arvados/v1/containers"] =
119 arvadostest.StubResponse{200, string(`{"items_available":1, "items":[{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx1","State":"Queued","Priority":1}]}`)}
120 apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx1"] =
121 arvadostest.StubResponse{500, string(`{}`)}
123 testWithServerStub(c, apiStubResponses, "echo", "error locking container zzzzz-dz642-xxxxxxxxxxxxxx1")
126 func (s *MockArvadosServerSuite) Test_ContainerStillInRunningAfterRun(c *C) {
127 apiStubResponses := make(map[string]arvadostest.StubResponse)
128 apiStubResponses["/arvados/v1/containers"] =
129 arvadostest.StubResponse{200, string(`{"items_available":1, "items":[{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx2","State":"Queued","Priority":1}]}`)}
130 apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx2/lock"] =
131 arvadostest.StubResponse{200, string(`{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx2", "state":"Locked", "priority":1, "locked_by_uuid": "` + arvadostest.Dispatch1AuthUUID + `"}`)}
132 apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx2"] =
133 arvadostest.StubResponse{200, string(`{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx2", "state":"Running", "priority":1, "locked_by_uuid": "` + arvadostest.Dispatch1AuthUUID + `"}`)}
135 testWithServerStub(c, apiStubResponses, "echo",
136 `After echo process termination, container state for Running is "zzzzz-dz642-xxxxxxxxxxxxxx2". Updating it to "Cancelled"`)
139 func (s *MockArvadosServerSuite) Test_ErrorRunningContainer(c *C) {
140 apiStubResponses := make(map[string]arvadostest.StubResponse)
141 apiStubResponses["/arvados/v1/containers"] =
142 arvadostest.StubResponse{200, string(`{"items_available":1, "items":[{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx3","State":"Queued","Priority":1}]}`)}
144 apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx3/lock"] =
145 arvadostest.StubResponse{200, string(`{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx3", "state":"Locked", "priority":1}`)}
147 testWithServerStub(c, apiStubResponses, "nosuchcommand", "Error starting nosuchcommand for zzzzz-dz642-xxxxxxxxxxxxxx3")
150 func testWithServerStub(c *C, apiStubResponses map[string]arvadostest.StubResponse, crunchCmd string, expected string) {
151 apiStubResponses["/arvados/v1/api_client_authorizations/current"] =
152 arvadostest.StubResponse{200, string(`{"uuid": "` + arvadostest.Dispatch1AuthUUID + `", "api_token": "xyz"}`)}
154 apiStub := arvadostest.ServerStub{apiStubResponses}
156 api := httptest.NewServer(&apiStub)
159 arv := &arvadosclient.ArvadosClient{
161 ApiServer: api.URL[7:],
163 Client: &http.Client{Transport: &http.Transport{}},
167 buf := bytes.NewBuffer(nil)
168 log.SetOutput(io.MultiWriter(buf, os.Stderr))
169 defer log.SetOutput(os.Stderr)
171 *crunchRunCommand = crunchCmd
173 ctx, cancel := context.WithCancel(context.Background())
174 dispatcher := dispatch.Dispatcher{
176 PollPeriod: time.Duration(1) * time.Second,
177 RunContainer: func(d *dispatch.Dispatcher, c arvados.Container, s <-chan arvados.Container) {
183 startCmd = func(container arvados.Container, cmd *exec.Cmd) error {
184 dispatcher.UpdateState(container.UUID, "Running")
185 dispatcher.UpdateState(container.UUID, "Complete")
190 for i := 0; i < 80 && !strings.Contains(buf.String(), expected); i++ {
191 time.Sleep(100 * time.Millisecond)
196 err := dispatcher.Run(ctx)
197 c.Assert(err, Equals, context.Canceled)
199 // Wait for all running crunch jobs to complete / terminate
202 c.Check(buf.String(), Matches, `(?ms).*`+expected+`.*`)