13 "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
14 "git.curoverse.com/arvados.git/sdk/go/blockdigest"
15 "git.curoverse.com/arvados.git/sdk/go/keepclient"
20 // Gocheck boilerplate
21 func Test(t *testing.T) {
25 type KeepSuite struct{}
27 var _ = Suite(&KeepSuite{})
29 type TestHandler struct {
33 func (ts *TestHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
34 r := json.NewDecoder(req.Body)
38 func (s *KeepSuite) TestSendTrashLists(c *C) {
40 server := httptest.NewServer(&th)
43 tl := map[string]TrashList{
44 server.URL: TrashList{TrashRequest{"000000000000000000000000deadbeef", 99}}}
46 arv := arvadosclient.ArvadosClient{ApiToken: "abc123"}
47 kc := keepclient.KeepClient{Arvados: &arv, Client: &http.Client{}}
48 kc.SetServiceRoots(map[string]string{"xxxx": server.URL},
49 map[string]string{"xxxx": server.URL},
52 err := SendTrashLists(&kc, tl)
62 type TestHandlerError struct {
65 func (tse *TestHandlerError) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
66 http.Error(writer, "I'm a teapot", 418)
69 func sendTrashListError(c *C, server *httptest.Server) {
70 tl := map[string]TrashList{
71 server.URL: TrashList{TrashRequest{"000000000000000000000000deadbeef", 99}}}
73 arv := arvadosclient.ArvadosClient{ApiToken: "abc123"}
74 kc := keepclient.KeepClient{Arvados: &arv, Client: &http.Client{}}
75 kc.SetServiceRoots(map[string]string{"xxxx": server.URL},
76 map[string]string{"xxxx": server.URL},
79 err := SendTrashLists(&kc, tl)
82 c.Check(err[0], NotNil)
85 func (s *KeepSuite) TestSendTrashListErrorResponse(c *C) {
86 server := httptest.NewServer(&TestHandlerError{})
87 sendTrashListError(c, server)
91 func (s *KeepSuite) TestSendTrashListUnreachable(c *C) {
92 sendTrashListError(c, httptest.NewUnstartedServer(&TestHandler{}))
95 type StatusAndBody struct {
100 type APIStub struct {
101 data map[string]StatusAndBody
104 func (stub *APIStub) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
105 if req.URL.Path == "/redirect-loop" {
106 http.Redirect(resp, req, "/redirect-loop", http.StatusFound)
110 pathResponse := stub.data[req.URL.Path]
111 if pathResponse.responseBody != "" {
112 if pathResponse.respStatus == -1 {
113 http.Redirect(resp, req, "/redirect-loop", http.StatusFound)
115 resp.WriteHeader(pathResponse.respStatus)
116 resp.Write([]byte(pathResponse.responseBody))
119 resp.WriteHeader(500)
120 resp.Write([]byte(``))
124 type KeepServerStub struct {
125 data map[string]StatusAndBody
128 func (stub *KeepServerStub) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
129 if req.URL.Path == "/redirect-loop" {
130 http.Redirect(resp, req, "/redirect-loop", http.StatusFound)
134 pathResponse := stub.data[req.URL.Path]
135 if pathResponse.responseBody != "" {
136 if pathResponse.respStatus == -1 {
137 http.Redirect(resp, req, "/redirect-loop", http.StatusFound)
139 resp.WriteHeader(pathResponse.respStatus)
140 resp.Write([]byte(pathResponse.responseBody))
143 resp.WriteHeader(500)
144 resp.Write([]byte(``))
148 type APITestData struct {
154 func (s *KeepSuite) TestGetKeepServers_UnsupportedServiceType(c *C) {
155 testGetKeepServersFromAPI(c, APITestData{1, "notadisk", 200})
158 func (s *KeepSuite) TestGetKeepServers_ReceivedTooFewServers(c *C) {
159 testGetKeepServersFromAPI(c, APITestData{2, "disk", 200})
162 func (s *KeepSuite) TestGetKeepServers_ServerError(c *C) {
163 testGetKeepServersFromAPI(c, APITestData{-1, "disk", -1})
166 func testGetKeepServersFromAPI(c *C, testData APITestData) {
167 keepServers := ServiceList{
168 ItemsAvailable: testData.numServers,
169 KeepServers: []ServerAddress{{
174 ServiceType: testData.serverType,
178 ksJSON, _ := json.Marshal(keepServers)
179 apiData := make(map[string]StatusAndBody)
180 apiData["/arvados/v1/keep_services"] = StatusAndBody{testData.statusCode, string(ksJSON)}
181 apiStub := APIStub{apiData}
183 api := httptest.NewServer(&apiStub)
186 arv := arvadosclient.ArvadosClient{
188 ApiServer: api.URL[7:],
190 Client: &http.Client{Transport: &http.Transport{}},
193 kc := keepclient.KeepClient{Arvados: &arv, Client: &http.Client{}}
194 kc.SetServiceRoots(map[string]string{"xxxx": "http://example.com:23456"},
195 map[string]string{"xxxx": "http://example.com:23456"},
198 params := GetKeepServersParams{
204 _, err := GetKeepServersAndSummarize(params)
205 if testData.numServers > 1 {
206 c.Assert(err, ErrorMatches, ".*Did not receive all available keep servers.*")
207 } else if testData.serverType != "disk" {
208 c.Assert(err, ErrorMatches, ".*Unsupported service type.*")
212 type KeepServerTestData struct {
213 // handle /status.json
218 indexResponseBody string
220 // expected error, if any
224 func (s *KeepSuite) TestGetKeepServers_ErrorGettingKeepServerStatus(c *C) {
225 testGetKeepServersAndSummarize(c, KeepServerTestData{500, 200, "ok",
226 "500 Internal Server Error"})
229 func (s *KeepSuite) TestGetKeepServers_GettingIndex(c *C) {
230 testGetKeepServersAndSummarize(c, KeepServerTestData{200, -1, "notok",
234 func (s *KeepSuite) TestGetKeepServers_ErrorReadServerResponse(c *C) {
235 testGetKeepServersAndSummarize(c, KeepServerTestData{200, 500, "notok",
236 "500 Internal Server Error"})
239 func (s *KeepSuite) TestGetKeepServers_ReadServerResponseTuncatedAtLineOne(c *C) {
240 testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200,
241 "notterminatedwithnewline", "truncated at line 1"})
244 func (s *KeepSuite) TestGetKeepServers_InvalidBlockLocatorPattern(c *C) {
245 testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200, "testing\n",
246 "Error parsing BlockInfo from index line"})
249 func (s *KeepSuite) TestGetKeepServers_ReadServerResponseEmpty(c *C) {
250 testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200, "\n", ""})
253 func (s *KeepSuite) TestGetKeepServers_ReadServerResponseWithTwoBlocks(c *C) {
254 testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200,
255 "51752ba076e461ec9ec1d27400a08548+20 1447526361\na048cc05c02ba1ee43ad071274b9e547+52 1447526362\n\n", ""})
258 func testGetKeepServersAndSummarize(c *C, testData KeepServerTestData) {
259 ksData := make(map[string]StatusAndBody)
260 ksData["/status.json"] = StatusAndBody{testData.statusStatusCode, string(`{}`)}
261 ksData["/index"] = StatusAndBody{testData.indexStatusCode, testData.indexResponseBody}
262 ksStub := KeepServerStub{ksData}
263 ks := httptest.NewServer(&ksStub)
266 ksURL, err := url.Parse(ks.URL)
268 ksURLParts := strings.Split(ksURL.Host, ":")
269 ksPort, err := strconv.Atoi(ksURLParts[1])
272 servers_list := ServiceList{
274 KeepServers: []ServerAddress{{
276 Host: strings.Split(ksURL.Host, ":")[0],
282 ksJSON, _ := json.Marshal(servers_list)
283 apiData := make(map[string]StatusAndBody)
284 apiData["/arvados/v1/keep_services"] = StatusAndBody{200, string(ksJSON)}
285 apiStub := APIStub{apiData}
287 api := httptest.NewServer(&apiStub)
290 arv := arvadosclient.ArvadosClient{
292 ApiServer: api.URL[7:],
294 Client: &http.Client{Transport: &http.Transport{}},
297 kc := keepclient.KeepClient{Arvados: &arv, Client: &http.Client{}}
298 kc.SetServiceRoots(map[string]string{"xxxx": ks.URL},
299 map[string]string{"xxxx": ks.URL},
302 params := GetKeepServersParams{
308 // GetKeepServersAndSummarize
309 results, err := GetKeepServersAndSummarize(params)
311 if testData.expectedError == "" {
313 c.Assert(results, NotNil)
315 blockToServers := results.BlockToServers
317 blockLocators := strings.Split(testData.indexResponseBody, "\n")
318 for _, loc := range blockLocators {
319 locator := strings.Split(loc, " ")[0]
321 blockLocator, err := blockdigest.ParseBlockLocator(locator)
324 blockDigestWithSize := blockdigest.DigestWithSize{blockLocator.Digest, uint32(blockLocator.Size)}
325 blockServerInfo := blockToServers[blockDigestWithSize]
326 c.Assert(blockServerInfo[0].Mtime, NotNil)
330 if testData.expectedError == "Error parsing BlockInfo from index line" {
331 // In this case ErrorMatches does not work because the error message contains regexp match characters
332 strings.Contains(err.Error(), testData.expectedError)
334 c.Assert(err, ErrorMatches, fmt.Sprintf(".*%s.*", testData.expectedError))