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