/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.legacy.webscript;
import java.text.MessageFormat;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMWebScriptTestCase;
import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.GUID;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.springframework.extensions.webscripts.TestWebScriptServer.DeleteRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.PostRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.PutRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
/**
* This class tests the Rest API for disposition related operations
*
* @author Gavin Cornwell
*/
public class DispositionRestApiTest extends BaseRMWebScriptTestCase implements RecordsManagementModel
{
protected static StoreRef SPACES_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
protected static final String GET_SCHEDULE_URL_FORMAT = "/api/node/{0}/dispositionschedule";
protected static final String GET_LIFECYCLE_URL_FORMAT = "/api/node/{0}/nextdispositionaction";
protected static final String POST_ACTIONDEF_URL_FORMAT = "/api/node/{0}/dispositionschedule/dispositionactiondefinitions";
protected static final String DELETE_ACTIONDEF_URL_FORMAT = "/api/node/{0}/dispositionschedule/dispositionactiondefinitions/{1}";
protected static final String PUT_ACTIONDEF_URL_FORMAT = "/api/node/{0}/dispositionschedule/dispositionactiondefinitions/{1}";
protected static final String GET_LIST_URL = "/api/rma/admin/listofvalues";
protected static final String SERVICE_URL_PREFIX = "/alfresco/service";
protected static final String APPLICATION_JSON = "application/json";
public void testGetDispositionSchedule() throws Exception
{
// Test 404 status for non existent node
int expectedStatus = 404;
String nonExistentNode = "workspace/SpacesStore/09ca1e02-1c87-4a53-97e7-xxxxxxxxxxxx";
String nonExistentUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, nonExistentNode);
Response rsp = sendRequest(new GetRequest(nonExistentUrl), expectedStatus);
// Test 404 status for node that doesn't have dispostion schedule i.e. a record series
String seriesNodeUrl = recordSeries.toString().replace("://", "/");
String wrongNodeUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, seriesNodeUrl);
rsp = sendRequest(new GetRequest(wrongNodeUrl), expectedStatus);
// Test data structure returned from "AIS Audit Records"
expectedStatus = 200;
String categoryNodeUrl = recordCategory.toString().replace("://", "/");
String requestUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, categoryNodeUrl);
rsp = sendRequest(new GetRequest(requestUrl), expectedStatus);
assertEquals("application/json;charset=UTF-8", rsp.getContentType());
// get response as JSON
JSONObject jsonParsedObject = new JSONObject(new JSONTokener(rsp.getContentAsString()));
assertNotNull(jsonParsedObject);
// check JSON data
JSONObject dataObj = jsonParsedObject.getJSONObject("data");
assertNotNull(dataObj);
JSONObject rootDataObject = (JSONObject)dataObj;
assertEquals(10, rootDataObject.length());
// check individual data items
String serviceUrl = SERVICE_URL_PREFIX + requestUrl;
String url = rootDataObject.getString("url");
assertEquals(serviceUrl, url);
String authority = rootDataObject.getString("authority");
assertEquals(CommonRMTestUtils.DEFAULT_DISPOSITION_AUTHORITY, authority);
String instructions = rootDataObject.getString("instructions");
assertEquals(CommonRMTestUtils.DEFAULT_DISPOSITION_INSTRUCTIONS, instructions);
String actionsUrl = rootDataObject.getString("actionsUrl");
assertEquals(serviceUrl + "/dispositionactiondefinitions", actionsUrl);
boolean recordLevel = rootDataObject.getBoolean("recordLevelDisposition");
assertFalse(recordLevel);
assertFalse(rootDataObject.getBoolean("canStepsBeRemoved"));
JSONArray actions = rootDataObject.getJSONArray("actions");
assertNotNull(actions);
assertEquals(2, actions.length());
JSONObject action1 = (JSONObject)actions.get(0);
assertEquals(9, action1.length());
assertNotNull(action1.get("id"));
assertNotNull(action1.get("url"));
assertEquals(0, action1.getInt("index"));
assertEquals("cutoff", action1.getString("name"));
assertTrue(action1.getBoolean("eligibleOnFirstCompleteEvent"));
JSONObject action2 = (JSONObject)actions.get(1);
assertEquals(8, action2.length());
// make sure the disposition schedule node ref is present and valid
String scheduleNodeRefJSON = rootDataObject.getString("nodeRef");
NodeRef scheduleNodeRef = new NodeRef(scheduleNodeRefJSON);
assertTrue(this.nodeService.exists(scheduleNodeRef));
// create a new recordCategory node in the recordSeries and then get
// the disposition schedule
NodeRef newRecordCategory = filePlanService.createRecordCategory(recordSeries, GUID.generate());
dispositionService.createDispositionSchedule(newRecordCategory, null);
categoryNodeUrl = newRecordCategory.toString().replace("://", "/");
requestUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, categoryNodeUrl);
//System.out.println("GET response: " + rsp.getContentAsString());
rsp = sendRequest(new GetRequest(requestUrl), expectedStatus);
// get response as JSON
jsonParsedObject = new JSONObject(new JSONTokener(rsp.getContentAsString()));
System.out.println(rsp.getContentAsString());
assertNotNull(jsonParsedObject);
// check JSON data
dataObj = jsonParsedObject.getJSONObject("data");
assertNotNull(dataObj);
rootDataObject = (JSONObject)dataObj;
assertEquals(8, rootDataObject.length());
actions = rootDataObject.getJSONArray("actions");
assertNotNull(actions);
assertEquals(0, actions.length());
}
public void testPostDispositionAction() throws Exception
{
// create a new recordCategory node in the recordSeries and then get
// the disposition schedule
NodeRef newRecordCategory = filePlanService.createRecordCategory(recordSeries, GUID.generate());
dispositionService.createDispositionSchedule(newRecordCategory, null);
String categoryNodeUrl = newRecordCategory.toString().replace("://", "/");
String requestUrl = MessageFormat.format(POST_ACTIONDEF_URL_FORMAT, categoryNodeUrl);
// Construct the JSON request.
String name = "destroy";
String desc = "Destroy this record after 5 years";
String period = "year|5";
String periodProperty = "rma:cutOffDate";
boolean eligibleOnFirstCompleteEvent = true;
JSONObject jsonPostData = new JSONObject();
jsonPostData.put("name", name);
jsonPostData.put("description", desc);
jsonPostData.put("period", period);
jsonPostData.put("location", "my location");
jsonPostData.put("periodProperty", periodProperty);
jsonPostData.put("eligibleOnFirstCompleteEvent", eligibleOnFirstCompleteEvent);
JSONArray events = new JSONArray();
events.put("superseded");
events.put("no_longer_needed");
jsonPostData.put("events", events);
// Submit the JSON request.
String jsonPostString = jsonPostData.toString();
Response rsp = sendRequest(new PostRequest(requestUrl, jsonPostString, APPLICATION_JSON), 200);
// check the returned data is what was expected
JSONObject jsonResponse = new JSONObject(new JSONTokener(rsp.getContentAsString()));
JSONObject dataObj = jsonResponse.getJSONObject("data");
JSONObject rootDataObject = (JSONObject)dataObj;
assertNotNull(rootDataObject.getString("id"));
assertNotNull(rootDataObject.getString("url"));
assertEquals(0, rootDataObject.getInt("index"));
assertEquals(name, rootDataObject.getString("name"));
assertEquals("Destroy", rootDataObject.getString("label"));
assertEquals(desc, rootDataObject.getString("description"));
assertEquals(period, rootDataObject.getString("period"));
assertEquals("my location", rootDataObject.getString("location"));
assertEquals(periodProperty, rootDataObject.getString("periodProperty"));
assertTrue(rootDataObject.getBoolean("eligibleOnFirstCompleteEvent"));
events = rootDataObject.getJSONArray("events");
assertNotNull(events);
assertEquals(2, events.length());
assertEquals("superseded", events.get(0));
assertEquals("no_longer_needed", events.get(1));
// test the minimum amount of data required to create an action definition
jsonPostData = new JSONObject();
jsonPostData.put("name", name);
jsonPostString = jsonPostData.toString();
rsp = sendRequest(new PostRequest(requestUrl, jsonPostString, APPLICATION_JSON), 200);
// check the returned data is what was expected
jsonResponse = new JSONObject(new JSONTokener(rsp.getContentAsString()));
dataObj = jsonResponse.getJSONObject("data");
assertNotNull(rootDataObject.getString("id"));
assertNotNull(rootDataObject.getString("url"));
assertEquals(0, rootDataObject.getInt("index"));
assertEquals(name, dataObj.getString("name"));
assertEquals("none|0", dataObj.getString("period"));
assertFalse(dataObj.has("description"));
assertFalse(dataObj.has("periodProperty"));
assertFalse(dataObj.has("events"));
assertTrue(dataObj.getBoolean("eligibleOnFirstCompleteEvent"));
// negative test to ensure not supplying mandatory data results in an error
jsonPostData = new JSONObject();
jsonPostData.put("description", desc);
jsonPostData.put("period", period);
jsonPostString = jsonPostData.toString();
sendRequest(new PostRequest(requestUrl, jsonPostString, APPLICATION_JSON), 400);
}
public void testPutDispositionAction() throws Exception
{
NodeRef newRecordCategory = filePlanService.createRecordCategory(recordSeries, GUID.generate());
dispositionService.createDispositionSchedule(newRecordCategory, null);
// create an action definition to then update
String categoryNodeUrl = newRecordCategory.toString().replace("://", "/");
String postRequestUrl = MessageFormat.format(POST_ACTIONDEF_URL_FORMAT, categoryNodeUrl);
JSONObject jsonPostData = new JSONObject();
jsonPostData.put("name", "cutoff");
String jsonPostString = jsonPostData.toString();
sendRequest(new PostRequest(postRequestUrl, jsonPostString, APPLICATION_JSON), 200);
// verify the action definition is present and retrieve it's id
String getRequestUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, categoryNodeUrl);
Response rsp = sendRequest(new GetRequest(getRequestUrl), 200);
JSONObject json = new JSONObject(new JSONTokener(rsp.getContentAsString()));
JSONObject actionDef = json.getJSONObject("data").getJSONArray("actions").getJSONObject(0);
String actionDefId = actionDef.getString("id");
assertEquals("cutoff", actionDef.getString("name"));
assertEquals("none|0", actionDef.getString("period"));
assertFalse(actionDef.has("description"));
assertFalse(actionDef.has("events"));
// define body for PUT request
String name = "destroy";
String desc = "Destroy this record after 5 years";
String period = "year|5";
String location = "my location";
String periodProperty = "rma:cutOffDate";
boolean eligibleOnFirstCompleteEvent = false;
jsonPostData = new JSONObject();
jsonPostData.put("name", name);
jsonPostData.put("description", desc);
jsonPostData.put("period", period);
jsonPostData.put("location", location);
jsonPostData.put("periodProperty", periodProperty);
jsonPostData.put("eligibleOnFirstCompleteEvent", eligibleOnFirstCompleteEvent);
JSONArray events = new JSONArray();
events.put("superseded");
events.put("no_longer_needed");
jsonPostData.put("events", events);
jsonPostString = jsonPostData.toString();
// try and update a non existent action definition to check for 404
String putRequestUrl = MessageFormat.format(PUT_ACTIONDEF_URL_FORMAT, categoryNodeUrl, "xyz");
rsp = sendRequest(new PutRequest(putRequestUrl, jsonPostString, APPLICATION_JSON), 404);
// update the action definition
putRequestUrl = MessageFormat.format(PUT_ACTIONDEF_URL_FORMAT, categoryNodeUrl, actionDefId);
rsp = sendRequest(new PutRequest(putRequestUrl, jsonPostString, APPLICATION_JSON), 200);
// check the update happened correctly
json = new JSONObject(new JSONTokener(rsp.getContentAsString()));
actionDef = json.getJSONObject("data");
assertEquals(name, actionDef.getString("name"));
assertEquals("Destroy", actionDef.getString("label"));
assertEquals(desc, actionDef.getString("description"));
assertEquals(period, actionDef.getString("period"));
assertEquals(location, actionDef.getString("location"));
assertEquals(periodProperty, actionDef.getString("periodProperty"));
assertFalse(actionDef.getBoolean("eligibleOnFirstCompleteEvent"));
assertEquals(2, actionDef.getJSONArray("events").length());
assertEquals("superseded", actionDef.getJSONArray("events").getString(0));
assertEquals("no_longer_needed", actionDef.getJSONArray("events").getString(1));
}
public void testDeleteDispositionAction() throws Exception
{
NodeRef newRecordCategory = filePlanService.createRecordCategory(recordSeries, GUID.generate());
dispositionService.createDispositionSchedule(newRecordCategory, null);
// create an action definition to then delete
String categoryNodeUrl = newRecordCategory.toString().replace("://", "/");
String postRequestUrl = MessageFormat.format(POST_ACTIONDEF_URL_FORMAT, categoryNodeUrl);
JSONObject jsonPostData = new JSONObject();
jsonPostData.put("name", "cutoff");
String jsonPostString = jsonPostData.toString();
sendRequest(new PostRequest(postRequestUrl, jsonPostString, APPLICATION_JSON), 200);
// verify the action definition is present and retrieve it's id
String getRequestUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, categoryNodeUrl);
Response rsp = sendRequest(new GetRequest(getRequestUrl), 200);
JSONObject json = new JSONObject(new JSONTokener(rsp.getContentAsString()));
String actionDefId = json.getJSONObject("data").getJSONArray("actions").getJSONObject(0).getString("id");
// try and delete a non existent action definition to check for 404
String deleteRequestUrl = MessageFormat.format(DELETE_ACTIONDEF_URL_FORMAT, categoryNodeUrl, "xyz");
rsp = sendRequest(new DeleteRequest(deleteRequestUrl), 404);
// now delete the action defintion created above
deleteRequestUrl = MessageFormat.format(DELETE_ACTIONDEF_URL_FORMAT, categoryNodeUrl, actionDefId);
rsp = sendRequest(new DeleteRequest(deleteRequestUrl), 200);
// verify it got deleted
getRequestUrl = MessageFormat.format(GET_SCHEDULE_URL_FORMAT, categoryNodeUrl);
rsp = sendRequest(new GetRequest(getRequestUrl), 200);
json = new JSONObject(new JSONTokener(rsp.getContentAsString()));
JSONArray actions = json.getJSONObject("data").getJSONArray("actions");
assertEquals(0, actions.length());
}
public void testGetDispositionLifecycle() throws Exception
{
// Test 404 for disposition lifecycle request on incorrect node
String categoryUrl = recordCategory.toString().replace("://", "/");
String requestUrl = MessageFormat.format(GET_LIFECYCLE_URL_FORMAT, categoryUrl);
Response rsp = sendRequest(new GetRequest(requestUrl), 200);
JSONObject notFound = new JSONObject(new JSONTokener(rsp.getContentAsString()));
assertEquals(true, notFound.getJSONObject("data").getBoolean("notFound"));
NodeRef newRecordFolder = recordFolderService.createRecordFolder(recordCategory, "recordFolder");
// there should now be a disposition lifecycle for the record
requestUrl = MessageFormat.format(GET_LIFECYCLE_URL_FORMAT, newRecordFolder.toString().replace("://", "/"));
rsp = sendRequest(new GetRequest(requestUrl), 200);
System.out.println("GET : " + rsp.getContentAsString());
assertEquals("application/json;charset=UTF-8", rsp.getContentType());
// get response as JSON
JSONObject jsonParsedObject = new JSONObject(new JSONTokener(rsp.getContentAsString()));
assertNotNull(jsonParsedObject);
// check mandatory stuff is present
JSONObject dataObj = jsonParsedObject.getJSONObject("data");
assertEquals(SERVICE_URL_PREFIX + requestUrl, dataObj.getString("url"));
assertEquals("cutoff", dataObj.getString("name"));
assertFalse(dataObj.getBoolean("eventsEligible"));
assertTrue(dataObj.has("events"));
JSONArray events = dataObj.getJSONArray("events");
assertEquals(1, events.length());
JSONObject event1 = events.getJSONObject(0);
assertEquals("case_closed", event1.get("name"));
assertEquals("Case Closed", event1.get("label"));
assertFalse(event1.getBoolean("complete"));
assertFalse(event1.getBoolean("automatic"));
// check stuff expected to be missing is missing
assertFalse(dataObj.has("asOf"));
assertFalse(dataObj.has("startedAt"));
assertFalse(dataObj.has("startedBy"));
assertFalse(dataObj.has("completedAt"));
assertFalse(dataObj.has("completedBy"));
assertFalse(event1.has("completedAt"));
assertFalse(event1.has("completedBy"));
}
public void testGetListOfValues() throws Exception
{
// call the list service
Response rsp = sendRequest(new GetRequest(GET_LIST_URL), 200);
assertEquals("application/json;charset=UTF-8", rsp.getContentType());
// get response as JSON
JSONObject jsonParsedObject = new JSONObject(new JSONTokener(rsp.getContentAsString()));
assertNotNull(jsonParsedObject);
JSONObject data = jsonParsedObject.getJSONObject("data");
// check dispostion actions
JSONObject actions = data.getJSONObject("dispositionActions");
assertEquals(SERVICE_URL_PREFIX + GET_LIST_URL + "/dispositionactions", actions.getString("url"));
JSONArray items = actions.getJSONArray("items");
assertEquals(actionService.getDispositionActions().size(), items.length());
assertTrue(items.length() > 0);
JSONObject item = items.getJSONObject(0);
assertTrue(item.length() == 2);
assertTrue(item.has("label"));
assertTrue(item.has("value"));
// check events
JSONObject events = data.getJSONObject("events");
assertEquals(SERVICE_URL_PREFIX + GET_LIST_URL + "/events", events.getString("url"));
items = events.getJSONArray("items");
assertEquals(eventService.getEvents().size(), items.length());
assertTrue(items.length() > 0);
item = items.getJSONObject(0);
assertTrue(item.length() == 3);
assertTrue(item.has("label"));
assertTrue(item.has("value"));
assertTrue(item.has("automatic"));
// check period types
JSONObject periodTypes = data.getJSONObject("periodTypes");
assertEquals(SERVICE_URL_PREFIX + GET_LIST_URL + "/periodtypes", periodTypes.getString("url"));
items = periodTypes.getJSONArray("items");
assertEquals(Period.getProviderNames().size()-1, items.length());
assertTrue(items.length() > 0);
item = items.getJSONObject(0);
assertTrue(item.length() == 2);
assertTrue(item.has("label"));
assertTrue(item.has("value"));
// check period properties
JSONObject periodProperties = data.getJSONObject("periodProperties");
assertEquals(SERVICE_URL_PREFIX + GET_LIST_URL + "/periodproperties", periodProperties.getString("url"));
items = periodProperties.getJSONArray("items");
assertEquals(5, items.length());
assertTrue(items.length() > 0);
item = items.getJSONObject(0);
assertTrue(item.length() == 2);
assertTrue(item.has("label"));
assertTrue(item.has("value"));
}
}