mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
108044: Merged 5.0.N (5.0.3) to HEAD-BUG-FIX (5.1/Cloud) 107731: Merged 5.0.2 (5.0.2) to 5.0.N (5.0.3) 107679: MNT-13820 "Model can be deactivated with a node referencing the model is in trashcan" Use the database to check if model is in use, rather than Search Fix up existing tests in light of these changes git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@108075 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* 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.dictionary;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.domain.qname.QNameDAO;
|
||||
import org.alfresco.repo.node.archive.NodeArchiveService;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.version.VersionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sglover
|
||||
*
|
||||
*/
|
||||
public class ModelValidatorTest
|
||||
{
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private String testNamespace;
|
||||
private String modelName;
|
||||
|
||||
private ModelValidator modelValidator;
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
private QNameDAO qnameDAO;
|
||||
private NamespaceDAO namespaceDAO;
|
||||
private NodeService nodeService;
|
||||
private FileFolderService fileFolderService;
|
||||
private ContentService contentService;
|
||||
private VersionService versionService;
|
||||
private TransactionService transactionService;
|
||||
private NodeArchiveService nodeArchiveService;
|
||||
|
||||
private M2Model model;
|
||||
private QName modelQName;
|
||||
private QName typeQName;
|
||||
private M2Type type;
|
||||
private QName propertyQName;
|
||||
private M2Property property;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
this.modelValidator = (ModelValidator)ctx.getBean("modelValidator");
|
||||
this.dictionaryDAO = (DictionaryDAO)ctx.getBean("dictionaryDAO");
|
||||
this.qnameDAO = (QNameDAO)ctx.getBean("qnameDAO");
|
||||
this.namespaceDAO = (NamespaceDAO)ctx.getBean("namespaceDAO");
|
||||
this.nodeService = (NodeService)ctx.getBean("NodeService");
|
||||
this.fileFolderService = (FileFolderService)ctx.getBean("FileFolderService");
|
||||
this.contentService = (ContentService)ctx.getBean("contentService");
|
||||
this.versionService = (VersionService)ctx.getBean("VersionService");
|
||||
this.transactionService = (TransactionService)ctx.getBean("TransactionService");
|
||||
this.nodeArchiveService = (NodeArchiveService)ctx.getBean("nodeArchiveService");
|
||||
|
||||
this.modelName = "modelvalidatortest" + System.currentTimeMillis();
|
||||
addModel();
|
||||
}
|
||||
|
||||
private QName addModel()
|
||||
{
|
||||
this.testNamespace = "http://www.alfresco.org/test/" + modelName;
|
||||
this.modelQName = QName.createQName(testNamespace, modelName);
|
||||
|
||||
// Create a model
|
||||
this.model = M2Model.createModel(modelName + ":" + modelName);
|
||||
model.createNamespace(testNamespace, modelName);
|
||||
model.createImport(NamespaceService.DICTIONARY_MODEL_1_0_URI, "d");
|
||||
model.createImport(NamespaceService.CONTENT_MODEL_1_0_URI, NamespaceService.CONTENT_MODEL_PREFIX);
|
||||
|
||||
this.typeQName = QName.createQName(testNamespace, "type1");
|
||||
this.type = model.createType(modelName + ":" + typeQName.getLocalName());
|
||||
type.setParentName("cm:folder");
|
||||
|
||||
this.propertyQName = QName.createQName(testNamespace, "prop1");
|
||||
this.property = type.createProperty(modelName + ":" + propertyQName.getLocalName());
|
||||
property.setType("d:text");
|
||||
|
||||
dictionaryDAO.putModel(model);
|
||||
|
||||
return modelQName;
|
||||
}
|
||||
|
||||
private NodeRef getParentNodeRef()
|
||||
{
|
||||
NodeRef rootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
// create temporary folder
|
||||
NodeRef parentNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "working root" + GUID.generate()),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
return parentNodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a model cannot be deleted if nodes and properties exist that reference it.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidModelDelete() throws Exception
|
||||
{
|
||||
// authenticate
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
final QName modelQName = QName.createQName(testNamespace, modelName);
|
||||
|
||||
// Create a node that uses the new type (type is created in setUp)
|
||||
RetryingTransactionCallback<NodeRef> createNodeCallback = new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Create a node that uses it
|
||||
NodeRef parentNodeRef = getParentNodeRef();
|
||||
FileInfo folder = fileFolderService.create(parentNodeRef, GUID.generate(), ContentModel.TYPE_FOLDER);
|
||||
assertNotNull(folder);
|
||||
NodeRef folderNodeRef = folder.getNodeRef();
|
||||
FileInfo node = fileFolderService.create(folderNodeRef, GUID.generate(), typeQName);
|
||||
assertNotNull(node);
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
|
||||
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
writer.putContent("Test");
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<>();
|
||||
properties.put(propertyQName, "Test");
|
||||
nodeService.setProperties(nodeRef, properties);
|
||||
|
||||
versionService.createVersion(nodeRef, null);
|
||||
|
||||
return nodeRef;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(createNodeCallback, false, true);
|
||||
|
||||
// try to delete the model
|
||||
RetryingTransactionCallback<Void> deleteModelCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
if(modelValidator.canDeleteModel(modelQName))
|
||||
{
|
||||
fail("Model delete should have failed");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteModelCallback, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a model cannot be deleted/made inactive when there are any archived nodes
|
||||
* still in the repository that use it.
|
||||
*
|
||||
* Test case for MNT-13820
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidModelDeleteArchivedNode() throws Exception
|
||||
{
|
||||
// authenticate
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
final QName modelQName = QName.createQName(testNamespace, modelName);
|
||||
|
||||
// Create a node that uses the new type (type is created in setUp)
|
||||
RetryingTransactionCallback<NodeRef> createNodeCallback = new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Create a node that uses it
|
||||
NodeRef parentNodeRef = getParentNodeRef();
|
||||
FileInfo folder = fileFolderService.create(parentNodeRef, GUID.generate(), ContentModel.TYPE_FOLDER);
|
||||
assertNotNull(folder);
|
||||
NodeRef folderNodeRef = folder.getNodeRef();
|
||||
FileInfo node = fileFolderService.create(folderNodeRef, GUID.generate(), typeQName);
|
||||
assertNotNull(node);
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
|
||||
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
writer.putContent("Test");
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<>();
|
||||
properties.put(propertyQName, "Test");
|
||||
nodeService.setProperties(nodeRef, properties);
|
||||
|
||||
versionService.createVersion(nodeRef, null);
|
||||
|
||||
return nodeRef;
|
||||
}
|
||||
};
|
||||
final NodeRef nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(createNodeCallback, false, true);
|
||||
|
||||
RetryingTransactionCallback<Void> deleteNodeCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeService.deleteNode(nodeRef);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteNodeCallback, false, true);
|
||||
|
||||
// try to delete the model
|
||||
RetryingTransactionCallback<Void> deleteModelCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
if(modelValidator.canDeleteModel(modelQName))
|
||||
{
|
||||
fail("Model delete should have failed");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteModelCallback, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a model can be deleted when nodes are deleted.
|
||||
*
|
||||
* Test case for MNT-13820
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testModelDelete() throws Exception
|
||||
{
|
||||
// authenticate
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
final QName modelQName = QName.createQName(testNamespace, modelName);
|
||||
|
||||
// Create a node that uses the new type (type is created in setUp)
|
||||
RetryingTransactionCallback<NodeRef> createNodeCallback = new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Create a node that uses it
|
||||
NodeRef parentNodeRef = getParentNodeRef();
|
||||
FileInfo folder = fileFolderService.create(parentNodeRef, GUID.generate(), ContentModel.TYPE_FOLDER);
|
||||
assertNotNull(folder);
|
||||
NodeRef folderNodeRef = folder.getNodeRef();
|
||||
FileInfo node = fileFolderService.create(folderNodeRef, GUID.generate(), typeQName);
|
||||
assertNotNull(node);
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
|
||||
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
writer.putContent("Test");
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<>();
|
||||
properties.put(propertyQName, "Test");
|
||||
nodeService.setProperties(nodeRef, properties);
|
||||
|
||||
versionService.createVersion(nodeRef, null);
|
||||
|
||||
return nodeRef;
|
||||
}
|
||||
};
|
||||
final NodeRef nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(createNodeCallback, false, true);
|
||||
|
||||
RetryingTransactionCallback<Void> deleteNodeCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeService.addAspect(nodeRef, ContentModel.ASPECT_TEMPORARY, null);
|
||||
nodeService.deleteNode(nodeRef);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteNodeCallback, false, true);
|
||||
|
||||
// try to delete the model
|
||||
RetryingTransactionCallback<Void> deleteModelCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
if(!modelValidator.canDeleteModel(modelQName))
|
||||
{
|
||||
fail("Model delete should have succeeded");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteModelCallback, false, true);
|
||||
|
||||
// Check that the qnames are still there
|
||||
// try to delete the model
|
||||
RetryingTransactionCallback<Void> checkQNamesCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertNotNull(qnameDAO.getQName(propertyQName));
|
||||
assertNotNull(qnameDAO.getQName(typeQName));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(checkQNamesCallback, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a model cannot be deleted if there are node properties referencing it.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidPropertyDelete() throws Exception
|
||||
{
|
||||
// authenticate
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// Create a node that uses the new type
|
||||
RetryingTransactionCallback<NodeRef> createNodeCallback = new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Create a node that uses it
|
||||
NodeRef parentNodeRef = getParentNodeRef();
|
||||
FileInfo folder = fileFolderService.create(parentNodeRef, GUID.generate(), ContentModel.TYPE_FOLDER);
|
||||
assertNotNull(folder);
|
||||
NodeRef folderNodeRef = folder.getNodeRef();
|
||||
FileInfo node = fileFolderService.create(folderNodeRef, GUID.generate(), typeQName);
|
||||
assertNotNull(node);
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
|
||||
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
writer.putContent("Test");
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<>();
|
||||
properties.put(propertyQName, "Test");
|
||||
nodeService.setProperties(nodeRef, properties);
|
||||
|
||||
versionService.createVersion(nodeRef, null);
|
||||
|
||||
return nodeRef;
|
||||
}
|
||||
};
|
||||
final NodeRef nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(createNodeCallback, false, true);
|
||||
|
||||
RetryingTransactionCallback<Void> deleteModelCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
type.removeProperty(modelName + ":" + propertyQName.getLocalName());
|
||||
CompiledModel compiledModel = model.compile(dictionaryDAO, namespaceDAO, true);
|
||||
try
|
||||
{
|
||||
modelValidator.validateModel(compiledModel);
|
||||
fail("Property delete should have failed");
|
||||
}
|
||||
catch(ModelInUseException e)
|
||||
{
|
||||
System.out.println("help");
|
||||
// ok
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteModelCallback, false, true);
|
||||
|
||||
// delete the node that is using properties in the model
|
||||
RetryingTransactionCallback<Void> deleteNodeCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeService.deleteNode(nodeRef);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteNodeCallback, false, true);
|
||||
|
||||
// make sure that the archive store is purged
|
||||
RetryingTransactionCallback<Void> purgeArchiveCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeArchiveService.purgeAllArchivedNodes(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(purgeArchiveCallback, false, true);
|
||||
|
||||
// try to delete model again - should work now
|
||||
RetryingTransactionCallback<Void> deleteModelAgainCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
type.removeProperty(modelName + ":" + propertyQName.getLocalName());
|
||||
CompiledModel compiledModel = model.compile(dictionaryDAO, namespaceDAO, true);
|
||||
modelValidator.validateModel(compiledModel);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(deleteModelAgainCallback, false, true);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user