Merge branch 'master' into 9161-node-state-fixes
[arvados.git] / services / crunch-dispatch-local / crunch-dispatch-local_test.go
1 package main
2
3 import (
4         "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
5         "git.curoverse.com/arvados.git/sdk/go/arvadostest"
6
7         "bytes"
8         "log"
9         "net/http"
10         "net/http/httptest"
11         "os"
12         "syscall"
13         "testing"
14         "time"
15
16         . "gopkg.in/check.v1"
17 )
18
19 // Gocheck boilerplate
20 func Test(t *testing.T) {
21         TestingT(t)
22 }
23
24 var _ = Suite(&TestSuite{})
25 var _ = Suite(&MockArvadosServerSuite{})
26
27 type TestSuite struct{}
28 type MockArvadosServerSuite struct{}
29
30 var initialArgs []string
31
32 func (s *TestSuite) SetUpSuite(c *C) {
33         initialArgs = os.Args
34         arvadostest.StartAPI()
35 }
36
37 func (s *TestSuite) TearDownSuite(c *C) {
38         arvadostest.StopAPI()
39 }
40
41 func (s *TestSuite) SetUpTest(c *C) {
42         args := []string{"crunch-dispatch-local"}
43         os.Args = args
44
45         var err error
46         arv, err = arvadosclient.MakeArvadosClient()
47         if err != nil {
48                 c.Fatalf("Error making arvados client: %s", err)
49         }
50 }
51
52 func (s *TestSuite) TearDownTest(c *C) {
53         arvadostest.ResetEnv()
54         os.Args = initialArgs
55 }
56
57 func (s *MockArvadosServerSuite) TearDownTest(c *C) {
58         arvadostest.ResetEnv()
59 }
60
61 func (s *TestSuite) Test_doMain(c *C) {
62         args := []string{"-poll-interval", "2", "-container-priority-poll-interval", "1", "-crunch-run-command", "echo"}
63         os.Args = append(os.Args, args...)
64
65         go func() {
66                 time.Sleep(5 * time.Second)
67                 sigChan <- syscall.SIGINT
68         }()
69
70         err := doMain()
71         c.Check(err, IsNil)
72
73         // There should be no queued containers now
74         params := arvadosclient.Dict{
75                 "filters": [][]string{[]string{"state", "=", "Queued"}},
76         }
77         var containers ContainerList
78         err = arv.List("containers", params, &containers)
79         c.Check(err, IsNil)
80         c.Assert(len(containers.Items), Equals, 0)
81
82         // Previously "Queued" container should now be in "Complete" state
83         var container Container
84         err = arv.Get("containers", "zzzzz-dz642-queuedcontainer", nil, &container)
85         c.Check(err, IsNil)
86         c.Check(container.State, Equals, "Complete")
87 }
88
89 func (s *MockArvadosServerSuite) Test_APIErrorGettingContainers(c *C) {
90         apiStubResponses := make(map[string]arvadostest.StubResponse)
91         apiStubResponses["/arvados/v1/containers"] = arvadostest.StubResponse{500, string(`{}`)}
92
93         testWithServerStub(c, apiStubResponses, "echo", "Error getting list of queued containers")
94 }
95
96 func (s *MockArvadosServerSuite) Test_APIErrorUpdatingContainerState(c *C) {
97         apiStubResponses := make(map[string]arvadostest.StubResponse)
98         apiStubResponses["/arvados/v1/containers"] =
99                 arvadostest.StubResponse{200, string(`{"items_available":1, "items":[{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx1"}]}`)}
100         apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx1"] =
101                 arvadostest.StubResponse{500, string(`{}`)}
102
103         testWithServerStub(c, apiStubResponses, "echo", "Error updating container zzzzz-dz642-xxxxxxxxxxxxxx1 to 'Locked' state")
104 }
105
106 func (s *MockArvadosServerSuite) Test_ContainerStillInRunningAfterRun(c *C) {
107         apiStubResponses := make(map[string]arvadostest.StubResponse)
108         apiStubResponses["/arvados/v1/containers"] =
109                 arvadostest.StubResponse{200, string(`{"items_available":1, "items":[{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx2"}]}`)}
110         apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx2"] =
111                 arvadostest.StubResponse{200, string(`{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx2", "state":"Running", "priority":1}`)}
112
113         testWithServerStub(c, apiStubResponses, "echo",
114                 "After crunch-run process termination, the state is still 'Running' for zzzzz-dz642-xxxxxxxxxxxxxx2")
115 }
116
117 func (s *MockArvadosServerSuite) Test_ErrorRunningContainer(c *C) {
118         apiStubResponses := make(map[string]arvadostest.StubResponse)
119         apiStubResponses["/arvados/v1/containers"] =
120                 arvadostest.StubResponse{200, string(`{"items_available":1, "items":[{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx3"}]}`)}
121         apiStubResponses["/arvados/v1/containers/zzzzz-dz642-xxxxxxxxxxxxxx3"] =
122                 arvadostest.StubResponse{200, string(`{"uuid":"zzzzz-dz642-xxxxxxxxxxxxxx3", "state":"Running", "priority":1}`)}
123
124         testWithServerStub(c, apiStubResponses, "nosuchcommand", "Error starting crunch-run for zzzzz-dz642-xxxxxxxxxxxxxx3")
125 }
126
127 func testWithServerStub(c *C, apiStubResponses map[string]arvadostest.StubResponse, crunchCmd string, expected string) {
128         apiStub := arvadostest.ServerStub{apiStubResponses}
129
130         api := httptest.NewServer(&apiStub)
131         defer api.Close()
132
133         arv = arvadosclient.ArvadosClient{
134                 Scheme:    "http",
135                 ApiServer: api.URL[7:],
136                 ApiToken:  "abc123",
137                 Client:    &http.Client{Transport: &http.Transport{}},
138                 Retries:   0,
139         }
140
141         buf := bytes.NewBuffer(nil)
142         log.SetOutput(buf)
143         defer log.SetOutput(os.Stderr)
144
145         go func() {
146                 time.Sleep(2 * time.Second)
147                 sigChan <- syscall.SIGTERM
148         }()
149
150         runQueuedContainers(time.Second, time.Second, crunchCmd)
151
152         // Wait for all running crunch jobs to complete / terminate
153         waitGroup.Wait()
154
155         c.Check(buf.String(), Matches, `(?ms).*`+expected+`.*`)
156 }