parameters = buildParameters
+ (
+ "store_type", filePlan.getStoreRef().getProtocol(),
+ "store_id", filePlan.getStoreRef().getIdentifier(),
+ "id", filePlan.getId(),
+ "itemNodeRef", record.toString(),
+ "includedInHold", "false"
+ );
+
+ // execute web script
+ JSONObject json = executeJSONWebScript(parameters);
+ assertNotNull(json);
+
+ // check the JSON result
+ testForBothHolds(json);
+ }
+
+ /**
+ * Helper method to test JSON object for the presence of both test holds.
+ *
+ * @param json json result from web script
+ */
+ private void testForBothHolds(JSONObject json) throws Exception
+ {
+ // check the JSON result
+ assertTrue(json.has("data"));
+ assertTrue(json.getJSONObject("data").has("holds"));
+
+ JSONArray jsonHolds = json.getJSONObject("data").getJSONArray("holds");
+ assertNotNull(jsonHolds);
+ assertEquals(2, jsonHolds.length());
+
+ JSONObject hold1 = jsonHolds.getJSONObject(0);
+ assertNotNull(hold1);
+ assertEquals("hold1", hold1.getString("name"));
+ assertEquals(hold1NodeRef.toString(), hold1.getString("nodeRef"));
+
+ JSONObject hold2 = jsonHolds.getJSONObject(1);
+ assertNotNull(hold2);
+ assertEquals("hold2", hold2.getString("name"));
+ assertEquals(hold2NodeRef.toString(), hold2.getString("nodeRef"));
+ }
+}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/AllUnitTestSuite.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java
old mode 100755
new mode 100644
similarity index 77%
rename from rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/AllUnitTestSuite.java
rename to rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java
index f5d000dd29..ca1eb72d62
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/AllUnitTestSuite.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java
@@ -16,13 +16,16 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
-package org.alfresco.module.org_alfresco_module_rm;
+package org.alfresco.module.org_alfresco_module_rm.test;
import org.alfresco.module.org_alfresco_module_rm.forms.RecordsManagementTypeFormFilterUnitTest;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldServiceImplUnitTest;
import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.TransferEvaluatorUnitTest;
import org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrapUnitTest;
import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImplUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPostUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPutUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldsGetUnitTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@@ -40,7 +43,10 @@ import org.junit.runners.Suite.SuiteClasses;
RecordServiceImplUnitTest.class,
RecordsManagementTypeFormFilterUnitTest.class,
HoldServiceImplUnitTest.class,
- TransferEvaluatorUnitTest.class
+ TransferEvaluatorUnitTest.class,
+ HoldsGetUnitTest.class,
+ HoldPostUnitTest.class,
+ HoldPutUnitTest.class
})
public class AllUnitTestSuite
{
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/BaseUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java
old mode 100755
new mode 100644
similarity index 64%
rename from rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/BaseUnitTest.java
rename to rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java
index 40ea420c7d..43d52c48a0
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/BaseUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
-package org.alfresco.module.org_alfresco_module_rm;
+package org.alfresco.module.org_alfresco_module_rm.test.util;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
@@ -29,6 +29,7 @@ import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
+import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
@@ -44,13 +45,19 @@ import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.util.GUID;
import org.alfresco.util.collections.CollectionUtils;
import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * Unit test for RecordServiceImpl
+ * Base unit test.
+ *
+ * Contains core and records management service mocks ready for injection. Helper methods
+ * provide an easy way to build RM or Alfresco constructs for use in tests.
*
* @author Roy Wetherall
+ * @since 2.2
*/
public class BaseUnitTest implements RecordsManagementModel
{
@@ -69,6 +76,11 @@ public class BaseUnitTest implements RecordsManagementModel
@Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;
@Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService;
@Mock(name="recordService") protected RecordService mockedRecordService;
+ @Mock(name="holdService") protected HoldService mockedHoldService;
+
+ /** expected exception rule */
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
/**
* Test method setup
@@ -78,19 +90,21 @@ public class BaseUnitTest implements RecordsManagementModel
{
MockitoAnnotations.initMocks(this);
+ // setup file plan
filePlan = generateNodeRef(TYPE_FILE_PLAN);
+ doReturn(true).when(mockedFilePlanService).isFilePlan(filePlan);
+
+ // setup basic file plan component
filePlanComponent = generateNodeRef();
setupAsFilePlanComponent(filePlanComponent);
- // set-up namespace service
- when(mockedNamespaceService.getNamespaceURI(RM_PREFIX)).thenReturn(RM_URI);
- when(mockedNamespaceService.getPrefixes(RM_URI)).thenReturn(CollectionUtils.unmodifiableSet(RM_PREFIX));
+ // setup namespace service
+ doReturn(RM_URI).when(mockedNamespaceService).getNamespaceURI(RM_PREFIX);
+ doReturn(CollectionUtils.unmodifiableSet(RM_PREFIX)).when(mockedNamespaceService).getPrefixes(RM_URI);
// setup record folder and record
recordFolder = generateRecordFolder();
- doReturn(true).when(mockedRecordFolderService).isRecordFolder(recordFolder);
record = generateRecord();
- doReturn(true).when(mockedRecordService).isRecord(record);
// set record as child of record folder
List result = new ArrayList(1);
@@ -112,41 +126,84 @@ public class BaseUnitTest implements RecordsManagementModel
return QName.createQName(RM_URI, GUID.generate());
}
+ /**
+ * Helper method to generate hold reference
+ *
+ * @param name hold name
+ * @return {@link NodeRef} node reference that will behave like a hold
+ */
+ protected NodeRef generateHoldNodeRef(String name)
+ {
+ NodeRef hold = generateNodeRef(TYPE_HOLD);
+ doReturn(name).when(mockedNodeService).getProperty(hold, ContentModel.PROP_NAME);
+ doReturn(true).when(mockedHoldService).isHold(hold);
+ return hold;
+ }
+
+ /**
+ * Helper method to generate record folder reference
+ *
+ * @return {@link NodeRef} node reference that will behave like a record folder
+ */
protected NodeRef generateRecordFolder()
{
NodeRef recordFolder = generateNodeRef(TYPE_RECORD_FOLDER);
- setupAsFilePlanComponent(recordFolder);
- return recordFolder;
-
+ setupAsFilePlanComponent(recordFolder);
+ doReturn(true).when(mockedRecordFolderService).isRecordFolder(recordFolder);
+ return recordFolder;
}
+ /**
+ * Helper method to generate a record node reference.
+ *
+ * @return {@link NodeRef} node reference that will behave like a record or type cm:content
+ */
protected NodeRef generateRecord()
{
NodeRef record = generateNodeRef(ContentModel.TYPE_CONTENT);
setupAsFilePlanComponent(record);
- doReturn(true).when(mockedNodeService).hasAspect(record, ASPECT_RECORD);
+ doReturn(true).when(mockedNodeService).hasAspect(record, ASPECT_RECORD);
+ doReturn(true).when(mockedRecordService).isRecord(record);
return record;
}
+ /**
+ * Helper method to setup a node reference as a file plan component.
+ *
+ * @param nodeRef {@link NodeRef} node reference that will now behave like a file plan component
+ */
protected void setupAsFilePlanComponent(NodeRef nodeRef)
{
doReturn(true).when(mockedNodeService).hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT);
+ doReturn(true).when(mockedFilePlanService).isFilePlanComponent(nodeRef);
doReturn(filePlan).when(mockedFilePlanService).getFilePlan(nodeRef);
doReturn(filePlan).when(mockedNodeService).getProperty(nodeRef, PROP_ROOT_NODEREF);
}
-
+
+ /**
+ * Helper method to generate a node reference.
+ *
+ * @return {@link NodeRef} node reference that behaves like a node that exists in the spaces store
+ */
protected NodeRef generateNodeRef()
{
return generateNodeRef(null);
}
+ /**
+ * Helper method to generate a node reference of a particular type.
+ *
+ * @param type content type qualified name
+ * @return {@link NodeRef} node reference that behaves like a node that exists in the spaces store with
+ * the content type provided
+ */
protected NodeRef generateNodeRef(QName type)
{
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate());
- when(mockedNodeService.exists(nodeRef)).thenReturn(true);
+ when(mockedNodeService.exists(eq(nodeRef))).thenReturn(true);
if (type != null)
{
- when(mockedNodeService.getType(nodeRef)).thenReturn(type);
+ when(mockedNodeService.getType(eq(nodeRef))).thenReturn(type);
}
return nodeRef;
}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java
new file mode 100644
index 0000000000..2a0f18a927
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseWebScriptUnitTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2005-2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.module.org_alfresco_module_rm.test.util;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONObject;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.springframework.extensions.surf.util.Content;
+import org.springframework.extensions.webscripts.Container;
+import org.springframework.extensions.webscripts.DeclarativeWebScript;
+import org.springframework.extensions.webscripts.Description;
+import org.springframework.extensions.webscripts.Description.RequiredCache;
+import org.springframework.extensions.webscripts.DescriptionExtension;
+import org.springframework.extensions.webscripts.FormatRegistry;
+import org.springframework.extensions.webscripts.Match;
+import org.springframework.extensions.webscripts.ScriptProcessorRegistry;
+import org.springframework.extensions.webscripts.SearchPath;
+import org.springframework.extensions.webscripts.TemplateProcessorRegistry;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+import org.springframework.extensions.webscripts.WebScriptResponse;
+import org.springframework.extensions.webscripts.json.JSONUtils;
+import org.springframework.extensions.webscripts.processor.FTLTemplateProcessor;
+
+import freemarker.cache.ClassTemplateLoader;
+import freemarker.cache.TemplateLoader;
+
+/**
+ * Base Web Script Unit Test.
+ *
+ * Provides helper methods that mock the nessesery classes needed to execute
+ * a Java backed webscript that implements DeclarativeWebScript.
+ *
+ * Note that execution of java script controllers is not currently supported.
+ *
+ * @author Roy Wetherall
+ * @since 2.2
+ */
+public abstract class BaseWebScriptUnitTest extends BaseUnitTest
+{
+ /** web script root folder for RM webscripts */
+ protected static final String WEBSCRIPT_ROOT_RM = "alfresco/templates/webscripts/org/alfresco/rma/";
+
+ /**
+ * @return declarative webscript
+ */
+ protected abstract DeclarativeWebScript getWebScript();
+
+ /**
+ * @return classpath location of webscript template
+ */
+ protected abstract String getWebScriptTemplate();
+
+ /**
+ * Helper method to build a map of web script parameter values
+ * mimicking those provided on the URL
+ *
+ * @param values
+ * @return
+ */
+ protected Map buildParameters(String ... values)
+ {
+ Map result = new HashMap(values.length/2);
+ for (int i = 0; i < values.length; i=i+2)
+ {
+ String key = values[i];
+ String value = values[i+1];
+ result.put(key, value);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @param parameters
+ * @return
+ * @throws Exception
+ */
+ protected JSONObject executeJSONWebScript(Map parameters) throws Exception
+ {
+ return executeJSONWebScript(parameters, null);
+ }
+
+ /**
+ * Execute web script and convert result into a JSON object.
+ *
+ * @param parameters map of all parameter values
+ * @return {@link JSONObject} result, parsed into a JSON object
+ */
+ protected JSONObject executeJSONWebScript(Map parameters, String content) throws Exception
+ {
+ String result = executeWebScript(parameters, content);
+ return new JSONObject(result);
+ }
+
+ /**
+ *
+ * @param parameters
+ * @return
+ * @throws Exception
+ */
+ protected String executeWebScript(Map parameters) throws Exception
+ {
+ return executeWebScript( parameters, null);
+ }
+
+ /**
+ * Execute web script and return result as a string.
+ *
+ * @param parameters map of all parameter values
+ * @return {@link String} result of web script
+ */
+ protected String executeWebScript(Map parameters, String content) throws Exception
+ {
+ DeclarativeWebScript webScript = getWebScript();
+ String template = getWebScriptTemplate();
+
+ // initialise webscript
+ webScript.init(getMockedContainer(template), getMockedDescription());
+
+ // execute webscript
+ WebScriptResponse mockedResponse = getMockedWebScriptResponse();
+ webScript.execute(getMockedWebScriptRequest(webScript, parameters, content), mockedResponse);
+
+ // return results
+ return mockedResponse.getWriter().toString();
+ }
+
+ /**
+ * Helper method to get the mocked web script request.
+ *
+ * @param webScript declarative web script
+ * @param parameters web script parameter values
+ * @return {@link WebScriptRequest} mocked web script request
+ */
+ @SuppressWarnings("rawtypes")
+ protected WebScriptRequest getMockedWebScriptRequest(DeclarativeWebScript webScript, final Map parameters, String content) throws Exception
+ {
+ Match match = new Match(null, parameters, null, webScript);
+ org.springframework.extensions.webscripts.Runtime mockedRuntime = mock(org.springframework.extensions.webscripts.Runtime.class);
+
+ WebScriptRequest mockedRequest = mock(WebScriptRequest.class);
+ doReturn(match).when(mockedRequest).getServiceMatch();
+ doReturn(mockedRuntime).when(mockedRequest).getRuntime();
+
+ if (content != null && !content.isEmpty())
+ {
+ Content mockedContent = mock(Content.class);
+ doReturn(content).when(mockedContent).getContent();
+ doReturn(mockedContent).when(mockedRequest).getContent();
+ }
+
+ String [] paramNames = (String[])parameters.keySet().toArray(new String[parameters.size()]);
+ doReturn(paramNames).when(mockedRequest).getParameterNames();
+ doAnswer(new Answer()
+ {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable
+ {
+ String paramName = (String)invocation.getArguments()[0];
+ return parameters.get(paramName);
+ }
+
+ }).when(mockedRequest).getParameter(anyString());
+
+ doReturn(new String[0]).when(mockedRequest).getHeaderNames();
+ doReturn("json").when(mockedRequest).getFormat();
+
+ return mockedRequest;
+ }
+
+ /**
+ * Helper method to get mocked web script response
+ *
+ * @return {@link WebScriptResponse} mocked web script response
+ */
+ protected WebScriptResponse getMockedWebScriptResponse() throws Exception
+ {
+ WebScriptResponse mockedResponse = mock(WebScriptResponse.class);
+ StringWriter writer = new StringWriter();
+ doReturn(writer).when(mockedResponse).getWriter();
+ return mockedResponse;
+ }
+
+ /**
+ * Helper method to get mocked container object.
+ *
+ * @param template classpath location of webscripts ftl template
+ * @return {@link Container} mocked container
+ */
+ protected Container getMockedContainer(String template) throws Exception
+ {
+ FormatRegistry mockedFormatRegistry = mock(FormatRegistry.class);
+ doReturn("application/json").when(mockedFormatRegistry).getMimeType(anyString(), anyString());
+
+ ScriptProcessorRegistry mockedScriptProcessorRegistry = mock(ScriptProcessorRegistry.class);
+ doReturn(null).when(mockedScriptProcessorRegistry).findValidScriptPath(anyString());
+
+ TemplateProcessorRegistry mockedTemplateProcessorRegistry = mock(TemplateProcessorRegistry.class);
+ doReturn(template).when(mockedTemplateProcessorRegistry).findValidTemplatePath(anyString());
+
+ FTLTemplateProcessor ftlTemplateProcessor = new FTLTemplateProcessor()
+ {
+ @Override
+ protected TemplateLoader getTemplateLoader()
+ {
+ return new ClassTemplateLoader(getClass(), "/");
+ }
+ };
+ ftlTemplateProcessor.init();
+
+ doReturn(ftlTemplateProcessor).when(mockedTemplateProcessorRegistry).getTemplateProcessor(anyString());
+
+ Container mockedContainer = mock(Container.class);
+ doReturn(mockedFormatRegistry).when(mockedContainer).getFormatRegistry();
+ doReturn(mockedScriptProcessorRegistry).when(mockedContainer).getScriptProcessorRegistry();
+ doReturn(mockedTemplateProcessorRegistry).when(mockedContainer).getTemplateProcessorRegistry();
+
+ Map containerTemplateParameters = new HashMap(5);
+ containerTemplateParameters.put("jsonUtils", new JSONUtils());
+ doReturn(containerTemplateParameters).when(mockedContainer).getTemplateParameters();
+
+ SearchPath mockedSearchPath = mock(SearchPath.class);
+ doReturn(false).when(mockedSearchPath).hasDocument(anyString());
+ doReturn(mockedSearchPath).when(mockedContainer).getSearchPath();
+
+ // setup description
+ Description mockDescription = mock(Description.class);
+ doReturn(mock(RequiredCache.class)).when(mockDescription).getRequiredCache();
+
+ return mockedContainer;
+ }
+
+ /**
+ * Helper method to get mocked description class
+ *
+ * @return {@link DescriptionExtension} mocked description class
+ */
+ protected Description getMockedDescription()
+ {
+ Description mockedDescription = mock(Description.class);
+ doReturn(mock(RequiredCache.class)).when(mockedDescription).getRequiredCache();
+ return mockedDescription;
+ }
+}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/WebScriptExceptionMatcher.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/WebScriptExceptionMatcher.java
new file mode 100644
index 0000000000..046b9fccf6
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/WebScriptExceptionMatcher.java
@@ -0,0 +1,80 @@
+package org.alfresco.module.org_alfresco_module_rm.test.util;
+
+import org.junit.internal.matchers.TypeSafeMatcher;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
+
+/**
+ * Web script exception matcher.
+ *
+ * Allows use to check whether the raised web script exception has the correct
+ * status number or not.
+ *
+ * @author Roy Wetherall
+ * @since 2.2
+ */
+@SuppressWarnings("deprecation")
+public class WebScriptExceptionMatcher extends TypeSafeMatcher
+{
+ /**
+ * Helper method to create a matcher for the file not found (404)
+ * exception status.
+ *
+ * @return {@link WebScriptExceptionMatcher}
+ */
+ public static WebScriptExceptionMatcher fileNotFound()
+ {
+ return new WebScriptExceptionMatcher(Status.STATUS_NOT_FOUND);
+ }
+
+ /**
+ * Helper method to create a matcher for the bad request status (400)
+ * exception status.
+ *
+ * @return {@link WebScriptExceptionMatcher}
+ */
+ public static WebScriptExceptionMatcher badRequest()
+ {
+ return new WebScriptExceptionMatcher(Status.STATUS_BAD_REQUEST);
+ }
+
+ /** expected status */
+ public int expectedStatus;
+
+ /** actual status */
+ public int actualStatus;
+
+ /**
+ * Constructor
+ *
+ * @param expectedStatus expected status
+ */
+ public WebScriptExceptionMatcher(int expectedStatus)
+ {
+ this.expectedStatus = expectedStatus;
+ }
+
+ /**
+ * Determines if the expected outcome matches the actual
+ * outcome.
+ *
+ * @return true if matches, false otherwise
+ */
+ @Override
+ public boolean matchesSafely(WebScriptException exception)
+ {
+ actualStatus = exception.getStatus();
+ return (actualStatus == expectedStatus);
+ }
+
+ /**
+ * Describe unexpected outcome.
+ */
+ @Override
+ public void describeTo(org.hamcrest.Description description)
+ {
+ description.appendValue(actualStatus)
+ .appendText(" was found instead of ")
+ .appendValue(expectedStatus);
+ }
+}
\ No newline at end of file