7255: improve createMultiStreamBlockCollection to create collection with multiple...
[arvados.git] / services / datamanager / datamanager_test.go
index c2cb762d52b625b625634f24d385ddbf9ad4e7d8..094cd44b0f2b0d7dcb714554587f762519f82bf5 100644 (file)
@@ -16,11 +16,6 @@ import (
        "time"
 )
 
-const (
-       ActiveUserToken = "3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi"
-       AdminToken      = "4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h"
-)
-
 var arv arvadosclient.ArvadosClient
 var keepClient *keepclient.KeepClient
 var keepServers []string
@@ -34,6 +29,7 @@ func SetupDataManagerTest(t *testing.T) {
        arvadostest.StartKeep(2, false)
 
        arv = makeArvadosClient()
+       arv.ApiToken = arvadostest.DataManagerToken
 
        // keep client
        keepClient = &keepclient.KeepClient{
@@ -124,7 +120,18 @@ func getFirstLocatorFromCollection(t *testing.T, uuid string) string {
        return match[1] + "+" + match[2]
 }
 
+func switchToken(t string) func() {
+       orig := arv.ApiToken
+       restore := func() {
+               arv.ApiToken = orig
+       }
+       arv.ApiToken = t
+       return restore
+}
+
 func getCollection(t *testing.T, uuid string) Dict {
+       defer switchToken(arvadostest.AdminToken)()
+
        getback := make(Dict)
        err := arv.Get("collections", uuid, nil, &getback)
        if err != nil {
@@ -138,6 +145,8 @@ func getCollection(t *testing.T, uuid string) Dict {
 }
 
 func updateCollection(t *testing.T, uuid string, paramName string, paramValue string) {
+       defer switchToken(arvadostest.AdminToken)()
+
        err := arv.Update("collections", uuid, arvadosclient.Dict{
                "collection": arvadosclient.Dict{
                        paramName: paramValue,
@@ -152,6 +161,8 @@ func updateCollection(t *testing.T, uuid string, paramName string, paramValue st
 type Dict map[string]interface{}
 
 func deleteCollection(t *testing.T, uuid string) {
+       defer switchToken(arvadostest.AdminToken)()
+
        getback := make(Dict)
        err := arv.Delete("collections", uuid, nil, &getback)
        if err != nil {
@@ -175,7 +186,7 @@ func getBlockIndexesForServer(t *testing.T, i int) []string {
        path := keepServers[i] + "/index"
        client := http.Client{}
        req, err := http.NewRequest("GET", path, nil)
-       req.Header.Add("Authorization", "OAuth2 "+AdminToken)
+       req.Header.Add("Authorization", "OAuth2 "+arvadostest.DataManagerToken)
        req.Header.Add("Content-Type", "application/octet-stream")
        resp, err := client.Do(req)
        defer resp.Body.Close()
@@ -297,7 +308,7 @@ func backdateBlocks(t *testing.T, oldUnusedBlockLocators []string) {
 func getStatus(t *testing.T, path string) interface{} {
        client := http.Client{}
        req, err := http.NewRequest("GET", path, nil)
-       req.Header.Add("Authorization", "OAuth2 "+AdminToken)
+       req.Header.Add("Authorization", "OAuth2 "+arvadostest.DataManagerToken)
        req.Header.Add("Content-Type", "application/octet-stream")
        resp, err := client.Do(req)
        if err != nil {
@@ -389,6 +400,10 @@ func TestPutAndGetBlocks(t *testing.T) {
                t.Fatalf("Locators for both these collections expected to be same: %s %s", oneOfTwoWithSameDataLocator, secondOfTwoWithSameDataLocator)
        }
 
+       // create collection with empty manifest text
+       emptyBlockLocator := putBlock(t, "")
+       emptyCollection := createCollection(t, "")
+
        // Verify blocks before doing any backdating / deleting.
        var expected []string
        expected = append(expected, oldUnusedBlockLocators...)
@@ -397,6 +412,7 @@ func TestPutAndGetBlocks(t *testing.T) {
        expected = append(expected, replicationCollectionLocator)
        expected = append(expected, oneOfTwoWithSameDataLocator)
        expected = append(expected, secondOfTwoWithSameDataLocator)
+       expected = append(expected, emptyBlockLocator)
 
        verifyBlocks(t, nil, expected, 2)
 
@@ -410,6 +426,8 @@ func TestPutAndGetBlocks(t *testing.T) {
        backdateBlocks(t, oldUnusedBlockLocators)
        deleteCollection(t, toBeDeletedCollectionUUID)
        deleteCollection(t, secondOfTwoWithSameDataUUID)
+       backdateBlocks(t, []string{emptyBlockLocator})
+       deleteCollection(t, emptyCollection)
 
        // Run data manager again
        dataManagerSingleRun(t)
@@ -422,6 +440,7 @@ func TestPutAndGetBlocks(t *testing.T) {
        expected = append(expected, toBeDeletedCollectionLocator)
        expected = append(expected, oneOfTwoWithSameDataLocator)
        expected = append(expected, secondOfTwoWithSameDataLocator)
+       expected = append(expected, emptyBlockLocator) // even when unreferenced, this remains
 
        verifyBlocks(t, oldUnusedBlockLocators, expected, 2)
 
@@ -504,10 +523,100 @@ func TestRunDatamanagerAsNonAdminUser(t *testing.T) {
        defer TearDownDataManagerTest(t)
        SetupDataManagerTest(t)
 
-       arv.ApiToken = ActiveUserToken
+       arv.ApiToken = arvadostest.ActiveToken
 
        err := singlerun(arv)
        if err == nil {
                t.Fatalf("Expected error during singlerun as non-admin user")
        }
 }
+
+// Create a collection with multiple streams and blocks
+func createMultiStreamBlockCollection(t *testing.T, data string, numStreams, numBlocks int) (string, []string) {
+       defer switchToken(arvadostest.AdminToken)()
+
+       manifest := ""
+       var locators []string
+       for s := 0; s < numStreams; s++ {
+               manifest += fmt.Sprintf("./stream%d ", s)
+               for b := 0; b < numBlocks; b++ {
+                       locator, _, err := keepClient.PutB([]byte(fmt.Sprintf("%s in stream %d and block %d", data, s, b)))
+                       if err != nil {
+                               t.Fatalf("Error creating block %d in stream %d: %v", b, s, err)
+                       }
+                       locators = append(locators, strings.Split(locator, "+A")[0])
+                       manifest += locator + " "
+               }
+               manifest += "0:1:dummyfile.txt\n"
+       }
+
+       collection := make(Dict)
+       err := arv.Create("collections",
+               arvadosclient.Dict{"collection": arvadosclient.Dict{"manifest_text": manifest}},
+               &collection)
+
+       if err != nil {
+               t.Fatalf("Error creating collection %v", err)
+       }
+
+       return collection["uuid"].(string), locators
+}
+
+/*
+  Create collection with multiple streams and blocks; backdate the blocks and but do not delete the collection.
+  Create another collection with multiple streams and blocks; backdate it's blocks and delete the collection.
+  After datamanager run: expect blocks from the first collection, but none from the second collection.
+*/
+func TestPutAndGetCollectionsWithMultipleStreamsAndBlocks(t *testing.T) {
+       defer TearDownDataManagerTest(t)
+       SetupDataManagerTest(t)
+
+       // create collection whose blocks will be backdated
+       collectionWithOldBlocks, oldBlocks := createMultiStreamBlockCollection(t, "old block", 100, 10)
+       if collectionWithOldBlocks == "" {
+               t.Fatalf("Failed to create collection with 1000 blocks")
+       }
+       if len(oldBlocks) != 1000 {
+               t.Fatalf("Not all blocks are created: expected %v, found %v", 1000, len(oldBlocks))
+       }
+
+       // create another collection, whose blocks will be backdated and the collection will be deleted
+       toBeDeletedCollection, toBeDeletedCollectionBlocks := createMultiStreamBlockCollection(t, "new block", 2, 5)
+       if toBeDeletedCollection == "" {
+               t.Fatalf("Failed to create collection with 10 blocks")
+       }
+
+       // create a stray block that will be backdated
+       strayOldBlock := putBlock(t, "this stray block is old")
+
+       // create another block that will not be backdated
+       strayNewBlock := putBlock(t, "this stray block is new")
+
+       expected := []string{}
+       expected = append(expected, oldBlocks...)
+       expected = append(expected, toBeDeletedCollectionBlocks...)
+       expected = append(expected, strayOldBlock)
+       expected = append(expected, strayNewBlock)
+       verifyBlocks(t, nil, expected, 2)
+
+       // Backdate old blocks; but the collection still references these blocks
+       backdateBlocks(t, oldBlocks)
+
+       // Backdate first block from the newer blocks and delete the collection; the rest are still be reachable
+       backdateBlocks(t, toBeDeletedCollectionBlocks)
+       deleteCollection(t, toBeDeletedCollection)
+
+       // also backdate the stray old block
+       backdateBlocks(t, []string{strayOldBlock})
+
+       // run datamanager
+       dataManagerSingleRun(t)
+
+       expected = []string{strayNewBlock}
+       expected = append(expected, oldBlocks...)
+
+       notExpected := []string{strayOldBlock}
+       notExpected = append(notExpected, toBeDeletedCollectionBlocks...)
+
+       verifyBlocks(t, notExpected, expected, 2)
+}