mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged HEAD-QA to HEAD (4.2) (including moving test classes into separate folders)
51903 to 54309 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@54310 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2013 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.util.test.junitrules;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.RuleChain;
|
||||
|
||||
/**
|
||||
* @author Neil Mc Erlean
|
||||
* @since 4.2
|
||||
*/
|
||||
public abstract class AbstractAlfrescoPersonTest
|
||||
{
|
||||
/** Gets the username of the test user to be created. */
|
||||
protected abstract String createTestUserName();
|
||||
|
||||
/** A hookpoint to allow subclasses to add addition validation. */
|
||||
protected void additionalValidations(String username, boolean userExists)
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
// Rule to initialise the default Alfresco spring configuration
|
||||
@ClassRule public static ApplicationContextInit APP_CONTEXT_INIT = new ApplicationContextInit();
|
||||
|
||||
// Rule to create a test user
|
||||
protected final String testUsername = createTestUserName();
|
||||
public final AlfrescoPerson testUserRule = new AlfrescoPerson(APP_CONTEXT_INIT, testUsername);
|
||||
|
||||
// A rule to allow individual test methods all to be run as "admin".
|
||||
public RunAsFullyAuthenticatedRule runAsRule = new RunAsFullyAuthenticatedRule(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
@Rule public final RuleChain ruleChain = RuleChain.outerRule(runAsRule).around(testUserRule);
|
||||
|
||||
protected static PersonService PERSON_SERVICE;
|
||||
protected static RetryingTransactionHelper TRANSACTION_HELPER;
|
||||
|
||||
@BeforeClass public static void initStaticData() throws Exception
|
||||
{
|
||||
PERSON_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("PersonService", PersonService.class);
|
||||
TRANSACTION_HELPER = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
}
|
||||
|
||||
@Test public void ensureTestUserWasCreated() throws Exception
|
||||
{
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
validateCmPersonNode(testUsername, true);
|
||||
additionalValidations(testUsername, true);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Validate that the person is correctly persisted (or not). */
|
||||
protected abstract void validateCmPersonNode(String username, boolean exists);
|
||||
|
||||
@Test public void ensureUserIsCleanedUp() throws Throwable
|
||||
{
|
||||
// Note that because we need to test that the Rule's 'after' behaviour has worked correctly, we cannot
|
||||
// use the Rule that has been declared in the normal way - otherwise nothing would be cleaned up until
|
||||
// after our test method.
|
||||
// Therefore we have to manually poke the Rule to get it to cleanup during test execution.
|
||||
// NOTE! This is *not* how a JUnit Rule would normally be used.
|
||||
|
||||
// First manually run the 'after' part of the rule on this class - so that it does not interfere.
|
||||
this.testUserRule.after();
|
||||
|
||||
final String testUserForThisMethodOnly = createTestUserName();
|
||||
|
||||
AlfrescoPerson myTestUser = new AlfrescoPerson(APP_CONTEXT_INIT, testUserForThisMethodOnly);
|
||||
|
||||
// Manually trigger the execution of the 'before' part of the rule.
|
||||
myTestUser.before();
|
||||
|
||||
// Now trigger the Rule's cleanup behaviour.
|
||||
myTestUser.after();
|
||||
|
||||
// and ensure that the nodes are all gone.
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
validateCmPersonNode(testUserForThisMethodOnly, false);
|
||||
additionalValidations(testUserForThisMethodOnly, false);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2013 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.util.test.junitrules;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.util.test.testusers.TestUserComponent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* This class is an abstract base class for JUnit rules which manage the lifecycle of <code>cm:person</code>
|
||||
* nodes and authentication details for the transient users often required within test code.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public abstract class AbstractPersonRule extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* Constructs a person rule with the specified spring context, which will be necessary
|
||||
* to actually create and delete the users.
|
||||
*
|
||||
* @param appContext the spring app context (needed to get at Alfresco services).
|
||||
*/
|
||||
public AbstractPersonRule(ApplicationContext appContext)
|
||||
{
|
||||
super(appContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a person rule with a reference to an {@link ApplicationContextInit rule}. This other rule will
|
||||
* be used to access the application context and from there the necessary services for the creation and deletion of users.
|
||||
*
|
||||
* @param appContext a rule which can provide the spring application context.
|
||||
*/
|
||||
public AbstractPersonRule(ApplicationContextInit appContextRule)
|
||||
{
|
||||
super(appContextRule);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a user with the specified username.
|
||||
* If an authentication for this username does not exist, it is created.
|
||||
* If a cm:person for this username does not exist, it is created.
|
||||
* This method does not handle transactions.
|
||||
*
|
||||
* @param userName the username of the new user.
|
||||
* @return the NodeRef of the created cm:person node.
|
||||
*/
|
||||
protected NodeRef createPerson(final String userName)
|
||||
{
|
||||
// Get the spring context
|
||||
final ApplicationContext ctxt = getApplicationContext();
|
||||
|
||||
// Extract required service beans
|
||||
final TestUserComponent testUserComponent = (TestUserComponent) ctxt.getBean("testUserComponent");
|
||||
|
||||
return testUserComponent.createTestUser(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deletes the specified user's person and authentication details if they are
|
||||
* present in the system.
|
||||
* This method does not handle transactions.
|
||||
*
|
||||
* @param userName the username of the user to be deleted.
|
||||
*/
|
||||
protected void deletePerson(final String userName)
|
||||
{
|
||||
// Get the spring context
|
||||
final ApplicationContext ctxt = getApplicationContext();
|
||||
|
||||
// Extract required service beans
|
||||
final TestUserComponent testUserComponent = (TestUserComponent) ctxt.getBean("testUserComponent");
|
||||
|
||||
testUserComponent.deleteTestUser(userName);
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
* 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.util.test.junitrules;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Abstract junit rule, which provides access to the Spring application context.
|
||||
*
|
||||
* An explicit ApplicationContext or an ApplicationContextInit rule can be passed at construction time.
|
||||
* getApplicationContext will either return the instance passed in, or retrieve one from the rule.
|
||||
*
|
||||
* @author Alex Miller
|
||||
*/
|
||||
public abstract class AbstractRule extends ExternalResource
|
||||
{
|
||||
|
||||
protected final ApplicationContext appContext;
|
||||
protected final ApplicationContextInit appContextRule;
|
||||
|
||||
/**
|
||||
* @param appContext for use by sub classes.
|
||||
*/
|
||||
protected AbstractRule(ApplicationContext appContext)
|
||||
{
|
||||
ParameterCheck.mandatory("appContext", appContext);
|
||||
|
||||
this.appContext = appContext;
|
||||
this.appContextRule = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param appContextRule {@link ApplicationContextInit} rule used to provide ApplicationContext to sub classes.
|
||||
*/
|
||||
protected AbstractRule(ApplicationContextInit appContextRule)
|
||||
{
|
||||
ParameterCheck.mandatory("appContextRule", appContextRule);
|
||||
|
||||
this.appContext = null;
|
||||
this.appContextRule = appContextRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method provides the spring application context to subclasses. It either provides the explicit ApplicationContext, passed in
|
||||
* at construction time, or retrieves it from the {@link ApplicationContextInit} rule, passed in the alternative constructor.
|
||||
*
|
||||
* @return the spring application context
|
||||
* @throws NullPointerException if the application context has not been initialised when requested.
|
||||
*/
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
ApplicationContext result = null;
|
||||
|
||||
// The app context is either provided explicitly:
|
||||
if (appContext != null)
|
||||
{
|
||||
result = appContext;
|
||||
}
|
||||
// or is implicitly accessed via another rule:
|
||||
else
|
||||
{
|
||||
ApplicationContext contextFromRule = appContextRule.getApplicationContext();
|
||||
if (contextFromRule != null)
|
||||
{
|
||||
result = contextFromRule;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NullPointerException("Cannot retrieve application context from provided rule.");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to setup and teardown a set of Alfresco users for test purposes.
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // Normally we would initialise the spring application context in another rule.
|
||||
* @ClassRule public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
*
|
||||
* // This rule will give us 8 GUID-named users.
|
||||
* @Rule public final AlfrescoPeople testPeople = new AlfrescoPeople(APP_CONTEXT_RULE, 8);
|
||||
*
|
||||
* @Test public void aTestMethod()
|
||||
* {
|
||||
* Set<String> userNames = testPeople.getUsernames();
|
||||
* // etc
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class AlfrescoPeople extends AbstractPersonRule
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(AlfrescoPeople.class);
|
||||
|
||||
private final int personCount;
|
||||
|
||||
/**
|
||||
* A Map (username: person nodeRef) of created users.
|
||||
*/
|
||||
Map<String, NodeRef> usersPersons = new TreeMap<String, NodeRef>();
|
||||
|
||||
/**
|
||||
* @param appContext the spring app context (needed to get at Alfresco services).
|
||||
* @param personCount the number of users to be created
|
||||
*/
|
||||
public AlfrescoPeople(ApplicationContext appContext, int personCount)
|
||||
{
|
||||
super(appContext);
|
||||
this.personCount = personCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
* @param personCount the number of users to be created
|
||||
*/
|
||||
public AlfrescoPeople(ApplicationContextInit appContextRule, int personCount)
|
||||
{
|
||||
super(appContextRule);
|
||||
this.personCount = personCount;
|
||||
}
|
||||
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
// Set up required services
|
||||
ApplicationContext ctxt = getApplicationContext();
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) ctxt.getBean("retryingTransactionHelper");
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Creating " + personCount + " users for test purposes...");
|
||||
}
|
||||
|
||||
for (int i = 0; i < personCount; i++)
|
||||
{
|
||||
final String userName = GUID.generate();
|
||||
NodeRef personNode = createPerson(userName);
|
||||
usersPersons.put(userName, personNode);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
// Set up required services
|
||||
ApplicationContext ctxt = getApplicationContext();
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) ctxt.getBean("retryingTransactionHelper");
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
for (Map.Entry<String, NodeRef> entry : usersPersons.entrySet())
|
||||
{
|
||||
deletePerson(entry.getKey());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the usernames of the people created by this rule.
|
||||
*/
|
||||
public Set<String> getUsernames()
|
||||
{
|
||||
return this.usersPersons.keySet();
|
||||
}
|
||||
}
|
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2013 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.util.test.junitrules;
|
||||
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to setup and teardown a single Alfresco user for test purposes.
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // Normally we would initialise the spring application context in another rule.
|
||||
* @ClassRule public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
*
|
||||
* // We pass the rule that creates the spring application context.
|
||||
* // This rule will give us a user with username 'NeilM'.
|
||||
* @Rule public final AlfrescoPerson namedPerson = new AlfrescoPerson(APP_CONTEXT_RULE, "NeilM");
|
||||
* // This rule with give us a user with a GUID-generated name.
|
||||
* @Rule public final AlfrescoPerson guidPerson = new AlfrescoPerson(APP_CONTEXT_RULE);
|
||||
*
|
||||
* @Test public void aTestMethod()
|
||||
* {
|
||||
* AuthenticationUtil.setFullyAuthenticatedUser(namedPerson.getUsername());
|
||||
* // etc
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class AlfrescoPerson extends AbstractPersonRule
|
||||
{
|
||||
private final String userName;
|
||||
|
||||
private NodeRef personNodeRef;
|
||||
|
||||
/**
|
||||
* Constructs the rule with a spring ApplicationContext.
|
||||
* A GUID-generated username will be used for the test user.
|
||||
*
|
||||
* @param appContext the spring app context (needed to get at Alfresco services).
|
||||
*/
|
||||
public AlfrescoPerson(ApplicationContext appContext)
|
||||
{
|
||||
this(appContext, GUID.generate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
* A GUID-generated username will be used for the test user.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
*/
|
||||
public AlfrescoPerson(ApplicationContextInit appContextRule)
|
||||
{
|
||||
this(appContextRule, GUID.generate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the rule with a spring ApplicationContext.
|
||||
*
|
||||
* @param appContext the spring app context (needed to get at Alfresco services).
|
||||
* @param userName the username for the person to be created.
|
||||
*/
|
||||
public AlfrescoPerson(ApplicationContext appContext, String userName)
|
||||
{
|
||||
super(appContext);
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
* @param userName the username for the person to be created.
|
||||
*/
|
||||
public AlfrescoPerson(ApplicationContextInit appContextRule, String userName)
|
||||
{
|
||||
super(appContextRule);
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
@Override protected void before()
|
||||
{
|
||||
ApplicationContext ctxt = getApplicationContext();
|
||||
RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) ctxt.getBean("retryingTransactionHelper");
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
personNodeRef = createPerson(userName);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
ApplicationContext ctxt = getApplicationContext();
|
||||
RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) ctxt.getBean("retryingTransactionHelper");
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
deletePerson(userName);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the username of the person created by this rule.
|
||||
*/
|
||||
public String getUsername()
|
||||
{
|
||||
return this.userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link NodeRef person node}.
|
||||
* @return the person node.
|
||||
*/
|
||||
public NodeRef getPersonNode()
|
||||
{
|
||||
return this.personNodeRef;
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2013 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.util.test.junitrules;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
/**
|
||||
* Test class for {@link AlfrescoPerson}.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since 4.2
|
||||
*/
|
||||
public class AlfrescoPersonTest extends AbstractAlfrescoPersonTest
|
||||
{
|
||||
@Override protected String createTestUserName()
|
||||
{
|
||||
// In Community/Enterprise Alfresco, usernames are "just Strings" - e.g. they need not be email addresses.
|
||||
return GUID.generate();
|
||||
}
|
||||
|
||||
@Override protected void validateCmPersonNode(final String username, final boolean exists)
|
||||
{
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertEquals("Test person's existence was wrong", exists, PERSON_SERVICE.personExists(username));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2013 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.util.test.junitrules;
|
||||
|
||||
import org.alfresco.repo.tenant.TenantAdminService;
|
||||
import org.alfresco.repo.tenant.TenantUtil;
|
||||
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to setup and teardown a single Alfresco Tenant for test purposes.
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // Normally we would initialise the spring application context in another rule.
|
||||
* @ClassRule public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
*
|
||||
* // We pass the rule that creates the spring application context.
|
||||
* // This rule will give us a tenant with the domain 'testtenant'.
|
||||
* @Rule public final AlfrescoTenant tenant = new AlfrescoTenant(APP_CONTEXT_RULE, "testtenant");
|
||||
*
|
||||
* @Test public void aTestMethod()
|
||||
* {
|
||||
tenant.runAsSystem(new TenantRunAsWork<Void>() {
|
||||
@Override
|
||||
public Void doWork() throws Exception {
|
||||
// Do something as the tenant system user.
|
||||
}
|
||||
});
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Alex Miller
|
||||
* @see AlfrescoPerson Consider using {@link AlfrescoPerson} instead, which will create tenants as needed when run in a Cloud build.
|
||||
*/
|
||||
public class AlfrescoTenant extends AbstractRule
|
||||
{
|
||||
public static final String ADMIN_PASSWORD = "password";
|
||||
|
||||
private final String tenantName;
|
||||
|
||||
/**
|
||||
* Constructs the rule with a spring ApplicationContext.
|
||||
* A GUID-generated tenant name will be used for the test tenant.
|
||||
*
|
||||
* @param appContext the spring app context (needed to get at Alfresco services).
|
||||
*/
|
||||
public AlfrescoTenant(ApplicationContext appContext)
|
||||
{
|
||||
this(appContext, GUID.generate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
* A GUID-generated tenant name will be used for the test user.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
*/
|
||||
public AlfrescoTenant(ApplicationContextInit appContextRule)
|
||||
{
|
||||
this(appContextRule, GUID.generate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the rule with a spring ApplicationContext.
|
||||
*
|
||||
* @param appContext the spring app context (needed to get at Alfresco services).
|
||||
* @param userName the username for the person to be created.
|
||||
*/
|
||||
public AlfrescoTenant(ApplicationContext appContext, String tenantName)
|
||||
{
|
||||
super(appContext);
|
||||
this.tenantName = tenantName.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
* @param tenantName the name for the tenant to be created.
|
||||
*/
|
||||
public AlfrescoTenant(ApplicationContextInit appContextRule, String tenantName)
|
||||
{
|
||||
super(appContextRule);
|
||||
this.tenantName = tenantName.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tenant.
|
||||
*/
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
final ApplicationContext appCtx = getApplicationContext();
|
||||
RetryingTransactionHelper transactionHelper = appCtx.getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
final TenantAdminService tenantAdminService = appCtx.getBean("tenantAdminService", TenantAdminService.class);
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
tenantAdminService.createTenant(tenantName, ADMIN_PASSWORD.toCharArray());
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the tenant
|
||||
*/
|
||||
@Override protected void after()
|
||||
{
|
||||
final ApplicationContext appCtx = getApplicationContext();
|
||||
RetryingTransactionHelper transactionHelper = appCtx.getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
final TenantAdminService tenantAdminService = appCtx.getBean("tenantAdminService", TenantAdminService.class);
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
tenantAdminService.deleteTenant(tenantName);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tenant domain.
|
||||
*/
|
||||
public String getTenantDomain() {
|
||||
return tenantName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do runAsWork as the system user for this tenant.
|
||||
*
|
||||
* @param runAsWork The work to be done as the system user of this tenant.
|
||||
* @return The result of the work
|
||||
*/
|
||||
public <T> T runAsSystem(TenantRunAsWork<T> runAsWork) {
|
||||
return TenantUtil.runAsSystemTenant(runAsWork, tenantName);
|
||||
}
|
||||
}
|
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to bring up a {@link ApplicationContext spring application context}.
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // Parameterless construction brings up the default Alfresco spring configuration.
|
||||
* @ClassRule public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
* private static NodeService NODE_SERVICE;
|
||||
*
|
||||
* @BeforeClass public static void initSpringServices() throws Exception
|
||||
* {
|
||||
* NODE_SERVICE = (NodeService) APP_CONTEXT_RULE.getApplicationContext().getBean("nodeService");
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class ApplicationContextInit extends ExternalResource
|
||||
{
|
||||
public static final String GLOBAL_INTEGRATION_TEST_CONFIG = "classpath:alfresco/test/global-integration-test-context.xml";
|
||||
|
||||
/**
|
||||
* The locations for the application context configurations.
|
||||
*/
|
||||
private final String[] configLocations;
|
||||
|
||||
/**
|
||||
* The initialised {@link ApplicationContext spring context}.
|
||||
*/
|
||||
private ApplicationContext appContext;
|
||||
|
||||
/**
|
||||
* Construct a JUnit rule which will bring up a spring ApplicationContext based on the default Alfresco spring context.
|
||||
*/
|
||||
public ApplicationContextInit()
|
||||
{
|
||||
this(ApplicationContextHelper.CONFIG_LOCATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JUnit rule which will bring up an ApplicationContext based on the specified spring contexts.
|
||||
*
|
||||
* @param configLocations locations of spring contexts
|
||||
*/
|
||||
public ApplicationContextInit(String... configLocations)
|
||||
{
|
||||
List<String> requestedConfigs = new ArrayList<String>();
|
||||
requestedConfigs.addAll(Arrays.asList(configLocations));
|
||||
|
||||
// No matter what spring contexts are provided in construction of this object, we always
|
||||
// add the global test integration config to the end.
|
||||
// Yes, this will mean that devs cannot override that context file, but it's almost empty anyway.
|
||||
// We may have to change how this class handles this, but for now: keep it simple, s.
|
||||
requestedConfigs.add(GLOBAL_INTEGRATION_TEST_CONFIG);
|
||||
|
||||
this.configLocations = requestedConfigs.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This factory method constructs a JUnit rule which will bring up an ApplicationContext consisting
|
||||
* of the default Alfresco context with any additionConfigLocations appended. It is a convenient way to specify
|
||||
* override contexts in test code.
|
||||
*
|
||||
* @param additionalConfigLocations addition config locations containing additional or overriding beans.
|
||||
*/
|
||||
public static ApplicationContextInit createStandardContextWithOverrides(String... additionalConfigLocations)
|
||||
{
|
||||
List<String> contexts = new ArrayList<String>();
|
||||
|
||||
// The defaults (currently only one)
|
||||
for (String defaultConfigLocation: ApplicationContextHelper.CONFIG_LOCATIONS)
|
||||
{
|
||||
contexts.add(defaultConfigLocation);
|
||||
}
|
||||
|
||||
// any user supplied extras
|
||||
for (String additionalContext : additionalConfigLocations)
|
||||
{
|
||||
contexts.add(additionalContext);
|
||||
}
|
||||
|
||||
String[] contextsAsArray = contexts.toArray(new String[0]);
|
||||
|
||||
return new ApplicationContextInit(contextsAsArray);
|
||||
}
|
||||
|
||||
@Override protected void before()
|
||||
{
|
||||
log.debug("Initialising custom Spring Configuration: " + Arrays.asList(configLocations).toString());
|
||||
|
||||
appContext = ApplicationContextHelper.getApplicationContext(configLocations);
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
// Intentionally empty. Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configLocations as supplied to the code on construction.
|
||||
*/
|
||||
public List<String> getConfigLocations()
|
||||
{
|
||||
return Arrays.asList(configLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ApplicationContext as initialised by the rule.
|
||||
*/
|
||||
public ApplicationContext getApplicationContext()
|
||||
{
|
||||
if (this.appContext == null)
|
||||
{
|
||||
// Chain order is wrong, try to help out by doing the @Before now
|
||||
before();
|
||||
}
|
||||
return this.appContext;
|
||||
}
|
||||
|
||||
private static final Log log = LogFactory.getLog(ApplicationContextInit.class);
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 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.util.test.junitrules;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class for {@link ApplicationContextInit}.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class ApplicationContextInitTest
|
||||
{
|
||||
// Some dummy contexts with test beans in them.
|
||||
public static final String[] dummySpringContexts = new String[] {"classpath:org/alfresco/util/test/junitrules/dummy1-context.xml",
|
||||
"classpath:org/alfresco/util/test/junitrules/dummy2-context.xml"};
|
||||
|
||||
// Rule to initialise the default Alfresco spring configuration
|
||||
@ClassRule public static ApplicationContextInit APP_CONTEXT_INIT = ApplicationContextInit.createStandardContextWithOverrides(dummySpringContexts);
|
||||
|
||||
@Test public void ensureSpringContextWasInitedWithOverrides() throws Exception
|
||||
{
|
||||
// Bean from the standard Alfresco context
|
||||
assertNotNull("Spring context did not contain expected bean.",
|
||||
APP_CONTEXT_INIT.getApplicationContext().getBean("contentService", ContentService.class));
|
||||
|
||||
// Bean from the first override context
|
||||
assertEquals("Value from dummy1-context.xml",
|
||||
APP_CONTEXT_INIT.getApplicationContext().getBean("testBean1", String.class));
|
||||
|
||||
// Bean from the second override context
|
||||
assertEquals("Value from dummy2-context.xml",
|
||||
APP_CONTEXT_INIT.getApplicationContext().getBean("testBean2", String.class));
|
||||
|
||||
// Bean overridden in second context
|
||||
assertEquals("Value from dummy2-context.xml",
|
||||
APP_CONTEXT_INIT.getApplicationContext().getBean("testBean1and2", String.class));
|
||||
}
|
||||
}
|
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.ErrorCollector;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to turn existing test code into Load Tests.
|
||||
* It does this in conjunction with the {@link AlfrescoPeople} JUnit rule.
|
||||
* That rule is used to {@link AlfrescoPeople#AlfrescoPeople(ApplicationContextInit, int) create} a
|
||||
* fixed number of Alfresco users. Then {@link LoadTestRule} will do the following for each of your JUnit 4 @Test methods:
|
||||
* <ul>
|
||||
* <li>if they are annotated with the {@link LoadTest} marker annotation:
|
||||
* <ol>
|
||||
* <li>one Java thread for each of the users created by the {@link AlfrescoPeople} rule will be created and started.</li>
|
||||
* <li>each of those threads will start by authenticating as a different user from the above set.</li>
|
||||
* <li>each of those threads will concurrently execute the same JUnit @Test method.</li>
|
||||
* <li>if all the concurrent threads complete execution successfully, the @Test method is passed.</li>
|
||||
* <li>but if one or more of those concurrent threads fail, the error messages will be aggregated together into a single error for that method.</li>
|
||||
* </ol>
|
||||
* <li>else they will be executed as normal and will pass or fail as normal.</li>
|
||||
* </ul>
|
||||
* <p/>
|
||||
* Example usage, where we have a 'normal' feature test and a load test for the same feature.:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // We need to ensure that JUnit Rules in the same 'group' (in this case the 'static' group) execute in the correct
|
||||
* // order. To do this we do not annotate the JUnit Rule fields themselves, but instead wrap them up in a RuleChain.
|
||||
*
|
||||
* // Initialise the spring application context with a rule.
|
||||
* public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
* public static final AlfrescoPeople TEST_USERS = new AlfrescoPeople(APP_CONTEXT_RULE, 32);
|
||||
*
|
||||
* @ClassRule public static RuleChain STATIC_RULE_CHAIN = RuleChain.outerRule(APP_CONTEXT_RULE)
|
||||
* .around(TEST_USERS);
|
||||
*
|
||||
* @Rule public LoadTestRule loadTestRule = new LoadTestRule(TEST_USERS);
|
||||
*
|
||||
* @Test public void aNormalTestMethod()
|
||||
* {
|
||||
* ensureFeatureFooWorks()
|
||||
* }
|
||||
*
|
||||
* @LoadTest @Test public void aLoadTestMethod()
|
||||
* {
|
||||
* ensureFeatureFooWorks()
|
||||
* }
|
||||
*
|
||||
* public void ensureFeatureFooWorks() {}
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
*/
|
||||
public class LoadTestRule extends ErrorCollector
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(LoadTestRule.class);
|
||||
|
||||
private final AlfrescoPeople people;
|
||||
|
||||
public LoadTestRule(AlfrescoPeople people)
|
||||
{
|
||||
this.people = people;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of users/concurrent threads that this Rule has been configured to use.
|
||||
* @return the number of users/threads.
|
||||
*/
|
||||
public int getCount()
|
||||
{
|
||||
return this.people.getUsernames().size();
|
||||
}
|
||||
|
||||
@Override public Statement apply(final Statement base, final Description description)
|
||||
{
|
||||
boolean loadTestingRequestedForThisMethod = false;
|
||||
|
||||
Collection<Annotation> annotations = description.getAnnotations();
|
||||
for (Annotation anno : annotations)
|
||||
{
|
||||
if (anno.annotationType().equals(LoadTest.class))
|
||||
{
|
||||
loadTestingRequestedForThisMethod = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (loadTestingRequestedForThisMethod)
|
||||
{
|
||||
log.debug(LoadTest.class.getSimpleName() + "-based testing configured for method " + description.getMethodName());
|
||||
|
||||
return new Statement()
|
||||
{
|
||||
@Override public void evaluate() throws Throwable
|
||||
{
|
||||
int executionCount = getCount();
|
||||
int currentIndex = 1;
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(executionCount);
|
||||
|
||||
for (String username: people.getUsernames())
|
||||
{
|
||||
log.debug("About to start " + description.getMethodName() + ". " + currentIndex + "/" + executionCount + " as " + username);
|
||||
new Thread(new StatementEvaluatorRunnable(username, base, latch)).start();
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
latch.await();
|
||||
|
||||
verify();
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug(LoadTest.class.getSimpleName() + "-based testing NOT configured for this method.");
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
private class StatementEvaluatorRunnable implements Runnable
|
||||
{
|
||||
private final String username;
|
||||
private final CountDownLatch latch;
|
||||
private final Statement base;
|
||||
public StatementEvaluatorRunnable(String username, Statement base, CountDownLatch latch)
|
||||
{
|
||||
this.username = username;
|
||||
this.latch = latch;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
log.debug("Setting fully auth'd user to " + username);
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(username);
|
||||
|
||||
base.evaluate();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
addError(t);
|
||||
}
|
||||
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This annotation is a marker used to identify a JUnit @Test method as a "load test".
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface LoadTest
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
}
|
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to make test methods run as a particular user.
|
||||
* A username can be provided on construction to the rule and then all <code>@Test</code> methods will be
|
||||
* run as that user.
|
||||
* <p/>
|
||||
* Furthermore, if an individual test method is annotated like this <code>@RunAsUser(userName="John")</code> than that
|
||||
* method (and only that method) will be run as "John".
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* @ClassRule public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
* @Rule public RunAsFullyAuthenticatedRule runAsGuidPerson = new RunAsFullyAuthenticatedRule("NeilM");
|
||||
*
|
||||
* @Test public void doSomething() throws Exception
|
||||
* {
|
||||
* // This will run as NeilM
|
||||
* }
|
||||
*
|
||||
* @Test @RunAsUser(userName="DaveC") public void doSomething() throws Exception
|
||||
* {
|
||||
* // This will run as DaveC
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class RunAsFullyAuthenticatedRule implements TestRule
|
||||
{
|
||||
/**
|
||||
* This annotation can be used to mark an individual {@link Test} method for running as a named user.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RunAsUser
|
||||
{
|
||||
String userName() default "";
|
||||
}
|
||||
|
||||
|
||||
private static final Log log = LogFactory.getLog(RunAsFullyAuthenticatedRule.class);
|
||||
|
||||
/**
|
||||
* A fixed username to run as.
|
||||
*/
|
||||
private final String fixedUserName;
|
||||
|
||||
/**
|
||||
* A rule which will provide a username to run as
|
||||
*/
|
||||
private final AlfrescoPerson personRule;
|
||||
|
||||
|
||||
/**
|
||||
* This constructs a rule where there is no specified user to run as.
|
||||
* For this to be useful (or legal) a user must be specified on every test method using {@link RunAsUser}.
|
||||
*/
|
||||
public RunAsFullyAuthenticatedRule()
|
||||
{
|
||||
this.fixedUserName = null;
|
||||
this.personRule = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userName the username which all test methods should run as.
|
||||
*/
|
||||
public RunAsFullyAuthenticatedRule(String userName)
|
||||
{
|
||||
ParameterCheck.mandatory("userName", userName);
|
||||
|
||||
this.fixedUserName = userName;
|
||||
this.personRule = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param personRule the rule which will provide the username which all test methods should run as.
|
||||
*/
|
||||
public RunAsFullyAuthenticatedRule(AlfrescoPerson personRule)
|
||||
{
|
||||
ParameterCheck.mandatory("personRule", personRule);
|
||||
|
||||
this.fixedUserName = null;
|
||||
this.personRule = personRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username which test methods will run as.
|
||||
*/
|
||||
public String getUsername()
|
||||
{
|
||||
return this.fixedUserName;
|
||||
}
|
||||
|
||||
|
||||
@Override public Statement apply(final Statement base, final Description description)
|
||||
{
|
||||
return new Statement()
|
||||
{
|
||||
@Override public void evaluate() throws Throwable
|
||||
{
|
||||
// Store the current authentication
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
|
||||
// First, try for a username provided on the @Test method itself.
|
||||
String runAsUser = getMethodAnnotatedUserName(description);
|
||||
|
||||
if (runAsUser != null)
|
||||
{
|
||||
// There is a @Test method username.
|
||||
log.debug("Running as method annotation-provided user: " + runAsUser);
|
||||
log.debug(" See " + description.getClassName() + "." + description.getMethodName());
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is no @Test method username, so fall back to rule-provided person.
|
||||
if (fixedUserName != null)
|
||||
{
|
||||
runAsUser = fixedUserName;
|
||||
log.debug("Running as username defined in this rule: " + runAsUser);
|
||||
}
|
||||
else if (personRule != null)
|
||||
{
|
||||
runAsUser = personRule.getUsername();
|
||||
log.debug("Running as username provided by another rule: " + runAsUser);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Illegal rule: must provide username or " +
|
||||
AlfrescoPerson.class.getSimpleName() + " at rule construction or else a " +
|
||||
RunAsUser.class.getSimpleName() + " annotation.");
|
||||
}
|
||||
}
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(runAsUser);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// Execute the test method or whatever other rules are configured further down the stack.
|
||||
base.evaluate();
|
||||
}
|
||||
finally
|
||||
{
|
||||
// After - ensure that pass or fail, the authentication is restored.
|
||||
AuthenticationUtil.popAuthentication();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param description the description object from JUnit
|
||||
* @return the username specified in the {@link RunAsUser} annotation, if there was one, else <code>null</code>.
|
||||
*/
|
||||
private String getMethodAnnotatedUserName(Description description) throws IllegalArgumentException,
|
||||
SecurityException, IllegalAccessException,
|
||||
InvocationTargetException, NoSuchMethodException
|
||||
{
|
||||
String result = null;
|
||||
|
||||
Collection<Annotation> annotations = description.getAnnotations();
|
||||
for (Annotation anno : annotations)
|
||||
{
|
||||
if (anno.annotationType().equals(RunAsUser.class))
|
||||
{
|
||||
result = (String) anno.annotationType().getMethod("userName").invoke(anno);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A JUnit rule designed to help with the automatic revert of test objects with mocked fields.
|
||||
* This is intended to be used when writing test code and you wish to set a mock object on a spring singleton bean.
|
||||
* By mocking out fields on spring singletons beans, if you don't remember to revert them to their original values, then
|
||||
* any subsequent tests that expect to see 'proper' services plugged in, may fail when they are instead given a mock.
|
||||
*
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // Declare the rule.
|
||||
* @Rule public final TemporaryMockOverride mockOverride = new TemporaryMockOverride();
|
||||
*
|
||||
* @Test public void aTestMethod()
|
||||
* {
|
||||
* // Get a singleton bean from the spring context
|
||||
* FooService fooService = appContext.getBean("fooService", FooService.class);
|
||||
*
|
||||
* // Create a mocked service (this uses Mockito, but that's not required for this rule to work)
|
||||
* BarService mockedBarService = mock(BarService.class);
|
||||
*
|
||||
* // Don't do this as you're just replacing the original barService: fooService.setBarService(mockedBarService);
|
||||
* // Instead do this:
|
||||
* mockOverride.setTemporaryField(fooService, barService, mockedBarService);
|
||||
*
|
||||
* // Go ahead and use the FooService in test code, whilst relying on a mocked BarService behind it.
|
||||
* // After the rule has completed, the original BarService which spring injected into the FooService will be reset.
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class TemporaryMockOverride extends ExternalResource
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(TemporaryMockOverride.class);
|
||||
|
||||
private List<FieldValueOverride> pristineFieldValues = new ArrayList<FieldValueOverride>();
|
||||
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
// For all objects that have been tampered with, we'll revert them to their original state.
|
||||
for (int i = pristineFieldValues.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
FieldValueOverride override = pristineFieldValues.get(i);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Reverting mocked field '" + override.fieldName + "' on object " + override.objectContainingField + " to original value '" + override.fieldPristineValue + "'");
|
||||
}
|
||||
|
||||
// Hack into the Java field object
|
||||
Field f = ReflectionUtils.findField(override.objectContainingField.getClass(), override.fieldName);
|
||||
ReflectionUtils.makeAccessible(f);
|
||||
// and revert its value.
|
||||
ReflectionUtils.setField(f, override.objectContainingField, override.fieldPristineValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTemporaryField(Object objectContainingField, String fieldName, Object fieldValue)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Overriding field '" + fieldName + "' on object " + objectContainingField + " to new value '" + fieldValue + "'");
|
||||
}
|
||||
|
||||
// Extract the pristine value of the field we're going to mock.
|
||||
Field f = ReflectionUtils.findField(objectContainingField.getClass(), fieldName);
|
||||
|
||||
if (f == null)
|
||||
{
|
||||
final String msg = "Object of type '" + objectContainingField.getClass().getSimpleName() + "' has no field named '" + fieldName + "'";
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug(msg);
|
||||
}
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
ReflectionUtils.makeAccessible(f);
|
||||
Object pristineValue = ReflectionUtils.getField(f, objectContainingField);
|
||||
|
||||
// and add it to the list.
|
||||
pristineFieldValues.add(new FieldValueOverride(objectContainingField, fieldName, pristineValue));
|
||||
|
||||
// and set it on the object
|
||||
ReflectionUtils.setField(f, objectContainingField, fieldValue);
|
||||
}
|
||||
|
||||
private static class FieldValueOverride
|
||||
{
|
||||
public FieldValueOverride(Object objectContainingField, String fieldName, Object pristineValue)
|
||||
{
|
||||
this.objectContainingField = objectContainingField;
|
||||
this.fieldName = fieldName;
|
||||
this.fieldPristineValue = pristineValue;
|
||||
}
|
||||
|
||||
public final Object objectContainingField;
|
||||
public final String fieldName;
|
||||
public final Object fieldPristineValue;
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 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.util.test.junitrules;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class for {@link TemporaryMockOverride}.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @since Odin
|
||||
*/
|
||||
public class TemporaryMockOverrideTest
|
||||
{
|
||||
private static final String REAL_DATA = "Hello";
|
||||
private static final String MOCKED_DATA = "--";
|
||||
|
||||
private final FooService realFooService = new FooServiceImpl();
|
||||
private final BarService realBarService = new BarServiceImpl();
|
||||
private final AbcService realAbcService = new AbcServiceImpl();
|
||||
|
||||
@Before public void init()
|
||||
{
|
||||
FooServiceImpl fooServiceImpl = (FooServiceImpl)realFooService;
|
||||
fooServiceImpl.setBarService(realBarService);
|
||||
fooServiceImpl.setAbcService(realAbcService);
|
||||
}
|
||||
|
||||
@Test public void mockFieldsWithinServiceAndThenEnsureTheProperFieldValuesAreRestoredAfterCleanup() throws Throwable
|
||||
{
|
||||
TemporaryMockOverride mockRule = new TemporaryMockOverride();
|
||||
mockRule.before();
|
||||
|
||||
assertEquals("Original BarService giving wrong data.", REAL_DATA, realFooService.getBarService().getString());
|
||||
assertEquals("Original AbcService giving wrong data.", REAL_DATA, realFooService.getAbcService().getString());
|
||||
|
||||
BarService mockedBarService = mock(BarService.class);
|
||||
when(mockedBarService.getString()).thenReturn(MOCKED_DATA);
|
||||
|
||||
AbcService mockedAbcService = mock(AbcService.class);
|
||||
when(mockedAbcService.getString()).thenReturn(MOCKED_DATA);
|
||||
|
||||
FooServiceImpl fooServiceWithMockedServices = new FooServiceImpl();
|
||||
// We'll start it off with the 'correct' values
|
||||
fooServiceWithMockedServices.setBarService(realBarService);
|
||||
fooServiceWithMockedServices.setAbcService(realAbcService);
|
||||
|
||||
// ...and then set the mocked values via the rule, which will remember the old values and revert them for us automatically.
|
||||
mockRule.setTemporaryField(fooServiceWithMockedServices, "barService", mockedBarService);
|
||||
mockRule.setTemporaryField(fooServiceWithMockedServices, "abcService", mockedAbcService);
|
||||
|
||||
|
||||
assertEquals("Mocked BarService giving wrong data.", MOCKED_DATA, fooServiceWithMockedServices.getBarService().getString());
|
||||
assertEquals("Mocked AbcService giving wrong data.", MOCKED_DATA, fooServiceWithMockedServices.getAbcService().getString());
|
||||
|
||||
mockRule.after();
|
||||
|
||||
// Now it should all be magically reverted.
|
||||
assertEquals("BarService giving wrong data.", REAL_DATA, fooServiceWithMockedServices.getBarService().getString());
|
||||
assertEquals("AbcService giving wrong data.", REAL_DATA, fooServiceWithMockedServices.getAbcService().getString());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class) public void mockNonExistentFieldsWithinService() throws Throwable
|
||||
{
|
||||
TemporaryMockOverride mockRule = new TemporaryMockOverride();
|
||||
mockRule.before();
|
||||
|
||||
assertEquals("Original BarService giving wrong data.", REAL_DATA, realFooService.getBarService().getString());
|
||||
|
||||
BarService mockedBarService = mock(BarService.class);
|
||||
when(mockedBarService.getString()).thenReturn(MOCKED_DATA);
|
||||
|
||||
FooServiceImpl fooServiceWithMockedServices = new FooServiceImpl();
|
||||
// We'll start it off with the 'correct' values
|
||||
fooServiceWithMockedServices.setBarService(realBarService);
|
||||
|
||||
// ...and then set an illegal mocked value via the rule.
|
||||
mockRule.setTemporaryField(fooServiceWithMockedServices, "noSuchService", mockedBarService);
|
||||
|
||||
|
||||
assertEquals("Mocked BarService giving wrong data.", MOCKED_DATA, fooServiceWithMockedServices.getBarService().getString());
|
||||
|
||||
mockRule.after();
|
||||
|
||||
// Now it should all be magically reverted.
|
||||
assertEquals("BarService giving wrong data.", REAL_DATA, fooServiceWithMockedServices.getBarService().getString());
|
||||
}
|
||||
|
||||
public interface FooService { public BarService getBarService(); public AbcService getAbcService(); }
|
||||
|
||||
public class FooServiceImpl implements FooService
|
||||
{
|
||||
private BarService barService;
|
||||
private AbcService abcService;
|
||||
|
||||
public BarService getBarService() { return this.barService; }
|
||||
public void setBarService(BarService barService) { this.barService = barService; }
|
||||
public AbcService getAbcService() { return this.abcService; }
|
||||
public void setAbcService(AbcService abcService) { this.abcService = abcService; }
|
||||
}
|
||||
|
||||
public interface BarService { public String getString(); }
|
||||
|
||||
public class BarServiceImpl implements BarService { public String getString() { return REAL_DATA; } }
|
||||
|
||||
public interface AbcService { public String getString(); }
|
||||
|
||||
public class AbcServiceImpl implements AbcService { public String getString() { return REAL_DATA; } }
|
||||
}
|
||||
|
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
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.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* A JUnit rule designed to help with the automatic cleanup of temporary models and to make it easier to
|
||||
* create common test models with JUnit code.
|
||||
*
|
||||
* @author Alex Miller
|
||||
* @since 4.2
|
||||
*/
|
||||
public class TemporaryModels extends ExternalResource
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(TemporaryModels.class);
|
||||
|
||||
private final ApplicationContextInit appContextRule;
|
||||
|
||||
private final Set<QName> loadedModels = new HashSet<QName>();
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
*/
|
||||
public TemporaryModels(ApplicationContextInit appContextRule)
|
||||
{
|
||||
this.appContextRule = appContextRule;
|
||||
}
|
||||
|
||||
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
final RetryingTransactionHelper transactionHelper = getTransactionHelper();
|
||||
final DictionaryDAO dictionaryDAO = getDictionaryDAO();
|
||||
|
||||
// Run as system to ensure all non-system nodes can be deleted irrespective of which user created them.
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
@Override public Void doWork() throws Exception
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
for (QName model : loadedModels)
|
||||
{
|
||||
dictionaryDAO.removeModel(model);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
|
||||
private RetryingTransactionHelper getTransactionHelper() {
|
||||
final ApplicationContext springContext = appContextRule.getApplicationContext();
|
||||
|
||||
final RetryingTransactionHelper transactionHelper = springContext.getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
return transactionHelper;
|
||||
}
|
||||
|
||||
public QName loadModel(String modelPath, ClassLoader classLoader)
|
||||
{
|
||||
InputStream modelStream = classLoader.getResourceAsStream(modelPath);
|
||||
if (modelStream == null)
|
||||
{
|
||||
throw new DictionaryException("Could not find bootstrap model " + modelPath);
|
||||
}
|
||||
try
|
||||
{
|
||||
return loadModel(modelStream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
modelStream.close();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
logger.warn("Failed to close model input stream for '"+modelPath+"': "+ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QName loadModel(InputStream modelStream)
|
||||
{
|
||||
try
|
||||
{
|
||||
final M2Model model = M2Model.createModel(modelStream);
|
||||
|
||||
return loadModel(model);
|
||||
}
|
||||
catch(DictionaryException e)
|
||||
{
|
||||
throw new DictionaryException("Could not import model", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private QName loadModel(final M2Model model) {
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Loading model: "+model.getName());
|
||||
}
|
||||
|
||||
final DictionaryDAO dictionaryDAO = getDictionaryDAO();
|
||||
QName modelQName = dictionaryDAO.putModel(model);
|
||||
loadedModels.add(modelQName);
|
||||
return modelQName;
|
||||
}
|
||||
|
||||
|
||||
private DictionaryDAO getDictionaryDAO() {
|
||||
final ApplicationContext springContext = appContextRule.getApplicationContext();
|
||||
|
||||
DictionaryDAO dictionaryDAO = springContext.getBean("dictionaryDAO", DictionaryDAO.class);
|
||||
return dictionaryDAO;
|
||||
}
|
||||
}
|
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
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.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* A JUnit rule designed to help with the automatic cleanup of temporary test nodes and to ake it easier to
|
||||
* create common test content with JUnit code.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since 4.1
|
||||
*/
|
||||
public class TemporaryNodes extends ExternalResource
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(TemporaryNodes.class);
|
||||
|
||||
private final ApplicationContextInit appContextRule;
|
||||
private List<NodeRef> temporaryNodeRefs = new ArrayList<NodeRef>();
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
*/
|
||||
public TemporaryNodes(ApplicationContextInit appContextRule)
|
||||
{
|
||||
this.appContextRule = appContextRule;
|
||||
}
|
||||
|
||||
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
final ApplicationContext springContext = appContextRule.getApplicationContext();
|
||||
|
||||
final RetryingTransactionHelper transactionHelper = springContext.getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
final CheckOutCheckInService cociService = springContext.getBean("CheckOutCheckInService", CheckOutCheckInService.class);
|
||||
final DictionaryService dictionaryService = springContext.getBean("DictionaryService", DictionaryService.class);
|
||||
final NodeService nodeService = springContext.getBean("NodeService", NodeService.class);
|
||||
final SiteService siteService = springContext.getBean("SiteService", SiteService.class);
|
||||
|
||||
// Run as system to ensure all non-system nodes can be deleted irrespective of which user created them.
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
@Override public Void doWork() throws Exception
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
// Although we loop through all nodes, this is a cascade-delete and so we may only need to delete the first node.
|
||||
for (NodeRef node : temporaryNodeRefs)
|
||||
{
|
||||
// If it's already been deleted, don't worry about it.
|
||||
if (nodeService.exists(node))
|
||||
{
|
||||
// If it has been checked out, cancel the checkout before deletion.
|
||||
if (cociService.isCheckedOut(node))
|
||||
{
|
||||
log.debug("Cancelling checkout of temporary node " + nodeService.getProperty(node, ContentModel.PROP_NAME));
|
||||
NodeRef workingCopy = cociService.getWorkingCopy(node);
|
||||
cociService.cancelCheckout(workingCopy);
|
||||
}
|
||||
log.debug("Deleting temporary node " + nodeService.getProperty(node, ContentModel.PROP_NAME));
|
||||
|
||||
// Site nodes are a special case which must be deleted through the SiteService.
|
||||
final QName nodeType = nodeService.getType(node);
|
||||
if (nodeType.equals(SiteModel.TYPE_SITE) || dictionaryService.isSubClass(nodeType, SiteModel.TYPE_SITE))
|
||||
{
|
||||
SiteInfo siteInfo = siteService.getSite(node);
|
||||
siteService.deleteSite(siteInfo.getShortName());
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeService.deleteNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a specified NodeRef to the list of NodeRefs to be deleted by this rule.
|
||||
*
|
||||
* @param temporaryNodeRef a NodeRef
|
||||
*/
|
||||
public void addNodeRef(NodeRef temporaryNodeRef)
|
||||
{
|
||||
this.temporaryNodeRefs.add(temporaryNodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a NodeRef and adds it to the internal list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the cm:creator of the new node.
|
||||
*
|
||||
* @param parentNode the parent node
|
||||
* @param nodeCmName the cm:name of the new node
|
||||
* @param nodeType the type of the new node
|
||||
* @param nodeCreator the username of the person who will create the node
|
||||
* @return the newly created NodeRef.
|
||||
*/
|
||||
public NodeRef createNode(final NodeRef parentNode, final String nodeCmName, final QName nodeType, final String nodeCreator)
|
||||
{
|
||||
return this.createNodeWithTextContent(parentNode, nodeCmName, nodeType, nodeCreator, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a NodeRef with some text/plain, UTF-8 content and adds it to the internal list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the cm:creator of the new node.
|
||||
*
|
||||
* @param parentNode the parent node
|
||||
* @param nodeCmName the cm:name of the new node
|
||||
* @param nodeType the type of the new node
|
||||
* @param nodeCreator the username of the person who will create the node
|
||||
* @param textContent the text/plain, UTF-8 content that will be stored in the node's content. <code>null</code> content will not be written.
|
||||
* @return the newly created NodeRef.
|
||||
*/
|
||||
public NodeRef createNodeWithTextContent(final NodeRef parentNode, final String nodeCmName, final QName nodeType, final String nodeCreator, final String textContent)
|
||||
{
|
||||
QName childName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, nodeCmName);
|
||||
return createNodeWithTextContent(parentNode, childName, nodeCmName, nodeType, nodeCreator, textContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a NodeRef with some text/plain, UTF-8 content and adds it to the internal list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the cm:creator of the new node.
|
||||
*
|
||||
* @param parentNode the parent node
|
||||
* @param nodeCmName the cm:name of the new node
|
||||
* @param nodeType the type of the new node
|
||||
* @param nodeCreator the username of the person who will create the node
|
||||
* @param textContent the text/plain, UTF-8 content that will be stored in the node's content. <code>null</code> content will not be written.
|
||||
* @return the newly created NodeRef.
|
||||
*/
|
||||
public NodeRef createNodeWithTextContent(final NodeRef parentNode, final QName childName, final String nodeCmName, final QName nodeType, final String nodeCreator, final String textContent)
|
||||
{
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper");
|
||||
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(nodeCreator);
|
||||
|
||||
NodeRef newNodeRef = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
final NodeService nodeService = (NodeService) appContextRule.getApplicationContext().getBean("nodeService");
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, nodeCmName);
|
||||
ChildAssociationRef childAssoc = nodeService.createNode(parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
childName,
|
||||
nodeType,
|
||||
props);
|
||||
|
||||
// If there is any content, add it.
|
||||
if (textContent != null)
|
||||
{
|
||||
ContentService contentService = appContextRule.getApplicationContext().getBean("contentService", ContentService.class);
|
||||
ContentWriter writer = contentService.getWriter(childAssoc.getChildRef(), ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
||||
writer.setEncoding("UTF-8");
|
||||
writer.putContent(textContent);
|
||||
}
|
||||
return childAssoc.getChildRef();
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.popAuthentication();
|
||||
|
||||
this.temporaryNodeRefs.add(newNodeRef);
|
||||
return newNodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a cm:folder NodeRef and adds it to the internal list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the cm:creator of the new node.
|
||||
*
|
||||
* @param parentNode the parent node
|
||||
* @param nodeCmName the cm:name of the new node
|
||||
* @param nodeCreator the username of the person who will create the node
|
||||
* @return the newly created NodeRef.
|
||||
*/
|
||||
public NodeRef createFolder(final NodeRef parentNode, final String nodeCmName, final String nodeCreator)
|
||||
{
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper");
|
||||
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(nodeCreator);
|
||||
|
||||
NodeRef newNodeRef = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
final NodeRef result = createNode(nodeCmName, parentNode, ContentModel.TYPE_FOLDER);
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.popAuthentication();
|
||||
|
||||
this.temporaryNodeRefs.add(newNodeRef);
|
||||
return newNodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a cm:content NodeRef whose content is taken from an Alfresco 'quick' file and adds it to the internal
|
||||
* list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the cm:creator of the new node.
|
||||
*
|
||||
* @param mimetype the MimeType of the content to put in the new node.
|
||||
* @param parentNode the parent node
|
||||
* @param nodeCmName the cm:name of the new node
|
||||
* @param nodeCreator the username of the person who will create the node
|
||||
* @return the newly created NodeRef.
|
||||
*/
|
||||
public NodeRef createQuickFile(final String mimetype, final NodeRef parentNode, final String nodeCmName, final String nodeCreator)
|
||||
{
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper");
|
||||
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(nodeCreator);
|
||||
|
||||
NodeRef newNodeRef = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
final NodeRef result = createNode(nodeCmName, parentNode, ContentModel.TYPE_CONTENT);
|
||||
|
||||
File quickFile = loadQuickFile(getQuickResource(mimetype));
|
||||
|
||||
ContentService contentService = appContextRule.getApplicationContext().getBean("contentService", ContentService.class);
|
||||
ContentWriter writer = contentService.getWriter(result, ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(mimetype);
|
||||
writer.setEncoding("UTF-8");
|
||||
writer.putContent(quickFile);
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.popAuthentication();
|
||||
|
||||
this.temporaryNodeRefs.add(newNodeRef);
|
||||
return newNodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a cm:content NodeRef whose content is taken from the named Alfresco 'quick' file and adds it to the internal
|
||||
* list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the cm:creator of the new node.
|
||||
*
|
||||
* @param parentNode the parent node
|
||||
* @param nodeCmName the file name of the quick file - will also be the cm:name of the new node.
|
||||
* @param nodeCreator the username of the person who will create the node
|
||||
* @return the newly created NodeRef.
|
||||
* @since 4.1.4
|
||||
*/
|
||||
public NodeRef createQuickFileByName(final String quickFileName, final NodeRef parentNode, final String nodeCreator)
|
||||
{
|
||||
final MimetypeMap mimetypeService = (MimetypeMap) appContextRule.getApplicationContext().getBean("mimetypeService");
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper");
|
||||
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(nodeCreator);
|
||||
|
||||
NodeRef newNodeRef = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
final NodeRef result = createNode(quickFileName, parentNode, ContentModel.TYPE_CONTENT);
|
||||
|
||||
File quickFile = loadQuickFile(quickFileName);
|
||||
|
||||
ContentService contentService = appContextRule.getApplicationContext().getBean("contentService", ContentService.class);
|
||||
ContentWriter writer = contentService.getWriter(result, ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(mimetypeService.guessMimetype(quickFileName));
|
||||
writer.setEncoding("UTF-8");
|
||||
writer.putContent(quickFile);
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.popAuthentication();
|
||||
|
||||
this.temporaryNodeRefs.add(newNodeRef);
|
||||
return newNodeRef;
|
||||
}
|
||||
|
||||
private NodeRef createNode(String cmName, NodeRef parentNode, QName nodeType)
|
||||
{
|
||||
final NodeService nodeService = (NodeService) appContextRule.getApplicationContext().getBean("nodeService");
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, cmName);
|
||||
ChildAssociationRef childAssoc = nodeService.createNode(parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
nodeType,
|
||||
props);
|
||||
|
||||
return childAssoc.getChildRef();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource name for the Alfresco 'quick file' associated with the given mime type.
|
||||
* @param mimetype the MIME type e.g. {@link MimetypeMap#MIMETYPE_IMAGE_JPEG}
|
||||
* @return the resource path e.g. "quick/quick.jpg"
|
||||
*/
|
||||
private String getQuickResource(String mimetype)
|
||||
{
|
||||
final MimetypeMap mimetypeService = (MimetypeMap) appContextRule.getApplicationContext().getBean("mimetypeService");
|
||||
final String extension = mimetypeService.getExtension(mimetype);
|
||||
|
||||
if (extension == null)
|
||||
{
|
||||
throw new UnsupportedOperationException("No 'quick' file for unrecognised mimetype: " + mimetype);
|
||||
}
|
||||
|
||||
return "quick." + extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource name for the named Alfresco 'quick file'.
|
||||
*
|
||||
* @param quickFileName e.g. "quickGEO.jpg"
|
||||
* @return the resource path e.g. "quick/quickGEO.jpg"
|
||||
*/
|
||||
private String getNamedQuickResource(String quickFileName)
|
||||
{
|
||||
return "quick/" + quickFileName;
|
||||
}
|
||||
|
||||
private File loadQuickFile(String quickfile)
|
||||
{
|
||||
final String quickResource = getNamedQuickResource(quickfile);
|
||||
|
||||
URL url = AbstractContentTransformerTest.class.getClassLoader().getResource(quickResource);
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
throw new UnsupportedOperationException("No 'quick' file for file: " + quickResource);
|
||||
}
|
||||
File file = new File(url.getFile());
|
||||
if (!file.exists())
|
||||
{
|
||||
throw new UnsupportedOperationException("No 'quick' file for file: " + quickResource);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 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.util.test.junitrules;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.cmr.site.SiteVisibility;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.RuleChain;
|
||||
|
||||
/**
|
||||
* Test class for {@link TemporaryNodes}.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since 4.1
|
||||
*/
|
||||
public class TemporaryNodesTest
|
||||
{
|
||||
// Rule to initialise the default Alfresco spring configuration
|
||||
public static ApplicationContextInit APP_CONTEXT_INIT = new ApplicationContextInit();
|
||||
|
||||
// Rules to create test users.
|
||||
public static AlfrescoPerson TEST_USER1 = new AlfrescoPerson(APP_CONTEXT_INIT, "UserOne");
|
||||
public static AlfrescoPerson TEST_USER2 = new AlfrescoPerson(APP_CONTEXT_INIT, "UserTwo");
|
||||
|
||||
// A rule to manage test nodes reused across all the test methods
|
||||
public static TemporaryNodes STATIC_TEST_NODES = new TemporaryNodes(APP_CONTEXT_INIT);
|
||||
|
||||
// Tie them together in a static Rule Chain
|
||||
@ClassRule public static RuleChain ruleChain = RuleChain.outerRule(APP_CONTEXT_INIT)
|
||||
.around(TEST_USER1)
|
||||
.around(TEST_USER2)
|
||||
.around(STATIC_TEST_NODES);
|
||||
|
||||
// A rule to manage test nodes use in each test method
|
||||
@Rule public TemporaryNodes testNodes = new TemporaryNodes(APP_CONTEXT_INIT);
|
||||
|
||||
// A rule to allow individual test methods all to be run as "admin".
|
||||
@Rule public RunAsFullyAuthenticatedRule runAsRule = new RunAsFullyAuthenticatedRule(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// Various services
|
||||
private static CheckOutCheckInService COCI_SERVICE;
|
||||
private static ContentService CONTENT_SERVICE;
|
||||
private static NodeService NODE_SERVICE;
|
||||
private static SiteService SITE_SERVICE;
|
||||
private static RetryingTransactionHelper TRANSACTION_HELPER;
|
||||
|
||||
private static NodeRef COMPANY_HOME;
|
||||
|
||||
// These NodeRefs are used by the test methods.
|
||||
private NodeRef testNode1, testNode2;
|
||||
|
||||
@BeforeClass public static void initStaticData() throws Exception
|
||||
{
|
||||
COCI_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("checkOutCheckInService", CheckOutCheckInService.class);
|
||||
CONTENT_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("contentService", ContentService.class);
|
||||
NODE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("nodeService", NodeService.class);
|
||||
SITE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("siteService", SiteService.class);
|
||||
TRANSACTION_HELPER = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
|
||||
Repository repositoryHelper = APP_CONTEXT_INIT.getApplicationContext().getBean("repositoryHelper", Repository.class);
|
||||
COMPANY_HOME = repositoryHelper.getCompanyHome();
|
||||
}
|
||||
|
||||
@Before public void createTestContent()
|
||||
{
|
||||
// Create some test content
|
||||
testNode1 = testNodes.createNode(COMPANY_HOME, "doc 1", ContentModel.TYPE_CONTENT, TEST_USER1.getUsername());
|
||||
testNode2 = testNodes.createNodeWithTextContent(COMPANY_HOME, "doc 2", ContentModel.TYPE_CONTENT, TEST_USER2.getUsername(), "Hello world");
|
||||
}
|
||||
|
||||
@Test public void ensureTestNodesWereCreatedOk() throws Exception
|
||||
{
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertTrue("Test node does not exist", NODE_SERVICE.exists(testNode1));
|
||||
assertTrue("Test node does not exist", NODE_SERVICE.exists(testNode2));
|
||||
|
||||
Map<QName, Serializable> node1Props = NODE_SERVICE.getProperties(testNode1);
|
||||
Map<QName, Serializable> node2Props = NODE_SERVICE.getProperties(testNode2);
|
||||
|
||||
// name
|
||||
assertEquals("cm:name was wrong", "doc 1", node1Props.get(ContentModel.PROP_NAME));
|
||||
assertEquals("cm:name was wrong", "doc 2", node2Props.get(ContentModel.PROP_NAME));
|
||||
|
||||
// creator
|
||||
assertEquals("cm:creator was wrong", TEST_USER1.getUsername(), node1Props.get(ContentModel.PROP_CREATOR));
|
||||
assertEquals("cm:creator was wrong", TEST_USER2.getUsername(), node2Props.get(ContentModel.PROP_CREATOR));
|
||||
|
||||
// content
|
||||
ContentReader reader = CONTENT_SERVICE.getReader(testNode1, ContentModel.PROP_CONTENT);
|
||||
assertNull("Content was unexpectedly present", reader);
|
||||
|
||||
reader = CONTENT_SERVICE.getReader(testNode2, ContentModel.PROP_CONTENT);
|
||||
assertEquals("Content was wrong", "Hello world", reader.getContentString("Hello world".length()));
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test public void ensureCheckedOutNodesAreCleanedUp() throws Throwable
|
||||
{
|
||||
// Note that because we need to test that the Rule's 'after' behaviour has worked correctly, we cannot
|
||||
// use the Rule that has been declared in the normal way - otherwise nothing would be cleaned up until
|
||||
// after our test method.
|
||||
// Therefore we have to manually poke the Rule to get it to cleanup during test execution.
|
||||
// NOTE! This is *not* how a JUnit Rule would normally be used.
|
||||
TemporaryNodes myTemporaryNodes = new TemporaryNodes(APP_CONTEXT_INIT);
|
||||
|
||||
// Currently this is a no-op, but just in case that changes.
|
||||
myTemporaryNodes.before();
|
||||
|
||||
|
||||
// Create some test nodes.
|
||||
final List<NodeRef> nodesThatShouldBeDeletedByRule = new ArrayList<NodeRef>();
|
||||
|
||||
nodesThatShouldBeDeletedByRule.add(myTemporaryNodes.createNode(COMPANY_HOME, "normal node", ContentModel.TYPE_CONTENT, TEST_USER1.getUsername()));
|
||||
final NodeRef checkedoutNode = myTemporaryNodes.createNode(COMPANY_HOME, "checkedout node", ContentModel.TYPE_CONTENT, TEST_USER1.getUsername());
|
||||
nodesThatShouldBeDeletedByRule.add(checkedoutNode);
|
||||
|
||||
// and check one of them out.
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
NodeRef workingCopy = COCI_SERVICE.checkout(checkedoutNode);
|
||||
|
||||
// Ensure that the working copy is cleaned up too.
|
||||
nodesThatShouldBeDeletedByRule.add(workingCopy);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Now trigger the Rule's cleanup behaviour.
|
||||
myTemporaryNodes.after();
|
||||
|
||||
// and ensure that the nodes are all gone.
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
for (NodeRef node : nodesThatShouldBeDeletedByRule)
|
||||
{
|
||||
if (NODE_SERVICE.exists(node))
|
||||
{
|
||||
fail("Node '" + NODE_SERVICE.getProperty(node, ContentModel.PROP_NAME) + "' still exists.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Site nodes are a special case as they can only be deleted through the SiteService. */
|
||||
@Test public void ensureSiteNodesAreCleanedUp() throws Throwable
|
||||
{
|
||||
// Note that because we need to test that the Rule's 'after' behaviour has worked correctly, we cannot
|
||||
// use the Rule that has been declared in the normal way - otherwise nothing would be cleaned up until
|
||||
// after our test method.
|
||||
// Therefore we have to manually poke the Rule to get it to cleanup during test execution.
|
||||
// NOTE! This is *not* how a JUnit Rule would normally be used.
|
||||
TemporaryNodes myTemporaryNodes = new TemporaryNodes(APP_CONTEXT_INIT);
|
||||
|
||||
// Currently this is a no-op, but just in case that changes.
|
||||
myTemporaryNodes.before();
|
||||
|
||||
|
||||
// and ensure that the site node is gone.
|
||||
SiteInfo createdSite = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<SiteInfo>()
|
||||
{
|
||||
public SiteInfo execute() throws Throwable
|
||||
{
|
||||
return SITE_SERVICE.createSite("sitePreset", "siteShortName", "site title", "site description", SiteVisibility.PUBLIC);
|
||||
}
|
||||
});
|
||||
final NodeRef siteNodeRef = createdSite.getNodeRef();
|
||||
myTemporaryNodes.addNodeRef(siteNodeRef);
|
||||
|
||||
// Now trigger the Rule's cleanup behaviour.
|
||||
myTemporaryNodes.after();
|
||||
|
||||
// and ensure that the site node is gone.
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
if (NODE_SERVICE.exists(siteNodeRef))
|
||||
{
|
||||
fail("Node '" + NODE_SERVICE.getProperty(siteNodeRef, ContentModel.PROP_NAME) + "' still exists.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test public void testCreateFolderAndQuickFiles() throws Throwable
|
||||
{
|
||||
// Note that because we need to test that the Rule's 'after' behaviour has worked correctly, we cannot
|
||||
// use the Rule that has been declared in the normal way - otherwise nothing would be cleaned up until
|
||||
// after our test method.
|
||||
// Therefore we have to manually poke the Rule to get it to cleanup during test execution.
|
||||
// NOTE! This is *not* how a JUnit Rule would normally be used.
|
||||
TemporaryNodes myTemporaryNodes = new TemporaryNodes(APP_CONTEXT_INIT);
|
||||
|
||||
// Currently this is a no-op, but just in case that changes.
|
||||
myTemporaryNodes.before();
|
||||
|
||||
|
||||
|
||||
// Create the temporary nodes relevant for this test.
|
||||
//
|
||||
// Create a target folder
|
||||
final NodeRef folder = myTemporaryNodes.createFolder(COMPANY_HOME, "testFolder", AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// create a normal 'quick' node under it.
|
||||
final NodeRef quickTxt = myTemporaryNodes.createQuickFile(MimetypeMap.MIMETYPE_TEXT_PLAIN, folder, "quickFile", AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// create a named 'quick' node under it.
|
||||
final NodeRef namedQuickTxt = myTemporaryNodes.createQuickFileByName("quickCorrupt.jpg", folder, AuthenticationUtil.getAdminUserName());
|
||||
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Check the nodes were created ok
|
||||
assertTrue(NODE_SERVICE.exists(folder));
|
||||
assertTrue(NODE_SERVICE.exists(quickTxt));
|
||||
assertTrue(NODE_SERVICE.exists(namedQuickTxt));
|
||||
|
||||
assertEquals(ContentModel.TYPE_FOLDER, NODE_SERVICE.getType(folder));
|
||||
assertEquals(ContentModel.TYPE_CONTENT, NODE_SERVICE.getType(quickTxt));
|
||||
assertEquals(ContentModel.TYPE_CONTENT, NODE_SERVICE.getType(namedQuickTxt));
|
||||
|
||||
assertEquals(AuthenticationUtil.getAdminUserName(), NODE_SERVICE.getProperty(folder, ContentModel.PROP_CREATOR));
|
||||
assertEquals(AuthenticationUtil.getAdminUserName(), NODE_SERVICE.getProperty(quickTxt, ContentModel.PROP_CREATOR));
|
||||
assertEquals(AuthenticationUtil.getAdminUserName(), NODE_SERVICE.getProperty(namedQuickTxt, ContentModel.PROP_CREATOR));
|
||||
|
||||
ContentReader reader = CONTENT_SERVICE.getReader(quickTxt, ContentModel.PROP_CONTENT);
|
||||
assertEquals(MimetypeMap.MIMETYPE_TEXT_PLAIN, reader.getMimetype());
|
||||
|
||||
assertEquals(235, reader.getSize()); // 235 chars in the quick.txt file
|
||||
final String content = reader.getContentString();
|
||||
assertTrue(content.contains("quick brown fox"));
|
||||
|
||||
ContentReader reader2 = CONTENT_SERVICE.getReader(namedQuickTxt, ContentModel.PROP_CONTENT);
|
||||
assertEquals(MimetypeMap.MIMETYPE_IMAGE_JPEG, reader2.getMimetype());
|
||||
// No checks on the actual content.
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Now trigger the Rule's cleanup behaviour.
|
||||
myTemporaryNodes.after();
|
||||
|
||||
// and ensure that the temporary nodes are gone.
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertFalse(NODE_SERVICE.exists(folder));
|
||||
assertFalse(NODE_SERVICE.exists(quickTxt));
|
||||
assertFalse(NODE_SERVICE.exists(namedQuickTxt));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.cmr.site.SiteVisibility;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.webscripts.GUID;
|
||||
|
||||
/**
|
||||
* A JUnit rule designed to help with the automatic cleanup of temporary st:site nodes.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public class TemporarySites extends AbstractPersonRule
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(TemporarySites.class);
|
||||
|
||||
private List<SiteInfo> temporarySites = new ArrayList<SiteInfo>();
|
||||
private List<String> temporarySiteUsers = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
*/
|
||||
public TemporarySites(ApplicationContextInit appContextRule)
|
||||
{
|
||||
super(appContextRule);
|
||||
}
|
||||
|
||||
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper");
|
||||
final SiteService siteService = appContextRule.getApplicationContext().getBean("siteService", SiteService.class);
|
||||
|
||||
// Run as admin to ensure all sites can be deleted irrespective of which user created them.
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
@Override public Void doWork() throws Exception
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override public Void execute() throws Throwable
|
||||
{
|
||||
for (SiteInfo site : temporarySites)
|
||||
{
|
||||
final String shortName = site.getShortName();
|
||||
if (siteService.getSite(shortName) != null)
|
||||
{
|
||||
log.debug("Deleting temporary site " + shortName);
|
||||
siteService.deleteSite(shortName);
|
||||
}
|
||||
}
|
||||
|
||||
for (String username : temporarySiteUsers)
|
||||
{
|
||||
log.debug("Deleting temporary site user " + username);
|
||||
deletePerson(username);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getAdminUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a specified site to the list of SiteInfos to be deleted by this rule.
|
||||
*
|
||||
* @param temporarySite a SiteInfo
|
||||
*/
|
||||
public void addSite(SiteInfo temporarySite)
|
||||
{
|
||||
this.temporarySites.add(temporarySite);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a Share Site and adds it to the internal list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the creator of the new site.
|
||||
*
|
||||
* @param sitePreset the site preset
|
||||
* @param siteShortName the short name of the new site
|
||||
* @param siteTitle the title of the new site
|
||||
* @param siteDescription the description of the new site
|
||||
* @param visibility the visibility
|
||||
* @param siteCreator the username of the person who will create the site
|
||||
* @return the newly created SiteInfo (will be of type st:site).
|
||||
*/
|
||||
public SiteInfo createSite(final String sitePreset, final String siteShortName, final String siteTitle, final String siteDescription,
|
||||
final SiteVisibility visibility, final String siteCreator)
|
||||
{
|
||||
return this.createSite(sitePreset, siteShortName, siteTitle, siteDescription, visibility, SiteModel.TYPE_SITE, siteCreator);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a Share Site (<b>or subtype</b>) and adds it to the internal list of NodeRefs to be tidied up by the rule.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the creator of the new site.
|
||||
*
|
||||
* @param sitePreset the site preset
|
||||
* @param siteShortName the short name of the new site
|
||||
* @param siteTitle the title of the new site
|
||||
* @param siteDescription the description of the new site
|
||||
* @param visibility the visibility
|
||||
* @param node type the node type of the site (must be st:site or subtype)
|
||||
* @param siteCreator the username of the person who will create the site
|
||||
* @return the newly created SiteInfo.
|
||||
*/
|
||||
public SiteInfo createSite(final String sitePreset, final String siteShortName, final String siteTitle, final String siteDescription,
|
||||
final SiteVisibility visibility, final QName siteType, final String siteCreator)
|
||||
{
|
||||
final RetryingTransactionHelper transactionHelper = appContextRule.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(siteCreator);
|
||||
|
||||
SiteInfo newSite = transactionHelper.doInTransaction(new RetryingTransactionCallback<SiteInfo>()
|
||||
{
|
||||
public SiteInfo execute() throws Throwable
|
||||
{
|
||||
final SiteService siteService = appContextRule.getApplicationContext().getBean("siteService", SiteService.class);
|
||||
|
||||
SiteInfo newSite = siteService.createSite(sitePreset, siteShortName, siteTitle, siteDescription, visibility, siteType);
|
||||
|
||||
// ensure that the Document Library folder is pre-created so that test code can start creating content straight away.
|
||||
// At the time of writing HEAD does not create this folder automatically, but Thor does.
|
||||
// So to be safe, I'll pre-check if the node is there.
|
||||
NodeRef docLibFolder = siteService.getContainer(siteShortName, SiteService.DOCUMENT_LIBRARY);
|
||||
if (docLibFolder == null)
|
||||
{
|
||||
docLibFolder = siteService.createContainer(siteShortName, SiteService.DOCUMENT_LIBRARY, ContentModel.TYPE_FOLDER, null);
|
||||
}
|
||||
|
||||
return newSite;
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.popAuthentication();
|
||||
|
||||
this.temporarySites.add(newSite);
|
||||
return newSite;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a test site (of Alfresco type <code>st:site</code>) and one user for each of the Share Site Roles.
|
||||
* This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
|
||||
* thus ensuring the named user is the creator of the new site.
|
||||
* The site and its users will be deleted automatically by the rule.
|
||||
*
|
||||
* @param sitePreset the site preset.
|
||||
* @param visibility the Site visibility.
|
||||
* @param siteCreator the username of a user who will be used to create the site (user must exist of course).
|
||||
* @return the {@link SiteInfo} object for the newly created site.
|
||||
*/
|
||||
public TestSiteAndMemberInfo createTestSiteWithUserPerRole(final String siteShortName, String sitePreset, SiteVisibility visibility, String siteCreator)
|
||||
{
|
||||
// create the site
|
||||
SiteInfo result = this.createSite(sitePreset, siteShortName, null, null, visibility, siteCreator);
|
||||
|
||||
// create the users
|
||||
final RetryingTransactionHelper transactionHelper = appContextRule.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
final SiteService siteService = appContextRule.getApplicationContext().getBean("siteService", SiteService.class);
|
||||
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(siteCreator);
|
||||
|
||||
// Create users for this test site that cover the various roles.
|
||||
List<String> userNames = transactionHelper.doInTransaction(new RetryingTransactionCallback<List<String>>()
|
||||
{
|
||||
public List<String> execute() throws Throwable
|
||||
{
|
||||
List<String> users = new ArrayList<String>(4);
|
||||
|
||||
for (String shareRole : SiteModel.STANDARD_PERMISSIONS)
|
||||
{
|
||||
final String userName = siteShortName + "_" + shareRole + "_" + GUID.generate();
|
||||
|
||||
log.debug("Creating temporary site user " + userName);
|
||||
|
||||
createPerson(userName);
|
||||
siteService.setMembership(siteShortName, userName, shareRole);
|
||||
users.add(userName);
|
||||
|
||||
temporarySiteUsers.add(userName);
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
});
|
||||
|
||||
NodeRef doclibFolder = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
return siteService.getContainer(siteShortName, SiteService.DOCUMENT_LIBRARY);
|
||||
}
|
||||
});
|
||||
|
||||
AuthenticationUtil.popAuthentication();
|
||||
|
||||
|
||||
return new TestSiteAndMemberInfo(result, doclibFolder, userNames.get(0),
|
||||
userNames.get(1),
|
||||
userNames.get(2),
|
||||
userNames.get(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple POJO class to store the {@link SiteInfo} for this site and its initial, automatically created members' usernames.
|
||||
*
|
||||
* @author Neil Mc Erlean
|
||||
*/
|
||||
public static class TestSiteAndMemberInfo
|
||||
{
|
||||
public final SiteInfo siteInfo;
|
||||
public final NodeRef doclib;
|
||||
public final String siteManager;
|
||||
public final String siteCollaborator;
|
||||
public final String siteContributor;
|
||||
public final String siteConsumer;
|
||||
|
||||
public TestSiteAndMemberInfo(SiteInfo siteInfo, NodeRef siteDocLib, String siteManager, String siteCollaborator, String siteContributor, String siteConsumer)
|
||||
{
|
||||
this.siteInfo = siteInfo;
|
||||
this.doclib = siteDocLib;
|
||||
this.siteManager = siteManager;
|
||||
this.siteCollaborator = siteCollaborator;
|
||||
this.siteContributor = siteContributor;
|
||||
this.siteConsumer = siteConsumer;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 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.util.test.junitrules;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.cmr.site.SiteVisibility;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.test.junitrules.TemporarySites.TestSiteAndMemberInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.RuleChain;
|
||||
|
||||
/**
|
||||
* Test class for {@link TemporarySites}.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public class TemporarySitesTest
|
||||
{
|
||||
// Rule to initialise the default Alfresco spring configuration
|
||||
public static ApplicationContextInit APP_CONTEXT_INIT =
|
||||
ApplicationContextInit.createStandardContextWithOverrides("classpath:sites/test-"
|
||||
+ TemporarySitesTest.class.getSimpleName() + "-context.xml");
|
||||
|
||||
// A rule to manage test sites reused across all the test methods
|
||||
public static TemporaryNodes STATIC_TEST_SITES = new TemporaryNodes(APP_CONTEXT_INIT);
|
||||
|
||||
// Tie them together in a static Rule Chain
|
||||
@ClassRule public static RuleChain ruleChain = RuleChain.outerRule(APP_CONTEXT_INIT)
|
||||
.around(STATIC_TEST_SITES);
|
||||
|
||||
// A rule to manage test sites use in each test method
|
||||
public TemporarySites testSites = new TemporarySites(APP_CONTEXT_INIT);
|
||||
|
||||
// A rule to allow individual test methods all to be run as "admin".
|
||||
public RunAsFullyAuthenticatedRule runAsRule = new RunAsFullyAuthenticatedRule(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
// A non-static rule chain to ensure execution order is correct.
|
||||
@Rule public RuleChain nonStaticRules = RuleChain.outerRule(runAsRule)
|
||||
.around(testSites);
|
||||
|
||||
// Various services
|
||||
private static NamespaceService NAMESPACE_SERVICE;
|
||||
private static NodeService NODE_SERVICE;
|
||||
private static SiteService SITE_SERVICE;
|
||||
private static RetryingTransactionHelper TRANSACTION_HELPER;
|
||||
|
||||
// These SiteInfos are used by the test methods.
|
||||
private SiteInfo testSite1, testSite2;
|
||||
private TestSiteAndMemberInfo testSiteWithMembers;
|
||||
|
||||
@BeforeClass public static void initStaticData() throws Exception
|
||||
{
|
||||
NAMESPACE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("namespaceService", NamespaceService.class);
|
||||
NODE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("nodeService", NodeService.class);
|
||||
SITE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("siteService", SiteService.class);
|
||||
TRANSACTION_HELPER = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
|
||||
}
|
||||
|
||||
@Before public void createTestContent()
|
||||
{
|
||||
// Create some test content
|
||||
final String guid = GUID.generate();
|
||||
|
||||
testSite1 = testSites.createSite("sitePreset", "testSite1_" + guid, "t", "d", SiteVisibility.PUBLIC, AuthenticationUtil.getAdminUserName());
|
||||
final QName subSiteType = QName.createQName("testsite", "testSubsite", NAMESPACE_SERVICE);
|
||||
testSite2 = testSites.createSite("sitePreset", "testSite2_" + guid, "T", "D", SiteVisibility.PUBLIC, subSiteType, AuthenticationUtil.getAdminUserName());
|
||||
|
||||
testSiteWithMembers = testSites.createTestSiteWithUserPerRole(GUID.generate(), "sitePreset", SiteVisibility.PUBLIC, AuthenticationUtil.getAdminUserName());
|
||||
}
|
||||
|
||||
@Test public void ensureTestSitesWereCreatedOk() throws Exception
|
||||
{
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
final SiteInfo recoveredSite1 = SITE_SERVICE.getSite(testSite1.getShortName());
|
||||
final SiteInfo recoveredSite2 = SITE_SERVICE.getSite(testSite2.getShortName());
|
||||
|
||||
assertNotNull("Test site does not exist", recoveredSite1);
|
||||
assertNotNull("Test site does not exist", recoveredSite2);
|
||||
|
||||
assertEquals("cm:title was wrong", "t", recoveredSite1.getTitle());
|
||||
assertEquals("cm:description was wrong", "d", recoveredSite1.getDescription());
|
||||
assertEquals("preset was wrong", "sitePreset", recoveredSite1.getSitePreset());
|
||||
|
||||
assertEquals("site visibility was wrong", SiteVisibility.PUBLIC, recoveredSite1.getVisibility());
|
||||
|
||||
for (String siteShortName : new String[] { testSite1.getShortName(), testSite2.getShortName() })
|
||||
{
|
||||
assertNotNull("site had no doclib container node", SITE_SERVICE.getContainer(siteShortName, SiteService.DOCUMENT_LIBRARY));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test public void ensureUsersWithShareRolesArePresentAndCorrect() throws Exception
|
||||
{
|
||||
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
final String shortName = testSiteWithMembers.siteInfo.getShortName();
|
||||
final SiteInfo recoveredSite = SITE_SERVICE.getSite(shortName);
|
||||
|
||||
assertNotNull("Test site does not exist", recoveredSite);
|
||||
|
||||
assertEquals(SiteModel.SITE_MANAGER, SITE_SERVICE.getMembersRole(shortName, testSiteWithMembers.siteManager));
|
||||
assertEquals(SiteModel.SITE_COLLABORATOR, SITE_SERVICE.getMembersRole(shortName, testSiteWithMembers.siteCollaborator));
|
||||
assertEquals(SiteModel.SITE_CONTRIBUTOR, SITE_SERVICE.getMembersRole(shortName, testSiteWithMembers.siteContributor));
|
||||
assertEquals(SiteModel.SITE_CONSUMER, SITE_SERVICE.getMembersRole(shortName, testSiteWithMembers.siteConsumer));
|
||||
|
||||
assertNotNull(testSiteWithMembers.doclib);
|
||||
assertTrue("Site doclib was not pre-created.", NODE_SERVICE.exists(testSiteWithMembers.doclib));
|
||||
assertEquals("Site doclib was in wrong place.", testSiteWithMembers.siteInfo.getNodeRef(),
|
||||
NODE_SERVICE.getPrimaryParent(testSiteWithMembers.doclib).getParentRef());
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
* 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.util.test.junitrules;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.tenant.TenantUtil;
|
||||
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
|
||||
/**
|
||||
* This JUnit rule can be used to setup and teardown a single Alfresco user, within a tenant, for test purposes.
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* public class YourTestClass
|
||||
* {
|
||||
* // Initialise the spring application context and tenant in a rule chain
|
||||
* public static final ApplicationContextInit APP_CONTEXT_RULE = new ApplicationContextInit();
|
||||
* public static final AlfrescoTenant TENANT_RULE = new AlfrescoTenant(APP_CONTEXT_RULE, "testtenant");
|
||||
*
|
||||
* @ClassRule public static RuleChain ruleChain = RuleChain.outerRule(APP_CONTEXT_INIT)
|
||||
* .around(TENANT);
|
||||
*
|
||||
* // We pass the rule that creates the spring application context.
|
||||
* // This rule will give us a user with username 'AlexM@testtenant'.
|
||||
* @Rule public final TenantPerson namedPerson = new AlfrescoPerson(APP_CONTEXT_RULE, "AlexM@testTenant", TENANT);
|
||||
*
|
||||
* @Test public void aTestMethod()
|
||||
* {
|
||||
* AUSTRALIAN_USER.runAsFullyAuthenticated(new TenantRunAsWork<Void>()
|
||||
* {
|
||||
* @Override
|
||||
* public Void doWork() throws Exception
|
||||
* {
|
||||
* // Do something as the tenant user
|
||||
* }
|
||||
* });
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Alex Miller
|
||||
*/
|
||||
public class TenantPerson extends AlfrescoPerson
|
||||
{
|
||||
|
||||
private AlfrescoTenant tenant;
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
* @param userName the username for the person to be created.
|
||||
* @param tenant the tenant the person should be created under.
|
||||
*/
|
||||
public TenantPerson(ApplicationContextInit appContextInit, String userName, AlfrescoTenant tenant) {
|
||||
super(appContextInit, userName + "@" + tenant.getTenantDomain());
|
||||
ParameterCheck.mandatory("tenant", tenant);
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the user, in the given tenant, using the tenant system user.
|
||||
*/
|
||||
@Override protected void before()
|
||||
{
|
||||
tenant.runAsSystem(new TenantRunAsWork<Void>() {
|
||||
|
||||
@Override
|
||||
public Void doWork() throws Exception {
|
||||
TenantPerson.super.before();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the user, using the system user for the tenant.
|
||||
*/
|
||||
@Override protected void after()
|
||||
{
|
||||
tenant.runAsSystem(new TenantRunAsWork<Void>() {
|
||||
|
||||
@Override
|
||||
public Void doWork() throws Exception {
|
||||
TenantPerson.super.after();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Do runAsWork as the fully authenticated user managed by this class,
|
||||
*
|
||||
* @param runAsWork
|
||||
* @return The result of runAsWork
|
||||
*/
|
||||
public <T> T runAsFullyAuthenticated(TenantRunAsWork<T> runAsWork)
|
||||
{
|
||||
AuthenticationUtil.pushAuthentication();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(getUsername());
|
||||
try
|
||||
{
|
||||
return TenantUtil.runAsUserTenant(runAsWork, getUsername(), tenant.getTenantDomain());
|
||||
}
|
||||
finally
|
||||
{
|
||||
AuthenticationUtil.popAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tenant name of the users tenant.
|
||||
*/
|
||||
public String getTenantName() {
|
||||
return tenant.getTenantDomain();
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012
|
||||
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.util.test.junitrules;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.rules.ExternalResource;
|
||||
|
||||
/**
|
||||
* A JUnit rule designed to help with finding well known nodes
|
||||
* in the system. It provides functionality similar to
|
||||
* {@link Repository}, but with extra nodes needed for testing
|
||||
*
|
||||
* @author Nick Burch
|
||||
* @since Odin
|
||||
*/
|
||||
public class WellKnownNodes extends ExternalResource
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(WellKnownNodes.class);
|
||||
|
||||
private final ApplicationContextInit appContextRule;
|
||||
private final Repository repositoryHelper;
|
||||
private final NodeService nodeService;
|
||||
|
||||
private static QName SYSTEM_FOLDER_QNAME =
|
||||
QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system");
|
||||
|
||||
/**
|
||||
* Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
|
||||
*
|
||||
* @param appContextRule a rule which can be used to retrieve the spring app context.
|
||||
*/
|
||||
public WellKnownNodes(ApplicationContextInit appContextRule)
|
||||
{
|
||||
this.appContextRule = appContextRule;
|
||||
this.repositoryHelper = (Repository)appContextRule.getApplicationContext().getBean("repositoryHelper");
|
||||
this.nodeService = (NodeService)appContextRule.getApplicationContext().getBean("NodeService");
|
||||
}
|
||||
|
||||
|
||||
@Override protected void before() throws Throwable
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
@Override protected void after()
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root of the workspace store
|
||||
*/
|
||||
public NodeRef getWorkspaceRoot()
|
||||
{
|
||||
return repositoryHelper.getRootHome();
|
||||
}
|
||||
/**
|
||||
* Returns company home
|
||||
*/
|
||||
public NodeRef getCompanyHome()
|
||||
{
|
||||
return repositoryHelper.getCompanyHome();
|
||||
}
|
||||
/**
|
||||
* Returns the system root
|
||||
*/
|
||||
public NodeRef getSystemRoot()
|
||||
{
|
||||
NodeRef root = getWorkspaceRoot();
|
||||
List<ChildAssociationRef> sysRefs = nodeService.getChildAssocs(
|
||||
root, ContentModel.ASSOC_CHILDREN, SYSTEM_FOLDER_QNAME);
|
||||
if (sysRefs.size() != 1)
|
||||
{
|
||||
throw new IllegalStateException("System folder missing / duplicated! Found " + sysRefs);
|
||||
}
|
||||
final NodeRef system = sysRefs.get(0).getChildRef();
|
||||
return system;
|
||||
}
|
||||
/**
|
||||
* Returns the given System Container
|
||||
*/
|
||||
public NodeRef getSystemContainer(QName containerName)
|
||||
{
|
||||
NodeRef system = getSystemRoot();
|
||||
List<ChildAssociationRef> containerRefs = nodeService.getChildAssocs(
|
||||
system, ContentModel.ASSOC_CHILDREN, containerName);
|
||||
if (containerRefs.size() != 1)
|
||||
{
|
||||
throw new IllegalStateException("System Container " + containerName + " missing / duplicated! Found " + containerRefs);
|
||||
}
|
||||
final NodeRef container = containerRefs.get(0).getChildRef();
|
||||
return container;
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This package contains <a href="http://junit.org/node/580">JUnit rules</a> intended for use in testing Alfresco.
|
||||
*/
|
||||
@PackageMarker
|
||||
package org.alfresco.util.test.junitrules;
|
||||
import org.alfresco.util.PackageMarker;
|
||||
|
Reference in New Issue
Block a user