Merge branch '9005-keep-http-client'
[arvados.git] / services / keepstore / pull_worker_integration_test.go
1 package main
2
3 import (
4         "bytes"
5         "errors"
6         "io"
7         "io/ioutil"
8         "os"
9         "strings"
10         "testing"
11
12         "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
13         "git.curoverse.com/arvados.git/sdk/go/arvadostest"
14         "git.curoverse.com/arvados.git/sdk/go/keepclient"
15 )
16
17 var keepClient *keepclient.KeepClient
18
19 type PullWorkIntegrationTestData struct {
20         Name     string
21         Locator  string
22         Content  string
23         GetError string
24 }
25
26 func SetupPullWorkerIntegrationTest(t *testing.T, testData PullWorkIntegrationTestData, wantData bool) PullRequest {
27         os.Setenv("ARVADOS_API_HOST_INSECURE", "true")
28
29         // start api and keep servers
30         arvadostest.StartAPI()
31         arvadostest.StartKeep(2, false)
32
33         // make arvadosclient
34         arv, err := arvadosclient.MakeArvadosClient()
35         if err != nil {
36                 t.Error("Error creating arv")
37         }
38
39         // keep client
40         keepClient = &keepclient.KeepClient{
41                 Arvados:       arv,
42                 Want_replicas: 1,
43         }
44
45         // discover keep services
46         var servers []string
47         if err := keepClient.DiscoverKeepServers(); err != nil {
48                 t.Error("Error discovering keep services")
49         }
50         for _, host := range keepClient.LocalRoots() {
51                 servers = append(servers, host)
52         }
53
54         // Put content if the test needs it
55         if wantData {
56                 locator, _, err := keepClient.PutB([]byte(testData.Content))
57                 if err != nil {
58                         t.Errorf("Error putting test data in setup for %s %s %v", testData.Content, locator, err)
59                 }
60                 if locator == "" {
61                         t.Errorf("No locator found after putting test data")
62                 }
63         }
64
65         // Create pullRequest for the test
66         pullRequest := PullRequest{
67                 Locator: testData.Locator,
68                 Servers: servers,
69         }
70         return pullRequest
71 }
72
73 // Do a get on a block that is not existing in any of the keep servers.
74 // Expect "block not found" error.
75 func TestPullWorkerIntegration_GetNonExistingLocator(t *testing.T) {
76         testData := PullWorkIntegrationTestData{
77                 Name:     "TestPullWorkerIntegration_GetLocator",
78                 Locator:  "5d41402abc4b2a76b9719d911017c592",
79                 Content:  "hello",
80                 GetError: "Block not found",
81         }
82
83         pullRequest := SetupPullWorkerIntegrationTest(t, testData, false)
84         defer arvadostest.StopAPI()
85         defer arvadostest.StopKeep(2)
86
87         performPullWorkerIntegrationTest(testData, pullRequest, t)
88 }
89
90 // Do a get on a block that exists on one of the keep servers.
91 // The setup method will create this block before doing the get.
92 func TestPullWorkerIntegration_GetExistingLocator(t *testing.T) {
93         testData := PullWorkIntegrationTestData{
94                 Name:     "TestPullWorkerIntegration_GetLocator",
95                 Locator:  "5d41402abc4b2a76b9719d911017c592",
96                 Content:  "hello",
97                 GetError: "",
98         }
99
100         pullRequest := SetupPullWorkerIntegrationTest(t, testData, true)
101         defer arvadostest.StopAPI()
102         defer arvadostest.StopKeep(2)
103
104         performPullWorkerIntegrationTest(testData, pullRequest, t)
105 }
106
107 // Perform the test.
108 // The test directly invokes the "PullItemAndProcess" rather than
109 // putting an item on the pullq so that the errors can be verified.
110 func performPullWorkerIntegrationTest(testData PullWorkIntegrationTestData, pullRequest PullRequest, t *testing.T) {
111
112         // Override writePulledBlock to mock PutBlock functionality
113         defer func(orig func(Volume, []byte, string)) { writePulledBlock = orig }(writePulledBlock)
114         writePulledBlock = func(v Volume, content []byte, locator string) {
115                 if string(content) != testData.Content {
116                         t.Errorf("writePulledBlock invoked with unexpected data. Expected: %s; Found: %s", testData.Content, content)
117                 }
118         }
119
120         // Override GetContent to mock keepclient Get functionality
121         defer func(orig func(string, *keepclient.KeepClient) (io.ReadCloser, int64, string, error)) {
122                 GetContent = orig
123         }(GetContent)
124         GetContent = func(signedLocator string, keepClient *keepclient.KeepClient) (reader io.ReadCloser, contentLength int64, url string, err error) {
125                 if testData.GetError != "" {
126                         return nil, 0, "", errors.New(testData.GetError)
127                 }
128                 rdr := ioutil.NopCloser(bytes.NewBufferString(testData.Content))
129                 return rdr, int64(len(testData.Content)), "", nil
130         }
131
132         err := PullItemAndProcess(pullRequest, keepClient)
133
134         if len(testData.GetError) > 0 {
135                 if (err == nil) || (!strings.Contains(err.Error(), testData.GetError)) {
136                         t.Errorf("Got error %v, expected %v", err, testData.GetError)
137                 }
138         } else {
139                 if err != nil {
140                         t.Errorf("Got error %v, expected nil", err)
141                 }
142         }
143 }