/******************************************************************************* * Copyright (c) 2015 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package com.ibm.ws.lars.rest; import static com.ibm.ws.lars.testutils.matchers.SummaryResultMatcher.summaryResult; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.http.ParseException; import org.apache.http.client.ClientProtocolException; import org.apache.http.entity.ContentType; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.ws.lars.rest.RepositoryContext.Protocol; import com.ibm.ws.lars.rest.exceptions.InvalidJsonAssetException; import com.ibm.ws.lars.rest.model.Asset; import com.ibm.ws.lars.rest.model.Asset.StateAction; import com.ibm.ws.lars.rest.model.AssetList; import com.ibm.ws.lars.rest.model.Attachment; import com.ibm.ws.lars.rest.model.AttachmentList; import com.ibm.ws.lars.testutils.FatUtils; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBObject; import com.mongodb.gridfs.GridFS; /** * Tests for the LARS REST API, which is designed to be compatible with the legacy Massive server. * Most tests should run against LARS or Massive, although some may not work exactly the same * against both, as LARS intends to do the 'right' thing in error cases, where this doesn't break * existing clients * */ @RunWith(Parameterized.class) public class ApiTest { /** ID for an asset which should never exist */ public static final String NON_EXISTENT_ID = "ffffffffffffffffffffffff"; private static final long RANDOM_SEED = 0xACEDEADBEEFL; private static final ObjectMapper MAPPER = new ObjectMapper(); private Random random; @Rule public final RepositoryContext repository; @Parameters(name = "{0}") public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { { Protocol.HTTP }, { Protocol.HTTPS } }); } public ApiTest(Protocol protocol) { this.repository = RepositoryContext.createAsAdmin(protocol); } @Before public void setUp() throws FileNotFoundException, IOException, InvalidJsonAssetException { random = new Random(RANDOM_SEED); } @After public void tearDown() throws IOException, InvalidJsonAssetException { } @Test public void testGetAllAssets() throws ClientProtocolException, IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); String attachmentName = "nocontent.txt"; Attachment createdAttachment = repository.doPostAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent); AssetList assets = repository.doGetAllAssets(); assertEquals("Wrong number of assets", 1, assets.size()); Asset retrievedAsset = assets.get(0); Object attachments = retrievedAsset.get("attachments"); assertTrue("The attachments field should be null", attachments == null); Asset assetAgain = repository.getAsset(returnedAsset.get_id()); Object attachmentsAgain = assetAgain.get("attachments"); List<?> attachmentsList = (List<?>) attachmentsAgain; assertEquals("Wrong number of attachments", 1, attachmentsList.size()); Map<?, ?> attachmentMap = (Map<?, ?>) attachmentsList.get(0); assertEquals("", createdAttachment.get_id(), attachmentMap.get("_id")); } @Test public void testGetUnpublishedAssets() throws ClientProtocolException, IOException, InvalidJsonAssetException { repository.addAssetNoAttachments(AssetUtils.getTestAsset()); Asset publishedAsset = repository.addAssetNoAttachmentsWithState(AssetUtils.getTestAsset(), Asset.State.PUBLISHED); AssetList assets = repository.doGetAllAssets(); assertEquals("Wrong number of assets", 2, assets.size()); RepositoryContext userRepository = RepositoryContext.toUserContext(repository); AssetList userAssets = userRepository.doGetAllAssets(); assertEquals("Wrong number of assets", 1, userAssets.size()); assertEquals("The wrong asset was retrieved", publishedAsset.get_id(), userAssets.get(0).get_id()); } @Test public void testGetAssetInvalid() throws Exception { String message = repository.getBadAsset("foo_bar_asset_id", 400); // massive gives a 500, LARS gives a 404 assertEquals("Unexpected error message returned from server", "Invalid asset id: foo_bar_asset_id", repository.parseErrorObject(message)); } /** * Test an asset id that doesn't exist * * @throws Exception */ @Test public void testGetAssetNonExistent() throws Exception { String message = repository.getBadAsset(NON_EXISTENT_ID, 404); // Massive gives a 400, LARS gives a 404 which is more helpful assertEquals("Incorrect error message from server", "asset not found for id: ffffffffffffffffffffffff", repository.parseErrorObject(message)); return; } /** * Test that only an admin user can GET an asset that is not published. * * @throws Exception */ @Test public void testGetAssetUnpublished() throws Exception { Asset original = AssetUtils.getTestAsset(); Asset unpublishedAsset = repository.addAssetNoAttachments(original); String id = unpublishedAsset.get_id(); RepositoryContext userRepository = RepositoryContext.toUserContext(repository); Asset fetchedAsset = repository.getAsset(id); AssetUtils.assertUploadedAssetEquivalentToOriginal("The retrieved asset is not as expected", original, fetchedAsset); // in state draft userRepository.getBadAsset(id, 404); repository.updateAssetState(id, Asset.StateAction.PUBLISH, 200); fetchedAsset = repository.getAsset(id); AssetUtils.assertUploadedAssetEquivalentToOriginal("The retrieved asset is not as expected", original, fetchedAsset); // in state awaiting approval userRepository.getBadAsset(id, 404); repository.updateAssetState(id, Asset.StateAction.NEED_MORE_INFO, 200); fetchedAsset = repository.getAsset(id); AssetUtils.assertUploadedAssetEquivalentToOriginal("The retrieved asset is not as expected", original, fetchedAsset); // in state need more info userRepository.getBadAsset(id, 404); repository.updateAssetState(id, Asset.StateAction.PUBLISH, 200); repository.updateAssetState(id, Asset.StateAction.APPROVE, 200); fetchedAsset = repository.getAsset(id); AssetUtils.assertUploadedAssetEquivalentToOriginal("The retrieved asset is not as expected", original, fetchedAsset); // in state published fetchedAsset = userRepository.getAsset(id); AssetUtils.assertUploadedAssetEquivalentToOriginal("The retrieved asset is not as expected", original, fetchedAsset); } /** * Attempt to delete an asset with an invalid asset id * */ @Test public void testDeleteAssetInvalidId() throws Exception { // Massive returns a 500 with an error of: // "Cannot read property 'createdBy' of null" // which really does look like a 500. String message = repository.deleteAsset("foobar", 400); assertEquals("Unexpected message from server", "Invalid asset id: foobar", repository.parseErrorObject(message)); return; } /** * Attempt to delete an asset with a non-existent id * */ @Test public void testDeleteAssetNonExistentId() throws Exception { repository.deleteAsset(NON_EXISTENT_ID, 404); } /** * Tests calling delete on /assets directly. This should be a 'not implemented error' * * @throws Exception */ @Test public void testDeleteAssets() throws Exception { repository.deleteAsset(null, 405); } /** * Attempt to post but with an ID specified. * * Massive gives a 404 with an error on this. LARS doesn't implement this, so jax-rs gives a * 405, method not allowed. Hmm, what is right? * */ @Test public void testPostAssetWithId() throws Exception { repository.doPost("/assets/" + NON_EXISTENT_ID, AssetUtils.getTestAsset().toJson(), 405); } /** * Massive gives a 500 error on this. 400 bad request seems better * * @throws Exception */ @Test public void testPostAssetInvalidJson() throws Exception { String message = repository.parseErrorObject(repository.doPost("/assets", "foobar", 400)); assertEquals("Unexpected error message", "Invalid asset definition", message); } /** * Update/PUT is not implemented this should fail * * @throws Exception */ @Test public void testUpdate() throws Exception { repository.updateAssetNoAttachments(AssetUtils.getTestAsset(), 405); } @Test public void testPutStateBadState() throws Exception { Asset newAsset = repository.addAssetNoAttachments(AssetUtils.getTestAsset()); String message = repository.updateAssetStateBad(newAsset.get_id(), "no state", 400); String expectedError = "Either the supplied JSON was badly formed, or it did not contain a valid 'action' field: {\"action\":\"no state\"}"; assertEquals("Unexpected error message from server", expectedError, repository.parseErrorObject(message)); repository.deleteAsset(newAsset.get_id(), -1); } @Test public void testPutStateInvalidAction() throws Exception { Asset newAsset = repository.addAssetNoAttachments(AssetUtils.getTestAsset()); String message = repository.updateAssetState(newAsset.get_id(), Asset.StateAction.UNPUBLISH, 400); String expectedError = "Invalid action " + Asset.StateAction.UNPUBLISH.getValue() + " performed on the asset with state " + newAsset.getState().getValue(); assertEquals("Unexpected error message from server", expectedError, repository.parseErrorObject(message)); repository.deleteAsset(newAsset.get_id(), -1); } @Test public void testPutStateNonExistentId() throws Exception { String message = repository.updateAssetState(NON_EXISTENT_ID, Asset.StateAction.UNPUBLISH, 404); assertEquals("Unexpected error message from server", "asset not found for id: ffffffffffffffffffffffff", repository.parseErrorObject(message)); } @Test public void testGeneratedFields() throws Exception { Asset testAsset = AssetUtils.getTestAsset(); testAsset = repository.addAssetNoAttachments(testAsset); Date now = new Date(); Date createdOn = IsoDate.parse(testAsset.getCreatedOn()); assertTrue("Created date is not close to current date", Math.abs(now.getTime() - createdOn.getTime()) < 2000); Date updatedOn = IsoDate.parse(testAsset.getLastUpdatedOn()); assertTrue("Updated date is not close to current date", Math.abs(now.getTime() - updatedOn.getTime()) < 2000); String createdBy = testAsset.getCreatedBy(); assertEquals(repository.getUser(), createdBy); } /** * Tests a create -> get -> -> change state -> delete, with valid data * * * @throws Exception */ @Test public void testAssetBasicLifecycle() throws Exception { Asset testAsset = AssetUtils.getTestAsset(); testAsset = repository.addAssetNoAttachments(testAsset); String id = testAsset.get_id(); Asset gotAsset = repository.getAsset(id); AssetUtils.assertAssetsEqual("Asset has been modified", testAsset, gotAsset); assertEquals("Asset was not created in draft state", Asset.State.DRAFT, gotAsset.getState()); repository.updateAssetState(id, Asset.StateAction.PUBLISH, 200); Asset publishedAsset = repository.getAsset(id); assertEquals("The asset is not in the expected state", Asset.State.AWAITING_APPROVAL, publishedAsset.getState()); repository.deleteAsset(id, -1); assertTrue(repository.repositoryIsEmpty()); } /** * Tests taking an attachment through create -> retrieve -> delete lifecycle. */ @Test public void testCRUDAttachmentWithContent() throws Exception { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentWithContent = AssetUtils.getTestAttachmentWithContent(); AttachmentList attachments = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertTrue("Asset should have zero attachments before creating any attachments", attachments.isEmpty()); String attachmentName = "attachment.txt"; byte[] content = "This is the content.\nIt is quite short.".getBytes("UTF-8"); Attachment createdAttachment = repository.doPostAttachmentWithContent(returnedAsset.get_id(), attachmentName, attachmentWithContent, content, ContentType.APPLICATION_OCTET_STREAM); Attachment returnedAttachment = repository.doGetOnlyAttachment(returnedAsset.get_id(), createdAttachment.get_id()); AssetUtils.assertAttachmentMetadataEquivalent(repository, "Expected returned attachment to match the one that was uploaded", returnedAttachment, returnedAsset.get_id(), createdAttachment.get_id(), attachmentName, "application/octet-stream", content.length, attachmentWithContent); byte[] retrievedContent = repository.doGetAttachmentContent(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName); assertTrue("retrieved attachment content should match created content", Arrays.equals(content, retrievedContent)); repository.doDeleteAttachment(returnedAsset.get_id(), createdAttachment.get_id()); AttachmentList attachmentsAfterDeletion = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertTrue("Asset should have zero attachments after deletion of only attachment", attachmentsAfterDeletion.isEmpty()); GridFS fs = new GridFS(FatUtils.getMongoDB()); assertEquals("Files in database after delete", 0, fs.getFileList().size()); } /** * Test that deleting an asset deletes its attachments */ @Test public void testDeleteAssetWithAttachments() throws Exception { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment att1 = AssetUtils.getTestAttachmentNoContent(); att1 = repository.doPostAttachmentNoContent(returnedAsset.get_id(), "att1", att1); Attachment att2 = AssetUtils.getTestAttachmentWithContent(); byte[] content = "Att2 test content".getBytes("UTF-8"); att2 = repository.doPostAttachmentWithContent(returnedAsset.get_id(), "att2", att2, content, ContentType.APPLICATION_OCTET_STREAM); repository.deleteAsset(returnedAsset.get_id(), -1); assertEquals("There should be no assets", 0, repository.doGetAllAssets().size()); DB db = FatUtils.getMongoDB(); assertEquals("There should be no remaining attachments", 0, db.getCollection("attachments").count()); } /** * Test getting the content of an attachment with the parent asset in various states */ @Test public void testGetAttachmentContentUnpublished() throws Exception { RepositoryContext userRepo = RepositoryContext.toUserContext(repository); Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentWithContent = AssetUtils.getTestAttachmentWithContent(); String attachmentName = "attachment.txt"; byte[] content = "This is the content.\nIt is quite short.".getBytes("UTF-8"); String assetId = returnedAsset.get_id(); Attachment createdAttachment = repository.doPostAttachmentWithContent(assetId, attachmentName, attachmentWithContent, content, ContentType.APPLICATION_OCTET_STREAM); // In state draft repository.doGetAttachmentContent(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName); userRepo.doGetAttachmentContentInError(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName, 404, "asset not found for id: " + assetId); // put into awaiting approval repository.updateAssetState(assetId, StateAction.PUBLISH, 200); repository.doGetAttachmentContent(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName); userRepo.doGetAttachmentContentInError(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName, 404, "asset not found for id: " + assetId); // put into need more info repository.updateAssetState(assetId, StateAction.NEED_MORE_INFO, 200); repository.doGetAttachmentContent(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName); userRepo.doGetAttachmentContentInError(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName, 404, "asset not found for id: " + assetId); // put into published repository.updateAssetState(assetId, StateAction.PUBLISH, 200); repository.updateAssetState(assetId, StateAction.APPROVE, 200); repository.doGetAttachmentContent(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName); userRepo.doGetAttachmentContent(returnedAsset.get_id(), createdAttachment.get_id(), attachmentName); } /** * Tries to upload an attachment that has both content and a url and verifies that the returns * HTTP 400 Bad Request. */ @Test public void testErrorAttachmentWithContentAndURL() throws Exception { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentWithContent = AssetUtils.getTestAttachmentWithContent(); attachmentWithContent.setUrl("any_url"); String attachmentName = "attachment.txt"; byte[] content = "This is the content.\nIt is quite short.".getBytes(StandardCharsets.UTF_8); repository.doPostBadAttachmentWithContent(returnedAsset.get_id(), attachmentName, attachmentWithContent, content, ContentType.APPLICATION_OCTET_STREAM, 400, "An attachment should not have the URL set if it is created with content"); } /** * Tries to upload an attachment that has both content and a linkType. Verifies that the server * does not allow this. */ @Test public void testAttachmentWithContentAndLinktype() throws Exception { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentWithContent = AssetUtils.getTestAttachmentWithContent(); attachmentWithContent.setLinkType("any_type"); String attachmentName = "attachment.txt"; byte[] content = "This is the content.\nIt is quite short.".getBytes("UTF-8"); repository.doPostBadAttachmentWithContent(returnedAsset.get_id(), attachmentName, attachmentWithContent, content, ContentType.APPLICATION_OCTET_STREAM, 400, "The link type must not be set for an attachment with content"); } /** * Takes an attachment with no content through create -> retrieve -> delete. */ @Test public void testCRUDAttachmentNoContent() throws ClientProtocolException, IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); AttachmentList attachments = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertTrue("Asset should have zero attachments before creating any attachments", attachments.isEmpty()); String attachmentName = "nocontent.txt"; Attachment createdAttachment = repository.doPostAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent); Attachment returnedAttachment = repository.doGetOnlyAttachment(returnedAsset.get_id(), createdAttachment.get_id()); AssetUtils.assertAttachmentNoContentMetadataEquivalent(returnedAttachment, returnedAsset.get_id(), createdAttachment.get_id(), attachmentName, attachmentNoContent); repository.doDeleteAttachment(returnedAsset.get_id(), createdAttachment.get_id()); AttachmentList attachmentsAfterDeletion = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertTrue("Asset should have zero attachments after deletion of only attachment", attachmentsAfterDeletion.isEmpty()); } /** * Tries to upload an attachment with no content and no URL. Verifies that the server does not * allow this. */ @Test public void testAttachmentNoContentNoUrl() throws ClientProtocolException, IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); attachmentNoContent.setUrl(null); String attachmentName = "nocontent.txt"; repository.doPostBadAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent, 400, "The URL of the supplied attachment was null"); } /** * Tries to upload an attachment with no content and no link type and verifies that the server * does not allow this. */ @Test public void testErrorAttachmentNoContentNoLinkType() throws ClientProtocolException, IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); attachmentNoContent.setLinkType(null); String attachmentName = "nocontent.txt"; repository.doPostBadAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent, 400, "The link type for the attachment was not set."); } /** * @return byte array containing pseudo-random attachment content. */ private byte[] createSomeAttachmentContent(int x) { int length = random.nextInt(50000); byte[] bytes = new byte[length]; random.nextBytes(bytes); return bytes; } /** * Creates an asset with multiple attachments and then verify that these attachments can be * retrieved correctly and with the same content that we uploaded. */ @Test public void testAddLotsOfAttachments() throws ClientProtocolException, IOException, InvalidJsonAssetException { int numAttachments = 100; Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); ArrayList<Attachment> attachments = new ArrayList<>(); ArrayList<String> names = new ArrayList<>(); ArrayList<byte[]> contents = new ArrayList<>(); ArrayList<String> attachmentIds = new ArrayList<>(); long totalTime = 0; for (int i = 0; i < numAttachments; i++) { Attachment attachment = new Attachment(); attachment.getProperties().put("randomProperty", "value" + i); attachments.add(attachment); names.add("attachment" + i); byte[] content = createSomeAttachmentContent(i); contents.add(content); long startTime = System.currentTimeMillis(); Attachment returnedAttachment = repository.doPostAttachmentWithContent(returnedAsset.get_id(), "attachment" + i, attachment, content, ContentType.APPLICATION_OCTET_STREAM); long endTime = System.currentTimeMillis(); totalTime += (endTime - startTime); attachmentIds.add(returnedAttachment.get_id()); } System.out.println("Total time to upload " + numAttachments + " assets: " + totalTime); AttachmentList returnedAttachments = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertEquals("Returned attachment list should have correct size", numAttachments, returnedAttachments.size()); Map<String, Attachment> attachmentsById = new HashMap<>(); for (Attachment a : returnedAttachments) { attachmentsById.put(a.get_id(), a); } for (int i = 0; i < numAttachments; i++) { Attachment returnedAttachment = attachmentsById.get(attachmentIds.get(i)); AssetUtils.assertAttachmentMetadataEquivalent(repository, "attachments not equal at index " + i, returnedAttachment, returnedAsset.get_id(), attachmentIds.get(i), names.get(i), ContentType.APPLICATION_OCTET_STREAM.getMimeType(), contents.get(i).length, attachments.get(i)); byte[] returnedContent = repository.doGetAttachmentContent(returnedAsset.get_id(), returnedAttachment.get_id(), returnedAttachment.getName()); assertArrayEquals("attachment content should match what was uploaded; index " + i, contents.get(i), returnedContent); } } /** * Attempts to retrieve an attachment that does not exist and verifies that we get HTTP 404 back * from the server. */ @Test public void testRetrieveNonExistentAttachment() throws IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); // This method basically asserts that we get HTTP 404 Not Found back from the server. repository.doGetAttachmentContentInError(returnedAsset.get_id(), NON_EXISTENT_ID, "non-existent", 404, "attachment not found for id: " + NON_EXISTENT_ID); } /** * Attempts to retrieve an attachment that does exist from a URL that contains a non-existent * asset id and verifies that the server does not allow this. * */ @Test public void testErrorRetrieveAttachmentOnNonExistentAsset() throws InvalidJsonAssetException, IOException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); String attachmentName = "nocontent.txt"; Attachment createdAttachment = repository.doPostAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent); repository.doGetAttachmentContentInError(NON_EXISTENT_ID, createdAttachment.get_id(), attachmentName, 404, "asset not found for id: " + NON_EXISTENT_ID); } /** * Attempts to retrieve an attachment that does exist from a URL but using the wrong name and * verifies that the server does not allow this. * */ @Test public void testErrorRetrieveAttachmentOnNonWrongName() throws InvalidJsonAssetException, IOException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); String attachmentName = "nocontent.txt"; Attachment createdAttachment = repository.doPostAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent); repository.doGetAttachmentContentInError(returnedAsset.get_id(), createdAttachment.get_id(), "foobar", 404, "Attachment with id " + createdAttachment.get_id() + " and name foobar does not exist in the repository."); } /** * Deletes a non-existent attachment and verify that we get HTTP 204 No Content back from the * server. This is because the current behaviour of LARS is to return 204 whether the attachment * existed or not. The post-condition of the call is the same: the attachment is not there. */ @Test public void testDeleteNonExistentAttachment() throws IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); // This method basically asserts that we get HTTP 204 No Content back from the server. // Which the server is meant to give us, whether there was an attachment or not. repository.doDeleteAttachment(returnedAsset.get_id(), NON_EXISTENT_ID); } /** * Test for /ma/v1/assets/{asset id}/attachments */ @Test public void testGetAttachments() throws ClientProtocolException, IOException, InvalidJsonAssetException { Asset testAsset = AssetUtils.getTestAsset(); Asset returnedAsset = repository.addAssetNoAttachments(testAsset); AttachmentList attachments = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertEquals("The wrong number of attachments was found", 0, attachments.size()); Attachment attachmentNoContent = AssetUtils.getTestAttachmentNoContent(); String attachmentName = "nocontent.txt"; Attachment createdAttachment = repository.doPostAttachmentNoContent(returnedAsset.get_id(), attachmentName, attachmentNoContent); attachments = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertEquals("The wrong number of attachments was found", 1, attachments.size()); Attachment one = attachments.get(0); AssetUtils.assertAttachmentNoContentMetadataEquivalent(one, returnedAsset.get_id(), createdAttachment.get_id(), "nocontent.txt", attachmentNoContent); Attachment attachmentNoContent2 = AssetUtils.getTestAttachmentNoContent(); String attachmentName2 = "nocontent2.txt"; repository.doPostAttachmentNoContent(returnedAsset.get_id(), attachmentName2, attachmentNoContent2); attachments = repository.doGetAllAttachmentsForAsset(returnedAsset.get_id()); assertEquals("The wrong number of attachments was found", 2, attachments.size()); String response = repository.doGetAllAttachmentsForAssetBad(NON_EXISTENT_ID, 404); assertEquals("Unexpected error message returned from server", "asset not found for id: " + NON_EXISTENT_ID, repository.parseErrorObject(response)); response = repository.doGetAllAttachmentsForAssetBad("foo_bar_asset_id", 400); assertEquals("Unexpected error message returned from server", "Invalid asset id: foo_bar_asset_id", repository.parseErrorObject(response)); } /** * Test for /ma/v1/assets/{asset id}/attachments */ @Test public void testGetAttachmentsUnpublished() throws ClientProtocolException, IOException, InvalidJsonAssetException { RepositoryContext userRepo = RepositoryContext.toUserContext(repository); Asset draftAsset = AssetUtils.getTestAsset(); Asset returnedDraftAsset = repository.addAssetNoAttachmentsWithState(draftAsset, Asset.State.DRAFT); String response = userRepo.doGetAllAttachmentsForAssetBad(returnedDraftAsset.get_id(), 404); assertEquals("Unexpected error message returned from server", "asset not found for id: " + returnedDraftAsset.get_id(), repository.parseErrorObject(response)); Asset waitingAsset = AssetUtils.getTestAsset(); Asset returnedWaitingAsset = repository.addAssetNoAttachmentsWithState(waitingAsset, Asset.State.AWAITING_APPROVAL); response = userRepo.doGetAllAttachmentsForAssetBad(returnedWaitingAsset.get_id(), 404); assertEquals("Unexpected error message returned from server", "asset not found for id: " + returnedWaitingAsset.get_id(), repository.parseErrorObject(response)); Asset moreInfoAsset = AssetUtils.getTestAsset(); Asset returnedMoreInfoAsset = repository.addAssetNoAttachmentsWithState(moreInfoAsset, Asset.State.NEED_MORE_INFO); response = userRepo.doGetAllAttachmentsForAssetBad(returnedMoreInfoAsset.get_id(), 404); assertEquals("Unexpected error message returned from server", "asset not found for id: " + returnedMoreInfoAsset.get_id(), repository.parseErrorObject(response)); Asset publishedAsset = AssetUtils.getTestAsset(); Asset returnedPublishedAsset = repository.addAssetNoAttachmentsWithState(publishedAsset, Asset.State.PUBLISHED); AttachmentList attachments = userRepo.doGetAllAttachmentsForAsset(returnedPublishedAsset.get_id()); assertEquals("The wrong number of attachments was found", 0, attachments.size()); } @Test public void testGetAllAssetsFiltered() throws IOException, InvalidJsonAssetException { Asset testAsset = addLittleAsset("foo", "bar"); Asset testAsset2 = addLittleAsset("foo", "bar"); Asset testAsset3 = addLittleAsset("foo", "barry"); addLittleAsset("foo", "baz"); addLittleAsset("fooser", "bar"); addLittleAsset("limit", "nolimit"); addLittleAsset("offset", "bigoffset"); Asset testAsset8 = addLittleAsset(new String[] { "foo", "baz", "bill", "ben", "jack", "jill" }); addLittleAsset(new String[] { "foo", "baz", "bill", "ben", "john", "janet" }); AssetList assets = repository.getAllAssets("foo=bar"); assertEquals("Unexpected number of assets retrieved", 2, assets.size()); String id_1 = testAsset.get_id(); String id_2 = testAsset2.get_id(); for (Asset retrievedAsset : assets) { String retrieved_id = retrievedAsset.get_id(); if (!retrieved_id.equals(id_1) && !retrieved_id.equals(id_2)) { fail("Expected to retrieve id " + id_1 + " or " + id_2 + " but got " + retrieved_id); } } AssetList assets2 = repository.getAllAssets("ben=bill"); assertEquals("Shouldn't have retrieved any assets", 0, assets2.size()); // This is to test that various parameters are ignored as filters by the server. // This is because Massive uses them for other purposes, but unhelpfully, // they are not clearly distinguished from filter parameters. AssetList assets8 = repository.getAllAssets("fields=fields_to_search_on"); assertEquals("fields should not be treated as a filter, so all assets should be retrieved", 9, assets8.size()); AssetList assets5 = repository.getAllAssets("foo=baz&jack=jill"); assertEquals("Unexpected number of assets retrieved", 1, assets5.size()); assertEquals("The wrong asset was retrieved.", testAsset8.get_id(), assets5.get(0).get_id()); AssetList assets6 = repository.getAllAssets("foo=randomvalue&foo=bar&foo=barry"); assertEquals("Unexpected number of assets retrieved", 1, assets6.size()); assertEquals("The wrong asset was retrieved.", testAsset3.get_id(), assets6.get(0).get_id()); } @Test public void testGetAllAssetsWithSearch() throws IOException, InvalidJsonAssetException { addLittleAsset("foo", "bar"); addLittleAsset("foo", "bar"); addLittleAsset("foo", "barry"); addLittleAsset("foo", "baz"); addLittleAsset("fooser", "bar"); addLittleAsset("limit", "nolimit"); addLittleAsset("offset", "bigoffset"); Asset testAsset8 = addLittleAsset(new String[] { "foo", "baz", "bill", "ben", "jack", "jill", "name", "searchable" }); addLittleAsset(new String[] { "foo", "baz", "bill", "ben", "john", "janet" }); AssetList assets7 = repository.getAllAssets("q=searchable"); assertEquals("Wrong number of assets retrieved", 1, assets7.size()); assertEquals("The wrong asset was retrieved.", testAsset8.get_id(), assets7.get(0).get_id()); AssetList assets1 = repository.getAllAssets("q=searchable&foo=baz"); assertEquals("Wrong number of assets retrieved", 1, assets1.size()); assertEquals("The wrong asset was retrieved.", testAsset8.get_id(), assets1.get(0).get_id()); // An empty search is treated is 'get everything' by massive. AssetList assets2 = repository.getAllAssets("q="); assertEquals("Wrong number of assets retrieved", 9, assets2.size()); // Testing phrases Asset testAsset9 = addLittleAsset(new String[] { "bill", "ben", "jack", "jill", "name", "a long name which can be searched" }); Asset testAsset10 = addLittleAsset(new String[] { "bill", "ben", "jack", "jill", "name", "long", "description", "name", "tags", "which can" }); // This should get just 9, as it is searching for a phrase String searchQuery = URLEncoder.encode("\"long name which\"", StandardCharsets.UTF_8.name()); AssetList assets9 = repository.getAllAssets("q=" + searchQuery); assertEquals("Wrong number of assets retrieved", 1, assets9.size()); assertEquals("The wrong asset was retrieved.", testAsset9.get_id(), assets9.get(0).get_id()); // This should get both 9 and 10 as it should be searching on separate words String searchQuery2 = URLEncoder.encode("name long can", StandardCharsets.UTF_8.name()); AssetList assets10 = repository.getAllAssets("q=" + searchQuery2); assertEquals("Wrong number of assets retrieved", 2, assets10.size()); String id_one = assets10.get(0).get_id(); String id_two = assets10.get(1).get_id(); assertTrue("The wrong asset was retrieved", id_one.equals(testAsset9.get_id()) || id_one.equals(testAsset10.get_id())); assertTrue("The wrong asset was retrieved", id_two.equals(testAsset9.get_id()) || id_two.equals(testAsset10.get_id())); } @Test public void testGetAllAssetsNotFiltered() throws InvalidJsonAssetException, IOException { addLittleAsset("foo", "bar"); addLittleAsset("foo", "bar"); addLittleAsset("foo", "barry"); addLittleAsset("foo", "baz"); addLittleAsset("fooser", "bar"); addLittleAsset("limit", "nolimit"); addLittleAsset("offset", "bigoffset"); addLittleAsset(new String[] { "foo", "baz", "bill", "ben", "jack", "jill" }); addLittleAsset(new String[] { "foo", "baz", "bill", "ben", "john", "janet" }); AssetList assets = repository.getAllAssets("foo=!bar"); assertEquals("Unexpected number of assets retrieved", 7, assets.size()); AssetList assets2 = repository.getAllAssets("foo=!wobble"); assertEquals("Unexpected number of assets retrieved", 9, assets2.size()); AssetList assets3 = repository.getAllAssets("foo=!bar&bill=ben"); assertEquals("Unexpected number of assets retrieved", 2, assets3.size()); } @Test public void testGetAllAssetsOrFiltered() throws Exception { addLittleAsset("weather", "hot", "ground", "flat"); addLittleAsset("weather", "hot", "ground", "hilly"); addLittleAsset("weather", "hot", "ground", "mountainous"); addLittleAsset("weather", "cold", "ground", "flat"); addLittleAsset("weather", "cold", "ground", "hilly"); addLittleAsset("weather", "cold", "ground", "mountainous"); addLittleAsset("weather", "warm", "ground", "flat"); addLittleAsset("weather", "warm", "ground", "hilly"); addLittleAsset("weather", "warm", "ground", "mountainous"); AssetList result1 = repository.getAllAssets("weather=hot|cold"); assertEquals("Unexpected number of assets retrieved", 6, result1.size()); AssetList result2 = repository.getAllAssets("weather=hot|cold&ground=!mountainous"); assertEquals("Unexpected number of assets retrieved", 4, result2.size()); AssetList result3 = repository.getAllAssets("weather=hot|warm&ground=hilly|mountainous"); assertEquals("Unexpected number of assets retrieved", 4, result3.size()); // Edge cases // ---------- // !hot|warm == (!hot) OR (warm) == !hot -> 6 results AssetList result4 = repository.getAllAssets("weather=!hot|warm"); assertEquals("Unexpected number of assets retrieved", 6, result4.size()); // !value is ignored if it is not the first value in the list // warm|!hot == warm -> 3 results AssetList result5 = repository.getAllAssets("weather=warm|!hot"); assertEquals("Unexpected number of assets retrieved", 3, result5.size()); // !hot|hot == (!hot) OR (hot) == everything -> 9 results AssetList result6 = repository.getAllAssets("weather=!hot|hot"); assertEquals("Unexpected number of assets retrieved", 9, result6.size()); } @Test public void testGetAllAssetsPagination() throws Exception { Asset asset1 = addLittleAsset("name", "asset1"); Asset asset2 = addLittleAsset("name", "asset2"); Asset asset3 = addLittleAsset("name", "asset3"); Asset asset4 = addLittleAsset("name", "asset4"); AssetList page1 = repository.getAllAssets("offset=0&limit=2"); assertEquals("Wrong number of assets on page 1", 2, page1.size()); AssetList page2 = repository.getAllAssets("offset=2&limit=2"); assertEquals("Wrong number of assets on page 2", 2, page2.size()); AssetList page3 = repository.getAllAssets("offset=4&limit=2"); assertEquals("Wrong number of assets on page 3", 0, page3.size()); assertThat(collatePages(page1, page2, page3), containsInAnyOrder(asset1, asset2, asset3, asset4)); page1 = repository.getAllAssets("offset=0&name=asset2|asset3|asset4&limit=2"); assertEquals("Wrong number of assets on page 1", 2, page1.size()); page2 = repository.getAllAssets("offset=2&name=asset2|asset3|asset4&limit=2"); assertEquals("Wrong number of assets on page 2", 1, page2.size()); page3 = repository.getAllAssets("offset=4&name=asset2|asset3|asset4&limit=2"); assertEquals("Wrong number of assets on page 3", 0, page3.size()); assertThat(collatePages(page1, page2, page3), containsInAnyOrder(asset2, asset3, asset4)); } @Test public void testGetAllAssetsSorted() throws Exception { Asset bigFoo = addLittleAsset("name", "Big Foo", "category", "foo", "size", "20"); Asset smallFoo = addLittleAsset("name", "Small Foo", "category", "foo", "size", "10"); Asset giantBar = addLittleAsset("name", "Giant Bar", "category", "bar", "size", "40"); // Test sort ASC and DESC AssetList result = repository.getAllAssets("sortBy=name&sortOrder=ASC"); assertThat(result, contains(bigFoo, giantBar, smallFoo)); result = repository.getAllAssets("sortBy=name&sortOrder=DESC"); assertThat(result, contains(smallFoo, giantBar, bigFoo)); // Test with filter result = repository.getAllAssets("sortBy=size&category=foo"); assertThat(result, contains(smallFoo, bigFoo)); // Test with search, sorting ascending result = repository.getAllAssets("sortBy=size&sortOrder=ASC&q=Foo"); assertThat(result, contains(smallFoo, bigFoo)); // Test with search, sorting descending to verify that sort order is respected when doing text search result = repository.getAllAssets("sortBy=size&sortOrder=DESC&q=Foo"); assertThat(result, contains(bigFoo, smallFoo)); // Test with pagination AssetList page1 = repository.getAllAssets("sortBy=size&sortOrder=ASC&offset=0&limit=2"); AssetList page2 = repository.getAllAssets("sortBy=size&sortOrder=ASC&offset=2&limit=2"); assertThat(collatePages(page1, page2), contains(smallFoo, bigFoo, giantBar)); } @SuppressWarnings("unused") @Test public void countAllAssets() throws Exception { RepositoryContext userContext = RepositoryContext.toUserContext(repository); Asset bigFoo = addLittleAssetWithState(Asset.State.PUBLISHED, "name", "Big Foo", "category", "foo", "size", "20"); Asset draftFoo = addLittleAssetWithState(Asset.State.DRAFT, "name", "Draft Foo", "category", "foo", "size", "20"); Asset moreInfoFoo = addLittleAssetWithState(Asset.State.NEED_MORE_INFO, "name", "More Info Foo", "category", "foo", "size", "10"); Asset waitingApprovalFoo = addLittleAssetWithState(Asset.State.AWAITING_APPROVAL, "name", "Waiting Approval Foo", "category", "foo", "size", "20"); Asset smallFoo = addLittleAssetWithState(Asset.State.PUBLISHED, "name", "Small Foo", "category", "foo", "size", "10"); Asset giantBar = addLittleAsset("name", "Giant Bar", "category", "bar", "size", "40"); Asset smallBar = addLittleAsset("name", "Small Bar", "category", "bar", "size", "10"); int result = repository.getAssetCount(""); assertEquals(7, result); result = userContext.getAssetCount(""); assertEquals(2, result); result = repository.getAssetCount("category=foo"); assertEquals(5, result); result = userContext.getAssetCount("category=foo"); assertEquals(2, result); result = repository.getAssetCount("q=foo"); assertEquals(5, result); result = userContext.getAssetCount("q=foo"); assertEquals(2, result); result = repository.getAssetCount("q=foo&size=10"); assertEquals(2, result); result = userContext.getAssetCount("q=foo&size=10"); assertEquals(1, result); } @SuppressWarnings("unchecked") @Test public void testGetAssetSummary() throws Exception { addLittleAssetWithState(Asset.State.PUBLISHED, "weather", "hot", "ground", "flat", "description", "lovely"); addLittleAsset("weather", "hot", "ground", "hilly", "description", "ok"); addLittleAsset("weather", "hot", "ground", "mountainous", "description", "exhausting"); addLittleAsset("weather", "cold", "ground", "flat", "description", "bleak"); addLittleAssetWithState(Asset.State.PUBLISHED, "weather", "cold", "ground", "hilly", "description", "ok"); addLittleAsset("weather", "cold", "ground", "mountainous"); addLittleAsset("weather", "warm", "ground", "flat"); addLittleAsset("weather", "warm", "ground", "hilly", "description", "dull"); addLittleAsset("weather", "warm", "ground", "mountainous"); List<Map<String, Object>> result; RepositoryContext userRepo = RepositoryContext.toUserContext(repository); result = repository.getAssetSummary("fields=weather"); assertThat(result, contains(summaryResult("weather", "hot", "cold", "warm"))); result = userRepo.getAssetSummary("fields=weather"); assertThat(result, contains(summaryResult("weather", "hot", "cold"))); result = repository.getAssetSummary("fields=weather,ground"); assertThat(result, containsInAnyOrder(summaryResult("weather", "hot", "cold", "warm"), summaryResult("ground", "flat", "hilly", "mountainous"))); result = userRepo.getAssetSummary("fields=weather,ground"); assertThat(result, containsInAnyOrder(summaryResult("weather", "hot", "cold"), summaryResult("ground", "flat", "hilly"))); result = repository.getAssetSummary("fields=description&ground=flat"); assertThat(result, contains(summaryResult("description", "lovely", "bleak"))); result = userRepo.getAssetSummary("fields=description&ground=flat"); assertThat(result, contains(summaryResult("description", "lovely"))); result = repository.getAssetSummary("fields=description&ground=mountainous"); assertThat(result, contains(summaryResult("description", "exhausting"))); result = userRepo.getAssetSummary("fields=description&ground=mountainous"); assertThat(result, contains(summaryResult("description"))); result = repository.getAssetSummary("fields=weather&q=ok"); assertThat(result, contains(summaryResult("weather", "hot", "cold"))); result = userRepo.getAssetSummary("fields=weather&q=ok"); assertThat(result, contains(summaryResult("weather", "cold"))); result = repository.getAssetSummary("fields=foo"); assertThat(result, contains(summaryResult("foo"))); result = userRepo.getAssetSummary("fields=foo"); assertThat(result, contains(summaryResult("foo"))); repository.getBadAssetSummary("fields=", 400); repository.getBadAssetSummary("", 400); } @Test public void testGetAssetSummaryUnpublished() throws Exception { addLittleAssetWithState(Asset.State.DRAFT, "weather", "cold", "ground", "flat", "description", "lovely"); addLittleAssetWithState(Asset.State.AWAITING_APPROVAL, "weather", "warm", "ground", "hilly", "description", "ok"); addLittleAssetWithState(Asset.State.NEED_MORE_INFO, "weather", "quite hot", "ground", "mountainous", "description", "exhausting"); addLittleAssetWithState(Asset.State.PUBLISHED, "weather", "hot", "ground", "flat", "description", "bleak"); RepositoryContext userRepo = RepositoryContext.toUserContext(repository); List<Map<String, Object>> result = userRepo.getAssetSummary("fields=weather"); assertThat(result, contains(summaryResult("weather", "hot"))); } // Add an asset with an extra properties private Asset addLittleAsset(String... values) throws IOException, InvalidJsonAssetException { Asset littleAsset = AssetUtils.getTestAsset(); for (int i = 0; i < values.length; i = i + 2) { littleAsset.setProperty(values[i], values[i + 1]); } return repository.addAssetNoAttachments(littleAsset); } /** * Add an asset with optional extra properties, and specify its target state after adding. */ private Asset addLittleAssetWithState(Asset.State targetState, String... values) throws IOException, InvalidJsonAssetException { Asset littleAsset = AssetUtils.getTestAsset(); for (int i = 0; i < values.length; i = i + 2) { littleAsset.setProperty(values[i], values[i + 1]); } Asset added = repository.addAssetNoAttachments(littleAsset); repository.moveAssetFromDraftToState(added.get_id(), targetState); return repository.getAsset(added.get_id()); } /** * Collate the contents of several AssetLists into one List. * <p> * The asset lists are processed in order, each asset in each list is appended to the result * list. * * @param lists the AssetLists * @return the collated list */ private static List<Asset> collatePages(AssetList... lists) { List<Asset> result = new ArrayList<Asset>(); for (AssetList list : lists) { for (Asset asset : list) { result.add(asset); } } return result; } /** * This test is for the handling of internal server errors. It provokes the error by directly * inserting bad data into the mongo database, and then sending a rest query to attempt (and * fail) to retrieve it. * * @throws IOException * @throws ParseException * @throws InvalidJsonAssetException */ @Test public void test500Mapping() throws InvalidJsonAssetException, ParseException, IOException { // First, make a direct connection to the database, and insert a dodgy asset String ID = "_id"; DB db = FatUtils.getMongoDB(); DBCollection assetCollection = db.getCollection("assets"); DBObject obj = new BasicDBObject(); obj.put("foo", "bar"); assetCollection.insert(obj); // Check that the 'asset' can be retrieved from the database. Object id = obj.get(ID); BasicDBObject query = new BasicDBObject(ID, id); DBObject resultObj = assetCollection.findOne(query); if (resultObj == null) { fail("The inserted 'asset' couldn't be found in the database using " + id); } // Check that the 'asset' can be retrieved via the REST interface AssetList assets = repository.doGetAllAssets(); assertEquals("Unexpected number of assets retrieved", 1, assets.size()); Asset retrievedAsset = assets.get(0); // Attempt to update the state of the 'asset'. This should fail and cause // a 500 error String message = repository.updateAssetState(retrievedAsset.get_id(), Asset.StateAction.UNPUBLISH, 500); assertEquals("Message was wrong", "Internal server error, please contact the server administrator", repository.parseErrorObject(message)); // Remove dodgy data from the database for the next test. Don't drop anything // as it will remove the database indexing. assetCollection.remove(new BasicDBObject()); } @Test public void testRuntimeException() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error/runtime", 500); assertJsonErrorResponse(500, "Internal server error, please contact the server administrator", response); } @Test public void testRepositoryException() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error/repository", 500); assertJsonErrorResponse(500, "Internal server error, please contact the server administrator", response); } @Test public void testClientException() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error/client", 500); assertJsonErrorResponse(500, "Test exception", response); } @Test public void testServletException() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error-servlet", 500); assertJsonErrorResponse(500, "Internal server error, please contact the server administrator", response); } @Test public void testServletRuntimeException() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error-servlet?type=runtime", 500); assertJsonErrorResponse(500, "Internal server error, please contact the server administrator", response); } @Test public void testServletSend500() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error-servlet?type=500", 500); assertJsonErrorResponse(500, "Internal server error, please contact the server administrator", response); } @Test public void testServletSend404() throws ClientProtocolException, IOException { String response = repository.doGet("/provoke-error-servlet?type=404", 404); assertThat(response, containsString("Test Error")); } /** * Assert that a JSON error response is correct */ private void assertJsonErrorResponse(int expectedStatusCode, String expectedMessage, String response) throws IOException { try { Map<?, ?> parseResponse = MAPPER.readValue(response, Map.class); String message = (String) parseResponse.get("message"); int statusCode = (Integer) parseResponse.get("statusCode"); assertEquals("statusCode", expectedStatusCode, statusCode); assertEquals("message", expectedMessage, message); } catch (JsonMappingException | JsonParseException e) { fail("Response did not parse as JSON. Response: " + response); } } /** * Test asset reviews */ @Test public void testAssetReviews() throws InvalidJsonAssetException, IOException { Asset a = addLittleAsset("weather", "hot", "ground", "flat", "description", "lovely"); List<Map<String, Object>> ars = repository.getAssetReviews(a.get_id()); // Story 165844, for now assetreviews just returns an empty JSON array assertEquals("Should be an empty List", 0, ars.size()); RepositoryContext userRepo = RepositoryContext.toUserContext(repository); userRepo.getAssetReviewsBad(a.get_id(), 404, "asset not found for id: " + a.get_id()); } /** * Test asset reviews, non-existent asset */ @Test public void testAssetReviewsNonExistent() throws InvalidJsonAssetException, IOException { repository.getAssetReviewsBad("bla-NonExistent", 400, "Invalid asset id: bla-NonExistent"); } }