gt: 		actions.add(new Action("DELETE", Action.TYPE.ENTRY));
context: package com.temenos.interaction.core.rim;
  
  /*
   * #%L
   * interaction-core
   * %%
   * Copyright (C) 2012 - 2013 Temenos Holdings N.V.
   * %%
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Affero General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU Affero General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   * #L%
   */
  
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.mockito.Matchers.any;
  import static org.mockito.Matchers.anyBoolean;
  import static org.mockito.Matchers.argThat;
  import static org.mockito.Mockito.doAnswer;
  import static org.mockito.Mockito.mock;
  import static org.mockito.Mockito.verify;
  import static org.mockito.Mockito.when;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import javax.ws.rs.core.HttpHeaders;
  import javax.ws.rs.core.MultivaluedMap;
  import javax.ws.rs.core.Response;
  import javax.ws.rs.core.Response.Status;
  import javax.ws.rs.core.UriInfo;
  
  import org.apache.wink.common.model.multipart.InMultiPart;
  import org.apache.wink.common.model.multipart.InPart;
  import org.junit.Assert;
  import org.junit.Before;
  import org.junit.Test;
  import org.mockito.ArgumentMatcher;
  import org.mockito.invocation.InvocationOnMock;
  import org.mockito.stubbing.Answer;
  
  import com.temenos.interaction.core.MultivaluedMapImpl;
  import com.temenos.interaction.core.command.CommandController;
  import com.temenos.interaction.core.command.InteractionCommand;
  import com.temenos.interaction.core.command.InteractionCommand.Result;
  import com.temenos.interaction.core.command.InteractionContext;
  import com.temenos.interaction.core.command.InteractionException;
  import com.temenos.interaction.core.entity.EntityMetadata;
  import com.temenos.interaction.core.entity.Metadata;
  import com.temenos.interaction.core.hypermedia.Action;
  import com.temenos.interaction.core.hypermedia.BeanTransformer;
  import com.temenos.interaction.core.hypermedia.ResourceState;
  import com.temenos.interaction.core.hypermedia.ResourceStateMachine;
  import com.temenos.interaction.core.hypermedia.Transition;
  import com.temenos.interaction.core.resource.EntityResource;
  import com.temenos.interaction.core.web.RequestContext;
  
  public class TestHTTPHypermediaRIM {
  
  	@Before
  	public void setup() {
  		// initialise the thread local request context with requestUri and baseUri
          RequestContext ctx = new RequestContext("http://localhost/myservice.svc", "/baseuri/", null);
          RequestContext.setRequestContext(ctx);
  	}
  
  	private List<Action> mockActions() {
  		List<Action> actions = new ArrayList<Action>();
  		actions.add(new Action("DO", Action.TYPE.ENTRY));
  		actions.add(new Action("GET", Action.TYPE.VIEW));
  		return actions;
  	}
  	
  	private CommandController mockCommandController() {
  		CommandController cc = mock(CommandController.class);
  		try {
  			InteractionCommand mockCommand = mock(InteractionCommand.class);
  			when(mockCommand.execute(any(InteractionContext.class))).thenReturn(Result.FAILURE);
  			when(cc.fetchCommand("DO")).thenReturn(mockCommand);
  			InteractionCommand mockCommand1 = mock(InteractionCommand.class);
  			when(mockCommand1.execute(any(InteractionContext.class))).thenReturn(Result.FAILURE);
  			when(cc.fetchCommand("GET")).thenReturn(mockCommand1);
  		}
  		catch(InteractionException ie) {
  			Assert.fail(ie.getMessage());
  		}
  		return cc;
  	}
  
  	private CommandController mockCommandController(InteractionCommand mockCommand) {
  		CommandController cc = mock(CommandController.class);
  		when(cc.fetchCommand("DO")).thenReturn(mockCommand);
  		when(cc.fetchCommand("GET")).thenReturn(mockCommand);
  		return cc;
  	}
  	
  	@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" })
  	@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>();
  		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()));
  	}
  
  	class InteractionContextArgumentMatcher extends ArgumentMatcher<InteractionContext> {
  		public boolean matches(Object o) {
  			if (o instanceof InteractionContext) {
  				InteractionContext ctx = (InteractionContext) o;
  				MultivaluedMap<String, String> mvmap = ctx.getQueryParameters();
  				if (!mvmap.getFirst("$filter").equals("this that")) {
  					return false;
  				}
  				return true;
  			}
              return false;
          }
      }
  
  	/* 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 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
  		CommandController 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());
  	}
  
  	/*
  	 * 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
  		CommandController mockCommandController = mock(CommandController.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 does not return a result.
  	 */
  	@Test(expected = AssertionError.class)
  	public void testDELETECommandNoResultShouldFail() throws Exception {
  		List<Action> actions = new ArrayList<Action>();
  