X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/a5f4236f9dfc56e7374d108cc595c2aab57e3a0e..3445ed729dbccd21878373e01477be79e74a8453:/services/keepstore/handler_test.go diff --git a/services/keepstore/handler_test.go b/services/keepstore/handler_test.go index 68e80c410c..3817ea1900 100644 --- a/services/keepstore/handler_test.go +++ b/services/keepstore/handler_test.go @@ -46,27 +46,27 @@ func TestGetHandler(t *testing.T) { defer KeepVM.Close() vols := KeepVM.AllWritable() - if err := vols[0].Put(TEST_HASH, TEST_BLOCK); err != nil { + if err := vols[0].Put(TestHash, TestBlock); err != nil { t.Error(err) } // Create locators for testing. // Turn on permission settings so we can generate signed locators. - enforce_permissions = true - PermissionSecret = []byte(known_key) - blob_signature_ttl = 300 * time.Second + enforcePermissions = true + PermissionSecret = []byte(knownKey) + blobSignatureTTL = 300 * time.Second var ( - unsignedLocator = "/" + TEST_HASH - validTimestamp = time.Now().Add(blob_signature_ttl) + unsignedLocator = "/" + TestHash + validTimestamp = time.Now().Add(blobSignatureTTL) expiredTimestamp = time.Now().Add(-time.Hour) - signedLocator = "/" + SignLocator(TEST_HASH, known_token, validTimestamp) - expiredLocator = "/" + SignLocator(TEST_HASH, known_token, expiredTimestamp) + signedLocator = "/" + SignLocator(TestHash, knownToken, validTimestamp) + expiredLocator = "/" + SignLocator(TestHash, knownToken, expiredTimestamp) ) // ----------------- // Test unauthenticated request with permissions off. - enforce_permissions = false + enforcePermissions = false // Unauthenticated request, unsigned locator // => OK @@ -79,33 +79,33 @@ func TestGetHandler(t *testing.T) { "Unauthenticated request, unsigned locator", http.StatusOK, response) ExpectBody(t, "Unauthenticated request, unsigned locator", - string(TEST_BLOCK), + string(TestBlock), response) receivedLen := response.Header().Get("Content-Length") - expectedLen := fmt.Sprintf("%d", len(TEST_BLOCK)) + expectedLen := fmt.Sprintf("%d", len(TestBlock)) if receivedLen != expectedLen { t.Errorf("expected Content-Length %s, got %s", expectedLen, receivedLen) } // ---------------- // Permissions: on. - enforce_permissions = true + enforcePermissions = true // Authenticated request, signed locator // => OK response = IssueRequest(&RequestTester{ method: "GET", uri: signedLocator, - apiToken: known_token, + apiToken: knownToken, }) ExpectStatusCode(t, "Authenticated request, signed locator", http.StatusOK, response) ExpectBody(t, - "Authenticated request, signed locator", string(TEST_BLOCK), response) + "Authenticated request, signed locator", string(TestBlock), response) receivedLen = response.Header().Get("Content-Length") - expectedLen = fmt.Sprintf("%d", len(TEST_BLOCK)) + expectedLen = fmt.Sprintf("%d", len(TestBlock)) if receivedLen != expectedLen { t.Errorf("expected Content-Length %s, got %s", expectedLen, receivedLen) } @@ -115,7 +115,7 @@ func TestGetHandler(t *testing.T) { response = IssueRequest(&RequestTester{ method: "GET", uri: unsignedLocator, - apiToken: known_token, + apiToken: knownToken, }) ExpectStatusCode(t, "unsigned locator", PermissionError.HTTPCode, response) @@ -134,7 +134,7 @@ func TestGetHandler(t *testing.T) { response = IssueRequest(&RequestTester{ method: "GET", uri: expiredLocator, - apiToken: known_token, + apiToken: knownToken, }) ExpectStatusCode(t, "Authenticated request, expired locator", @@ -158,25 +158,25 @@ func TestPutHandler(t *testing.T) { // Unauthenticated request, no server key // => OK (unsigned response) - unsignedLocator := "/" + TEST_HASH + unsignedLocator := "/" + TestHash response := IssueRequest( &RequestTester{ method: "PUT", uri: unsignedLocator, - requestBody: TEST_BLOCK, + requestBody: TestBlock, }) ExpectStatusCode(t, "Unauthenticated request, no server key", http.StatusOK, response) ExpectBody(t, "Unauthenticated request, no server key", - TEST_HASH_PUT_RESPONSE, response) + TestHashPutResp, response) // ------------------ // With a server key. - PermissionSecret = []byte(known_key) - blob_signature_ttl = 300 * time.Second + PermissionSecret = []byte(knownKey) + blobSignatureTTL = 300 * time.Second // When a permission key is available, the locator returned // from an authenticated PUT request will be signed. @@ -187,15 +187,15 @@ func TestPutHandler(t *testing.T) { &RequestTester{ method: "PUT", uri: unsignedLocator, - requestBody: TEST_BLOCK, - apiToken: known_token, + requestBody: TestBlock, + apiToken: knownToken, }) ExpectStatusCode(t, "Authenticated PUT, signed locator, with server key", http.StatusOK, response) responseLocator := strings.TrimSpace(response.Body.String()) - if VerifySignature(responseLocator, known_token) != nil { + if VerifySignature(responseLocator, knownToken) != nil { t.Errorf("Authenticated PUT, signed locator, with server key:\n"+ "response '%s' does not contain a valid signature", responseLocator) @@ -207,7 +207,7 @@ func TestPutHandler(t *testing.T) { &RequestTester{ method: "PUT", uri: unsignedLocator, - requestBody: TEST_BLOCK, + requestBody: TestBlock, }) ExpectStatusCode(t, @@ -215,12 +215,12 @@ func TestPutHandler(t *testing.T) { http.StatusOK, response) ExpectBody(t, "Unauthenticated PUT, unsigned locator, with server key", - TEST_HASH_PUT_RESPONSE, response) + TestHashPutResp, response) } func TestPutAndDeleteSkipReadonlyVolumes(t *testing.T) { defer teardown() - data_manager_token = "fake-data-manager-token" + dataManagerToken = "fake-data-manager-token" vols := []*MockVolume{CreateMockVolume(), CreateMockVolume()} vols[0].Readonly = true KeepVM = MakeRRVolumeManager([]Volume{vols[0], vols[1]}) @@ -228,19 +228,19 @@ func TestPutAndDeleteSkipReadonlyVolumes(t *testing.T) { IssueRequest( &RequestTester{ method: "PUT", - uri: "/" + TEST_HASH, - requestBody: TEST_BLOCK, + uri: "/" + TestHash, + requestBody: TestBlock, }) defer func(orig bool) { - never_delete = orig - }(never_delete) - never_delete = false + neverDelete = orig + }(neverDelete) + neverDelete = false IssueRequest( &RequestTester{ method: "DELETE", - uri: "/" + TEST_HASH, - requestBody: TEST_BLOCK, - apiToken: data_manager_token, + uri: "/" + TestHash, + requestBody: TestBlock, + apiToken: dataManagerToken, }) type expect struct { volnum int @@ -274,7 +274,7 @@ func TestPutAndDeleteSkipReadonlyVolumes(t *testing.T) { // - authenticated /index/prefix request | superuser // // The only /index requests that should succeed are those issued by the -// superuser. They should pass regardless of the value of enforce_permissions. +// superuser. They should pass regardless of the value of enforcePermissions. // func TestIndexHandler(t *testing.T) { defer teardown() @@ -286,12 +286,12 @@ func TestIndexHandler(t *testing.T) { defer KeepVM.Close() vols := KeepVM.AllWritable() - vols[0].Put(TEST_HASH, TEST_BLOCK) - vols[1].Put(TEST_HASH_2, TEST_BLOCK_2) - vols[0].Put(TEST_HASH+".meta", []byte("metadata")) - vols[1].Put(TEST_HASH_2+".meta", []byte("metadata")) + vols[0].Put(TestHash, TestBlock) + vols[1].Put(TestHash2, TestBlock2) + vols[0].Put(TestHash+".meta", []byte("metadata")) + vols[1].Put(TestHash2+".meta", []byte("metadata")) - data_manager_token = "DATA MANAGER TOKEN" + dataManagerToken = "DATA MANAGER TOKEN" unauthenticatedReq := &RequestTester{ method: "GET", @@ -300,41 +300,51 @@ func TestIndexHandler(t *testing.T) { authenticatedReq := &RequestTester{ method: "GET", uri: "/index", - apiToken: known_token, + apiToken: knownToken, } superuserReq := &RequestTester{ method: "GET", uri: "/index", - apiToken: data_manager_token, + apiToken: dataManagerToken, } unauthPrefixReq := &RequestTester{ method: "GET", - uri: "/index/" + TEST_HASH[0:3], + uri: "/index/" + TestHash[0:3], } authPrefixReq := &RequestTester{ method: "GET", - uri: "/index/" + TEST_HASH[0:3], - apiToken: known_token, + uri: "/index/" + TestHash[0:3], + apiToken: knownToken, } superuserPrefixReq := &RequestTester{ method: "GET", - uri: "/index/" + TEST_HASH[0:3], - apiToken: data_manager_token, + uri: "/index/" + TestHash[0:3], + apiToken: dataManagerToken, + } + superuserNoSuchPrefixReq := &RequestTester{ + method: "GET", + uri: "/index/abcd", + apiToken: dataManagerToken, + } + superuserInvalidPrefixReq := &RequestTester{ + method: "GET", + uri: "/index/xyz", + apiToken: dataManagerToken, } // ------------------------------------------------------------- // Only the superuser should be allowed to issue /index requests. // --------------------------- - // enforce_permissions enabled + // enforcePermissions enabled // This setting should not affect tests passing. - enforce_permissions = true + enforcePermissions = true // unauthenticated /index request // => UnauthorizedError response := IssueRequest(unauthenticatedReq) ExpectStatusCode(t, - "enforce_permissions on, unauthenticated request", + "enforcePermissions on, unauthenticated request", UnauthorizedError.HTTPCode, response) @@ -371,9 +381,9 @@ func TestIndexHandler(t *testing.T) { response) // ---------------------------- - // enforce_permissions disabled + // enforcePermissions disabled // Valid Request should still pass. - enforce_permissions = false + enforcePermissions = false // superuser /index request // => OK @@ -383,8 +393,8 @@ func TestIndexHandler(t *testing.T) { http.StatusOK, response) - expected := `^` + TEST_HASH + `\+\d+ \d+\n` + - TEST_HASH_2 + `\+\d+ \d+\n\n$` + expected := `^` + TestHash + `\+\d+ \d+\n` + + TestHash2 + `\+\d+ \d+\n\n$` match, _ := regexp.MatchString(expected, response.Body.String()) if !match { t.Errorf( @@ -400,13 +410,33 @@ func TestIndexHandler(t *testing.T) { http.StatusOK, response) - expected = `^` + TEST_HASH + `\+\d+ \d+\n\n$` + expected = `^` + TestHash + `\+\d+ \d+\n\n$` match, _ = regexp.MatchString(expected, response.Body.String()) if !match { t.Errorf( "permissions on, superuser /index/prefix request: expected %s, got:\n%s", expected, response.Body.String()) } + + // superuser /index/{no-such-prefix} request + // => OK + response = IssueRequest(superuserNoSuchPrefixReq) + ExpectStatusCode(t, + "permissions on, superuser request", + http.StatusOK, + response) + + if "\n" != response.Body.String() { + t.Errorf("Expected empty response for %s. Found %s", superuserNoSuchPrefixReq.uri, response.Body.String()) + } + + // superuser /index/{invalid-prefix} request + // => StatusBadRequest + response = IssueRequest(superuserInvalidPrefixReq) + ExpectStatusCode(t, + "permissions on, superuser request", + http.StatusBadRequest, + response) } // TestDeleteHandler @@ -445,39 +475,39 @@ func TestDeleteHandler(t *testing.T) { defer KeepVM.Close() vols := KeepVM.AllWritable() - vols[0].Put(TEST_HASH, TEST_BLOCK) + vols[0].Put(TestHash, TestBlock) - // Explicitly set the blob_signature_ttl to 0 for these + // Explicitly set the blobSignatureTTL to 0 for these // tests, to ensure the MockVolume deletes the blocks // even though they have just been created. - blob_signature_ttl = time.Duration(0) + blobSignatureTTL = time.Duration(0) var userToken = "NOT DATA MANAGER TOKEN" - data_manager_token = "DATA MANAGER TOKEN" + dataManagerToken = "DATA MANAGER TOKEN" - never_delete = false + neverDelete = false unauthReq := &RequestTester{ method: "DELETE", - uri: "/" + TEST_HASH, + uri: "/" + TestHash, } userReq := &RequestTester{ method: "DELETE", - uri: "/" + TEST_HASH, + uri: "/" + TestHash, apiToken: userToken, } superuserExistingBlockReq := &RequestTester{ method: "DELETE", - uri: "/" + TEST_HASH, - apiToken: data_manager_token, + uri: "/" + TestHash, + apiToken: dataManagerToken, } superuserNonexistentBlockReq := &RequestTester{ method: "DELETE", - uri: "/" + TEST_HASH_2, - apiToken: data_manager_token, + uri: "/" + TestHash2, + apiToken: dataManagerToken, } // Unauthenticated request returns PermissionError. @@ -508,14 +538,14 @@ func TestDeleteHandler(t *testing.T) { http.StatusNotFound, response) - // Authenticated admin request for existing block while never_delete is set. - never_delete = true + // Authenticated admin request for existing block while neverDelete is set. + neverDelete = true response = IssueRequest(superuserExistingBlockReq) ExpectStatusCode(t, "authenticated request, existing block, method disabled", MethodDisabledError.HTTPCode, response) - never_delete = false + neverDelete = false // Authenticated admin request for existing block. response = IssueRequest(superuserExistingBlockReq) @@ -531,16 +561,16 @@ func TestDeleteHandler(t *testing.T) { expectedDc, responseDc) } // Confirm the block has been deleted - _, err := vols[0].Get(TEST_HASH) + _, err := vols[0].Get(TestHash) var blockDeleted = os.IsNotExist(err) if !blockDeleted { t.Error("superuserExistingBlockReq: block not deleted") } - // A DELETE request on a block newer than blob_signature_ttl + // A DELETE request on a block newer than blobSignatureTTL // should return success but leave the block on the volume. - vols[0].Put(TEST_HASH, TEST_BLOCK) - blob_signature_ttl = time.Hour + vols[0].Put(TestHash, TestBlock) + blobSignatureTTL = time.Hour response = IssueRequest(superuserExistingBlockReq) ExpectStatusCode(t, @@ -555,7 +585,7 @@ func TestDeleteHandler(t *testing.T) { expectedDc, responseDc) } // Confirm the block has NOT been deleted. - _, err = vols[0].Get(TEST_HASH) + _, err = vols[0].Get(TestHash) if err != nil { t.Errorf("testing delete on new block: %s\n", err) } @@ -592,7 +622,7 @@ func TestPullHandler(t *testing.T) { defer teardown() var userToken = "USER TOKEN" - data_manager_token = "DATA MANAGER TOKEN" + dataManagerToken = "DATA MANAGER TOKEN" pullq = NewWorkQueue() @@ -637,13 +667,13 @@ func TestPullHandler(t *testing.T) { }, { "Valid pull request from the data manager", - RequestTester{"/pull", data_manager_token, "PUT", goodJSON}, + RequestTester{"/pull", dataManagerToken, "PUT", goodJSON}, http.StatusOK, "Received 3 pull requests\n", }, { "Invalid pull request from the data manager", - RequestTester{"/pull", data_manager_token, "PUT", badJSON}, + RequestTester{"/pull", dataManagerToken, "PUT", badJSON}, http.StatusBadRequest, "", }, @@ -698,7 +728,7 @@ func TestTrashHandler(t *testing.T) { defer teardown() var userToken = "USER TOKEN" - data_manager_token = "DATA MANAGER TOKEN" + dataManagerToken = "DATA MANAGER TOKEN" trashq = NewWorkQueue() @@ -741,13 +771,13 @@ func TestTrashHandler(t *testing.T) { }, { "Valid trash list from the data manager", - RequestTester{"/trash", data_manager_token, "PUT", goodJSON}, + RequestTester{"/trash", dataManagerToken, "PUT", goodJSON}, http.StatusOK, "Received 3 trash requests\n", }, { "Invalid trash list from the data manager", - RequestTester{"/trash", data_manager_token, "PUT", badJSON}, + RequestTester{"/trash", dataManagerToken, "PUT", badJSON}, http.StatusBadRequest, "", }, @@ -822,7 +852,7 @@ func TestPutNeedsOnlyOneBuffer(t *testing.T) { defer func(orig *bufferPool) { bufs = orig }(bufs) - bufs = newBufferPool(1, BLOCKSIZE) + bufs = newBufferPool(1, BlockSize) ok := make(chan struct{}) go func() { @@ -830,8 +860,8 @@ func TestPutNeedsOnlyOneBuffer(t *testing.T) { response := IssueRequest( &RequestTester{ method: "PUT", - uri: "/" + TEST_HASH, - requestBody: TEST_BLOCK, + uri: "/" + TestHash, + requestBody: TestBlock, }) ExpectStatusCode(t, "TestPutNeedsOnlyOneBuffer", http.StatusOK, response) @@ -860,18 +890,18 @@ func TestPutHandlerNoBufferleak(t *testing.T) { for i := 0; i < maxBuffers+1; i++ { // Unauthenticated request, no server key // => OK (unsigned response) - unsignedLocator := "/" + TEST_HASH + unsignedLocator := "/" + TestHash response := IssueRequest( &RequestTester{ method: "PUT", uri: unsignedLocator, - requestBody: TEST_BLOCK, + requestBody: TestBlock, }) ExpectStatusCode(t, "TestPutHandlerBufferleak", http.StatusOK, response) ExpectBody(t, "TestPutHandlerBufferleak", - TEST_HASH_PUT_RESPONSE, response) + TestHashPutResp, response) } ok <- true }() @@ -893,7 +923,7 @@ func TestGetHandlerNoBufferleak(t *testing.T) { defer KeepVM.Close() vols := KeepVM.AllWritable() - if err := vols[0].Put(TEST_HASH, TEST_BLOCK); err != nil { + if err := vols[0].Put(TestHash, TestBlock); err != nil { t.Error(err) } @@ -902,7 +932,7 @@ func TestGetHandlerNoBufferleak(t *testing.T) { for i := 0; i < maxBuffers+1; i++ { // Unauthenticated request, unsigned locator // => OK - unsignedLocator := "/" + TEST_HASH + unsignedLocator := "/" + TestHash response := IssueRequest( &RequestTester{ method: "GET", @@ -912,7 +942,7 @@ func TestGetHandlerNoBufferleak(t *testing.T) { "Unauthenticated request, unsigned locator", http.StatusOK, response) ExpectBody(t, "Unauthenticated request, unsigned locator", - string(TEST_BLOCK), + string(TestBlock), response) } ok <- true @@ -924,3 +954,19 @@ func TestGetHandlerNoBufferleak(t *testing.T) { case <-ok: } } + +func TestPutReplicationHeader(t *testing.T) { + defer teardown() + + KeepVM = MakeTestVolumeManager(2) + defer KeepVM.Close() + + resp := IssueRequest(&RequestTester{ + method: "PUT", + uri: "/" + TestHash, + requestBody: TestBlock, + }) + if r := resp.Header().Get("X-Keep-Replicas-Stored"); r != "1" { + t.Errorf("Got X-Keep-Replicas-Stored: %q, expected %q", r, "1") + } +}