12 "git.curoverse.com/arvados.git/sdk/go/arvadostest"
13 "git.curoverse.com/arvados.git/sdk/go/keepclient"
18 // Gocheck boilerplate
19 func Test(t *testing.T) {
23 // Gocheck boilerplate
24 var _ = Suite(&ServerRequiredSuite{})
26 // Tests that require the Keep server running
27 type ServerRequiredSuite struct{}
29 func (s *ServerRequiredSuite) SetUpSuite(c *C) {
32 func (s *ServerRequiredSuite) SetUpTest(c *C) {
33 arvadostest.ResetEnv()
34 srcKeepServicesJSON = ""
35 dstKeepServicesJSON = ""
41 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
42 arvadostest.StopKeep()
46 var testKeepServicesJSON = "{ \"kind\":\"arvados#keepServiceList\", \"etag\":\"\", \"self_link\":\"\", \"offset\":null, \"limit\":null, \"items\":[ { \"href\":\"/keep_services/zzzzz-bi6l4-123456789012340\", \"kind\":\"arvados#keepService\", \"etag\":\"641234567890enhj7hzx432e5\", \"uuid\":\"zzzzz-bi6l4-123456789012340\", \"owner_uuid\":\"zzzzz-tpzed-123456789012345\", \"service_host\":\"keep0.zzzzz.arvadosapi.com\", \"service_port\":25107, \"service_ssl_flag\":false, \"service_type\":\"disk\", \"read_only\":false }, { \"href\":\"/keep_services/zzzzz-bi6l4-123456789012341\", \"kind\":\"arvados#keepService\", \"etag\":\"641234567890enhj7hzx432e5\", \"uuid\":\"zzzzz-bi6l4-123456789012341\", \"owner_uuid\":\"zzzzz-tpzed-123456789012345\", \"service_host\":\"keep0.zzzzz.arvadosapi.com\", \"service_port\":25108, \"service_ssl_flag\":false, \"service_type\":\"disk\", \"read_only\":false } ], \"items_available\":2 }"
48 // Testing keep-rsync needs two sets of keep services: src and dst.
49 // The test setup hence tweaks keep-rsync initialization to achieve this.
50 // First invoke initializeKeepRsync and then invoke StartKeepWithParams
51 // to create the keep servers to be used as destination.
52 func setupRsync(c *C, enforcePermissions bool, overwrite bool) {
54 srcConfig.APIHost = os.Getenv("ARVADOS_API_HOST")
55 srcConfig.APIToken = os.Getenv("ARVADOS_API_TOKEN")
56 srcConfig.APIHostInsecure = matchTrue.MatchString(os.Getenv("ARVADOS_API_HOST_INSECURE"))
59 dstConfig.APIHost = os.Getenv("ARVADOS_API_HOST")
60 dstConfig.APIToken = os.Getenv("ARVADOS_API_TOKEN")
61 dstConfig.APIHostInsecure = matchTrue.MatchString(os.Getenv("ARVADOS_API_HOST_INSECURE"))
63 if enforcePermissions {
64 blobSigningKey = "zfhgfenhffzltr9dixws36j1yhksjoll2grmku38mi7yxd66h5j4q9w4jzanezacp8s6q0ro3hxakfye02152hncy6zml2ed0uc"
67 // Start API and Keep servers
68 arvadostest.StartAPI()
69 arvadostest.StartKeepWithParams(false, enforcePermissions)
71 // initialize keep-rsync
72 err := initializeKeepRsync()
75 // Create an additional keep server to be used as destination and reload kcDst
76 // Set replications to 1 since those many keep servers were created for dst.
78 arvadostest.StartKeepWithParams(true, enforcePermissions)
81 kcDst, err = keepclient.MakeKeepClient(&arvDst)
83 kcDst.Want_replicas = 1
87 // Test readConfigFromFile method
88 func (s *ServerRequiredSuite) TestReadConfigFromFile(c *C) {
89 // Setup a test config file
90 file, err := ioutil.TempFile(os.TempDir(), "config")
92 defer os.Remove(file.Name())
94 fileContent := "ARVADOS_API_HOST=testhost\n"
95 fileContent += "ARVADOS_API_TOKEN=testtoken\n"
96 fileContent += "ARVADOS_API_HOST_INSECURE=true\n"
97 fileContent += "ARVADOS_BLOB_SIGNING_KEY=abcdefg"
99 _, err = file.Write([]byte(fileContent))
101 // Invoke readConfigFromFile method with this test filename
102 config, err := readConfigFromFile(file.Name())
104 c.Assert(config.APIHost, Equals, "testhost")
105 c.Assert(config.APIToken, Equals, "testtoken")
106 c.Assert(config.APIHostInsecure, Equals, true)
107 c.Assert(config.ExternalClient, Equals, false)
108 c.Assert(blobSigningKey, Equals, "abcdefg")
111 // Test keep-rsync initialization, with src and dst keep servers.
112 // Do a Put and Get in src, both of which should succeed.
113 // Do a Put and Get in dst, both of which should succeed.
114 // Do a Get in dst for the src hash, which should raise block not found error.
115 // Do a Get in src for the dst hash, which should raise block not found error.
116 func (s *ServerRequiredSuite) TestRsyncPutInOne_GetFromOtherShouldFail(c *C) {
117 setupRsync(c, false, true)
119 // Put a block in src using kcSrc and Get it
120 srcData := []byte("test-data1")
121 locatorInSrc := fmt.Sprintf("%x", md5.Sum(srcData))
123 hash, rep, err := kcSrc.PutB(srcData)
124 c.Check(hash, Matches, fmt.Sprintf(`^%s\+10(\+.+)?$`, locatorInSrc))
125 c.Check(rep, Equals, 2)
126 c.Check(err, Equals, nil)
128 reader, blocklen, _, err := kcSrc.Get(locatorInSrc)
130 c.Check(blocklen, Equals, int64(10))
131 all, err := ioutil.ReadAll(reader)
132 c.Check(all, DeepEquals, srcData)
134 // Put a different block in src using kcSrc and Get it
135 dstData := []byte("test-data2")
136 locatorInDst := fmt.Sprintf("%x", md5.Sum(dstData))
138 hash, rep, err = kcDst.PutB(dstData)
139 c.Check(hash, Matches, fmt.Sprintf(`^%s\+10(\+.+)?$`, locatorInDst))
140 c.Check(rep, Equals, 1)
141 c.Check(err, Equals, nil)
143 reader, blocklen, _, err = kcDst.Get(locatorInDst)
145 c.Check(blocklen, Equals, int64(10))
146 all, err = ioutil.ReadAll(reader)
147 c.Check(all, DeepEquals, dstData)
149 // Get srcLocator using kcDst should fail with Not Found error
150 _, _, _, err = kcDst.Get(locatorInSrc)
151 c.Assert(err.Error(), Equals, "Block not found")
153 // Get dstLocator using kcSrc should fail with Not Found error
154 _, _, _, err = kcSrc.Get(locatorInDst)
155 c.Assert(err.Error(), Equals, "Block not found")
158 // Test keep-rsync initialization, with srcKeepServicesJSON
159 func (s *ServerRequiredSuite) TestRsyncInitializeWithKeepServicesJSON(c *C) {
160 srcKeepServicesJSON = testKeepServicesJSON
162 setupRsync(c, false, true)
164 localRoots := kcSrc.LocalRoots()
165 c.Check(localRoots != nil, Equals, true)
168 for k := range localRoots {
169 if k == "zzzzz-bi6l4-123456789012340" {
173 c.Check(foundIt, Equals, true)
176 for k := range localRoots {
177 if k == "zzzzz-bi6l4-123456789012341" {
181 c.Check(foundIt, Equals, true)
184 // Test keep-rsync initialization, with src and dst keep servers with blobSigningKey.
185 // Do a Put and Get in src, both of which should succeed.
186 // Do a Put and Get in dst, both of which should succeed.
187 // Do a Get in dst for the src hash, which should raise block not found error.
188 // Do a Get in src for the dst hash, which should raise block not found error.
189 func (s *ServerRequiredSuite) TestRsyncWithBlobSigning_PutInOne_GetFromOtherShouldFail(c *C) {
190 setupRsync(c, true, true)
192 // Put a block in src using kcSrc and Get it
193 srcData := []byte("test-data1")
194 locatorInSrc := fmt.Sprintf("%x", md5.Sum(srcData))
196 hash, rep, err := kcSrc.PutB(srcData)
197 c.Check(hash, Matches, fmt.Sprintf(`^%s\+10(\+.+)?$`, locatorInSrc))
198 c.Check(rep, Equals, 2)
199 c.Check(err, Equals, nil)
201 tomorrow := time.Now().AddDate(0, 0, 1)
202 signedLocator := keepclient.SignLocator(locatorInSrc, arvSrc.ApiToken, tomorrow, []byte(blobSigningKey))
204 reader, blocklen, _, err := kcSrc.Get(signedLocator)
206 c.Check(blocklen, Equals, int64(10))
207 all, err := ioutil.ReadAll(reader)
208 c.Check(all, DeepEquals, srcData)
210 // Put a different block in src using kcSrc and Get it
211 dstData := []byte("test-data2")
212 locatorInDst := fmt.Sprintf("%x", md5.Sum(dstData))
214 hash, rep, err = kcDst.PutB(dstData)
215 c.Check(hash, Matches, fmt.Sprintf(`^%s\+10(\+.+)?$`, locatorInDst))
216 c.Check(rep, Equals, 1)
217 c.Check(err, Equals, nil)
219 signedLocator = keepclient.SignLocator(locatorInDst, arvDst.ApiToken, tomorrow, []byte(blobSigningKey))
221 reader, blocklen, _, err = kcDst.Get(signedLocator)
223 c.Check(blocklen, Equals, int64(10))
224 all, err = ioutil.ReadAll(reader)
225 c.Check(all, DeepEquals, dstData)
227 // Get srcLocator using kcDst should fail with Not Found error
228 signedLocator = keepclient.SignLocator(locatorInSrc, arvDst.ApiToken, tomorrow, []byte(blobSigningKey))
229 _, _, _, err = kcDst.Get(locatorInSrc)
230 c.Assert(err.Error(), Equals, "Block not found")
232 // Get dstLocator using kcSrc should fail with Not Found error
233 signedLocator = keepclient.SignLocator(locatorInDst, arvSrc.ApiToken, tomorrow, []byte(blobSigningKey))
234 _, _, _, err = kcSrc.Get(locatorInDst)
235 c.Assert(err.Error(), Equals, "Block not found")
238 // Test keep-rsync initialization with default replications count
239 func (s *ServerRequiredSuite) TestInitializeRsyncDefaultReplicationsCount(c *C) {
240 setupRsync(c, false, false)
242 // Must have got default replications value as 2 from dst discovery document
243 c.Assert(replications, Equals, 2)
246 // Test keep-rsync initialization with replications count argument
247 func (s *ServerRequiredSuite) TestInitializeRsyncReplicationsCount(c *C) {
248 // First set replications to 3 to mimic passing input argument
251 setupRsync(c, false, false)
253 // Since replications value is provided, default is not used
254 c.Assert(replications, Equals, 3)
257 // Put some blocks in Src and some more in Dst
258 // And copy missing blocks from Src to Dst
259 func (s *ServerRequiredSuite) TestKeepRsync(c *C) {
260 testKeepRsync(c, false, "")
263 // Put some blocks in Src and some more in Dst with blob signing enabled.
264 // And copy missing blocks from Src to Dst
265 func (s *ServerRequiredSuite) TestKeepRsync_WithBlobSigning(c *C) {
266 testKeepRsync(c, true, "")
269 // Put some blocks in Src and some more in Dst
270 // Use prefix while doing rsync
271 // And copy missing blocks from Src to Dst
272 func (s *ServerRequiredSuite) TestKeepRsync_WithPrefix(c *C) {
273 data := []byte("test-data-4")
274 hash := fmt.Sprintf("%x", md5.Sum(data))
276 testKeepRsync(c, false, hash[0:3])
279 // Put some blocks in Src and some more in Dst
280 // Use prefix not in src while doing rsync
281 // And copy missing blocks from Src to Dst
282 func (s *ServerRequiredSuite) TestKeepRsync_WithNoSuchPrefixInSrc(c *C) {
283 testKeepRsync(c, false, "999")
286 // Put 5 blocks in src. Put 2 of those blocks in dst
287 // Hence there are 3 additional blocks in src
288 // Also, put 2 extra blocks in dst; they are hence only in dst
289 // Run rsync and verify that those 7 blocks are now available in dst
290 func testKeepRsync(c *C, enforcePermissions bool, indexPrefix string) {
291 setupRsync(c, enforcePermissions, true)
295 tomorrow := time.Now().AddDate(0, 0, 1)
297 // Put a few blocks in src using kcSrc
298 var srcLocators []string
299 var srcLocatorsMatchingPrefix []string
300 for i := 0; i < 5; i++ {
301 data := []byte(fmt.Sprintf("test-data-%d", i))
302 hash := fmt.Sprintf("%x", md5.Sum(data))
304 hash2, rep, err := kcSrc.PutB(data)
305 c.Check(hash2, Matches, fmt.Sprintf(`^%s\+11(\+.+)?$`, hash))
306 c.Check(rep, Equals, 2)
310 if enforcePermissions {
311 getLocator = keepclient.SignLocator(getLocator, arvSrc.ApiToken, tomorrow, []byte(blobSigningKey))
314 reader, blocklen, _, err := kcSrc.Get(getLocator)
316 c.Check(blocklen, Equals, int64(11))
317 all, err := ioutil.ReadAll(reader)
318 c.Check(all, DeepEquals, data)
320 srcLocators = append(srcLocators, fmt.Sprintf("%s+%d", hash, blocklen))
321 if strings.HasPrefix(hash, indexPrefix) {
322 srcLocatorsMatchingPrefix = append(srcLocatorsMatchingPrefix, fmt.Sprintf("%s+%d", hash, blocklen))
326 // Put first two of those src blocks in dst using kcDst
327 var dstLocators []string
328 for i := 0; i < 2; i++ {
329 data := []byte(fmt.Sprintf("test-data-%d", i))
330 hash := fmt.Sprintf("%x", md5.Sum(data))
332 hash2, rep, err := kcDst.PutB(data)
333 c.Check(hash2, Matches, fmt.Sprintf(`^%s\+11(\+.+)?$`, hash))
334 c.Check(rep, Equals, 1)
338 if enforcePermissions {
339 getLocator = keepclient.SignLocator(getLocator, arvDst.ApiToken, tomorrow, []byte(blobSigningKey))
342 reader, blocklen, _, err := kcDst.Get(getLocator)
344 c.Check(blocklen, Equals, int64(11))
345 all, err := ioutil.ReadAll(reader)
346 c.Check(all, DeepEquals, data)
348 dstLocators = append(dstLocators, fmt.Sprintf("%s+%d", hash, blocklen))
351 // Put two more blocks in dst; they are not in src at all
352 var extraDstLocators []string
353 for i := 0; i < 2; i++ {
354 data := []byte(fmt.Sprintf("other-data-%d", i))
355 hash := fmt.Sprintf("%x", md5.Sum(data))
357 hash2, rep, err := kcDst.PutB(data)
358 c.Check(hash2, Matches, fmt.Sprintf(`^%s\+12(\+.+)?$`, hash))
359 c.Check(rep, Equals, 1)
363 if enforcePermissions {
364 getLocator = keepclient.SignLocator(getLocator, arvDst.ApiToken, tomorrow, []byte(blobSigningKey))
367 reader, blocklen, _, err := kcDst.Get(getLocator)
369 c.Check(blocklen, Equals, int64(12))
370 all, err := ioutil.ReadAll(reader)
371 c.Check(all, DeepEquals, data)
373 extraDstLocators = append(extraDstLocators, fmt.Sprintf("%s+%d", hash, blocklen))
376 err := performKeepRsync()
379 // Now GetIndex from dst and verify that all 5 from src and the 2 extra blocks are found
380 dstIndex, err := getUniqueLocators(kcDst, "")
384 for _, locator := range srcLocators {
385 _, ok := dstIndex[locator]
386 c.Assert(ok, Equals, true)
389 for _, locator := range srcLocatorsMatchingPrefix {
390 _, ok := dstIndex[locator]
391 c.Assert(ok, Equals, true)
395 for _, locator := range extraDstLocators {
396 _, ok := dstIndex[locator]
397 c.Assert(ok, Equals, true)
401 // all blocks from src and the two extra blocks
402 c.Assert(len(dstIndex), Equals, len(srcLocators)+len(extraDstLocators))
404 // one matching prefix, 2 that were initially copied into dst along with src, and the extra blocks
405 c.Assert(len(dstIndex), Equals, len(srcLocatorsMatchingPrefix)+len(extraDstLocators)+2)
409 // Setup rsync using srcKeepServicesJSON with fake keepservers.
410 // Expect error during performKeepRsync due to unreachable src keepservers.
411 func (s *ServerRequiredSuite) TestErrorDuringRsync_FakeSrcKeepservers(c *C) {
412 srcKeepServicesJSON = testKeepServicesJSON
414 setupRsync(c, false, true)
416 err := performKeepRsync()
420 // Setup rsync using dstKeepServicesJSON with fake keepservers.
421 // Expect error during performKeepRsync due to unreachable dst keepservers.
422 func (s *ServerRequiredSuite) TestErrorDuringRsync_FakeDstKeepservers(c *C) {
423 dstKeepServicesJSON = testKeepServicesJSON
425 setupRsync(c, false, false)
427 err := performKeepRsync()