mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged DEV to HEAD
109455: Merged modules/custommodelmanagement/HEAD to DEV. 93923: SHA-300: Added ALFRESCO_MODEL_ADMINISTRATORS group. 95982: SHA-401: Implemented repo service for retrieving Custom Models. (WIP) 95983: SHA-400: Added Private REST API to retrieve custom model(s) - Get All models: http://localhost:8080/alfresco/api/-default-/private/alfresco/versions/1/cmm - Get the model: http://localhost:8080/alfresco/api/-default-/private/alfresco/versions/1/cmm/<model-name> 95984: SHA-401: Fixed the service to return null rather than throwing an exception, when the model does not exist. 96053: SHA-400: Modified the custom model API response to return the "status" as "ACTIVE" or "DRAFT". 96775: SHA-542: Added support to create a custom model. (WIP) 96779: SHA-543: Added Private REST API to create custom model(s). - SHA-539: Cleaned up test data. 96850: SHA-543: Added Author and Description properties to the custom model API. 97410: SHA-407, SHA-555: Added tests for custom model backend service and the related REST API. Also, a minor modification as a result of added tests. 97570: Modified the CMM REST API, per Kevin's request, to return empty arrays for model's types and aspects if they don't exist. 97731: SHA-386: Added support to activate custom models. Also, a minor modification to the backend service and REST API, based on the Alfresco REST API guidelines. 97775: SHA-386: Added tests for custom model activation (backend service). As well as, fixed the build failure by refactoring the public API tests. 97992: SHA-573, SHA-393, SHA-494: Added support to deactivate custom model, create a new type and create a new property group (aspect). 97994: Fixed the test as a result of renaming the service method. 98123: SHA-393, SHA-494: Enabled the CMM REST API to create/update Types and/or Aspects via PUT. Also added validations for aspect/type's name. 98259: SHA-453: Added backend and REST API support to delete a custom model. 98690: SHA-393, SHA-494, SHA-453, SHA-575: Added tests for custom model backend service and the related REST API. Also, a minor modification as a result of added tests. 99276: SHA-549: Added backend support to update a custom model. Also, refactored the service to externalise the error messages. - SHA-550: Added REST API support to update a custom model. - SHA-619: Made sure the backend service validates the model before creating a node. - SHA-623: Added checks to not allow a user to create a custom model with the same name as the bootstrapped models. 99287: SHA-619: Added InvalidCustomModelException for the CMM service to throw when the model validation fails. 99514: SHA-506: added backend and API support to create custom Type/Aspect properties. Also refactored the API to overcome the Public API limitations. 99522: SHA-506: Modified the Type/Aspect JSON payload to include a new read only property "prefixedName". 99527: Fixed Bamboo build failure as the result of r99522 commit. 99630: SHA-506: - Updated the API to exclude the inherited properties. - Added API tests for creating properties. - Modified the Custom Properties JSON response to include a new read only attribute "prefixedName". 99662: SHA-351: Updated the API to support 'mandatory' and 'mandatoryEnforced' properties. - SHA-410: Updated the API to support 'defaultValue' property. - SHA-506: Modified the Custom Properties JSON response to include 'description' and 'multiValued' attributes. 99669: SHA-506: Removed the unnecessary (at least in this sprint) methods from the backend service. 99684: SHA-638: Added checks to not allow a user to create a custom model with already in-use namespace prefix. 99959: SHA-679: Modified the custom model API to not import the already defined namespace. 100211: SHA-607: Modified the custom model API to support delete model's type. Also, removed the unnecessary test as we depend on the dictionary service, so no need to test it in the custom model API. 100281: Added Types and Aspects to the GET a single model API response, when it is requested with "?select=all" query string. 100335: Added test for "?select=all" query string within the GET a single model API (see rev 100281). 100366: SHA-612: Modified the custom model API to support delete model's aspect. 100738: SHA-698: Added checks so the model Admin is not allowed to deactivate a custom model when its types/aspects are parent to other models' types/aspects (regardless of the model being active or not). 100740: SHA-698: Fixed Bamboo build failures. 101085: SHA-703: Added dependency validation before deleting custom type/aspect in the custom model API. 101160: Modified the custom model API to return all properties (including the inherited properties) of the type/aspect, when requested by "?select=allProps". 101636: SHA-697. 101771: SHA-706: Made custom models hidden in the data dictionary. 101863: SHA-701: Added checks to not allow creating duplicate properties within the same model. Also, removed unnecessary/duplicate constants from the custom model service class. 101983: SHA-688: Fixed the error message by getting the root-cause-exception and returning its message. However, DictionaryException messages are not localised, so this will be fixed in the alfresco core. 102223: Fix for SHA-726: Not able to edit prefix field of deactivated model when model type is referenced within same model - The API will update the parent prefixed name with the new prefix. - Also, added more validations to the CMM API, when setting a type/asptect's parent. 102587: SHA-741, SHA-745, SHA-747: Added custom model Constraints support. 102725: SHA-784: Fixed parent validation of the type/aspect. 103030: SHA-741, SHA-745, SHA-747: Added tests for custom model Constraints. - Also fixed and refactored the API code as the result of tests. 103753: SHA-846: Added inline constraints support. Also: - Modified the backend CMM service to throw CustomModelConstraintException when the root cause is DuplicateDefinitionException. - Removed the duplicate name check from the CMM API, as now it will depend on the exceptions thrown upon model compilation. 103885: SHA-819, SHA-833: Added support to edit existing type/aspect. 103973: SHA-819, SHA-833: Added API tests for types/aspects Edit. Also, refactored CMM API tests by moving the tests to their corresponding test class. 104079: SHA-808: Fixed custom models bidirectional dependency. 104158: Deleted the ExtendedRepoAdminService class as the required functionality has been added (see SHA-879) to the core alfresco code. 104287: SHA-843: Modified the custom model API to support delete property. Also, minor refactoring of the API tests. 104403: SHA-842: Modified the custom model API to support Edit property. 104475: SHA-842: Added API tests for Edit property. 104569: SHA-913 - Remove case sensitive option from the UI - SHA-914 - Update PO and tests that use the case sensitive option - Remove case sensitive option on LIST constraint throughout Also: - Update Aikau version to 1.0.18 104690: Fixed Bamboo build failure caused by r104569. 104849: SHA-808: Fixed custom models circular dependencies. 105297: SHA-807: Added property default-value and constraint (REGEX, MINMAX and LENGTH) validators. 105642: SHA-950: Wrapped backend CMM service method with a NEW transaction, in order to catch the thrown exception within DictionaryModelTypeTransactionListener. Also refactored the CMM backend service tests as the result of this change. 106677: SHA-888, SHA-889, SHA-890: Added Backend and API support to export a custom model and its associated Share form. 106722: SHA-888, SHA-889, SHA-890: Fixed a few minor issues raised during code review. 107007: ACE-4019: Modified the CMM service to not start a new TX when creating a new model. 107070: Temporarily enabled (hard coded) index and facetable attributes in the custom model properties. 107296: GERMAN: Model Manager files localised as per EN-rev105921 107297: FRENCH: Model Manager localised files based on EN-rev105921 107315: SPANISH: Model Manager localised files based on EN-rev105921 107317: JAPANESE: Model Manager localised files based on EN-rev105921 107321: ITALIAN: Model Manager localised files based on EN-rev105921 107322: DUTCH: Model Manager localised files based on EN-rev105921 107335: SHA-889: Modified the CMM service to not throw an exception when exporting the model and its associated share extension module, where the Share extension module has not been created for the model yet. 107456: SHA-893: Added API support to upload/import a custom model and its associated Share extension module. 107560: SHA-893: Added model upload API tests as well as minor fixes. 107647: SHA-893: Fixed minor issues raised during code review. 107773: Docs review of message labels and errors. 107866: SHA-1126: Added check for the maximum value of the MINMAX constraint to be a positive nonzero value. 108117: SHA-832: Added validation for properties' default values to be checked against the property defined constraint. 108256: SHA-1194: Modified CMM API to support indexing options. 108510: SHA-1151: Externalised CMM rest API error messages. - SHA-1196: Changed the CMM Rest API input validator to use the same RegExs as the CMM Share. 108518: SHA-1194: Changed CMM property facetable options to include "UNSET". 108561: GERMAN: Model Manager files updated as per EN-rev107962 108562: FRENCH: Model Manager files updated as per EN-rev107962 108565: ITALIAN: Model Manager files updated as per EN-rev107962 108566: SPANISH: Model Manager files updated as per EN-rev107962 108567: JAPANESE: Model Manager files updated as per EN-rev107962 108568: NORWEGIAN Bokmal: Model Manager files updated as per EN-rev107962 108570: DUTCH: Model Manager files updated as per EN-rev107962 108571: RUSSIAN: Model Manager files updated as per EN-rev107962 108572: BRAZILIAN Portuguese: Model Manager files updated as per EN-rev107962 108573: SIMPLIFIED CHINESE: Model Manager files updated as per EN-rev107962 108604: Removed the unnecessary escaped quotation from the strings which don't have variables. 108721: Api message changes from docs. 108728: Changed "Property group" to "Aspect" in the CMM API error messages. 108934: Added the missing escaped quotation into API messages. 109037: Changes from docs for mandatory field character messages in the API. 109204: ITALIAN: Updated bundle based on EN rev109039 109205: GERMAN: Updated bundle based on EN rev109039 109206: FRENCH: Updated bundle based on EN rev109039 109223: GERMAN: Updated bundle based on EN rev109039 - fixed single quotes 109226: FRENCH: Updated bundle based on EN rev109039 - fixed single quotes 109228: ITALIAN: Updated bundle based on EN rev109039 - fixed single quotes 109230: FRENCH: Updated bundle based on EN rev109039 - fixed single quotes again 109235: JAPANESE: Updated bundle based on EN rev109039 109293: SPANISH: Updated bundle based on EN rev109039 109300: DUTCH: Updated bundle based on EN rev109039 109412: - Refactored the CMM JMX support to return CompositeData for performance reasons. - Reorganised a few of CMM classes/interfaces to make it easier for merging to alfresco core. - A minor fixes as a result of Find Bugs analysis. - Added the minimum and maximum repo versions for CMM module. 109421: NORWEGIAN: Updated bundle based on EN rev109039 109424: BRAZILIAN PORTUGUESE: Updated bundle based on EN rev109039 109426: RUSSIAN: Updated bundle based on EN rev109039 109427: CHINESE: Updated bundle based on EN rev10903 109475: Added CMM Model into the core services (missed from previous commit). 109480: SHA-723: Added custom models analytics in HeartBeat data. 109481: SHA-528: Added GROUP_ALFRESCO_MODEL_ADMINISTRATORS_AUTHORITY patch. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@109490 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -93,4 +93,9 @@ public class RemoteApi01TestSuite extends TestSuite
|
||||
suite.addTest(new JUnit4TestAdapter(org.alfresco.rest.workflow.api.tests.ProcessWorkflowApiTest.class));
|
||||
suite.addTest(new JUnit4TestAdapter(org.alfresco.rest.workflow.api.tests.TaskWorkflowApiTest.class));
|
||||
}
|
||||
|
||||
static void tests8(TestSuite suite) //
|
||||
{
|
||||
suite.addTest(org.alfresco.rest.api.tests.CMMApiTestSuite.suite());
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ import org.alfresco.repo.web.scripts.admin.AdminWebScriptTest;
|
||||
import org.alfresco.repo.web.scripts.audit.AuditWebScriptTest;
|
||||
import org.alfresco.repo.web.scripts.blogs.BlogServiceTest;
|
||||
import org.alfresco.repo.web.scripts.comment.CommentsApiTest;
|
||||
import org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest;
|
||||
import org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest;
|
||||
import org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest;
|
||||
import org.alfresco.repo.web.scripts.facet.FacetRestApiTest;
|
||||
@@ -98,12 +99,13 @@ public class WebScriptTestSuite extends TestSuite
|
||||
suite.addTestSuite( SOLRWebScriptTest.class );
|
||||
suite.addTestSuite( SubscriptionServiceRestApiTest.class );
|
||||
suite.addTestSuite( FacetRestApiTest.class );
|
||||
suite.addTestSuite( CommentsApiTest.class );
|
||||
suite.addTestSuite( CommentsApiTest.class );
|
||||
suite.addTestSuite( DeclarativeSpreadsheetWebScriptTest.class );
|
||||
suite.addTestSuite( XssVulnerabilityTest.class );
|
||||
suite.addTestSuite( LinksRestApiTest.class );
|
||||
suite.addTestSuite( RemoteFileFolderLoaderTest.class );
|
||||
suite.addTestSuite( ReadOnlyTransactionInGetRestApiTest.class );
|
||||
suite.addTestSuite( CustomModelImportTest.class );
|
||||
// This uses a slightly different context
|
||||
// As such, we can't run it in the same suite as the others,
|
||||
// due to finalisers closing caches when we're not looking
|
||||
|
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.web.scripts.custommodel;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.dictionary.CustomModelServiceImpl;
|
||||
import org.alfresco.repo.dictionary.M2Association;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
import org.alfresco.repo.dictionary.M2Type;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelService;
|
||||
import org.alfresco.service.cmr.security.AuthorityService;
|
||||
import org.alfresco.service.cmr.security.AuthorityType;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.alfresco.util.XMLUtil;
|
||||
import org.apache.commons.httpclient.methods.multipart.FilePart;
|
||||
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
|
||||
import org.apache.commons.httpclient.methods.multipart.Part;
|
||||
import org.apache.commons.httpclient.params.HttpMethodParams;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
import org.springframework.extensions.webscripts.TestWebScriptServer.PostRequest;
|
||||
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* This class tests the custom model upload REST API.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class CustomModelImportTest extends BaseWebScriptTest
|
||||
{
|
||||
private static final String NON_ADMIN_USER = "nonAdminUserName";
|
||||
private static final String CUSTOM_MODEL_ADMIN = "customModelAdmin";
|
||||
private static final String RESOURCE_PREFIX = "custommodel/";
|
||||
private static final String UPLOAD_URL = "/api/cmm/upload";
|
||||
private static final int BUFFER_SIZE = 20 * 1024;
|
||||
|
||||
private MutableAuthenticationService authenticationService;
|
||||
private AuthorityService authorityService;
|
||||
private PersonService personService;
|
||||
private RetryingTransactionHelper transactionHelper;
|
||||
private CustomModelService customModelService;
|
||||
private List<String> importedModels = new ArrayList<>();
|
||||
private List<File> tempFiles = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
authenticationService = getServer().getApplicationContext().getBean("AuthenticationService", MutableAuthenticationService.class);
|
||||
authorityService = getServer().getApplicationContext().getBean("AuthorityService", AuthorityService.class);
|
||||
personService = getServer().getApplicationContext().getBean("PersonService", PersonService.class);
|
||||
transactionHelper = getServer().getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
customModelService = getServer().getApplicationContext().getBean("customModelService", CustomModelService.class);
|
||||
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
createUser(NON_ADMIN_USER);
|
||||
createUser(CUSTOM_MODEL_ADMIN);
|
||||
|
||||
if (!authorityService.getContainingAuthorities(AuthorityType.GROUP, CUSTOM_MODEL_ADMIN, true).contains(
|
||||
CustomModelServiceImpl.GROUP_ALFRESCO_MODEL_ADMINISTRATORS_AUTHORITY))
|
||||
{
|
||||
authorityService.addAuthority(CustomModelServiceImpl.GROUP_ALFRESCO_MODEL_ADMINISTRATORS_AUTHORITY, CUSTOM_MODEL_ADMIN);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(CUSTOM_MODEL_ADMIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
for (File file : tempFiles)
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
for (String modelName : importedModels)
|
||||
{
|
||||
customModelService.deleteCustomModel(modelName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
deleteUser(NON_ADMIN_USER);
|
||||
deleteUser(CUSTOM_MODEL_ADMIN);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testValidUpload_ModelAndExtModule() throws Exception
|
||||
{
|
||||
File zipFile = getResourceFile("validModelAndExtModule.zip");
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(NON_ADMIN_USER);
|
||||
Response response = sendRequest(postRequest, 403);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(CUSTOM_MODEL_ADMIN);
|
||||
response = sendRequest(postRequest, 200);
|
||||
|
||||
JSONObject json = new JSONObject(new JSONTokener(response.getContentAsString()));
|
||||
|
||||
String importedModelName = json.getString("modelName");
|
||||
importedModels.add(importedModelName);
|
||||
|
||||
String extModule = json.getString("shareExtModule");
|
||||
Document document = XMLUtil.parse(extModule);
|
||||
NodeList nodes = document.getElementsByTagName("id");
|
||||
assertEquals(1, nodes.getLength());
|
||||
assertNotNull(nodes.item(0).getTextContent());
|
||||
}
|
||||
|
||||
public void testValidUpload_ModelOnly() throws Exception
|
||||
{
|
||||
File zipFile = getResourceFile("validModel.zip");
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(NON_ADMIN_USER);
|
||||
Response response = sendRequest(postRequest, 403);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(CUSTOM_MODEL_ADMIN);
|
||||
response = sendRequest(postRequest, 200);
|
||||
|
||||
JSONObject json = new JSONObject(new JSONTokener(response.getContentAsString()));
|
||||
String importedModelName = json.getString("modelName");
|
||||
importedModels.add(importedModelName);
|
||||
|
||||
assertFalse(json.has("shareExtModule"));
|
||||
|
||||
// Import the same model again
|
||||
sendRequest(postRequest, 409); // name conflict
|
||||
}
|
||||
|
||||
public void testValidUpload_ExtModuleOnly() throws Exception
|
||||
{
|
||||
File zipFile = getResourceFile("validExtModule.zip");
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(NON_ADMIN_USER);
|
||||
Response response = sendRequest(postRequest, 403);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(CUSTOM_MODEL_ADMIN);
|
||||
response = sendRequest(postRequest, 200);
|
||||
|
||||
JSONObject json = new JSONObject(new JSONTokener(response.getContentAsString()));
|
||||
assertFalse(json.has("modelName"));
|
||||
|
||||
String extModule = json.getString("shareExtModule");
|
||||
Document document = XMLUtil.parse(extModule);
|
||||
NodeList nodes = document.getElementsByTagName("id");
|
||||
assertEquals(1, nodes.getLength());
|
||||
assertNotNull(nodes.item(0).getTextContent());
|
||||
}
|
||||
|
||||
public void testNotZipFileUpload() throws Exception
|
||||
{
|
||||
File file = getResourceFile("validModel.zip");
|
||||
ZipFile zipFile = new ZipFile(file);
|
||||
ZipEntry zipEntry = zipFile.entries().nextElement();
|
||||
|
||||
File unzippedModelFile = TempFileProvider.createTempFile(zipFile.getInputStream(zipEntry), "validModel", ".xml");
|
||||
tempFiles.add(unzippedModelFile);
|
||||
zipFile.close();
|
||||
|
||||
PostRequest postRequest = buildMultipartPostRequest(unzippedModelFile);
|
||||
sendRequest(postRequest, 400); // CMM upload supports only zip file.
|
||||
}
|
||||
|
||||
public void testInvalidZipUpload() throws Exception
|
||||
{
|
||||
String content = "<note>"
|
||||
+ "<from>Jane</from>"
|
||||
+ "<to>John</to>"
|
||||
+ "<heading>Upload test</heading>"
|
||||
+ "<body>This is an invalid model or a Share extension module</body>"
|
||||
+"</note>";
|
||||
|
||||
ZipEntryContext context = new ZipEntryContext("invalidFormat.xml", content.getBytes());
|
||||
File zipFile = createZip(context);
|
||||
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
sendRequest(postRequest, 400); // Invalid. Neither a model nor a Share extension module file
|
||||
}
|
||||
|
||||
public void testUploadModel_Invalid() throws Exception
|
||||
{
|
||||
long timestamp = System.currentTimeMillis();
|
||||
final String modelName = getClass().getSimpleName() + timestamp;
|
||||
final String prefix = "prefix" + timestamp;
|
||||
final String uri = "uriNamespace" + timestamp;
|
||||
|
||||
M2Model model = M2Model.createModel(prefix + QName.NAMESPACE_PREFIX + modelName);
|
||||
model.setAuthor("Admin");
|
||||
model.setDescription("Desc");
|
||||
|
||||
ByteArrayOutputStream xml = new ByteArrayOutputStream();
|
||||
model.toXML(xml);
|
||||
ZipEntryContext context = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
File zipFile = createZip(context);
|
||||
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
sendRequest(postRequest, 409); // no namespace has been defined
|
||||
|
||||
// Create two namespaces
|
||||
model.createNamespace(uri, prefix);
|
||||
model.createNamespace(uri + "anotherUri", prefix + "anotherPrefix");
|
||||
xml = new ByteArrayOutputStream();
|
||||
model.toXML(xml);
|
||||
context = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
zipFile = createZip(context);
|
||||
|
||||
postRequest = buildMultipartPostRequest(zipFile);
|
||||
sendRequest(postRequest, 409); // custom model can only have one namespace
|
||||
}
|
||||
|
||||
public void testUploadModel_UnsupportedModelElements() throws Exception
|
||||
{
|
||||
// Note: here we only test a couple of not-supported model elements to check for the correct status code.
|
||||
// This test should be removed when we implement the required support
|
||||
|
||||
long timestamp = System.currentTimeMillis();
|
||||
final String modelName = getClass().getSimpleName() + timestamp;
|
||||
final String prefix = "prefix"+timestamp;
|
||||
final String uri = "uriNamespace"+timestamp;
|
||||
final String aspectName = prefix + QName.NAMESPACE_PREFIX + "testAspec";
|
||||
final String typeName = prefix + QName.NAMESPACE_PREFIX + "testType";
|
||||
final String associationName = prefix + QName.NAMESPACE_PREFIX + "testAssociation";
|
||||
|
||||
M2Model model = M2Model.createModel(prefix + QName.NAMESPACE_PREFIX + modelName);
|
||||
model.createNamespace(uri, prefix);
|
||||
model.setAuthor("John Doe");
|
||||
model.createAspect(aspectName);
|
||||
model.createImport(NamespaceService.CONTENT_MODEL_1_0_URI, NamespaceService.CONTENT_MODEL_PREFIX);
|
||||
|
||||
M2Type type = model.createType(typeName);
|
||||
// Add 'association' not supported yet.
|
||||
M2Association association = type.createAssociation(associationName);
|
||||
association.setSourceMandatory(false);
|
||||
association.setSourceMany(false);
|
||||
association.setTargetMandatory(false);
|
||||
association.setTargetClassName("cm:content");
|
||||
|
||||
ByteArrayOutputStream xml = new ByteArrayOutputStream();
|
||||
model.toXML(xml);
|
||||
ZipEntryContext context = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
File zipFile = createZip(context);
|
||||
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
sendRequest(postRequest, 409); // <associations> element is not supported yet
|
||||
|
||||
type.removeAssociation(associationName);
|
||||
// Add 'mandatory-aspect' not supported yet.
|
||||
type.addMandatoryAspect(aspectName);
|
||||
xml = new ByteArrayOutputStream();
|
||||
model.toXML(xml);
|
||||
context = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
zipFile = createZip(context);
|
||||
|
||||
postRequest = buildMultipartPostRequest(zipFile);
|
||||
sendRequest(postRequest, 409); // <mandatory-aspects> element is not supported yet
|
||||
}
|
||||
|
||||
public void testInvalidNumberOfZipEntries() throws Exception
|
||||
{
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String modelName = getClass().getSimpleName() + timestamp;
|
||||
String prefix = "prefix" + timestamp;
|
||||
String uri = "uriNamespace" + timestamp;
|
||||
|
||||
// Model one
|
||||
M2Model modelOne = M2Model.createModel(prefix + QName.NAMESPACE_PREFIX + modelName);
|
||||
modelOne.createNamespace(uri, prefix);
|
||||
modelOne.setDescription("Model 1");
|
||||
ByteArrayOutputStream xml = new ByteArrayOutputStream();
|
||||
modelOne.toXML(xml);
|
||||
ZipEntryContext contextOne = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
|
||||
// Model two
|
||||
modelName += "two";
|
||||
prefix += "two";
|
||||
uri += "two";
|
||||
M2Model modelTwo = M2Model.createModel(prefix + QName.NAMESPACE_PREFIX + modelName);
|
||||
modelTwo.createNamespace(uri, prefix);
|
||||
modelTwo.setDescription("Model 2");
|
||||
xml = new ByteArrayOutputStream();
|
||||
modelTwo.toXML(xml);
|
||||
ZipEntryContext contextTwo = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
|
||||
// Model three
|
||||
modelName += "three";
|
||||
prefix += "three";
|
||||
uri += "three";
|
||||
M2Model modelThree = M2Model.createModel(prefix + QName.NAMESPACE_PREFIX + modelName);
|
||||
modelThree.createNamespace(uri, prefix);
|
||||
modelThree.setDescription("Model 3");
|
||||
xml = new ByteArrayOutputStream();
|
||||
modelThree.toXML(xml);
|
||||
ZipEntryContext contextThree = new ZipEntryContext(modelName + ".xml", xml.toByteArray());
|
||||
|
||||
File zipFile = createZip(contextOne, contextTwo, contextThree);
|
||||
|
||||
PostRequest postRequest = buildMultipartPostRequest(zipFile);
|
||||
sendRequest(postRequest, 400); // more than two zip entries
|
||||
}
|
||||
|
||||
public PostRequest buildMultipartPostRequest(File file) throws IOException
|
||||
{
|
||||
Part[] parts = { new FilePart("filedata", file.getName(), file, "application/zip", null) };
|
||||
|
||||
MultipartRequestEntity multipartRequestEntity = new MultipartRequestEntity(parts, new HttpMethodParams());
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
multipartRequestEntity.writeRequest(os);
|
||||
|
||||
PostRequest postReq = new PostRequest(UPLOAD_URL, os.toByteArray(), multipartRequestEntity.getContentType());
|
||||
return postReq;
|
||||
}
|
||||
|
||||
private void createUser(String userName)
|
||||
{
|
||||
if (!authenticationService.authenticationExists(userName))
|
||||
{
|
||||
authenticationService.createAuthentication(userName, "PWD".toCharArray());
|
||||
}
|
||||
|
||||
if (!personService.personExists(userName))
|
||||
{
|
||||
PropertyMap ppOne = new PropertyMap(4);
|
||||
ppOne.put(ContentModel.PROP_USERNAME, userName);
|
||||
ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
|
||||
ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
|
||||
ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
|
||||
ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
|
||||
|
||||
personService.createPerson(ppOne);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteUser(String userName)
|
||||
{
|
||||
if (personService.personExists(userName))
|
||||
{
|
||||
personService.deletePerson(userName);
|
||||
}
|
||||
}
|
||||
|
||||
private File getResourceFile(String xmlFileName) throws FileNotFoundException
|
||||
{
|
||||
URL url = CustomModelImportTest.class.getClassLoader().getResource(RESOURCE_PREFIX + xmlFileName);
|
||||
if (url == null)
|
||||
{
|
||||
fail("Cannot get the resource: " + xmlFileName);
|
||||
}
|
||||
return ResourceUtils.getFile(url);
|
||||
}
|
||||
|
||||
private File createZip(ZipEntryContext... zipEntryContexts)
|
||||
{
|
||||
File zipFile = TempFileProvider.createTempFile(getClass().getSimpleName(), ".zip");
|
||||
tempFiles.add(zipFile);
|
||||
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
try
|
||||
{
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(zipFile), BUFFER_SIZE);
|
||||
ZipOutputStream zos = new ZipOutputStream(out);
|
||||
|
||||
for (ZipEntryContext context : zipEntryContexts)
|
||||
{
|
||||
ZipEntry zipEntry = new ZipEntry(context.getZipEntryName());
|
||||
zos.putNextEntry(zipEntry);
|
||||
|
||||
InputStream input = context.getEntryContent();
|
||||
int len;
|
||||
while ((len = input.read(buffer)) > 0)
|
||||
{
|
||||
zos.write(buffer, 0, len);
|
||||
}
|
||||
input.close();
|
||||
}
|
||||
zos.closeEntry();
|
||||
zos.close();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
fail("couldn't create zip file.");
|
||||
}
|
||||
|
||||
return zipFile;
|
||||
}
|
||||
|
||||
private static class ZipEntryContext
|
||||
{
|
||||
private final String zipEntryName;
|
||||
private final InputStream entryContent;
|
||||
|
||||
public ZipEntryContext(String zipEntryName, byte[] zipEntryContent)
|
||||
{
|
||||
this.zipEntryName = zipEntryName;
|
||||
this.entryContent = new ByteArrayInputStream(zipEntryContent);
|
||||
}
|
||||
|
||||
public String getZipEntryName()
|
||||
{
|
||||
return this.zipEntryName;
|
||||
}
|
||||
|
||||
public InputStream getEntryContent()
|
||||
{
|
||||
return this.entryContent;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.api.tests;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.dictionary.CustomModelServiceImpl;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.rest.api.model.AbstractClassModel;
|
||||
import org.alfresco.rest.api.model.CustomAspect;
|
||||
import org.alfresco.rest.api.model.CustomModel;
|
||||
import org.alfresco.rest.api.model.CustomModelConstraint;
|
||||
import org.alfresco.rest.api.model.CustomModelNamedValue;
|
||||
import org.alfresco.rest.api.model.CustomModelProperty;
|
||||
import org.alfresco.rest.api.model.CustomType;
|
||||
import org.alfresco.rest.api.model.CustomModel.ModelStatus;
|
||||
import org.alfresco.rest.api.tests.RepoService.TestPerson;
|
||||
import org.alfresco.rest.api.tests.client.HttpResponse;
|
||||
import org.alfresco.rest.api.tests.client.RequestContext;
|
||||
import org.alfresco.rest.api.tests.client.PublicApiClient.Paging;
|
||||
import org.alfresco.rest.api.tests.util.RestApiUtil;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelService;
|
||||
import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
|
||||
import org.alfresco.service.cmr.security.AuthorityService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Base class for CMM API tests
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class BaseCustomModelApiTest extends EnterpriseTestApi
|
||||
{
|
||||
public static final String CMM_SCOPE = "private";
|
||||
public static final String SELECT_PROPS_QS = "?select=props";
|
||||
public static final String SELECT_STATUS_QS = "?select=status";
|
||||
public static final String SELECT_ALL = "?select=all";
|
||||
public static final String SELECT_ALL_PROPS = "?select=allProps";
|
||||
|
||||
protected String nonAdminUserName;
|
||||
protected String customModelAdmin;
|
||||
|
||||
protected MutableAuthenticationService authenticationService;
|
||||
protected PersonService personService;
|
||||
protected CustomModelService customModelService;
|
||||
|
||||
private List<String> users = new ArrayList<>();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception
|
||||
{
|
||||
authenticationService = applicationContext.getBean("authenticationService", MutableAuthenticationService.class);
|
||||
personService = applicationContext.getBean("personService", PersonService.class);
|
||||
customModelService = applicationContext.getBean("customModelService", CustomModelService.class);
|
||||
|
||||
final AuthorityService authorityService = applicationContext.getBean("authorityService", AuthorityService.class);
|
||||
|
||||
this.nonAdminUserName = createUser("nonAdminUser" + System.currentTimeMillis());
|
||||
this.customModelAdmin = createUser("customModelAdmin" + System.currentTimeMillis());
|
||||
users.add(nonAdminUserName);
|
||||
users.add(customModelAdmin);
|
||||
// Add 'customModelAdmin' user into 'ALFRESCO_MODEL_ADMINISTRATORS' group
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
authorityService.addAuthority(CustomModelServiceImpl.GROUP_ALFRESCO_MODEL_ADMINISTRATORS_AUTHORITY, customModelAdmin);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
|
||||
for (final String user : users)
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
authenticationService.deleteAuthentication(user);
|
||||
personService.deletePerson(user);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
users.clear();
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
protected String createUser(String username)
|
||||
{
|
||||
PersonInfo personInfo = new PersonInfo(username, username, username, "password", null, null, null, null, null, null, null);
|
||||
TestPerson person = repoService.createUser(personInfo, username, null);
|
||||
return person.getId();
|
||||
}
|
||||
|
||||
protected HttpResponse post(String url, String runAsUser, String body, int expectedStatus) throws Exception
|
||||
{
|
||||
publicApiClient.setRequestContext(new RequestContext(runAsUser));
|
||||
|
||||
HttpResponse response = publicApiClient.post(CMM_SCOPE, url, null, null, null, body);
|
||||
checkStatus(expectedStatus, response.getStatusCode());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected HttpResponse post(String url, String runAsUser, String body, String queryString, int expectedStatus) throws Exception
|
||||
{
|
||||
publicApiClient.setRequestContext(new RequestContext(runAsUser));
|
||||
if (queryString != null)
|
||||
{
|
||||
url += queryString;
|
||||
}
|
||||
HttpResponse response = publicApiClient.post(CMM_SCOPE, url, null, null, null, body);
|
||||
checkStatus(expectedStatus, response.getStatusCode());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected HttpResponse getAll(String url, String runAsUser, Paging paging, int expectedStatus) throws Exception
|
||||
{
|
||||
publicApiClient.setRequestContext(new RequestContext(runAsUser));
|
||||
Map<String, String> params = (paging == null) ? null : createParams(paging, null);
|
||||
|
||||
HttpResponse response = publicApiClient.get(CMM_SCOPE, url, null, null, null, params);
|
||||
checkStatus(expectedStatus, response.getStatusCode());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected HttpResponse getSingle(String url, String runAsUser, String entityId, int expectedStatus) throws Exception
|
||||
{
|
||||
publicApiClient.setRequestContext(new RequestContext(runAsUser));
|
||||
|
||||
HttpResponse response = publicApiClient.get(CMM_SCOPE, url, entityId, null, null, null);
|
||||
checkStatus(expectedStatus, response.getStatusCode());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected HttpResponse put(String url, String runAsUser, String entityId, String body, String queryString, int expectedStatus) throws Exception
|
||||
{
|
||||
publicApiClient.setRequestContext(new RequestContext(runAsUser));
|
||||
if (queryString != null)
|
||||
{
|
||||
entityId += queryString;
|
||||
}
|
||||
HttpResponse response = publicApiClient.put(CMM_SCOPE, url, entityId, null, null, body, null);
|
||||
checkStatus(expectedStatus, response.getStatusCode());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected HttpResponse delete(String url, String runAsUser, String entityId, int expectedStatus) throws Exception
|
||||
{
|
||||
publicApiClient.setRequestContext(new RequestContext(runAsUser));
|
||||
|
||||
HttpResponse response = publicApiClient.delete(CMM_SCOPE, url, entityId, null, null);
|
||||
checkStatus(expectedStatus, response.getStatusCode());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected void checkStatus(int expectedStatus, int actualStatus)
|
||||
{
|
||||
if (expectedStatus > 0 && expectedStatus != actualStatus)
|
||||
{
|
||||
fail("Status code " + actualStatus + " returned, but expected " + expectedStatus);
|
||||
}
|
||||
}
|
||||
|
||||
protected CustomModel createCustomModel(String modelName, Pair<String, String> namespacePair, ModelStatus status) throws Exception
|
||||
{
|
||||
return createCustomModel(modelName, namespacePair, status, "Test model description", null);
|
||||
}
|
||||
|
||||
protected CustomModel createCustomModel(String modelName, Pair<String, String> namespacePair, ModelStatus status, String desc, String author)
|
||||
throws Exception
|
||||
{
|
||||
CustomModel customModel = new CustomModel();
|
||||
customModel.setName(modelName);
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
customModel.setDescription(desc);
|
||||
customModel.setStatus(status);
|
||||
customModel.setAuthor(author);
|
||||
|
||||
// Create the model as a Model Administrator
|
||||
HttpResponse response = post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 201);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
if (author == null)
|
||||
{
|
||||
// ignore 'author' in the comparison
|
||||
compareCustomModels(customModel, returnedModel, "author");
|
||||
}
|
||||
else
|
||||
{
|
||||
compareCustomModels(customModel, returnedModel);
|
||||
}
|
||||
|
||||
return customModel;
|
||||
}
|
||||
|
||||
protected <T extends AbstractClassModel> T createTypeAspect(Class<T> glazz, String modelName, String typeAspectName, String title, String desc,
|
||||
String parent) throws Exception
|
||||
{
|
||||
AbstractClassModel classModel = null;
|
||||
String uri = "cmm/" + modelName;
|
||||
if (glazz.equals(CustomType.class))
|
||||
{
|
||||
classModel = new CustomType();
|
||||
uri += "/types";
|
||||
}
|
||||
else
|
||||
{
|
||||
classModel = new CustomAspect();
|
||||
uri += "/aspects";
|
||||
}
|
||||
|
||||
classModel.setName(typeAspectName);
|
||||
classModel.setDescription(desc);
|
||||
classModel.setTitle(title);
|
||||
classModel.setParentName(parent);
|
||||
|
||||
// Create type as a Model Administrator
|
||||
HttpResponse response = post(uri, customModelAdmin, RestApiUtil.toJsonAsString(classModel), 201);
|
||||
T returnedClassModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), glazz);
|
||||
|
||||
compareCustomTypesAspects(classModel, returnedClassModel, "prefixedName");
|
||||
|
||||
return returnedClassModel;
|
||||
}
|
||||
|
||||
protected void compareCustomModels(CustomModel expectedModel, CustomModel actualModel, String... excludeFields)
|
||||
{
|
||||
boolean result = EqualsBuilder.reflectionEquals(expectedModel, actualModel, excludeFields);
|
||||
assertTrue("Two models are not equal. Expected:<" + expectedModel.toString() + "> but was:<" + actualModel.toString() + ">", result);
|
||||
}
|
||||
|
||||
protected void compareCustomTypesAspects(AbstractClassModel expectedDetails, AbstractClassModel actualDetails, String... excludeFields)
|
||||
{
|
||||
List<CustomModelProperty> expectedProps = expectedDetails.getProperties();
|
||||
List<CustomModelProperty> actualProps = actualDetails.getProperties();
|
||||
// Sort them
|
||||
sortIfnotNull(expectedProps);
|
||||
sortIfnotNull(actualProps);
|
||||
|
||||
boolean propEqualResult = true;
|
||||
if (expectedProps.size() == actualProps.size())
|
||||
{
|
||||
for (int i = 0, size = expectedProps.size(); i < size; i++)
|
||||
{
|
||||
boolean equalProp = EqualsBuilder.reflectionEquals(expectedProps.get(i), actualProps.get(i), excludeFields);
|
||||
if (!equalProp)
|
||||
{
|
||||
propEqualResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
propEqualResult = false;
|
||||
}
|
||||
|
||||
if (excludeFields.length > 0)
|
||||
{
|
||||
int size = excludeFields.length;
|
||||
excludeFields = Arrays.copyOf(excludeFields, size + 1);
|
||||
excludeFields[size] = "properties";
|
||||
}
|
||||
boolean result = EqualsBuilder.reflectionEquals(expectedDetails, actualDetails, excludeFields);
|
||||
|
||||
String typesAspects = (expectedDetails instanceof CustomAspect) ? "aspects" : "types";
|
||||
assertTrue("Two " + typesAspects + " are not equal. Expected:<" + expectedDetails.toString() + "> but was:<" + actualDetails.toString() + ">",
|
||||
(result && propEqualResult));
|
||||
}
|
||||
|
||||
protected void compareCustomModelConstraints(CustomModelConstraint expectedConstraint, CustomModelConstraint actualConstraint, String... excludeFields)
|
||||
{
|
||||
boolean result = EqualsBuilder.reflectionEquals(expectedConstraint, actualConstraint, excludeFields);
|
||||
assertTrue("Two constraints are not equal. Expected:<" + expectedConstraint.toString() + "> but was:<" + actualConstraint.toString() + ">", result);
|
||||
}
|
||||
|
||||
protected void compareCustomModelProperties(CustomModelProperty expectedProperty, CustomModelProperty actualProperty, String... excludeFields)
|
||||
{
|
||||
boolean result = EqualsBuilder.reflectionEquals(expectedProperty, actualProperty, excludeFields);
|
||||
assertTrue("Two constraints are not equal. Expected:<" + expectedProperty.toString() + "> but was:<" + actualProperty.toString() + ">", result);
|
||||
}
|
||||
|
||||
protected Pair<String, String> getTestNamespaceUriPrefixPair()
|
||||
{
|
||||
long timeMillis = System.currentTimeMillis();
|
||||
String uri = "http://www.alfresco.org/model/testcmmnamespace" + timeMillis + "/1.0";
|
||||
String prefix = "testcmm" + timeMillis;
|
||||
|
||||
return new Pair<String, String>(uri, prefix);
|
||||
}
|
||||
|
||||
protected CustomModelDefinition getModelDefinition(final String modelName)
|
||||
{
|
||||
return transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelDefinition>()
|
||||
{
|
||||
@Override
|
||||
public CustomModelDefinition execute() throws Throwable
|
||||
{
|
||||
return customModelService.getCustomModel(modelName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void sortIfnotNull(List<CustomModelProperty> list)
|
||||
{
|
||||
if (list != null && list.size() > 0)
|
||||
{
|
||||
Collections.sort(list);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasNamespaceUri(Collection<NamespaceDefinition> namespaces, String expectedNamespaceUri)
|
||||
{
|
||||
for (NamespaceDefinition ns : namespaces)
|
||||
{
|
||||
if (ns.getUri().equals(expectedNamespaceUri))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean hasNamespacePrefix(Collection<NamespaceDefinition> namespaces, String expectedNamespacePrefix)
|
||||
{
|
||||
for (NamespaceDefinition ns : namespaces)
|
||||
{
|
||||
if (ns.getPrefix().equals(expectedNamespacePrefix))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected CustomModelProperty getProperty(List<CustomModelProperty> properties, String propName)
|
||||
{
|
||||
for (CustomModelProperty prop : properties)
|
||||
{
|
||||
if (prop.getName().equals(propName))
|
||||
{
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected CustomModelNamedValue buildNamedValue(String name, String simpleValue, String... listValue)
|
||||
{
|
||||
CustomModelNamedValue namedValue = new CustomModelNamedValue();
|
||||
namedValue.setName(name);
|
||||
namedValue.setSimpleValue(simpleValue);
|
||||
if (listValue.length > 0)
|
||||
{
|
||||
namedValue.setListValue(Arrays.asList(listValue));
|
||||
}
|
||||
|
||||
return namedValue;
|
||||
}
|
||||
|
||||
protected String getParameterSimpleValue(List<CustomModelNamedValue> params, String paramName)
|
||||
{
|
||||
for (CustomModelNamedValue p : params)
|
||||
{
|
||||
if (p.getName().equals(paramName))
|
||||
{
|
||||
return p.getSimpleValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<String> getParameterListValue(List<CustomModelNamedValue> params, String paramName)
|
||||
{
|
||||
for (CustomModelNamedValue p : params)
|
||||
{
|
||||
if (p.getName().equals(paramName))
|
||||
{
|
||||
return p.getListValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.api.tests;
|
||||
|
||||
import junit.framework.JUnit4TestAdapter;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class CMMApiTestSuite extends TestSuite
|
||||
{
|
||||
/**
|
||||
* Creates the test suite
|
||||
*
|
||||
* @return the test suite
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.addTest(new JUnit4TestAdapter(TestCustomModel.class));
|
||||
suite.addTest(new JUnit4TestAdapter(TestCustomTypeAspect.class));
|
||||
suite.addTest(new JUnit4TestAdapter(TestCustomProperty.class));
|
||||
suite.addTest(new JUnit4TestAdapter(TestCustomConstraint.class));
|
||||
suite.addTest(new JUnit4TestAdapter(TestCustomModelExport.class));
|
||||
|
||||
return suite;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.api.tests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.api.model.CustomAspect;
|
||||
import org.alfresco.rest.api.model.CustomModel;
|
||||
import org.alfresco.rest.api.model.CustomModel.ModelStatus;
|
||||
import org.alfresco.rest.api.model.CustomType;
|
||||
import org.alfresco.rest.api.tests.client.HttpResponse;
|
||||
import org.alfresco.rest.api.tests.client.PublicApiClient.Paging;
|
||||
import org.alfresco.rest.api.tests.util.RestApiUtil;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests the REST API of the models of the {@link CustomModelService}.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class TestCustomModel extends BaseCustomModelApiTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testCreateBasicModel() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
|
||||
CustomModel customModel = new CustomModel();
|
||||
customModel.setName(modelName);
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
customModel.setDescription("Test model description");
|
||||
customModel.setStatus(CustomModel.ModelStatus.DRAFT);
|
||||
|
||||
// Try to create the model as a non Admin user
|
||||
post("cmm", nonAdminUserName, RestApiUtil.toJsonAsString(customModel), 403);
|
||||
|
||||
// Create the model as a Model Administrator
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 201);
|
||||
|
||||
// Retrieve the created model
|
||||
HttpResponse response = getSingle("cmm", customModelAdmin, modelName, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
// Check the retrieved model is the expected model.
|
||||
// Note: since we didn't specify the Author when created the Model,
|
||||
// we have to exclude it from the objects comparison. Because,
|
||||
// the system will add the current authenticated user as the author
|
||||
// of the model, if the Author hasn't been set.
|
||||
compareCustomModels(customModel, returnedModel, "author");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateBasicModel_Invalid() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
|
||||
CustomModel customModel = new CustomModel();
|
||||
customModel.setName(modelName);
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
|
||||
// Test invalid inputs
|
||||
{
|
||||
customModel.setName(modelName + "<script>alert('oops')</script>");
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400);
|
||||
|
||||
customModel.setName("prefix:" + modelName);
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // Invalid name. Contains ':'
|
||||
|
||||
customModel.setName("prefix " + modelName);
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // Invalid name. Contains space
|
||||
|
||||
customModel.setName(modelName);
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond()+" space");
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // Invalid prefix. Contains space
|
||||
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond()+"invalid/");
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // Invalid prefix. Contains '/'
|
||||
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
customModel.setNamespaceUri(namespacePair.getFirst()+" space");
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // Invalid URI. Contains space
|
||||
|
||||
customModel.setNamespaceUri(namespacePair.getFirst()+"\\");
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // Invalid URI. Contains '\'
|
||||
}
|
||||
|
||||
// Test mandatory properties of the model
|
||||
{
|
||||
customModel.setName("");
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // name is mandatory
|
||||
|
||||
customModel.setName(modelName);
|
||||
customModel.setNamespaceUri(null);
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // namespaceUri is mandatory
|
||||
|
||||
customModel.setName(modelName);
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
customModel.setNamespacePrefix(null);
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 400); // namespacePrefix is mandatory
|
||||
}
|
||||
|
||||
// Test duplicate model name
|
||||
{
|
||||
// Test create a model with the same name as the bootstrapped model
|
||||
customModel.setName("contentmodel");
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 409);
|
||||
|
||||
// Create the model
|
||||
customModel.setName(modelName);
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 201);
|
||||
|
||||
// Create a duplicate model
|
||||
// Set a new namespace to make sure the 409 status code is returned
|
||||
// because of a name conflict rather than namespace URI
|
||||
namespacePair = getTestNamespaceUriPrefixPair();
|
||||
customModel.setNamespaceUri(namespacePair.getFirst());
|
||||
customModel.setNamespacePrefix(namespacePair.getSecond());
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 409);
|
||||
}
|
||||
|
||||
// Test duplicate namespaceUri
|
||||
{
|
||||
String modelNameTwo = "testModelTwo" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairTwo = getTestNamespaceUriPrefixPair();
|
||||
|
||||
CustomModel customModelTwo = new CustomModel();
|
||||
customModelTwo.setName(modelNameTwo);
|
||||
customModelTwo.setNamespaceUri(namespacePairTwo.getFirst());
|
||||
customModelTwo.setNamespacePrefix(namespacePairTwo.getSecond());
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModelTwo), 201);
|
||||
|
||||
String modelNameThree = "testModelThree" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairThree = getTestNamespaceUriPrefixPair();
|
||||
CustomModel customModelThree = new CustomModel();
|
||||
customModelThree.setName(modelNameThree);
|
||||
customModelThree.setNamespaceUri(namespacePairTwo.getFirst()); // duplicate URI
|
||||
customModelThree.setNamespacePrefix(namespacePairThree.getSecond());
|
||||
|
||||
// Try to create a model with a namespace uri which has already been used.
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModelThree), 409);
|
||||
|
||||
customModelThree.setNamespaceUri(namespacePairThree.getFirst());
|
||||
customModelThree.setNamespacePrefix(namespacePairTwo.getSecond()); // duplicate prefix
|
||||
|
||||
// Try to create a model with a namespace prefix which has already been used.
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModelThree), 409);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListBasicModels() throws Exception
|
||||
{
|
||||
String modelName_1 = "testModel1" + System.currentTimeMillis();
|
||||
// Create the model as a Model Administrator
|
||||
CustomModel customModel_1 = createCustomModel(modelName_1, getTestNamespaceUriPrefixPair(), ModelStatus.DRAFT);
|
||||
|
||||
String modelName_2 = "testModel2" + System.currentTimeMillis();
|
||||
CustomModel customModel_2 = createCustomModel(modelName_2, getTestNamespaceUriPrefixPair(), ModelStatus.DRAFT);
|
||||
|
||||
String modelName_3 = "testModel3" + System.currentTimeMillis();
|
||||
CustomModel customModel_3 = createCustomModel(modelName_3, getTestNamespaceUriPrefixPair(), ModelStatus.DRAFT);
|
||||
|
||||
Paging paging = getPaging(0, Integer.MAX_VALUE);
|
||||
HttpResponse response = getAll("cmm", customModelAdmin, paging, 200);
|
||||
List<CustomModel> models = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), CustomModel.class);
|
||||
|
||||
assertTrue(models.size() >= 3);
|
||||
assertTrue(models.contains(customModel_1));
|
||||
assertTrue(models.contains(customModel_2));
|
||||
assertTrue(models.contains(customModel_3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivateCustomModel() throws Exception
|
||||
{
|
||||
String modelNameOne = "testActivateModelOne" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
CustomModel customModelOne = createCustomModel(modelNameOne, namespacePair, ModelStatus.DRAFT, "Test model description", "Jane Doe");
|
||||
|
||||
// Retrieve the created model and check its status (the default is DRAFT)
|
||||
HttpResponse response = getSingle("cmm", customModelAdmin, modelNameOne, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.DRAFT, returnedModel.getStatus());
|
||||
|
||||
// We only want to update the status, so ignore the other properties
|
||||
CustomModel updatePayload = new CustomModel();
|
||||
updatePayload.setStatus(ModelStatus.ACTIVE);
|
||||
|
||||
// Try to activate the model as a non Admin user
|
||||
put("cmm", nonAdminUserName, modelNameOne, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 403);
|
||||
|
||||
// Activate the model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
response = getSingle("cmm", customModelAdmin, modelNameOne, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.ACTIVE, returnedModel.getStatus());
|
||||
// Check other properties have not been modified
|
||||
compareCustomModels(customModelOne, returnedModel, "status");
|
||||
|
||||
// Try to activate the already activated model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 500);
|
||||
|
||||
// Create another Model
|
||||
String modelNameTwo = "testActivateModelTwo" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairTwo = getTestNamespaceUriPrefixPair();
|
||||
CustomModel customModelTwo = createCustomModel(modelNameTwo, namespacePairTwo, ModelStatus.DRAFT, null, "John Doe");
|
||||
|
||||
// Activate the model as a Model Administrator
|
||||
customModelTwo.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameTwo, RestApiUtil.toJsonAsString(customModelTwo), SELECT_STATUS_QS, 200);
|
||||
|
||||
response = getSingle("cmm", customModelAdmin, modelNameTwo, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.ACTIVE, returnedModel.getStatus());
|
||||
// Check other properties have not been modified
|
||||
compareCustomModels(customModelTwo, returnedModel, "status");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeactivateCustomModel() throws Exception
|
||||
{
|
||||
String modelNameOne = "testDeactivateModelOne" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
CustomModel customModelOne = createCustomModel(modelNameOne, namespacePair, ModelStatus.ACTIVE, null, "Mark Moe");
|
||||
|
||||
// Retrieve the created model and check its status
|
||||
HttpResponse response = getSingle("cmm", customModelAdmin, modelNameOne, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.ACTIVE, returnedModel.getStatus());
|
||||
|
||||
// We only want to update the status (Deactivate), so ignore the other properties
|
||||
CustomModel updatePayload = new CustomModel();
|
||||
updatePayload.setStatus(ModelStatus.DRAFT);
|
||||
|
||||
// Try to deactivate the model as a non Admin user
|
||||
put("cmm", nonAdminUserName, modelNameOne, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 403);
|
||||
|
||||
// Deactivate the model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
response = getSingle("cmm", customModelAdmin, modelNameOne, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.DRAFT, returnedModel.getStatus());
|
||||
// Check other properties have not been modified
|
||||
compareCustomModels(customModelOne, returnedModel, "status");
|
||||
|
||||
// Try to deactivate the already deactivated model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 500);
|
||||
|
||||
// Activate/Deactivate a model with an aspect
|
||||
{
|
||||
// Create another Model
|
||||
final String modelNameTwo = "testDeactivateModelTwo" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairTwo = getTestNamespaceUriPrefixPair();
|
||||
CustomModel customModelTwo = createCustomModel(modelNameTwo, namespacePairTwo, ModelStatus.DRAFT, null, "Mark Moe");
|
||||
|
||||
// Aspect
|
||||
CustomAspect aspect = new CustomAspect();
|
||||
aspect.setName("testMarkerAspect");
|
||||
post("cmm/" + modelNameTwo + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 201);
|
||||
// Retrieve the created aspect
|
||||
getSingle("cmm/" + modelNameTwo + "/aspects", customModelAdmin, aspect.getName(), 200);
|
||||
|
||||
// Activate the model as a Model Administrator
|
||||
customModelTwo.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameTwo, RestApiUtil.toJsonAsString(customModelTwo), SELECT_STATUS_QS, 200);
|
||||
|
||||
response = getSingle("cmm", customModelAdmin, modelNameTwo, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.ACTIVE, returnedModel.getStatus());
|
||||
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setStatus(ModelStatus.DRAFT);
|
||||
// Deactivate the model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelNameTwo, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
response = getSingle("cmm", customModelAdmin, modelNameTwo, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.DRAFT, returnedModel.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteCustomModel() throws Exception
|
||||
{
|
||||
String modelName = "testDeleteModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
CustomModel customModel = createCustomModel(modelName, namespacePair, ModelStatus.DRAFT, null, "Joe Bloggs");
|
||||
|
||||
// Retrieve the created model
|
||||
HttpResponse response = getSingle("cmm", customModelAdmin, modelName, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
compareCustomModels(customModel, returnedModel);
|
||||
|
||||
// Try to delete the model as a non Admin user
|
||||
delete("cmm", nonAdminUserName, modelName, 403);
|
||||
|
||||
// Delete the model as a Model Administrator
|
||||
delete("cmm", customModelAdmin, modelName, 204);
|
||||
|
||||
// Create the model again
|
||||
post("cmm", customModelAdmin, RestApiUtil.toJsonAsString(customModel), 201);
|
||||
|
||||
// Activated the model
|
||||
CustomModel updatePayload = new CustomModel();
|
||||
updatePayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Try to delete the active model
|
||||
delete("cmm", customModelAdmin, modelName, 409);
|
||||
|
||||
// Deactivate and then delete the model
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setStatus(ModelStatus.DRAFT);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 200);
|
||||
delete("cmm", customModelAdmin, modelName, 204);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateBasicModel() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT, "Test model description", null);
|
||||
|
||||
//Test update name
|
||||
CustomModel updatePayload = new CustomModel();
|
||||
String newName = modelName + "Modified";
|
||||
updatePayload.setName(newName);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 400); // Cannot update the model name
|
||||
|
||||
// Test update the namespace URI (already in-use)
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespaceUri("http://www.alfresco.org/model/content/1.0");
|
||||
updatePayload.setNamespacePrefix("newPrefix");
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 409); // The namespace uri has already been used
|
||||
|
||||
// Test update the namespace Prefix (already in-use)
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespaceUri(getTestNamespaceUriPrefixPair().getFirst());
|
||||
updatePayload.setNamespacePrefix("cm");
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 409); // The namespace prefix has already been used
|
||||
|
||||
// Test update the namespace URI (without sending the namespace prefix)
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespaceUri(getTestNamespaceUriPrefixPair().getFirst());
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 400); // The namespace prefix is mandatory
|
||||
|
||||
// Test update the namespace URI only
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespacePrefix( namespacePair.getSecond());
|
||||
Pair<String, String> newURI = getTestNamespaceUriPrefixPair();
|
||||
updatePayload.setNamespaceUri(newURI.getFirst());
|
||||
HttpResponse response = put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(newURI.getFirst(), returnedModel.getNamespaceUri());
|
||||
assertEquals("The namespace prefix shouldn't have changed.", namespacePair.getSecond(), returnedModel.getNamespacePrefix());
|
||||
|
||||
// Test update the namespace prefix (without sending the namespace URI)
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespacePrefix("newPrefix");
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 400); // The namespce uri is mandatory
|
||||
|
||||
// Test update the namespace prefix only
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespaceUri(namespacePair.getFirst());
|
||||
Pair<String, String> newPrefix = getTestNamespaceUriPrefixPair();
|
||||
updatePayload.setNamespacePrefix( newPrefix.getSecond());
|
||||
response = put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(newPrefix.getSecond(), returnedModel.getNamespacePrefix());
|
||||
assertEquals("The namespace URI shouldn't have changed.", namespacePair.getFirst(), returnedModel.getNamespaceUri());
|
||||
|
||||
// Test a valid update
|
||||
updatePayload = new CustomModel();
|
||||
Pair<String, String> newNamespacePair = getTestNamespaceUriPrefixPair();
|
||||
updatePayload.setNamespaceUri(newNamespacePair.getFirst());
|
||||
updatePayload.setNamespacePrefix(newNamespacePair.getSecond());
|
||||
updatePayload.setDescription("Test model description Modified");
|
||||
updatePayload.setAuthor("John Moe");
|
||||
updatePayload.setStatus(ModelStatus.ACTIVE); // This should be ignored
|
||||
|
||||
// Try to update the model as a non Admin user
|
||||
put("cmm", nonAdminUserName, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 403);
|
||||
// Update the model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 200);
|
||||
|
||||
// Retrieve the updated model
|
||||
response = getSingle("cmm", customModelAdmin, modelName, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
compareCustomModels(updatePayload, returnedModel, "name", "status");
|
||||
assertEquals("The model status should only be updated via '?select=status' request.", ModelStatus.DRAFT, returnedModel.getStatus());
|
||||
|
||||
// Activate the model as a Model Administrator
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setStatus(ModelStatus.ACTIVE);
|
||||
response = put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), SELECT_STATUS_QS, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.ACTIVE, returnedModel.getStatus());
|
||||
|
||||
// Try to update the ACTIVE model's namespace URI
|
||||
updatePayload = new CustomModel();
|
||||
newNamespacePair = getTestNamespaceUriPrefixPair();
|
||||
updatePayload.setNamespaceUri(newNamespacePair.getFirst());
|
||||
updatePayload.setNamespacePrefix(returnedModel.getNamespacePrefix());
|
||||
// Cannot update the namespace uri and/or namespace prefix when the model is Active.
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 409);
|
||||
|
||||
// Try to update the ACTIVE model's namespace Prefix
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespaceUri(returnedModel.getNamespaceUri());
|
||||
updatePayload.setNamespacePrefix("myNewPrefix");
|
||||
// Cannot update the namespace uri and/or namespace prefix when the model is Active.
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 409);
|
||||
|
||||
// Test a valid update of an Active model (you can only update desc and author)
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespaceUri(returnedModel.getNamespaceUri());
|
||||
updatePayload.setNamespacePrefix(returnedModel.getNamespacePrefix());
|
||||
updatePayload.setDescription("Test modifying active model description");
|
||||
updatePayload.setAuthor("Mark Miller");
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 200);
|
||||
|
||||
// Retrieve the updated active model
|
||||
response = getSingle("cmm", customModelAdmin, modelName, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
compareCustomModels(updatePayload, returnedModel, "name", "status");
|
||||
}
|
||||
|
||||
@Test
|
||||
//SHA-726
|
||||
public void testUpdateModel_WithAspectsAndTypes() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
// Add type
|
||||
String typeBaseName = "testTypeBase" + System.currentTimeMillis();
|
||||
final String typeBaseNameWithPrefix = namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeBaseName;
|
||||
createTypeAspect(CustomType.class, modelName, typeBaseName, "test typeBase title", null, "cm:content");
|
||||
|
||||
// Add aspect
|
||||
final String aspectName = "testAspect" + System.currentTimeMillis();
|
||||
final String aspectNameWithPrefix = namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName;
|
||||
createTypeAspect(CustomAspect.class, modelName, aspectName, null, null, null);
|
||||
|
||||
// Activate the model
|
||||
CustomModel modelOneStatusPayload = new CustomModel();
|
||||
modelOneStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Add another type with 'typeBaseName' as its parent
|
||||
String childTypeName = "testTypeChild" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelName, childTypeName, "test typeChild title", "test typeChild Desc", typeBaseNameWithPrefix);
|
||||
|
||||
// Add another aspect with 'aspectName' as its parent
|
||||
final String childAspectName = "testChildAspect" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomAspect.class, modelName, childAspectName, "test child aspect title", null, aspectNameWithPrefix);
|
||||
|
||||
// Deactivate the model
|
||||
modelOneStatusPayload = new CustomModel();
|
||||
modelOneStatusPayload.setStatus(ModelStatus.DRAFT);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Test update the namespace prefix
|
||||
CustomModel updatePayload = new CustomModel();
|
||||
String modifiedPrefix = namespacePair.getSecond() + "Modified";
|
||||
updatePayload.setNamespacePrefix(modifiedPrefix);
|
||||
updatePayload.setNamespaceUri(namespacePair.getFirst());
|
||||
HttpResponse response = put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(modifiedPrefix, returnedModel.getNamespacePrefix());
|
||||
assertEquals("The namespace URI shouldn't have changed.", namespacePair.getFirst(), returnedModel.getNamespaceUri());
|
||||
|
||||
// Test update the namespace URI
|
||||
updatePayload = new CustomModel();
|
||||
updatePayload.setNamespacePrefix(modifiedPrefix);
|
||||
String modifiedURI = namespacePair.getFirst() + "Modified";
|
||||
updatePayload.setNamespaceUri(modifiedURI);
|
||||
response = put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(updatePayload), null, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(modifiedURI, returnedModel.getNamespaceUri());
|
||||
assertEquals("The namespace prefix shouldn't have changed.", modifiedPrefix, returnedModel.getNamespacePrefix());
|
||||
|
||||
// Retrieve the child type
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, childTypeName, 200);
|
||||
CustomType returnedChildType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
final String newTypeParentName = modifiedPrefix + QName.NAMESPACE_PREFIX + typeBaseName;
|
||||
assertEquals("The parent name prefix should have been updated.", newTypeParentName, returnedChildType.getParentName());
|
||||
|
||||
// Retrieve the child aspect
|
||||
response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, childAspectName, 200);
|
||||
CustomAspect returnedChildAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
final String newAspectParentName = modifiedPrefix + QName.NAMESPACE_PREFIX + aspectName;
|
||||
assertEquals("The parent name prefix should have been updated.", newAspectParentName, returnedChildAspect.getParentName());
|
||||
}
|
||||
|
||||
// SHA-808
|
||||
@Test
|
||||
public void testModelsCircularDependency() throws Exception
|
||||
{
|
||||
// Model One
|
||||
String modelNameOne = "testModelOne" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairOne = getTestNamespaceUriPrefixPair();
|
||||
// Create the modelOne as a Model Administrator
|
||||
createCustomModel(modelNameOne, namespacePairOne, ModelStatus.DRAFT);
|
||||
|
||||
// Add typeA_M1 into modelOne
|
||||
String typeA_M1 = "testTypeA_M1" + System.currentTimeMillis();
|
||||
final String typeA_M1_WithPrefix = namespacePairOne.getSecond() + QName.NAMESPACE_PREFIX + typeA_M1;
|
||||
createTypeAspect(CustomType.class, modelNameOne, typeA_M1, "test typeA_M1 title", null, "cm:content");
|
||||
|
||||
// Activate modelOne
|
||||
CustomModel modelOneStatusPayload = new CustomModel();
|
||||
modelOneStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Add another type into modelOne with 'typeA_M1' as its parent
|
||||
String typeB_M1 = "testTypeB_M1" + System.currentTimeMillis();
|
||||
final String typeB_M1_WithPrefix = namespacePairOne.getSecond() + QName.NAMESPACE_PREFIX + typeB_M1;
|
||||
createTypeAspect(CustomType.class, modelNameOne, typeB_M1, "test typeB_M1 title", "test typeB_M1 Desc", typeA_M1_WithPrefix);
|
||||
|
||||
// Model Two
|
||||
String modelNameTwo = "testModelTwo" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairTwo = getTestNamespaceUriPrefixPair();
|
||||
// Create the modelTwo as a Model Administrator
|
||||
createCustomModel(modelNameTwo, namespacePairTwo, ModelStatus.DRAFT);
|
||||
|
||||
// Add type1_M2 into modelTwo with 'typeB_M1' (from modelOne) as its parent
|
||||
String type1_M2 = "testType1_M2" + System.currentTimeMillis();
|
||||
final String type1_M2_WithPrefix = namespacePairTwo.getSecond() + QName.NAMESPACE_PREFIX + type1_M2;
|
||||
createTypeAspect(CustomType.class, modelNameTwo, type1_M2, "test type1_M2 title", null, typeB_M1_WithPrefix );
|
||||
|
||||
// Activate modelTwo
|
||||
CustomModel modelTwoStatusPayload = new CustomModel();
|
||||
modelTwoStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameTwo, RestApiUtil.toJsonAsString(modelTwoStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Test that the API can handle "circular dependency" - (modelOne depends on modelTwo)
|
||||
{
|
||||
// Add another type into modelOne with 'type1_M2' (from modelTwo) as its parent
|
||||
String typeC_M1 = "testTypeC_M1" + System.currentTimeMillis();
|
||||
CustomType typeC_M1_Payload = new CustomType();
|
||||
typeC_M1_Payload.setName(typeC_M1);
|
||||
typeC_M1_Payload.setTitle("test typeC_M1 title");
|
||||
typeC_M1_Payload.setParentName(type1_M2_WithPrefix); // => 'type1_M2' (from modelTwo)
|
||||
|
||||
// Try to create typeC_M1 which has 'circular dependency'
|
||||
post("cmm/" + modelNameOne + "/types", customModelAdmin, RestApiUtil.toJsonAsString(typeC_M1_Payload), 409); //Constraint violation
|
||||
}
|
||||
|
||||
// Model Three
|
||||
String modelNameThree = "testModelThree" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairThree = getTestNamespaceUriPrefixPair();
|
||||
// Create the modelThree as a Model Administrator
|
||||
createCustomModel(modelNameThree, namespacePairThree, ModelStatus.DRAFT);
|
||||
|
||||
// Add type1_M3 into modelThree with 'type1_M2' (from modelTwo) as its parent
|
||||
String type1_M3 = "testType1_M3" + System.currentTimeMillis();
|
||||
final String type1_M3_WithPrefix = namespacePairThree.getSecond() + QName.NAMESPACE_PREFIX + type1_M3;
|
||||
createTypeAspect(CustomType.class, modelNameThree, type1_M3, "test type1_M3 title", null, type1_M2_WithPrefix );
|
||||
|
||||
// Activate modelThree
|
||||
CustomModel modelThreeStatusPayload = new CustomModel();
|
||||
modelThreeStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameThree, RestApiUtil.toJsonAsString(modelThreeStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Test that the API can handle "circular dependency" - (modelOne depends on modelThree)
|
||||
{
|
||||
// Add another type into modelOne with 'type1_M3' (from modelThree) as its parent
|
||||
String typeC_M1 = "testTypeC_M1" + System.currentTimeMillis();
|
||||
CustomType typeC_M1_Payload = new CustomType();
|
||||
typeC_M1_Payload.setName(typeC_M1);
|
||||
typeC_M1_Payload.setTitle("test typeC_M1 title");
|
||||
typeC_M1_Payload.setParentName(type1_M3_WithPrefix); // => 'type1_M3' (from modelThree)
|
||||
|
||||
// Try to create typeC_M1 which has 'circular dependency'
|
||||
post("cmm/" + modelNameOne + "/types", customModelAdmin, RestApiUtil.toJsonAsString(typeC_M1_Payload), 409); //Constraint violation
|
||||
}
|
||||
|
||||
// Model Three
|
||||
String modelNameFour = "testModelFour" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePairFour = getTestNamespaceUriPrefixPair();
|
||||
// Create the modelFour as a Model Administrator
|
||||
createCustomModel(modelNameFour, namespacePairFour, ModelStatus.DRAFT);
|
||||
|
||||
// Add type1_M4 into modelFour with 'type1_M3' (from modelThree) as its parent
|
||||
String type1_M4 = "testType1_M4" + System.currentTimeMillis();
|
||||
final String type1_M4_WithPrefix = namespacePairFour.getSecond() + QName.NAMESPACE_PREFIX + type1_M4;
|
||||
createTypeAspect(CustomType.class, modelNameFour, type1_M4, "test type1_M4 title", null, type1_M3_WithPrefix );
|
||||
|
||||
// Activate modelFour
|
||||
CustomModel modelFourStatusPayload = new CustomModel();
|
||||
modelFourStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameFour, RestApiUtil.toJsonAsString(modelFourStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Test that the API can handle "circular dependency" - (modelOne depends on modelFour)
|
||||
{
|
||||
// Add another type into modelOne with 'type1_M4' (from modelFour) as its parent
|
||||
String typeC_M1 = "testTypeC_M1" + System.currentTimeMillis();
|
||||
CustomType typeC_M1_Payload = new CustomType();
|
||||
typeC_M1_Payload.setName(typeC_M1);
|
||||
typeC_M1_Payload.setTitle("test typeC_M1 title");
|
||||
typeC_M1_Payload.setParentName(type1_M4_WithPrefix); // => 'type1_M4' (from modelFour)
|
||||
|
||||
// Try to create typeC_M1 which has 'circular dependency'
|
||||
post("cmm/" + modelNameOne + "/types", customModelAdmin, RestApiUtil.toJsonAsString(typeC_M1_Payload), 409); //Constraint violation
|
||||
}
|
||||
|
||||
// Test that the API can handle "circular dependency" - (modelTwo depends on modelFour)
|
||||
{
|
||||
// Add another type into modelTwo with 'type1_M4' (from modelFour) as its parent
|
||||
String type2_M2 = "testType2_M2" + System.currentTimeMillis();
|
||||
CustomType type2_M2_Payload = new CustomType();
|
||||
type2_M2_Payload.setName(type2_M2);
|
||||
type2_M2_Payload.setTitle("test type2_M2 title");
|
||||
type2_M2_Payload.setParentName(type1_M4_WithPrefix); // => 'type1_M4' (from modelFour)
|
||||
|
||||
// Try to create type2_M2 which has 'circular dependency'
|
||||
post("cmm/" + modelNameTwo + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type2_M2_Payload), 409); //Constraint violation
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
package org.alfresco.rest.api.tests;
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.dictionary.CMMDownloadTestUtil;
|
||||
import org.alfresco.rest.api.model.CustomModelDownload;
|
||||
import org.alfresco.rest.api.model.CustomType;
|
||||
import org.alfresco.rest.api.model.CustomModel.ModelStatus;
|
||||
import org.alfresco.rest.api.tests.client.HttpResponse;
|
||||
import org.alfresco.rest.api.tests.util.RestApiUtil;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelService;
|
||||
import org.alfresco.service.cmr.download.DownloadStatus;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests REST API download of the {@link CustomModelService}.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class TestCustomModelExport extends BaseCustomModelApiTest
|
||||
{
|
||||
|
||||
private static final long PAUSE_TIME = 1000;
|
||||
|
||||
private CMMDownloadTestUtil downloadTestUtil;
|
||||
|
||||
@Override
|
||||
public void setup() throws Exception
|
||||
{
|
||||
super.setup();
|
||||
this.downloadTestUtil = new CMMDownloadTestUtil(applicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
this.downloadTestUtil.cleanup();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateDownload() throws Exception
|
||||
{
|
||||
final String modelName = "testModel" + System.currentTimeMillis();
|
||||
final String modelExportFileName = modelName + ".xml";
|
||||
final String shareExtExportFileName = "CMM_" + modelName + "_module.xml";
|
||||
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT, null, "Mark Moe");
|
||||
|
||||
// Add type
|
||||
String typeBaseName = "testTypeBase" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelName, typeBaseName, "test typeBase title", "test typeBase Desc", "cm:content");
|
||||
|
||||
// Create Share extension module
|
||||
downloadTestUtil.createShareExtModule(modelName);
|
||||
|
||||
// Try to create download the model as a non Admin user
|
||||
post("cmm/" + modelName + "/download", nonAdminUserName, RestApiUtil.toJsonAsString(new CustomModelDownload()), getExtModuleQS(false), 403);
|
||||
|
||||
// Create download for custom model only
|
||||
HttpResponse response = post("cmm/" + modelName + "/download", customModelAdmin, RestApiUtil.toJsonAsString(new CustomModelDownload()), getExtModuleQS(false), 201);
|
||||
CustomModelDownload returnedDownload = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModelDownload.class);
|
||||
assertNotNull(returnedDownload);
|
||||
assertNotNull(returnedDownload.getNodeRef());
|
||||
|
||||
NodeRef downloadNode = new NodeRef(returnedDownload.getNodeRef());
|
||||
|
||||
DownloadStatus status = downloadTestUtil.getDownloadStatus(downloadNode);
|
||||
while (status.getStatus() == DownloadStatus.Status.PENDING)
|
||||
{
|
||||
Thread.sleep(PAUSE_TIME);
|
||||
status = downloadTestUtil.getDownloadStatus(downloadNode);
|
||||
}
|
||||
|
||||
Set<String> entries = downloadTestUtil.getDownloadEntries(downloadNode);
|
||||
assertEquals(1, entries.size());
|
||||
String modelEntry = downloadTestUtil.getDownloadEntry(entries, modelExportFileName);
|
||||
assertNotNull(modelEntry);
|
||||
assertEquals(modelEntry, modelExportFileName);
|
||||
|
||||
// Create download for custom model and its share extension module
|
||||
response = post("cmm/" + modelName + "/download", customModelAdmin, RestApiUtil.toJsonAsString(new CustomModelDownload()), getExtModuleQS(true), 201);
|
||||
returnedDownload = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModelDownload.class);
|
||||
assertNotNull(returnedDownload);
|
||||
assertNotNull(returnedDownload.getNodeRef());
|
||||
|
||||
downloadNode = new NodeRef(returnedDownload.getNodeRef());
|
||||
|
||||
status = downloadTestUtil.getDownloadStatus(downloadNode);
|
||||
while (status.getStatus() == DownloadStatus.Status.PENDING)
|
||||
{
|
||||
Thread.sleep(PAUSE_TIME);
|
||||
status = downloadTestUtil.getDownloadStatus(downloadNode);
|
||||
}
|
||||
|
||||
entries = downloadTestUtil.getDownloadEntries(downloadNode);
|
||||
assertEquals(2, entries.size());
|
||||
|
||||
modelEntry = downloadTestUtil.getDownloadEntry(entries, modelExportFileName);
|
||||
assertNotNull(modelEntry);
|
||||
assertEquals(modelEntry, modelExportFileName);
|
||||
|
||||
String shareExtEntry = downloadTestUtil.getDownloadEntry(entries, shareExtExportFileName);
|
||||
assertNotNull(shareExtEntry);
|
||||
assertEquals(shareExtEntry, shareExtExportFileName);
|
||||
}
|
||||
|
||||
private String getExtModuleQS(boolean withShareExtModule)
|
||||
{
|
||||
return "?extModule=" + withShareExtModule;
|
||||
}
|
||||
}
|
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.api.tests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.dictionary.Facetable;
|
||||
import org.alfresco.repo.dictionary.IndexTokenisationMode;
|
||||
import org.alfresco.rest.api.model.CustomAspect;
|
||||
import org.alfresco.rest.api.model.CustomModel;
|
||||
import org.alfresco.rest.api.model.CustomModelConstraint;
|
||||
import org.alfresco.rest.api.model.CustomModelNamedValue;
|
||||
import org.alfresco.rest.api.model.CustomModelProperty;
|
||||
import org.alfresco.rest.api.model.CustomType;
|
||||
import org.alfresco.rest.api.model.CustomModel.ModelStatus;
|
||||
import org.alfresco.rest.api.tests.client.HttpResponse;
|
||||
import org.alfresco.rest.api.tests.util.RestApiUtil;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests the REST API of the properties of the {@link CustomModelService}.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class TestCustomProperty extends BaseCustomModelApiTest
|
||||
{
|
||||
@Test
|
||||
public void testCreateProperties() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
{
|
||||
// Create aspect
|
||||
String aspectName = "testAspect1" + System.currentTimeMillis();
|
||||
CustomAspect aspect = createTypeAspect(CustomAspect.class, modelName, aspectName, null, null, null);
|
||||
|
||||
// Update the Aspect by adding property
|
||||
CustomAspect payload = new CustomAspect();
|
||||
String aspectPropName = "testAspect1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty aspectProp = new CustomModelProperty();
|
||||
aspectProp.setName(aspectPropName);
|
||||
aspectProp.setTitle("property title");
|
||||
aspectProp.setMultiValued(true);
|
||||
aspectProp.setIndexed(true);
|
||||
aspectProp.setFacetable(Facetable.TRUE);
|
||||
aspectProp.setIndexTokenisationMode(IndexTokenisationMode.BOTH);
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(aspectProp);
|
||||
payload.setProperties(props);
|
||||
// Try to update the aspect as a non Admin user
|
||||
put("cmm/" + modelName + "/aspects", nonAdminUserName, aspectName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 403);
|
||||
|
||||
// Try to update the aspect as a Model Administrator
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 400); // Type name is mandatory
|
||||
|
||||
// Add the mandatory aspect name to the payload
|
||||
payload.setName(aspectName);
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated aspect
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspect.getName(), 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
// Check the aspect's added property
|
||||
assertEquals(1, returnedAspect.getProperties().size());
|
||||
CustomModelProperty customModelProperty = returnedAspect.getProperties().get(0);
|
||||
assertEquals(aspectPropName, customModelProperty.getName());
|
||||
assertEquals("property title", customModelProperty.getTitle());
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectPropName, customModelProperty.getPrefixedName());
|
||||
assertEquals("Default data type is 'd:text'.", "d:text", customModelProperty.getDataType());
|
||||
assertNull(customModelProperty.getDescription());
|
||||
assertTrue(customModelProperty.isMultiValued());
|
||||
assertFalse(customModelProperty.isMandatory());
|
||||
assertFalse(customModelProperty.isMandatoryEnforced());
|
||||
assertNull(customModelProperty.getDefaultValue());
|
||||
assertTrue(customModelProperty.isIndexed());
|
||||
assertEquals(Facetable.TRUE, customModelProperty.getFacetable());
|
||||
assertEquals(IndexTokenisationMode.BOTH, customModelProperty.getIndexTokenisationMode());
|
||||
|
||||
// Test duplicate property name
|
||||
aspectProp = new CustomModelProperty();
|
||||
aspectProp.setName(aspectPropName); // Existing name
|
||||
aspectProp.setTitle("new property title");
|
||||
props = new ArrayList<>(1);
|
||||
props.add(aspectProp);
|
||||
payload.setProperties(props);
|
||||
// Try to update the aspect as a Model Administrator
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 409); // property name already exists
|
||||
}
|
||||
|
||||
{
|
||||
// Create type
|
||||
String typeName = "testType1" + System.currentTimeMillis();
|
||||
CustomType type = createTypeAspect(CustomType.class, modelName, typeName, "test type1 title", "test type1 Desc", "cm:content");
|
||||
|
||||
// Update the Type by adding property
|
||||
CustomType payload = new CustomType();
|
||||
String typePropName = "testType1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName);
|
||||
typeProp.setTitle("property title");
|
||||
typeProp.setDataType("d:int");
|
||||
typeProp.setIndexed(false);
|
||||
typeProp.setFacetable(Facetable.FALSE);
|
||||
typeProp.setIndexTokenisationMode(IndexTokenisationMode.FALSE);
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
payload.setProperties(props);
|
||||
|
||||
// Try to update the type as a non Admin user
|
||||
put("cmm/" + modelName + "/types", nonAdminUserName, typeName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 403);
|
||||
|
||||
// Try to update the type as a Model Administrator
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 400); // Type name is mandatory
|
||||
|
||||
// Add the mandatory type name to the payload
|
||||
payload.setName(typeName);
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated type
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/types", customModelAdmin, type.getName(), 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
// Check the type's added property
|
||||
assertEquals(1, returnedType.getProperties().size());
|
||||
CustomModelProperty customModelProperty = returnedType.getProperties().get(0);
|
||||
assertEquals(typePropName, customModelProperty.getName());
|
||||
assertEquals("property title", customModelProperty.getTitle());
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typePropName, customModelProperty.getPrefixedName());
|
||||
assertEquals("d:int", customModelProperty.getDataType());
|
||||
assertNull(customModelProperty.getDescription());
|
||||
assertFalse(customModelProperty.isMultiValued());
|
||||
assertFalse(customModelProperty.isMandatory());
|
||||
assertFalse(customModelProperty.isMandatoryEnforced());
|
||||
assertNull(customModelProperty.getDefaultValue());
|
||||
assertFalse(customModelProperty.isIndexed());
|
||||
assertEquals(Facetable.FALSE, customModelProperty.getFacetable());
|
||||
assertEquals(IndexTokenisationMode.FALSE, customModelProperty.getIndexTokenisationMode());
|
||||
|
||||
// Retrieve the updated type with all the properties (include inherited)
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, type.getName()+SELECT_ALL_PROPS, 200);
|
||||
returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(3, returnedType.getProperties().size());
|
||||
// Check for the inherited properties
|
||||
assertNotNull(getProperty(returnedType.getProperties(), "content")); // cm:content
|
||||
assertNotNull(getProperty(returnedType.getProperties(), "name")); // cm:name
|
||||
|
||||
// Create another property and set all of its attributes
|
||||
payload = new CustomType();
|
||||
payload.setName(typeName);
|
||||
String typePropName2 = "testType1Prop2" + System.currentTimeMillis();
|
||||
typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName2);
|
||||
typeProp.setTitle("property2 title");
|
||||
typeProp.setDescription("property2 desciption");
|
||||
typeProp.setDataType("d:int");
|
||||
typeProp.setDefaultValue("0");
|
||||
typeProp.setMultiValued(false);
|
||||
typeProp.setMandatory(true);
|
||||
typeProp.setMandatoryEnforced(true);
|
||||
props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
payload.setProperties(props);
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated type
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, type.getName(), 200);
|
||||
returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
// Check the type's added property
|
||||
assertEquals(2, returnedType.getProperties().size());
|
||||
customModelProperty = getProperty(returnedType.getProperties(), typePropName2);
|
||||
assertNotNull(customModelProperty);
|
||||
assertEquals(typePropName2, customModelProperty.getName());
|
||||
assertEquals("property2 title", customModelProperty.getTitle());
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typePropName2, customModelProperty.getPrefixedName());
|
||||
assertEquals("d:int", customModelProperty.getDataType());
|
||||
assertEquals("property2 desciption", customModelProperty.getDescription());
|
||||
assertFalse(customModelProperty.isMultiValued());
|
||||
assertTrue(customModelProperty.isMandatory());
|
||||
assertTrue(customModelProperty.isMandatoryEnforced());
|
||||
assertEquals("0", customModelProperty.getDefaultValue());
|
||||
|
||||
// Test duplicate property name
|
||||
typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName2); // Existing name
|
||||
typeProp.setTitle("new property title");
|
||||
typeProp.setDataType("d:text");
|
||||
props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
payload.setProperties(props);
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 409); // property name already exists
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteProperty() throws Exception
|
||||
{
|
||||
String modelName = "testModelDeleteProp" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
/*
|
||||
* Create aspect and update it by adding two properties
|
||||
*/
|
||||
String aspectName = "testAspect1" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomAspect.class, modelName, aspectName, null, null, null);
|
||||
// Update the Aspect by adding property - property one
|
||||
CustomAspect aspectPayload = new CustomAspect();
|
||||
aspectPayload.setName(aspectName);
|
||||
|
||||
String aspectPropNameOne = "testAspect1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty aspectPropOne = new CustomModelProperty();
|
||||
aspectPropOne.setName(aspectPropNameOne);
|
||||
aspectPropOne.setTitle("aspect property one title");
|
||||
aspectPropOne.setMultiValued(true);
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(aspectPropOne);
|
||||
aspectPayload.setProperties(props);
|
||||
// create property one
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Update the Aspect by adding another property - property two
|
||||
aspectPayload = new CustomAspect();
|
||||
aspectPayload.setName(aspectName);
|
||||
|
||||
String aspectPropNameTwo = "testAspect1Prop2" + System.currentTimeMillis();
|
||||
CustomModelProperty aspectPropTwo = new CustomModelProperty();
|
||||
aspectPropTwo.setName(aspectPropNameTwo);
|
||||
aspectPropTwo.setTitle("aspect property two title");
|
||||
aspectPropTwo.setMandatory(true);
|
||||
aspectPropTwo.setDataType("d:int");
|
||||
aspectPropTwo.setDefaultValue("1");
|
||||
props = new ArrayList<>(1);
|
||||
props.add(aspectPropTwo);
|
||||
aspectPayload.setProperties(props);
|
||||
// create property two
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated aspect
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
// Check the aspect's added properties
|
||||
assertEquals(2, returnedAspect.getProperties().size());
|
||||
|
||||
/*
|
||||
* Create type and update it by adding two properties
|
||||
*/
|
||||
String typeName = "testType1" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelName, typeName, "test type1 title", null, "cm:content");
|
||||
|
||||
// Update the Type by adding property - property one
|
||||
CustomType typePayload = new CustomType();
|
||||
typePayload.setName(typeName);
|
||||
|
||||
String typePropNameOne = "testType1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty typePropOne = new CustomModelProperty();
|
||||
typePropOne.setName(typePropNameOne);
|
||||
typePropOne.setTitle("type property one title");
|
||||
props = new ArrayList<>(1);
|
||||
props.add(typePropOne);
|
||||
typePayload.setProperties(props);
|
||||
// create property one
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Update the Type by adding another property - property two
|
||||
typePayload = new CustomType();
|
||||
typePayload.setName(typeName);
|
||||
|
||||
// Create inline MINMAX constraint
|
||||
CustomModelConstraint inlineMinMaxConstraint = new CustomModelConstraint();
|
||||
inlineMinMaxConstraint.setType("MINMAX");
|
||||
inlineMinMaxConstraint.setTitle("test MINMAX title");
|
||||
// Create the MinMax constraint's parameters
|
||||
List<CustomModelNamedValue> parameters = new ArrayList<>(2);
|
||||
parameters.add(buildNamedValue("maxValue", "100.0"));
|
||||
parameters.add(buildNamedValue("minValue", "0.0"));
|
||||
// Add the parameters into the constraint
|
||||
inlineMinMaxConstraint.setParameters(parameters);
|
||||
|
||||
String typePropNameTwo = "testType1Prop2" + System.currentTimeMillis();
|
||||
CustomModelProperty typePropTwo = new CustomModelProperty();
|
||||
typePropTwo.setName(typePropNameTwo);
|
||||
typePropTwo.setTitle("type property two title");
|
||||
typePropTwo.setDataType("d:int");
|
||||
typePropTwo.setConstraints(Arrays.asList(inlineMinMaxConstraint)); // add the inline constraint
|
||||
props = new ArrayList<>(1);
|
||||
props.add(typePropTwo);
|
||||
typePayload.setProperties(props);
|
||||
// create property one
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated type
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
// Check the type's added properties
|
||||
assertEquals(2, returnedType.getProperties().size());
|
||||
|
||||
// Delete aspect's property one - model is inactive
|
||||
{
|
||||
final String deletePropOneAspectQS = getPropDeleteUpdateQS(aspectPropNameOne, true);
|
||||
// Try to delete propertyOne from aspect
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, null, deletePropOneAspectQS, 400); // missing payload
|
||||
|
||||
CustomAspect deletePropAspectPayload = new CustomAspect();
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(deletePropAspectPayload), deletePropOneAspectQS, 400); // missing aspect name
|
||||
|
||||
deletePropAspectPayload.setName(aspectName);
|
||||
put("cmm/" + modelName + "/aspects", nonAdminUserName, aspectName, RestApiUtil.toJsonAsString(deletePropAspectPayload), deletePropOneAspectQS, 403); // unauthorised
|
||||
// Delete as a Model Administrator
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(deletePropAspectPayload), deletePropOneAspectQS, 200);
|
||||
|
||||
// Check the property has been deleted
|
||||
response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 200);
|
||||
returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
assertEquals(1, returnedAspect.getProperties().size());
|
||||
assertFalse("Property one should have been deleted.", aspectPropNameOne.equals(returnedAspect.getProperties().get(0).getName()));
|
||||
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(deletePropAspectPayload), deletePropOneAspectQS, 404); //Not found
|
||||
}
|
||||
|
||||
// Delete type's property two - model is inactive
|
||||
{
|
||||
final String deletePropTwoTypeQS = getPropDeleteUpdateQS(typePropNameTwo, true);
|
||||
// Try to delete propertyOne from type
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, null, deletePropTwoTypeQS, 400); // missing payload
|
||||
|
||||
CustomType deletePropTypePayload = new CustomType();
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(deletePropTypePayload), deletePropTwoTypeQS,
|
||||
400); // missing type name
|
||||
|
||||
deletePropTypePayload.setName(typeName);
|
||||
put("cmm/" + modelName + "/types", nonAdminUserName, typeName, RestApiUtil.toJsonAsString(deletePropTypePayload), deletePropTwoTypeQS, 403); // unauthorised
|
||||
// Delete as a Model Administrator
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(deletePropTypePayload), deletePropTwoTypeQS, 200);
|
||||
|
||||
// Check the property has been deleted
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 200);
|
||||
returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(1, returnedType.getProperties().size());
|
||||
assertFalse("Property two should have been deleted.", typePropNameTwo.equals(returnedType.getProperties().get(0).getName()));
|
||||
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(deletePropTypePayload), deletePropTwoTypeQS, 404); //Not found
|
||||
}
|
||||
|
||||
// Note: at the time of writing, we can't delete a property of an active model, as ModelValidatorImpl.validateIndexedProperty depends on Solr
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProperty() throws Exception
|
||||
{
|
||||
String modelName = "testModelUpdateProp" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
/*
|
||||
* Create aspect and update it by adding a property
|
||||
*/
|
||||
String aspectName = "testAspect1" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomAspect.class, modelName, aspectName, null, null, null);
|
||||
// Update the Aspect by adding property
|
||||
CustomAspect aspectPayload = new CustomAspect();
|
||||
aspectPayload.setName(aspectName);
|
||||
|
||||
String aspectPropName = "testAspect1Prop" + System.currentTimeMillis();
|
||||
CustomModelProperty aspectProp = new CustomModelProperty();
|
||||
aspectProp.setName(aspectPropName);
|
||||
aspectProp.setTitle("aspect property title");
|
||||
aspectProp.setMultiValued(true);
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(aspectProp);
|
||||
aspectPayload.setProperties(props);
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated aspect
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
// Check the aspect's added property
|
||||
assertEquals(1, returnedAspect.getProperties().size());
|
||||
|
||||
/*
|
||||
* Create type and update it by adding a property
|
||||
*/
|
||||
String typeName = "testType1" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelName, typeName, "test type1 title", null, "cm:content");
|
||||
|
||||
// Update the Type by adding property - property one
|
||||
CustomType typePayload = new CustomType();
|
||||
typePayload.setName(typeName);
|
||||
|
||||
// Create inline MINMAX constraint
|
||||
CustomModelConstraint inlineMinMaxConstraint = new CustomModelConstraint();
|
||||
inlineMinMaxConstraint.setType("MINMAX");
|
||||
inlineMinMaxConstraint.setTitle("test MINMAX title");
|
||||
// Create the MinMax constraint's parameters
|
||||
List<CustomModelNamedValue> parameters = new ArrayList<>(2);
|
||||
parameters.add(buildNamedValue("maxValue", "100.0"));
|
||||
parameters.add(buildNamedValue("minValue", "0.0"));
|
||||
// Add the parameters into the constraint
|
||||
inlineMinMaxConstraint.setParameters(parameters);
|
||||
|
||||
String typePropName = "testType1Prop" + System.currentTimeMillis();
|
||||
CustomModelProperty typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName);
|
||||
typeProp.setDataType("d:int");
|
||||
typeProp.setTitle("type property title");
|
||||
typeProp.setDefaultValue("0");
|
||||
typeProp.setConstraints(Arrays.asList(inlineMinMaxConstraint)); // add the inline constraint
|
||||
props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
typePayload.setProperties(props);
|
||||
// create property
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Retrieve the updated type
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
// Check the type's added property
|
||||
assertEquals(1, returnedType.getProperties().size());
|
||||
|
||||
// Update aspect's property - model is inactive
|
||||
{
|
||||
final String updatePropOneAspectQS = getPropDeleteUpdateQS(aspectPropName, false);
|
||||
// Try to update property from aspect
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, null, updatePropOneAspectQS, 400); // missing payload
|
||||
|
||||
CustomAspect updatePropAspectPayload = new CustomAspect();
|
||||
CustomModelProperty propertyAspect = new CustomModelProperty();
|
||||
propertyAspect.setTitle("new Title");
|
||||
propertyAspect.setDescription("new Desc");
|
||||
propertyAspect.setDataType("d:int"); // the original value was d:text
|
||||
propertyAspect.setMultiValued(false); // the original value was true
|
||||
propertyAspect.setMandatory(true); // the original value was false
|
||||
propertyAspect.setDefaultValue("10");
|
||||
List<CustomModelProperty> modifiedProp = new ArrayList<>(1);
|
||||
modifiedProp.add(propertyAspect);
|
||||
updatePropAspectPayload.setProperties(modifiedProp);
|
||||
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(updatePropAspectPayload), updatePropOneAspectQS, 400); // missing aspect name
|
||||
|
||||
// set a random name
|
||||
updatePropAspectPayload.setName(aspectName + System.currentTimeMillis());
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(updatePropAspectPayload), updatePropOneAspectQS, 404); // Aspect not found
|
||||
|
||||
// set the correct name
|
||||
updatePropAspectPayload.setName(aspectName);
|
||||
// the requested property name dose not match the payload
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(updatePropAspectPayload), updatePropOneAspectQS, 400);
|
||||
|
||||
// set the property name that matches the requested property
|
||||
propertyAspect.setName(aspectPropName);
|
||||
put("cmm/" + modelName + "/aspects", nonAdminUserName, aspectName, RestApiUtil.toJsonAsString(updatePropAspectPayload), updatePropOneAspectQS, 403); // unauthorised
|
||||
// Update as a Model Administrator
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(updatePropAspectPayload), updatePropOneAspectQS, 200);
|
||||
|
||||
// Check the property has been updated
|
||||
response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 200);
|
||||
returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
assertEquals(1, returnedAspect.getProperties().size());
|
||||
CustomModelProperty modifiedAspectProperty = returnedAspect.getProperties().get(0);
|
||||
compareCustomModelProperties(propertyAspect, modifiedAspectProperty, "prefixedName", "indexTokenisationMode");
|
||||
}
|
||||
|
||||
// Activate the model
|
||||
CustomModel statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Update type's property - model is active
|
||||
{
|
||||
final String updatePropTwoTypeQS = getPropDeleteUpdateQS(typePropName, false);
|
||||
CustomType updatePropTypePayload = new CustomType();
|
||||
updatePropTypePayload.setName(typeName);
|
||||
CustomModelProperty propertyType = new CustomModelProperty();
|
||||
propertyType.setName(typePropName);
|
||||
propertyType.setTitle("new Title");
|
||||
propertyType.setDescription("new Desc");
|
||||
propertyType.setDataType("d:long"); // the original value was d:int
|
||||
propertyType.setDefaultValue("5");
|
||||
List<CustomModelProperty> modifiedProp = new ArrayList<>(1);
|
||||
modifiedProp.add(propertyType);
|
||||
updatePropTypePayload.setProperties(modifiedProp);
|
||||
|
||||
// Unauthorised
|
||||
put("cmm/" + modelName + "/types", nonAdminUserName, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 403);
|
||||
// Try to update an active model as a Model Administrator - Cannot change the data type of the property of an active model
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 409);
|
||||
|
||||
// Set the data type with its original value
|
||||
propertyType.setDataType("d:int");
|
||||
propertyType.setMultiValued(true);// the original value was false
|
||||
// Cannot change the multi-valued option of the property of an active model
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 409);
|
||||
|
||||
propertyType.setMultiValued(false);
|
||||
propertyType.setMandatory(true);// the original value was false
|
||||
// Cannot change the mandatory option of the property of an active model
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 409);
|
||||
|
||||
propertyType.setMandatory(false);
|
||||
propertyType.setMandatoryEnforced(true);// the original value was false
|
||||
// Cannot change the mandatory-enforced option of the property of an active model
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 409);
|
||||
|
||||
// Set the mandatory-enforced with its original value
|
||||
propertyType.setMandatoryEnforced(false);
|
||||
// Update the MinMax constraint's parameters
|
||||
parameters = new ArrayList<>(2);
|
||||
parameters.add(buildNamedValue("maxValue", "120.0")); // the original value was 100.0
|
||||
parameters.add(buildNamedValue("minValue", "20.0")); // the original value was 0.0
|
||||
// Add the parameters into the constraint
|
||||
inlineMinMaxConstraint.setParameters(parameters);
|
||||
propertyType.setConstraints(Arrays.asList(inlineMinMaxConstraint)); // add the updated inline constraint
|
||||
|
||||
// Try to Update - constraint violation. The default value is 5 which is not in the MinMax range [20, 120]
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 409);
|
||||
|
||||
propertyType.setDefaultValue("25"); // we changed the MinMax constraint to be [20, 120]
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 200);
|
||||
|
||||
// Check the property has been updated
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 200);
|
||||
returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(1, returnedType.getProperties().size());
|
||||
CustomModelProperty modifiedTypeProperty = returnedType.getProperties().get(0);
|
||||
assertEquals("new Title", modifiedTypeProperty.getTitle());
|
||||
assertEquals("new Desc", modifiedTypeProperty.getDescription());
|
||||
assertEquals("25", modifiedTypeProperty.getDefaultValue());
|
||||
assertEquals("Shouldn't be able to change the data type of the property of an active model." ,"d:int", modifiedTypeProperty.getDataType());
|
||||
assertFalse(modifiedTypeProperty.isMandatory());
|
||||
assertFalse(modifiedTypeProperty.isMultiValued());
|
||||
assertFalse(modifiedTypeProperty.isMandatoryEnforced());
|
||||
assertEquals(1, modifiedTypeProperty.getConstraints().size());
|
||||
CustomModelConstraint modifiedConstraint = modifiedTypeProperty.getConstraints().get(0);
|
||||
assertEquals("MINMAX", modifiedConstraint.getType());
|
||||
assertEquals("120.0", getParameterSimpleValue(modifiedConstraint.getParameters(), "maxValue"));
|
||||
assertEquals("20.0", getParameterSimpleValue(modifiedConstraint.getParameters(), "minValue"));
|
||||
|
||||
// Change the constraint type and parameter
|
||||
inlineMinMaxConstraint.setType("LENGTH");
|
||||
inlineMinMaxConstraint.setTitle("test LENGTH title");
|
||||
parameters = new ArrayList<>(2);
|
||||
parameters.add(buildNamedValue("maxLength", "256"));
|
||||
parameters.add(buildNamedValue("minLength", "0"));
|
||||
// Add the parameters into the constraint
|
||||
inlineMinMaxConstraint.setParameters(parameters);
|
||||
propertyType.setConstraints(Arrays.asList(inlineMinMaxConstraint));
|
||||
// LENGTH can only be used with textual data type
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 400);
|
||||
|
||||
//update the property by removing the constraint
|
||||
propertyType.setConstraints(Collections.<CustomModelConstraint>emptyList());
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(updatePropTypePayload), updatePropTwoTypeQS, 200);
|
||||
|
||||
response = getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 200);
|
||||
returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(1, returnedType.getProperties().size());
|
||||
modifiedTypeProperty = returnedType.getProperties().get(0);
|
||||
assertEquals(0, modifiedTypeProperty.getConstraints().size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidatePropertyDefaultValue() throws Exception
|
||||
{
|
||||
String modelName = "testModelPropDefaultValue" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
/*
|
||||
* Create aspect and update it by adding a property
|
||||
*/
|
||||
String aspectName = "testAspect1" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomAspect.class, modelName, aspectName, null, null, null);
|
||||
// Update the Aspect by adding property
|
||||
CustomAspect aspectPayload = new CustomAspect();
|
||||
aspectPayload.setName(aspectName);
|
||||
|
||||
String aspectPropName = "testAspectProp" + System.currentTimeMillis();
|
||||
final String updatePropAspectQS = getPropDeleteUpdateQS(aspectPropName, false);
|
||||
|
||||
CustomModelProperty aspectProp = new CustomModelProperty();
|
||||
aspectProp.setName(aspectPropName);
|
||||
aspectProp.setTitle("aspect property title");
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(aspectProp);
|
||||
aspectPayload.setProperties(props);
|
||||
|
||||
// d:int tests
|
||||
{
|
||||
aspectProp.setDataType("d:int");
|
||||
aspectProp.setDefaultValue(" ");// space
|
||||
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("abc"); // text
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("1.0"); // double
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("1,2,3"); // text
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
}
|
||||
|
||||
// d:float tests
|
||||
{
|
||||
aspectProp.setDataType("d:float");
|
||||
aspectProp.setDefaultValue(" ");// space
|
||||
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("abc"); // text
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("1,2,3"); // text
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("1.0"); // float
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
aspectProp.setDefaultValue("1.0f"); // float - update
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 200);
|
||||
|
||||
aspectProp.setDefaultValue("1.0d"); // double - update
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 200);
|
||||
}
|
||||
|
||||
// d:boolean tests
|
||||
{
|
||||
aspectProp.setDataType("d:boolean");
|
||||
aspectProp.setDefaultValue(" ");// space
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("abc"); // text
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("1"); // number
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 400);
|
||||
|
||||
aspectProp.setDefaultValue("true"); // valid value
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 200);
|
||||
|
||||
aspectProp.setDefaultValue("false"); // valid value
|
||||
// create property
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), updatePropAspectQS, 200);
|
||||
}
|
||||
}
|
||||
|
||||
private String getPropDeleteUpdateQS(String propName, boolean isDelete)
|
||||
{
|
||||
String req = (isDelete ? "&delete=" : "&update=");
|
||||
return SELECT_PROPS_QS + req + propName;
|
||||
}
|
||||
}
|
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.api.tests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.dictionary.Facetable;
|
||||
import org.alfresco.repo.dictionary.IndexTokenisationMode;
|
||||
import org.alfresco.rest.api.model.CustomAspect;
|
||||
import org.alfresco.rest.api.model.CustomModel;
|
||||
import org.alfresco.rest.api.model.CustomModelProperty;
|
||||
import org.alfresco.rest.api.model.CustomType;
|
||||
import org.alfresco.rest.api.model.CustomModel.ModelStatus;
|
||||
import org.alfresco.rest.api.tests.client.HttpResponse;
|
||||
import org.alfresco.rest.api.tests.client.PublicApiClient.Paging;
|
||||
import org.alfresco.rest.api.tests.util.RestApiUtil;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.CustomModelService;
|
||||
import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests the REST API of the types and aspects of the {@link CustomModelService}.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class TestCustomTypeAspect extends BaseCustomModelApiTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testCreateAspectsAndTypes_ExistingModel() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
final String aspectName = "testAspect1" + System.currentTimeMillis();
|
||||
{
|
||||
// Add aspect
|
||||
CustomAspect aspect = new CustomAspect();
|
||||
aspect.setName(aspectName);
|
||||
|
||||
// Try to create aspect as a non Admin user
|
||||
post("cmm/" + modelName + "/aspects", nonAdminUserName, RestApiUtil.toJsonAsString(aspect), 403);
|
||||
|
||||
// Set the aspect's parent with a type name!
|
||||
aspect.setParentName("cm:content");
|
||||
// Try to create an invalid aspect as a Model Administrator
|
||||
post("cmm/" + modelName + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 409);
|
||||
|
||||
// Create aspect as a Model Administrator
|
||||
aspect.setParentName(null);
|
||||
post("cmm/" + modelName + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 201);
|
||||
|
||||
// Create the aspect again - duplicate name
|
||||
post("cmm/" + modelName + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 409);
|
||||
|
||||
// Retrieve the created aspect
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspect.getName(), 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
compareCustomTypesAspects(aspect, returnedAspect, "prefixedName");
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName, returnedAspect.getPrefixedName());
|
||||
}
|
||||
|
||||
String typeName = "testType" + System.currentTimeMillis();
|
||||
{
|
||||
// Add type
|
||||
CustomType type = new CustomType();
|
||||
type.setName(typeName);
|
||||
type.setDescription("test type Desc");
|
||||
type.setTitle("test type title");
|
||||
type.setParentName("cm:content");
|
||||
|
||||
// Try to create type as a non Admin user
|
||||
post("cmm/" + modelName + "/types", nonAdminUserName, RestApiUtil.toJsonAsString(type), 403);
|
||||
|
||||
// Set the type's parent with an aspect name!
|
||||
type.setParentName("cm:titled");
|
||||
// Try to create an invalid type as a Model Administrator
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 409);
|
||||
|
||||
// Create type as a Model Administrator
|
||||
type.setParentName("cm:content");
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 201);
|
||||
|
||||
// Create the type again - duplicate name
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 409);
|
||||
|
||||
// Retrieve the created type
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/types", customModelAdmin, type.getName(), 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
compareCustomTypesAspects(type, returnedType, "prefixedName");
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName, returnedType.getPrefixedName());
|
||||
|
||||
// for now this is the simplest way to check for the imported namespaces
|
||||
CustomModelDefinition modelDef = getModelDefinition(modelName);
|
||||
assertNotNull(modelDef);
|
||||
Collection<NamespaceDefinition> importedNamespaces = modelDef.getImportedNamespaces();
|
||||
|
||||
assertTrue(hasNamespaceUri(importedNamespaces, "http://www.alfresco.org/model/content/1.0"));
|
||||
assertTrue(hasNamespacePrefix(importedNamespaces, "cm"));
|
||||
}
|
||||
|
||||
// Existing name
|
||||
{
|
||||
// Add aspect
|
||||
CustomAspect aspect = new CustomAspect();
|
||||
// Set the aspect name with an existing type name. The model
|
||||
// cannot have a type and an aspect with the same name.
|
||||
aspect.setName(typeName);
|
||||
post("cmm/" + modelName + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 409);
|
||||
|
||||
CustomType type = new CustomType();
|
||||
// Set the type name with an existing aspect name
|
||||
type.setName(aspectName);
|
||||
type.setParentName("cm:content");
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 409);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateModel_WithAspectsAndTypes_Invalid() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
// Add type
|
||||
{
|
||||
final String typeURL = "cmm/" + modelName + "/types";
|
||||
CustomType type = new CustomType();
|
||||
type.setName(null);
|
||||
type.setDescription("test type Desc");
|
||||
|
||||
// Try to create a model with an invalid type name (null)
|
||||
post(typeURL, customModelAdmin, RestApiUtil.toJsonAsString(type), 400);
|
||||
|
||||
// Try to create a model with an invalid type name (name contains ':')
|
||||
type.setName("prefix:someTypename");
|
||||
post(typeURL, customModelAdmin, RestApiUtil.toJsonAsString(type), 400);
|
||||
|
||||
// Try to create a model with an invalid type name (name is empty)
|
||||
type.setName("");
|
||||
post(typeURL, customModelAdmin, RestApiUtil.toJsonAsString(type), 400);
|
||||
|
||||
// Try to create a model with an invalid type name (name contains '<')
|
||||
type.setName("testType<name");
|
||||
post(typeURL, customModelAdmin, RestApiUtil.toJsonAsString(type), 400);
|
||||
}
|
||||
|
||||
// Add aspect
|
||||
{
|
||||
final String aspectURL = "cmm/" + modelName + "/aspects";
|
||||
CustomAspect aspect = new CustomAspect();
|
||||
aspect.setName(null);
|
||||
aspect.setTitle("test aspect title");
|
||||
|
||||
// Try to create a model with an invalid aspect name (null)
|
||||
post(aspectURL, customModelAdmin, RestApiUtil.toJsonAsString(aspect), 400);
|
||||
|
||||
// Try to create a model with an invalid aspect name (name contains ':')
|
||||
aspect.setName("prefix:someAspectname");
|
||||
post(aspectURL, customModelAdmin, RestApiUtil.toJsonAsString(aspect), 400);
|
||||
|
||||
// Try to create a model with an invalid aspect name (name is empty)
|
||||
aspect.setName("");
|
||||
post(aspectURL, customModelAdmin, RestApiUtil.toJsonAsString(aspect), 400);
|
||||
|
||||
// Try to create a model with an invalid aspect name (name contains '>')
|
||||
aspect.setName("testType>name");
|
||||
post(aspectURL, customModelAdmin, RestApiUtil.toJsonAsString(aspect), 400);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAspectsAndTypesWithProperties() throws Exception
|
||||
{
|
||||
String modelName = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
{
|
||||
// Add aspect with property
|
||||
String aspectName = "testAspect1" + System.currentTimeMillis();
|
||||
CustomAspect aspect = new CustomAspect();
|
||||
aspect.setName(aspectName);
|
||||
|
||||
String aspectPropName = "testAspect1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty aspectProp = new CustomModelProperty();
|
||||
aspectProp.setName(aspectPropName);
|
||||
aspectProp.setTitle("property title");
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(aspectProp);
|
||||
aspect.setProperties(props);
|
||||
|
||||
// Create aspect as a Model Administrator
|
||||
post("cmm/" + modelName + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 201);
|
||||
// Retrieve the created aspect
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspect.getName(), 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
compareCustomTypesAspects(aspect, returnedAspect, "prefixedName", "dataType", "indexTokenisationMode");
|
||||
assertEquals(1, returnedAspect.getProperties().size());
|
||||
CustomModelProperty customModelProperty = returnedAspect.getProperties().get(0);
|
||||
assertEquals(aspectPropName, customModelProperty.getName());
|
||||
assertEquals("property title", customModelProperty.getTitle());
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectPropName, customModelProperty.getPrefixedName());
|
||||
assertEquals("Default data type is 'd:text'.", "d:text", customModelProperty.getDataType());
|
||||
// Test default indexing options
|
||||
assertTrue(customModelProperty.isIndexed());
|
||||
assertEquals(Facetable.UNSET, customModelProperty.getFacetable());
|
||||
assertEquals(IndexTokenisationMode.TRUE, customModelProperty.getIndexTokenisationMode());
|
||||
}
|
||||
|
||||
{
|
||||
// Add type with properties
|
||||
String typeName = "testType1" + System.currentTimeMillis();
|
||||
CustomType type = new CustomType();
|
||||
type.setName(typeName);
|
||||
type.setDescription("test type1 Desc");
|
||||
type.setTitle("test type1 title");
|
||||
type.setParentName("cm:content");
|
||||
|
||||
String typePropName = "testType1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName);
|
||||
typeProp.setDataType("int"); // data type without dictionary prefix
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
type.setProperties(props);
|
||||
|
||||
// Create type as a Model Administrator
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 400);
|
||||
|
||||
typeProp.setDataType("d:int");
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 201);
|
||||
|
||||
// Retrieve the created type
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/types", customModelAdmin, type.getName(), 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
compareCustomTypesAspects(type, returnedType, "prefixedName", "indexTokenisationMode");
|
||||
assertEquals("Shouldn't list the inherited properties from 'cm:content'.", 1, returnedType.getProperties().size());
|
||||
CustomModelProperty customModelProperty = returnedType.getProperties().get(0);
|
||||
assertEquals(typePropName, customModelProperty.getName());
|
||||
assertEquals("d:int", customModelProperty.getDataType());
|
||||
assertEquals(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typePropName, customModelProperty.getPrefixedName());
|
||||
// Test default indexing options
|
||||
assertTrue(customModelProperty.isIndexed());
|
||||
assertEquals(Facetable.UNSET, customModelProperty.getFacetable());
|
||||
assertEquals(IndexTokenisationMode.TRUE, customModelProperty.getIndexTokenisationMode());
|
||||
}
|
||||
|
||||
{
|
||||
// Add more types with the same parent
|
||||
// Test to make sure the inherited properties are excluded properly.
|
||||
// As without parent’s property exclusion, we won’t be able to
|
||||
// create multiple types|aspects with the same parent.
|
||||
String typeName2 = "testType2" + System.currentTimeMillis();
|
||||
CustomType type2 = new CustomType();
|
||||
type2.setName(typeName2);
|
||||
type2.setDescription("test type2 Desc");
|
||||
type2.setTitle("test type2 title");
|
||||
type2.setParentName("cm:content");
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type2), 201);
|
||||
|
||||
String typeName3 = "testType3" + System.currentTimeMillis();
|
||||
CustomType type3 = new CustomType();
|
||||
type3.setName(typeName3);
|
||||
type3.setDescription("test type3 Desc");
|
||||
type3.setTitle("test type3 title");
|
||||
type3.setParentName("cm:content");
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type3), 201);
|
||||
}
|
||||
|
||||
{
|
||||
// Retrieve the created model
|
||||
HttpResponse response = getSingle("cmm", customModelAdmin, modelName, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertNull(returnedModel.getTypes());
|
||||
assertNull(returnedModel.getAspects());
|
||||
|
||||
// Retrieve the created model with its types and aspects
|
||||
response = getSingle("cmm", customModelAdmin, modelName + SELECT_ALL, 200);
|
||||
returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertNotNull(returnedModel.getTypes());
|
||||
assertEquals(3, returnedModel.getTypes().size());
|
||||
assertNotNull(returnedModel.getAspects());
|
||||
assertEquals(1, returnedModel.getAspects().size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
//SHA-679
|
||||
public void testCustomModelTypesAspectsDependencies() throws Exception
|
||||
{
|
||||
String modelNameOne = "testModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelNameOne, namespacePair, ModelStatus.DRAFT, null, "Mark Moe");
|
||||
|
||||
// Add type
|
||||
String typeBaseName = "testTypeBase" + System.currentTimeMillis();
|
||||
final String typeBaseNameWithPrefix = namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeBaseName;
|
||||
createTypeAspect(CustomType.class, modelNameOne, typeBaseName, "test typeBase title", "test typeBase Desc", "cm:content");
|
||||
|
||||
// Activate the model
|
||||
CustomModel modelOneStatusPayload = new CustomModel();
|
||||
modelOneStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
HttpResponse response = getSingle("cmm", customModelAdmin, modelNameOne, 200);
|
||||
CustomModel returnedModel = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomModel.class);
|
||||
assertEquals(ModelStatus.ACTIVE, returnedModel.getStatus());
|
||||
|
||||
// Add another type with 'typeBaseName' as its parent
|
||||
String typeName2 = "testTypeChild" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelNameOne, typeName2, "test typeChild title", "test typeChild Desc", typeBaseNameWithPrefix);
|
||||
|
||||
Paging paging = getPaging(0, Integer.MAX_VALUE);
|
||||
response = getAll("cmm/" + modelNameOne + "/types", customModelAdmin, paging, 200);
|
||||
List<CustomType> returnedTypes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(2, returnedTypes.size());
|
||||
|
||||
// Create another model
|
||||
String modelNameTwo = "testModelTwo" + System.currentTimeMillis();
|
||||
Pair<String, String> modelTwoNamespacePair = getTestNamespaceUriPrefixPair();
|
||||
createCustomModel(modelNameTwo, modelTwoNamespacePair, ModelStatus.DRAFT, null, "Admin");
|
||||
|
||||
// Add a type with 'typeBaseName' from the modelOne as its parent
|
||||
String modelTwoTypeName = "testModelTwoChild" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelNameTwo, modelTwoTypeName, "test model two type child title", null, typeBaseNameWithPrefix);
|
||||
|
||||
// Try to deactivate modelOne
|
||||
modelOneStatusPayload = new CustomModel();
|
||||
modelOneStatusPayload.setStatus(ModelStatus.DRAFT);
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 409); // ModelTwo depends on ModelOne
|
||||
|
||||
// Activate modelTwo
|
||||
CustomModel modelTwoStatusPayload = new CustomModel();
|
||||
modelTwoStatusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelNameTwo, RestApiUtil.toJsonAsString(modelTwoStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Try to deactivate modelOne again. The dependent model is Active now, however, the result should be the same.
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 409); // ModelTwo depends on ModelOne
|
||||
|
||||
// Deactivate modelTwo
|
||||
modelTwoStatusPayload = new CustomModel();
|
||||
modelTwoStatusPayload.setStatus(ModelStatus.DRAFT);
|
||||
put("cmm", customModelAdmin, modelNameTwo, RestApiUtil.toJsonAsString(modelTwoStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Delete the modelTwo's type as a Model Administrator
|
||||
delete("cmm/" + modelNameTwo + "/types", customModelAdmin, modelTwoTypeName, 204);
|
||||
|
||||
// Try to deactivate modelOne again. There is no dependency
|
||||
put("cmm", customModelAdmin, modelNameOne, RestApiUtil.toJsonAsString(modelOneStatusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteTypeAspect() throws Exception
|
||||
{
|
||||
final String modelName = "testDeleteTypeModel" + System.currentTimeMillis();
|
||||
Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT, null, "Joe Bloggs");
|
||||
|
||||
// Add type
|
||||
final String typeName = "testType" + System.currentTimeMillis();
|
||||
final String typeNameWithPrefix = namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName;
|
||||
CustomType type = createTypeAspect(CustomType.class, modelName, typeName, "test type title", "test type Desc", "cm:content");
|
||||
|
||||
// Add aspect
|
||||
final String aspectName = "testAspect" + System.currentTimeMillis();
|
||||
final String aspectNameWithPrefix = namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName;
|
||||
CustomAspect aspect = createTypeAspect(CustomAspect.class, modelName, aspectName, null, null, null);
|
||||
|
||||
// Delete type
|
||||
{
|
||||
// Try to delete the model's type as a non Admin user
|
||||
delete("cmm/" + modelName + "/types", nonAdminUserName, typeName, 403);
|
||||
// Delete the model's type as a Model Administrator
|
||||
delete("cmm/" + modelName + "/types", customModelAdmin, typeName, 204);
|
||||
// Try to retrieve the deleted type
|
||||
getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 404);
|
||||
}
|
||||
// Delete Aspect
|
||||
{
|
||||
// Try to delete the model's aspect as a non Admin user
|
||||
delete("cmm/" + modelName + "/aspects", nonAdminUserName, aspectName, 403);
|
||||
// Delete the model's aspect as a Model Administrator
|
||||
delete("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 204);
|
||||
// Try to retrieve the deleted aspect
|
||||
getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 404);
|
||||
}
|
||||
|
||||
// Create the type again
|
||||
post("cmm/" + modelName + "/types", customModelAdmin, RestApiUtil.toJsonAsString(type), 201);
|
||||
// Retrieve the created type
|
||||
HttpResponse response = getSingle("cmm/" + modelName + "/types", customModelAdmin, type.getName(), 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
compareCustomTypesAspects(type, returnedType, "prefixedName");
|
||||
|
||||
// Create the aspect again
|
||||
post("cmm/" + modelName + "/aspects", customModelAdmin, RestApiUtil.toJsonAsString(aspect), 201);
|
||||
// Retrieve the created aspect
|
||||
response = getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspect.getName(), 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
compareCustomTypesAspects(aspect, returnedAspect, "prefixedName");
|
||||
|
||||
// Update the Type by adding property
|
||||
CustomType payload = new CustomType();
|
||||
payload.setName(typeName);
|
||||
|
||||
String typePropName = "testType1Prop1" + System.currentTimeMillis();
|
||||
CustomModelProperty typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName);
|
||||
typeProp.setTitle("property title");
|
||||
typeProp.setDataType("d:int");
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
payload.setProperties(props);
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(payload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Activate the model
|
||||
CustomModel statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
// Activate the model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Test for SHA-703
|
||||
// Add another type with 'typeName' as its parent
|
||||
final String childTypeName = "testChildType" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelName, childTypeName, "test child type title", null, typeNameWithPrefix);
|
||||
|
||||
// Add another aspect with 'aspectName' as its parent
|
||||
final String childAspectName = "testChildAspect" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomAspect.class, modelName, childAspectName, "test child aspect title", null, aspectNameWithPrefix);
|
||||
|
||||
// Delete the model's type as a Model Administrator
|
||||
delete("cmm/" + modelName + "/types", customModelAdmin, typeName, 409); // Cannot delete a type of an active model
|
||||
|
||||
// Delete the model's aspect as a Model Administrator
|
||||
delete("cmm/" + modelName + "/aspects", customModelAdmin, childAspectName, 409); // Cannot delete an aspect of an active model
|
||||
|
||||
// Deactivate the model
|
||||
statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.DRAFT);
|
||||
// Deactivate the model as a Model Administrator
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Delete type
|
||||
{
|
||||
// Try to delete the model's type (parent) as a Model Administrator
|
||||
delete("cmm/" + modelName + "/types", customModelAdmin, typeName, 409); // conflict: childTypeName depends on typeName
|
||||
|
||||
// Delete the child type first
|
||||
delete("cmm/" + modelName + "/types", customModelAdmin, childTypeName, 204);
|
||||
// Try to retrieve the deleted child type
|
||||
getSingle("cmm/" + modelName + "/types", customModelAdmin, childTypeName, 404);
|
||||
|
||||
// Now delete the parent type
|
||||
delete("cmm/" + modelName + "/types", customModelAdmin, typeName, 204);
|
||||
// Try to retrieve the deleted parent type
|
||||
getSingle("cmm/" + modelName + "/types", customModelAdmin, typeName, 404);
|
||||
|
||||
}
|
||||
|
||||
// Delete Aspect
|
||||
{
|
||||
// Try to delete the model's aspect (parent) as a Model Administrator
|
||||
delete("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 409); // conflict: childAspectName depends on aspectName
|
||||
|
||||
// Delete the child aspect first
|
||||
delete("cmm/" + modelName + "/aspects", customModelAdmin, childAspectName, 204);
|
||||
// Try to retrieve the deleted child aspect
|
||||
getSingle("cmm/" + modelName + "/aspects", customModelAdmin, childAspectName, 404);
|
||||
|
||||
// Now delete the parent aspect
|
||||
delete("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 204);
|
||||
// Try to retrieve the deleted parent aspect
|
||||
getSingle("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, 404);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAspectsTypes() throws Exception
|
||||
{
|
||||
String modelName = "testModeEditAspectType" + System.currentTimeMillis();
|
||||
final Pair<String, String> namespacePair = getTestNamespaceUriPrefixPair();
|
||||
// Create the model as a Model Administrator
|
||||
createCustomModel(modelName, namespacePair, ModelStatus.DRAFT);
|
||||
|
||||
// Test update aspect
|
||||
{
|
||||
// Create aspect
|
||||
String aspectName = "testAspect" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomAspect.class, modelName, aspectName, "title", "desc", null);
|
||||
// Update the aspect
|
||||
CustomAspect aspectPayload = new CustomAspect();
|
||||
aspectPayload.setDescription(null);
|
||||
aspectPayload.setTitle("title modified");
|
||||
aspectPayload.setParentName("cm:titled");
|
||||
|
||||
// Try to update the aspect as a non Admin user
|
||||
put("cmm/" + modelName + "/aspects", nonAdminUserName, aspectName, RestApiUtil.toJsonAsString(aspectPayload), null, 403);
|
||||
|
||||
// Modify the name
|
||||
aspectPayload.setName(aspectName + "Modified");
|
||||
// Try to update the aspect as a Model Administrator
|
||||
// Note: aspect/type name cannot be modified
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), null, 404);
|
||||
|
||||
aspectPayload.setName(aspectName);
|
||||
// Update the aspect as a Model Administrator
|
||||
HttpResponse response = put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), null, 200);
|
||||
CustomAspect returnedAspect = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomAspect.class);
|
||||
compareCustomTypesAspects(aspectPayload, returnedAspect, "prefixedName");
|
||||
|
||||
// Update the aspect with an invalid parent
|
||||
aspectPayload.setParentName("cm:titled" + System.currentTimeMillis());
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), null, 409);
|
||||
|
||||
// Activate the model
|
||||
CustomModel statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Remove the aspect's parent
|
||||
// Note: cannot update the parent of an ACTIVE type/aspect.
|
||||
aspectPayload.setParentName(null);
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), null, 409);
|
||||
|
||||
statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.DRAFT);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// now update the aspect's parent - model is inactive
|
||||
put("cmm/" + modelName + "/aspects", customModelAdmin, aspectName, RestApiUtil.toJsonAsString(aspectPayload), null, 200);
|
||||
}
|
||||
|
||||
// Test update type
|
||||
{
|
||||
// Create type
|
||||
String typeName = "testType" + System.currentTimeMillis();
|
||||
createTypeAspect(CustomType.class, modelName, typeName, "title", "desc", "cm:content");
|
||||
|
||||
// Add property
|
||||
CustomType addPropertyPayload = new CustomType();
|
||||
addPropertyPayload.setName(typeName);
|
||||
String typePropName = "testTypeProp1" + System.currentTimeMillis();
|
||||
CustomModelProperty typeProp = new CustomModelProperty();
|
||||
typeProp.setName(typePropName);
|
||||
typeProp.setTitle("property title");
|
||||
typeProp.setDataType("d:text");
|
||||
List<CustomModelProperty> props = new ArrayList<>(1);
|
||||
props.add(typeProp);
|
||||
addPropertyPayload.setProperties(props);
|
||||
// Create the property
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(addPropertyPayload), SELECT_PROPS_QS, 200);
|
||||
|
||||
// Update the type
|
||||
CustomType typePayload = new CustomType();
|
||||
typePayload.setDescription("desc modified");
|
||||
typePayload.setTitle("title modified");
|
||||
|
||||
// Try to update the type as a non Admin user
|
||||
put("cmm/" + modelName + "/types", nonAdminUserName, typeName, RestApiUtil.toJsonAsString(typePayload), null, 403);
|
||||
|
||||
// Modify the name
|
||||
typePayload.setName(typeName + "Modified");
|
||||
// Try to update the type as a Model Administrator
|
||||
// Note: type/type name cannot be modified
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), null, 404);
|
||||
|
||||
typePayload.setName(typeName);
|
||||
// Update the type as a Model Administrator
|
||||
HttpResponse response = put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), null, 200);
|
||||
CustomType returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(typePayload.getDescription(), returnedType.getDescription());
|
||||
assertEquals(typePayload.getTitle(), returnedType.getTitle());
|
||||
// Check that properties are unmodified
|
||||
assertNotNull(returnedType.getProperties());
|
||||
assertEquals(1, returnedType.getProperties().size());
|
||||
assertEquals(typePropName, returnedType.getProperties().iterator().next().getName());
|
||||
|
||||
// Update the type with an invalid parent
|
||||
typePayload.setParentName("cm:folder" + System.currentTimeMillis());
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), null, 409);
|
||||
|
||||
// Activate the model
|
||||
CustomModel statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.ACTIVE);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// Remove the type's parent
|
||||
// Note: cannot update the parent of an ACTIVE type/type.
|
||||
typePayload.setParentName("cm:folder");
|
||||
put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), null, 409);
|
||||
|
||||
statusPayload = new CustomModel();
|
||||
statusPayload.setStatus(ModelStatus.DRAFT);
|
||||
put("cmm", customModelAdmin, modelName, RestApiUtil.toJsonAsString(statusPayload), SELECT_STATUS_QS, 200);
|
||||
|
||||
// now update the type's parent - model is inactive
|
||||
response = put("cmm/" + modelName + "/types", customModelAdmin, typeName, RestApiUtil.toJsonAsString(typePayload), null, 200);
|
||||
returnedType = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), CustomType.class);
|
||||
assertEquals(typePayload.getParentName(), returnedType.getParentName());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.api.tests.util;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* A utility class for Rest API tests
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class RestApiUtil
|
||||
{
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private RestApiUtil()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the alfresco REST API response for a collection of entries.
|
||||
* Basically, it looks for the {@code list} JSON object, then it uses
|
||||
* {@literal Jackson} to convert the list's entries to their corresponding
|
||||
* POJOs based on the given {@code clazz}.
|
||||
*
|
||||
* @param jsonObject the {@code JSONObject} derived from the response
|
||||
* @param clazz the class which represents the JSON payload
|
||||
* @return list of POJOs of the given {@code clazz} type
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T> List<T> parseRestApiEntries(JSONObject jsonObject, Class<T> clazz) throws Exception
|
||||
{
|
||||
assertNotNull(jsonObject);
|
||||
assertNotNull(clazz);
|
||||
|
||||
List<T> models = new ArrayList<>();
|
||||
|
||||
JSONObject jsonList = (JSONObject) jsonObject.get("list");
|
||||
assertNotNull(jsonList);
|
||||
|
||||
JSONArray jsonEntries = (JSONArray) jsonList.get("entries");
|
||||
assertNotNull(jsonEntries);
|
||||
|
||||
for (int i = 0; i < jsonEntries.size(); i++)
|
||||
{
|
||||
JSONObject jsonEntry = (JSONObject) jsonEntries.get(i);
|
||||
T pojoModel = parseRestApiEntry(jsonEntry, clazz);
|
||||
models.add(pojoModel);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the alfresco REST API response for a single entry. Basically, it
|
||||
* looks for the {@code entry} JSON object, then it uses {@literal Jackson}
|
||||
* to convert it to its corresponding POJO based on the given {@code clazz}.
|
||||
*
|
||||
* @param jsonObject the {@code JSONObject} derived from the response
|
||||
* @param clazz the class which represents the JSON payload
|
||||
* @return the POJO of the given {@code clazz} type
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T> T parseRestApiEntry(JSONObject jsonObject, Class<T> clazz) throws Exception
|
||||
{
|
||||
assertNotNull(jsonObject);
|
||||
assertNotNull(clazz);
|
||||
|
||||
JSONObject entry = (JSONObject) jsonObject.get("entry");
|
||||
T pojoModel = OBJECT_MAPPER.readValue(entry.toJSONString(), clazz);
|
||||
assertNotNull(pojoModel);
|
||||
|
||||
return pojoModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the POJO which represents the JSON payload into a JSON string
|
||||
*/
|
||||
public static String toJsonAsString(Object object) throws Exception
|
||||
{
|
||||
assertNotNull(object);
|
||||
return OBJECT_MAPPER.writeValueAsString(object);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user