@Test public void testChildrenRIMsDifferentEntity() { ResourceState initial = new ResourceState("Note", "initial", mockActions(), "/note/{id}"); ResourceState comment = new ResourceState("Comment", "draft", mockActions(), "/comments/{noteid}"); // example uri linkage uses 'id' from Note entity to transition to 'noteid' of comments resource Map<String, String> uriLinkageMap = new HashMap<String, String>(); uriLinkageMap.put("noteid", "id"); // create comment for note initial.addTransition( new Transition.Builder() .method("PUT") .target(comment) .uriParameters(uriLinkageMap) .build()); // update comment comment.addTransition(new Transition.Builder().method("PUT").target(comment).build()); // supply a transformer to check that this is copied into child resource BeanTransformer transformer = new BeanTransformer(); ResourceStateMachine stateMachine = new ResourceStateMachine(initial, transformer); HTTPHypermediaRIM parent = new HTTPHypermediaRIM(mockCommandController(), stateMachine, createMockMetadata()); Collection<ResourceInteractionModel> resources = parent.getChildren(); assertEquals(1, resources.size()); assertEquals(comment.getPath(), resources.iterator().next().getResourcePath()); assertEquals( transformer, ((HTTPHypermediaRIM) resources.iterator().next()).getHypermediaEngine().getTransformer()); }
/* Test the contract for multipart POST commands. * A POST command should should receive an InteractionContext that has the new resource set; enabling the * command to process the resource contained in the current part of the multipart request */ @SuppressWarnings("unchecked") @Test public void testMultipartPostCommandReceivesResource() throws InteractionException { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/test"); initialState.addTransition( new Transition.Builder().method("POST").target(initialState).build()); // create a mock command to test the context is initialised correctly InteractionCommand mockCommand = mock(InteractionCommand.class); when(mockCommand.execute(any(InteractionContext.class))).thenReturn(Result.SUCCESS); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController(mockCommand), new ResourceStateMachine(initialState), createMockMetadata()); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getPathParameters(anyBoolean())).thenReturn(mock(MultivaluedMap.class)); when(uriInfo.getQueryParameters(anyBoolean())).thenReturn(mock(MultivaluedMap.class)); InMultiPart inMP = mock(InMultiPart.class); when(inMP.hasNext()).thenReturn(true, false); when(inMP.next()).thenReturn(mock(InPart.class)); rim.post(mock(HttpHeaders.class), uriInfo, inMP); verify(mockCommand) .execute((InteractionContext) argThat(new CommandReceivesResourceArgumentMatcher())); }
/* @Test public void testBootstrapRIMsCRUD() { String ENTITY_NAME = "NOTE"; String resourcePath = "/notes/{id}"; ResourceState initial = new ResourceState(ENTITY_NAME, "initial", mockActions(), resourcePath); ResourceState exists = new ResourceState(ENTITY_NAME, "exists", mockActions(), resourcePath); ResourceState deleted = new ResourceState(ENTITY_NAME, "deleted", mockActions(), resourcePath); // create initial.addTransition(new Transition.Builder().method("PUT").target(exists); // update exists.addTransition(new Transition.Builder().method("PUT").target(exists); // delete exists.addTransition("DELETE", deleted); // mock command controller to do nothing NewCommandController cc = mock(NewCommandController.class); when(cc.fetchCommand(anyString(), anyString())).thenReturn(mock(InteractionCommand.class)); HTTPHypermediaRIM parent = new HTTPHypermediaRIM(cc, new ResourceStateMachine(initial)); verify(cc).fetchCommand("GET", resourcePath); Collection<ResourceInteractionModel> resources = parent.getChildren(); assertEquals(0, resources.size()); verify(cc, times(1)).fetchCommand("GET", resourcePath); verify(cc, times(1)).fetchCommand("PUT", resourcePath); verify(cc, times(1)).fetchCommand("DELETE", resourcePath); } @Test public void testBootstrapRIMsSubstate() { String ENTITY_NAME = "DraftNote"; String resourcePath = "/notes/{id}"; ResourceState initial = new ResourceState(ENTITY_NAME, "initial", resourcePath); ResourceState exists = new ResourceState(initial, "exists", "/exists"); ResourceState deleted = new ResourceState(exists, "deleted", null); ResourceState draft = new ResourceState(ENTITY_NAME, "draft", "/notes/{id}/draft"); ResourceState deletedDraft = new ResourceState(draft, "deleted"); // create initial.addTransition(new Transition.Builder().method("PUT").target(exists); // create draft initial.addTransition(new Transition.Builder().method("PUT").target(draft); // updated draft draft.addTransition(new Transition.Builder().method("PUT").target(draft); // publish draft.addTransition(new Transition.Builder().method("PUT").target(exists); // delete draft draft.addTransition("DELETE", deletedDraft); // delete published exists.addTransition("DELETE", deleted); // mock command controller to do nothing NewCommandController cc = mock(NewCommandController.class); when(cc.fetchCommand(anyString(), anyString())).thenReturn(mock(InteractionCommand.class)); ResourceStateMachine stateMachine = new ResourceStateMachine(initial); HTTPHypermediaRIM parent = new HTTPHypermediaRIM(cc, stateMachine); verify(cc).fetchCommand("GET", "/notes/{id}"); Collection<ResourceInteractionModel> resources = parent.getChildren(); assertEquals(2, resources.size()); assertEquals(draft, resources.iterator().next().getCurrentState()); verify(cc, times(1)).fetchCommand("GET", "/notes/{id}/exists"); verify(cc).fetchCommand("DELETE", "/notes/{id}/exists"); verify(cc).fetchCommand("PUT", "/notes/{id}/exists"); verify(cc, times(1)).fetchCommand("GET", "/notes/{id}/draft"); verify(cc).fetchCommand("DELETE", "/notes/{id}/draft"); verify(cc).fetchCommand("PUT", "/notes/{id}/draft"); } @Test public void testBootstrapRIMsMultipleSubstates() { String ENTITY_NAME = "PublishNote"; String resourcePath = "/notes/{id}"; ResourceState initial = new ResourceState(ENTITY_NAME, "initial", resourcePath); ResourceState published = new ResourceState(ENTITY_NAME, "published", "/notes/{id}/published"); ResourceState publishedDeleted = new ResourceState(published, "publishedDeleted", null); ResourceState draft = new ResourceState(ENTITY_NAME, "draft", "/notes/{id}/draft"); ResourceState deletedDraft = new ResourceState(draft, "draftDeleted"); // create draft initial.addTransition(new Transition.Builder().method("PUT").target(draft); // updated draft draft.addTransition(new Transition.Builder().method("PUT").target(draft); // publish draft.addTransition(new Transition.Builder().method("PUT").target(published); // delete draft draft.addTransition("DELETE", deletedDraft); // delete published published.addTransition("DELETE", publishedDeleted); // mock command controller to do nothing NewCommandController cc = mock(NewCommandController.class); when(cc.fetchCommand(anyString(), anyString())).thenReturn(mock(InteractionCommand.class)); ResourceStateMachine stateMachine = new ResourceStateMachine(initial); HTTPHypermediaRIM parent = new HTTPHypermediaRIM(cc, stateMachine); verify(cc).fetchCommand("GET", "/notes/{id}"); Collection<ResourceInteractionModel> resources = parent.getChildren(); assertEquals(2, resources.size()); verify(cc, times(1)).fetchCommand("GET", "/notes/{id}"); verify(cc, times(1)).fetchCommand("GET", "/notes/{id}/draft"); verify(cc).fetchCommand("PUT", "/notes/{id}/draft"); verify(cc).fetchCommand("DELETE", "/notes/{id}/draft"); verify(cc, times(1)).fetchCommand("GET", "/notes/{id}/published"); verify(cc).fetchCommand("DELETE", "/notes/{id}/published"); verify(cc).fetchCommand("PUT", "/notes/{id}/published"); } @Test public void testBootstrapRIMsMultipleSubstates1() { String ENTITY_NAME = "BOOKING"; String resourcePath = "/bookings"; // the booking ResourceState begin = new ResourceState(ENTITY_NAME, "begin", resourcePath); ResourceState bookingCreated = new ResourceState(begin, "bookingCreated", "/{id}"); ResourceState bookingCancellation = new ResourceState(bookingCreated, "cancellation", "/cancellation"); ResourceState deleted = new ResourceState(bookingCancellation, "deleted", null); begin.addTransition(new Transition.Builder().method("PUT").target(bookingCreated); bookingCreated.addTransition(new Transition.Builder().method("PUT").target(bookingCancellation); bookingCancellation.addTransition("DELETE", deleted); // the payment ResourceState payment = new ResourceState(bookingCreated, "payment", "/payment"); ResourceState confirmation = new ResourceState(payment, "pconfirmation", "/pconfirmation"); ResourceState waitingForConfirmation = new ResourceState(payment, "pwaiting", "/pwaiting"); payment.addTransition(new Transition.Builder().method("PUT").target(waitingForConfirmation); payment.addTransition(new Transition.Builder().method("PUT").target(confirmation); waitingForConfirmation.addTransition(new Transition.Builder().method("PUT").target(confirmation); // linking the two state machines together bookingCreated.addTransition(new Transition.Builder().method("PUT").target(payment); // TODO needs to be conditional confirmation.addTransition(new Transition.Builder().method("PUT").target(bookingCancellation); // mock command controller to do nothing NewCommandController cc = mock(NewCommandController.class); when(cc.fetchCommand(anyString(), anyString())).thenReturn(mock(InteractionCommand.class)); HTTPHypermediaRIM parent = new HTTPHypermediaRIM(cc, new ResourceStateMachine(begin)); verify(cc, times(1)).fetchCommand("GET", "/bookings"); Collection<ResourceInteractionModel> resources = parent.getChildren(); assertEquals(5, resources.size()); verify(cc, times(1)).fetchCommand("GET", "/bookings/{id}"); verify(cc).fetchCommand("PUT", "/bookings/{id}"); verify(cc, times(1)).fetchCommand("GET", "/bookings/{id}/cancellation"); verify(cc).fetchCommand("DELETE", "/bookings/{id}/cancellation"); verify(cc).fetchCommand("PUT", "/bookings/{id}/cancellation"); verify(cc, times(1)).fetchCommand("GET", "/bookings/{id}/payment"); verify(cc).fetchCommand("PUT", "/bookings/{id}/payment"); verify(cc, times(1)).fetchCommand("GET", "/bookings/{id}/payment/pconfirmation"); verify(cc).fetchCommand("PUT", "/bookings/{id}/payment/pconfirmation"); verify(cc, times(1)).fetchCommand("GET", "/bookings/{id}/payment/pwaiting"); verify(cc).fetchCommand("PUT", "/bookings/{id}/payment/pwaiting"); } */ @Test public void testChildrenRIMsSubstate() { String ENTITY_NAME = "DraftNote"; String resourcePath = "/notes/{id}"; ResourceState initial = new ResourceState(ENTITY_NAME, "initial", mockActions(), resourcePath); ResourceState draft = new ResourceState(ENTITY_NAME, "draft", mockActions(), "/draft"); // create draft initial.addTransition(new Transition.Builder().method("PUT").target(draft).build()); // updated draft draft.addTransition(new Transition.Builder().method("PUT").target(draft).build()); // supply a transformer to check that this is copied into child resource BeanTransformer transformer = new BeanTransformer(); ResourceStateMachine stateMachine = new ResourceStateMachine(initial, transformer); HTTPHypermediaRIM parent = new HTTPHypermediaRIM(mockCommandController(), stateMachine, createMockMetadata()); Collection<ResourceInteractionModel> resources = parent.getChildren(); assertEquals(1, resources.size()); assertEquals(draft.getPath(), resources.iterator().next().getResourcePath()); assertEquals( transformer, ((HTTPHypermediaRIM) resources.iterator().next()).getHypermediaEngine().getTransformer()); }
@SuppressWarnings("unchecked") @Test public void testPutCommandWithIfMatchHeader() throws InteractionException { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/test"); initialState.addTransition(new Transition.Builder().method("PUT").target(initialState).build()); // this test incorrectly supplies a resource as a result of the command. InteractionCommand mockCommand = new InteractionCommand() { public Result execute(InteractionContext ctx) { assertNotNull(ctx.getResource()); assertNull( ctx.getResource().getEntityTag()); // Etag is a response header and should be null assertNotNull(ctx.getPreconditionIfMatch()); assertEquals("ABCDEFG", ctx.getPreconditionIfMatch()); return Result.SUCCESS; } }; // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController(mockCommand), new ResourceStateMachine(initialState), createMockMetadata()); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getPathParameters(anyBoolean())).thenReturn(mock(MultivaluedMap.class)); when(uriInfo.getQueryParameters(anyBoolean())).thenReturn(mock(MultivaluedMap.class)); // EntityResource without Etag EntityResource<Object> er = new EntityResource<Object>("test resource"); // Apply If-Match header HttpHeaders httpHeaders = mock(HttpHeaders.class); doAnswer( new Answer<List<String>>() { @SuppressWarnings("serial") @Override public List<String> answer(InvocationOnMock invocation) throws Throwable { String headerName = (String) invocation.getArguments()[0]; if (headerName.equals(HttpHeaders.IF_MATCH)) { return new ArrayList<String>() { { add("ABCDEFG"); } }; } return null; } }) .when(httpHeaders) .getRequestHeader(any(String.class)); // execute rim.put(httpHeaders, "id", uriInfo, er); }
@Test public void testResourcePath() throws InteractionException { String ENTITY_NAME = "NOTE"; ResourceState initial = new ResourceState(ENTITY_NAME, "initial", mockActions(), "/notes/{id}"); HTTPHypermediaRIM resource = new HTTPHypermediaRIM( mockCommandController(), new ResourceStateMachine(initial), createMockMetadata()); assertEquals("/notes/{id}", resource.getResourcePath()); }
/* We decode the query parameters to workaround an issue in Wink */ @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testDecodeQueryParametersNullValue() { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/test"); // RIM with command controller that issues commands that always return FAILURE HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController(), new ResourceStateMachine(initialState), createMockMetadata()); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getPathParameters(true)).thenReturn(mock(MultivaluedMap.class)); MultivaluedMap<String, String> queryMap = new MultivaluedMapImpl(); queryMap.add(null, null); when(uriInfo.getQueryParameters(anyBoolean())).thenReturn(queryMap); // should get past here without a NullPointerException rim.get(mock(HttpHeaders.class), "id", uriInfo); }
/* * This test is for a GET request where the command does not return a result. */ @Test(expected = AssertionError.class) public void testGETCommandNoResultShouldFail() throws Exception { List<Action> actions = new ArrayList<Action>(); actions.add(new Action("GET", Action.TYPE.VIEW)); ResourceState initialState = new ResourceState("entity", "state", actions, "/path"); // this test mocks a command that incorrectly returns no result InteractionCommand mockCommand = mock(InteractionCommand.class); // create mock command controller NewCommandController mockCommandController = mock(NewCommandController.class); when(mockCommandController.fetchCommand("GET")).thenReturn(mockCommand); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController, new ResourceStateMachine(initialState), createMockMetadata()); rim.get(mock(HttpHeaders.class), "id", mockEmptyUriInfo()); }
/* * This test is for a GET request where the command succeeds, but * does not return a resource. * A successful GET command should set the requested resource onto * the InteractionContext; we test this with an assertion. */ @Test(expected = AssertionError.class) public void testSuccessfulGETCommandNoResourceShouldFail() throws Exception { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/path"); // this test incorrectly supplies a resource as a result of the command. InteractionCommand mockCommand = new InteractionCommand() { public Result execute(InteractionContext ctx) { ctx.setResource(null); return Result.SUCCESS; } }; // create mock command controller NewCommandController mockCommandController = mockCommandController(mockCommand); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController, new ResourceStateMachine(initialState), createMockMetadata()); rim.get(mock(HttpHeaders.class), "id", mockEmptyUriInfo()); }
@Test public void testPUTCommandConflict() throws Exception { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/path"); // this test incorrectly supplies a resource as a result of the command. InteractionCommand mockCommand = new InteractionCommand() { public Result execute(InteractionContext ctx) { ctx.setResource(null); return Result.CONFLICT; } }; // create mock command controller NewCommandController mockCommandController = mockCommandController(mockCommand); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController, new ResourceStateMachine(initialState), createMockMetadata()); Response response = rim.get(mock(HttpHeaders.class), "id", mockEmptyUriInfo()); assertEquals(Status.PRECONDITION_FAILED.getStatusCode(), response.getStatus()); }
/* * This test is for a GET request where the command succeeds. * A successful GET command should set the requested resource onto * the InteractionContext. */ public void testSuccessfulGETCommand() throws Exception { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/path"); // this test incorrectly supplies a resource as a result of the command. InteractionCommand mockCommand = new InteractionCommand() { public Result execute(InteractionContext ctx) { ctx.setResource(new EntityResource<Object>()); return Result.SUCCESS; } }; // create mock command controller NewCommandController mockCommandController = mock(NewCommandController.class); when(mockCommandController.fetchCommand("DO")).thenReturn(mockCommand); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController, new ResourceStateMachine(initialState), mock(Metadata.class)); Response response = rim.get(mock(HttpHeaders.class), "id", mockEmptyUriInfo()); assertNotNull(response.getEntity()); }
/* * This test is for a DELETE request where the command returns a resource. * A successful DELETE command should not return a new resource and we test * this with an assertion. */ @Test(expected = AssertionError.class) public void testDeleteCommandReturnsResourceShouldFail() throws Exception { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/path"); initialState.addTransition( new Transition.Builder().method("DELETE").target(initialState).build()); // this test incorrectly supplies a resource as a result of the command. InteractionCommand mockCommand = new InteractionCommand() { public Result execute(InteractionContext ctx) { ctx.setResource(new EntityResource<Object>()); return Result.SUCCESS; } }; // create mock command controller NewCommandController mockCommandController = mockCommandController(mockCommand); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController, new ResourceStateMachine(initialState), createMockMetadata()); rim.delete(mock(HttpHeaders.class), "id", mockEmptyUriInfo()); }
/* We decode the query parameters to workaround an issue in Wink */ @SuppressWarnings({"unchecked"}) @Test public void testDecodeQueryParameters() throws InteractionException { ResourceState initialState = new ResourceState("entity", "state", mockActions(), "/test"); // this test simply mocks a command to test the context query parameters is initialised properly InteractionCommand mockCommand = mock(InteractionCommand.class); when(mockCommand.execute(any(InteractionContext.class))).thenReturn(Result.FAILURE); // RIM with command controller that issues commands that always return SUCCESS HTTPHypermediaRIM rim = new HTTPHypermediaRIM( mockCommandController(mockCommand), new ResourceStateMachine(initialState), createMockMetadata()); UriInfo uriInfo = mock(UriInfo.class); when(uriInfo.getPathParameters(true)).thenReturn(mock(MultivaluedMap.class)); MultivaluedMap<String, String> queryMap = new MultivaluedMapImpl<String, String>(); queryMap.add("$filter", "this+that"); when(uriInfo.getQueryParameters(anyBoolean())).thenReturn(queryMap); rim.get(mock(HttpHeaders.class), "id", uriInfo); verify(mockCommand) .execute((InteractionContext) argThat(new InteractionContextArgumentMatcher())); }