mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
ACS 9256 improve async tests stability (#3191)
* ACS-9256 Improved stability in DynamicallySizedThreadPoolExecutorTest * ACS-9256 Removed unused unstable test in SpringAwareUserTransactionTest * ACS-9256 Improved stability in DynamicallySizedThreadPoolExecutorTest * ACS-9256 Improved stability in ActionServiceImplTest and RuleServiceCoverageTest * ACS-9256 Improved stability in ActionTrackingServiceImplTest * ACS-9256 Improved performance in ComparePropertyValueEvaluatorTest * ACS-9256 Improved performance in LockServiceImplTest * ACS-9256 Improved stability in LockBehaviourImplTest * ACS-9256 Improved stability in ContentMetadataExtracterTest * ACS-9256 Removed unstable and unused tests * ACS-9256 Improve stability in CachedContentCleanupJobTest * ACS-9256 Pre-commit fixes
This commit is contained in:
@@ -1431,26 +1431,6 @@
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
"repository/src/test/java/org/alfresco/repo/lock/LockBehaviourImplTest.java": [
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "repository/src/test/java/org/alfresco/repo/lock/LockBehaviourImplTest.java",
|
||||
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
|
||||
"is_verified": false,
|
||||
"line_number": 112,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
"repository/src/test/java/org/alfresco/repo/lock/LockServiceImplTest.java": [
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "repository/src/test/java/org/alfresco/repo/lock/LockServiceImplTest.java",
|
||||
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
|
||||
"is_verified": false,
|
||||
"line_number": 103,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
"repository/src/test/java/org/alfresco/repo/management/JmxDumpUtilTest.java": [
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
@@ -1888,5 +1868,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2024-12-19T08:58:42Z"
|
||||
"generated_at": "2025-02-11T13:28:51Z"
|
||||
}
|
||||
|
@@ -145,6 +145,12 @@
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>${dependency.awaitility.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2025 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -26,11 +29,10 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for our instance of {@link java.util.concurrent.ThreadPoolExecutor}
|
||||
*
|
||||
@@ -39,7 +41,8 @@ import junit.framework.TestCase;
|
||||
public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
{
|
||||
|
||||
private static Log logger = LogFactory.getLog(DynamicallySizedThreadPoolExecutorTest.class);
|
||||
private static final Duration MAX_WAIT_TIMEOUT = Duration.ofSeconds(1);
|
||||
private static final Log logger = LogFactory.getLog(DynamicallySizedThreadPoolExecutorTest.class);
|
||||
private static final int DEFAULT_KEEP_ALIVE_TIME = 90;
|
||||
|
||||
@Override
|
||||
@@ -48,9 +51,9 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
SleepUntilAllWake.reset();
|
||||
}
|
||||
|
||||
public void testUpToCore() throws Exception
|
||||
public void testUpToCore()
|
||||
{
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(5,10, DEFAULT_KEEP_ALIVE_TIME);
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(5, 10, DEFAULT_KEEP_ALIVE_TIME);
|
||||
|
||||
assertEquals(0, exec.getPoolSize());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
@@ -63,13 +66,13 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
assertEquals(5, exec.getPoolSize());
|
||||
|
||||
SleepUntilAllWake.wakeAll();
|
||||
Thread.sleep(100);
|
||||
waitForPoolSizeEquals(exec, 5);
|
||||
assertEquals(5, exec.getPoolSize());
|
||||
}
|
||||
|
||||
public void testPastCoreButNotHugeQueue() throws Exception
|
||||
public void testPastCoreButNotHugeQueue()
|
||||
{
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(5,10, DEFAULT_KEEP_ALIVE_TIME);
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(5, 10, DEFAULT_KEEP_ALIVE_TIME);
|
||||
|
||||
assertEquals(0, exec.getPoolSize());
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
@@ -96,13 +99,13 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
assertEquals(7, exec.getQueue().size());
|
||||
|
||||
SleepUntilAllWake.wakeAll();
|
||||
Thread.sleep(100);
|
||||
waitForPoolSizeEquals(exec, 5);
|
||||
assertEquals(5, exec.getPoolSize());
|
||||
}
|
||||
|
||||
public void testToExpandQueue() throws Exception
|
||||
{
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(2,4,1);
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(2, 4, 5);
|
||||
|
||||
assertEquals(0, exec.getPoolSize());
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
@@ -119,13 +122,13 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
|
||||
// Next should add one
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
Thread.sleep(20); // Let the new thread spin up
|
||||
waitForPoolSizeEquals(exec, 3); // Let the new thread spin up
|
||||
assertEquals(3, exec.getPoolSize());
|
||||
assertEquals(3, exec.getQueue().size());
|
||||
|
||||
// And again
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
Thread.sleep(20); // Let the new thread spin up
|
||||
waitForPoolSizeEquals(exec, 4); // Let the new thread spin up
|
||||
assertEquals(4, exec.getPoolSize());
|
||||
assertEquals(3, exec.getQueue().size());
|
||||
|
||||
@@ -139,139 +142,10 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
SleepUntilAllWake.wakeAll();
|
||||
Thread.sleep(100);
|
||||
|
||||
// All threads still running, as 1 second timeout
|
||||
// All threads still running, as 5 second timeout
|
||||
assertEquals(4, exec.getPoolSize());
|
||||
}
|
||||
|
||||
public void offTestToExpandThenContract() throws Exception
|
||||
{
|
||||
DynamicallySizedThreadPoolExecutor exec = createInstance(2,4,1);
|
||||
exec.setKeepAliveTime(30, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertEquals(0, exec.getPoolSize());
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
assertEquals(2, exec.getPoolSize());
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
assertEquals(2, exec.getPoolSize());
|
||||
assertEquals(3, exec.getQueue().size());
|
||||
|
||||
// Next should add one
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
Thread.sleep(20); // Let the new thread spin up
|
||||
assertEquals(3, exec.getPoolSize());
|
||||
assertEquals(3, exec.getQueue().size());
|
||||
|
||||
// And again
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
Thread.sleep(20); // Let the new thread spin up
|
||||
assertEquals(4, exec.getPoolSize());
|
||||
assertEquals(3, exec.getQueue().size());
|
||||
|
||||
// But no more will be added, as we're at max
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
assertEquals(4, exec.getPoolSize());
|
||||
assertEquals(6, exec.getQueue().size());
|
||||
|
||||
SleepUntilAllWake.wakeAll();
|
||||
Thread.sleep(100);
|
||||
|
||||
// Wait longer than the timeout without any work, which should
|
||||
// let all the extra threads go away
|
||||
// (Depending on how closely your JVM follows the specification,
|
||||
// we may fall back to the core size which is correct, or we
|
||||
// may go to zero which is wrong, but hey, it's the JVM...)
|
||||
logger.debug("Core pool size is " + exec.getCorePoolSize());
|
||||
logger.debug("Current pool size is " + exec.getPoolSize());
|
||||
logger.debug("Queue size is " + exec.getQueue().size());
|
||||
assertTrue(
|
||||
"Pool size should be 0-2 as everything is idle, was " + exec.getPoolSize(),
|
||||
exec.getPoolSize() >= 0
|
||||
);
|
||||
assertTrue(
|
||||
"Pool size should be 0-2 as everything is idle, was " + exec.getPoolSize(),
|
||||
exec.getPoolSize() <= 2
|
||||
);
|
||||
|
||||
SleepUntilAllWake.reset();
|
||||
|
||||
// Add 2 new jobs, will stay/ go to at 2 threads
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
|
||||
// Let the idle threads grab them, then check
|
||||
Thread.sleep(20);
|
||||
assertEquals(2, exec.getPoolSize());
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
|
||||
// 3 more, still at 2 threads
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
assertEquals(2, exec.getPoolSize());
|
||||
assertEquals(3, exec.getQueue().size());
|
||||
|
||||
// And again wait for it all
|
||||
SleepUntilAllWake.wakeAll();
|
||||
Thread.sleep(100);
|
||||
assertEquals(2, exec.getPoolSize());
|
||||
|
||||
|
||||
// Now decrease the overall pool size
|
||||
// Will rise and fall to there now
|
||||
exec.setCorePoolSize(1);
|
||||
|
||||
// Run a quick job, to ensure that the
|
||||
// "can I kill one yet" logic is applied
|
||||
SleepUntilAllWake.reset();
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
SleepUntilAllWake.wakeAll();
|
||||
|
||||
Thread.sleep(100);
|
||||
assertEquals(1, exec.getPoolSize());
|
||||
assertEquals(0, exec.getQueue().size());
|
||||
|
||||
SleepUntilAllWake.reset();
|
||||
|
||||
|
||||
// Push enough on to go up to 4 active threads
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
exec.execute(new SleepUntilAllWake());
|
||||
|
||||
Thread.sleep(20); // Let the new threads spin up
|
||||
assertEquals(4, exec.getPoolSize());
|
||||
assertEquals(6, exec.getQueue().size());
|
||||
|
||||
// Wait for them all to finish, should drop back to 1 now
|
||||
// (Or zero, if your JVM can't read the specification...)
|
||||
SleepUntilAllWake.wakeAll();
|
||||
Thread.sleep(100);
|
||||
assertTrue(
|
||||
"Pool size should be 0 or 1 as everything is idle, was " + exec.getPoolSize(),
|
||||
exec.getPoolSize() >= 0
|
||||
);
|
||||
assertTrue(
|
||||
"Pool size should be 0 or 1 as everything is idle, was " + exec.getPoolSize(),
|
||||
exec.getPoolSize() <= 1
|
||||
);
|
||||
}
|
||||
|
||||
private DynamicallySizedThreadPoolExecutor createInstance(int corePoolSize, int maximumPoolSize, int keepAliveTime)
|
||||
{
|
||||
// We need a thread factory
|
||||
@@ -291,6 +165,11 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
private void waitForPoolSizeEquals(DynamicallySizedThreadPoolExecutor exec, int expectedSize)
|
||||
{
|
||||
await().atMost(MAX_WAIT_TIMEOUT).until(() -> exec.getPoolSize() == expectedSize);
|
||||
}
|
||||
|
||||
public static class SleepUntilAllWake implements Runnable
|
||||
{
|
||||
private static ConcurrentMap<String, Thread> sleeping = new ConcurrentHashMap<String, Thread>();
|
||||
@@ -299,17 +178,18 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if(allAwake) return;
|
||||
if (allAwake)
|
||||
return;
|
||||
|
||||
// Track us, and wait for the bang
|
||||
logger.debug("Adding thread: " + Thread.currentThread().getName());
|
||||
sleeping.put(Thread.currentThread().getName(), Thread.currentThread());
|
||||
try
|
||||
{
|
||||
Thread.sleep(30*1000);
|
||||
Thread.sleep(30 * 1000);
|
||||
System.err.println("Warning - Thread finished sleeping without wake!");
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
logger.debug("Interrupted thread: " + Thread.currentThread().getName());
|
||||
}
|
||||
@@ -318,12 +198,13 @@ public class DynamicallySizedThreadPoolExecutorTest extends TestCase
|
||||
public static void wakeAll()
|
||||
{
|
||||
allAwake = true;
|
||||
for(Entry<String, Thread> t : sleeping.entrySet())
|
||||
for (Entry<String, Thread> t : sleeping.entrySet())
|
||||
{
|
||||
logger.debug("Interrupting thread: " + t.getKey());
|
||||
t.getValue().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public static void reset()
|
||||
{
|
||||
logger.debug("Resetting.");
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2023 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2025 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -20,13 +20,11 @@ package org.alfresco.util.transaction;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
||||
import jakarta.transaction.RollbackException;
|
||||
import jakarta.transaction.Status;
|
||||
import jakarta.transaction.UserTransaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.transaction.CannotCreateTransactionException;
|
||||
import org.springframework.transaction.NoTransactionException;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
@@ -35,9 +33,8 @@ import org.springframework.transaction.support.AbstractPlatformTransactionManage
|
||||
import org.springframework.transaction.support.DefaultTransactionStatus;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.util.transaction.SpringAwareUserTransaction
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @see org.alfresco.util.transaction.SpringAwareUserTransaction
|
||||
*/
|
||||
public class SpringAwareUserTransactionTest extends TestCase
|
||||
{
|
||||
@@ -245,58 +242,6 @@ public class SpringAwareUserTransactionTest extends TestCase
|
||||
checkNoStatusOnThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for leaked transactions (no guarantee it will succeed due to reliance
|
||||
* on garbage collector), so disabled by default.
|
||||
*
|
||||
* Also, if it succeeds, transaction call stack tracing will be enabled
|
||||
* potentially hitting the performance of all subsequent tests.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void xtestLeakedTransactionLogging() throws Exception
|
||||
{
|
||||
assertFalse(SpringAwareUserTransaction.isCallStackTraced());
|
||||
|
||||
TrxThread t1 = new TrxThread();
|
||||
t1.start();
|
||||
System.gc();
|
||||
Thread.sleep(1000);
|
||||
|
||||
TrxThread t2 = new TrxThread();
|
||||
t2.start();
|
||||
System.gc();
|
||||
Thread.sleep(1000);
|
||||
|
||||
assertTrue(SpringAwareUserTransaction.isCallStackTraced());
|
||||
|
||||
TrxThread t3 = new TrxThread();
|
||||
t3.start();
|
||||
System.gc();
|
||||
Thread.sleep(3000);
|
||||
System.gc();
|
||||
Thread.sleep(3000);
|
||||
}
|
||||
|
||||
private class TrxThread extends Thread
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
getTrx();
|
||||
}
|
||||
catch (Exception e) {}
|
||||
}
|
||||
|
||||
public void getTrx() throws Exception
|
||||
{
|
||||
UserTransaction txn = getTxn();
|
||||
txn.begin();
|
||||
txn = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void testConnectionPoolException() throws Exception
|
||||
{
|
||||
testNoTxnStatus();
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -26,7 +26,12 @@
|
||||
|
||||
package org.alfresco.repo.action;
|
||||
|
||||
import static java.time.Duration.ofSeconds;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -38,6 +43,13 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.executer.ActionExecuter;
|
||||
import org.alfresco.repo.action.executer.ContentMetadataExtracter;
|
||||
@@ -64,12 +76,6 @@ import org.alfresco.util.test.junitrules.TemporaryNodes;
|
||||
import org.alfresco.util.test.junitrules.TemporarySites;
|
||||
import org.alfresco.util.test.junitrules.TemporarySites.TestSiteAndMemberInfo;
|
||||
import org.alfresco.util.test.junitrules.WellKnownNodes;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
@@ -77,13 +83,13 @@ import org.junit.Test;
|
||||
*/
|
||||
public class ActionServiceImpl2Test
|
||||
{
|
||||
private static final int MAX_WAIT_TIMEOUT = 10;
|
||||
// Rule to initialise the default Alfresco spring configuration
|
||||
@ClassRule
|
||||
public static ApplicationContextInit APP_CONTEXT_INIT = new ApplicationContextInit();
|
||||
|
||||
/**
|
||||
* This JUnit rule will allow us to create Share sites and users and have
|
||||
* them automatically cleaned up for us.
|
||||
* This JUnit rule will allow us to create Share sites and users and have them automatically cleaned up for us.
|
||||
*/
|
||||
@Rule
|
||||
public TemporarySites temporarySites = new TemporarySites(APP_CONTEXT_INIT);
|
||||
@@ -107,8 +113,6 @@ public class ActionServiceImpl2Test
|
||||
|
||||
private NodeRef testNode;
|
||||
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void initStaticData() throws Exception
|
||||
{
|
||||
@@ -132,8 +136,7 @@ public class ActionServiceImpl2Test
|
||||
SiteVisibility.PUBLIC, AuthenticationUtil.getAdminUserName());
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
testNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
testNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>() {
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// get the Document Library NodeRef
|
||||
@@ -150,8 +153,7 @@ public class ActionServiceImpl2Test
|
||||
@Test
|
||||
public void testIncrementCounterOnDeletedNode() throws Exception
|
||||
{
|
||||
final NodeRef deletedNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
final NodeRef deletedNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>() {
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// get the Document Library NodeRef
|
||||
@@ -165,8 +167,7 @@ public class ActionServiceImpl2Test
|
||||
});
|
||||
|
||||
// before the fix that would thrown an error
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Action incrementAction = actionService.createAction(CounterIncrementActionExecuter.NAME);
|
||||
@@ -182,8 +183,7 @@ public class ActionServiceImpl2Test
|
||||
{
|
||||
// Set authentication to SiteManager.
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteManager);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// add the cm:countable aspect and set the value to 1
|
||||
@@ -200,8 +200,7 @@ public class ActionServiceImpl2Test
|
||||
|
||||
// Set authentication to SiteConsumer.
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteConsumer);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Action incrementAction = actionService.createAction(CounterIncrementActionExecuter.NAME);
|
||||
@@ -217,7 +216,7 @@ public class ActionServiceImpl2Test
|
||||
assertEquals(2, afterIncrement);
|
||||
}
|
||||
|
||||
@Test//(expected = AccessDeniedException.class)
|
||||
@Test // (expected = AccessDeniedException.class)
|
||||
public void testTransform() throws Exception
|
||||
{
|
||||
final File file = loadAndAddQuickFileAsManager(testNode, "quick.txt", MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
||||
@@ -225,8 +224,7 @@ public class ActionServiceImpl2Test
|
||||
|
||||
// Set authentication to SiteConsumer.
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteManager);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Action action = actionService.createAction(TransformActionExecuter.NAME);
|
||||
@@ -269,8 +267,7 @@ public class ActionServiceImpl2Test
|
||||
|
||||
// Set authentication to SiteConsumer
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteConsumer);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Create the action
|
||||
@@ -295,8 +292,7 @@ public class ActionServiceImpl2Test
|
||||
|
||||
// Set authentication to SiteManager
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteManager);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Create the action
|
||||
@@ -312,16 +308,15 @@ public class ActionServiceImpl2Test
|
||||
}
|
||||
});
|
||||
|
||||
//Execute script not in Data Dictionary > Scripts
|
||||
// Execute script not in Data Dictionary > Scripts
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteManager);
|
||||
NodeRef companyHomeRef = wellKnownNodes.getCompanyHome();
|
||||
NodeRef sharedFolderRef = nodeService.getChildByName(companyHomeRef, ContentModel.ASSOC_CONTAINS,
|
||||
"Shared");
|
||||
final NodeRef invalidScriptRef = addTempScript("changeFileNameTest.js",
|
||||
"document.properties.name = \"Invalid_Change.pdf\";\ndocument.save();",sharedFolderRef);
|
||||
"document.properties.name = \"Invalid_Change.pdf\";\ndocument.save();", sharedFolderRef);
|
||||
assertNotNull("Failed to add the test script.", scriptToBeExecuted);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Create the action
|
||||
@@ -349,8 +344,7 @@ public class ActionServiceImpl2Test
|
||||
public void testActionResult() throws Exception
|
||||
{
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
try
|
||||
@@ -389,8 +383,7 @@ public class ActionServiceImpl2Test
|
||||
|
||||
// Set authentication to SiteConsumer
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteConsumer);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Create the action
|
||||
@@ -412,8 +405,7 @@ public class ActionServiceImpl2Test
|
||||
|
||||
// Set authentication to SiteCollaborator
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteCollaborator);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Create the action
|
||||
@@ -424,24 +416,23 @@ public class ActionServiceImpl2Test
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(3000); // Need to wait for the async extract
|
||||
// Need to wait for the async extract
|
||||
await().atMost(ofSeconds(MAX_WAIT_TIMEOUT))
|
||||
.until(() -> nonNull(getProperty(testNode, ContentModel.PROP_DESCRIPTION)));
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertEquals("Pangram, fox, dog, Gym class featuring a brown fox and lazy dog",
|
||||
nodeService.getProperty(testNode, ContentModel.PROP_DESCRIPTION));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
assertThat(getProperty(testNode, ContentModel.PROP_DESCRIPTION))
|
||||
.isEqualTo("Pangram, fox, dog, Gym class featuring a brown fox and lazy dog");
|
||||
}
|
||||
|
||||
private Serializable getProperty(NodeRef nodeRef, QName propertyName)
|
||||
{
|
||||
return transactionHelper.doInTransaction(() -> nodeService.getProperty(nodeRef, propertyName));
|
||||
}
|
||||
|
||||
private NodeRef addTempScript(final String scriptFileName, final String javaScript, final NodeRef parentRef)
|
||||
{
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
return transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
return transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>() {
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
|
||||
@@ -466,8 +457,7 @@ public class ActionServiceImpl2Test
|
||||
private NodeRef addTempScript(final String scriptFileName, final String javaScript)
|
||||
{
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
return transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
return transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>() {
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
|
||||
@@ -490,12 +480,14 @@ public class ActionServiceImpl2Test
|
||||
{
|
||||
final File file = AbstractContentTransformerTest.loadNamedQuickTestFile(quickFileName);
|
||||
|
||||
if (file == null) { return null; }
|
||||
if (file == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set authentication to SiteManager and add a file
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(testSiteAndMemberInfo.siteManager);
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, quickFileName);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -26,10 +26,16 @@
|
||||
package org.alfresco.repo.action.evaluator;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionConditionImpl;
|
||||
import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation;
|
||||
@@ -54,10 +60,6 @@ import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Compare property value evaluator test
|
||||
@@ -99,9 +101,9 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
// Need to create model to contain our custom type
|
||||
createTestModel();
|
||||
|
||||
this.nodeService = (NodeService)this.applicationContext.getBean("nodeService");
|
||||
this.contentService = (ContentService)this.applicationContext.getBean("contentService");
|
||||
actionService = (ActionService)applicationContext.getBean("actionService");
|
||||
this.nodeService = (NodeService) this.applicationContext.getBean("nodeService");
|
||||
this.contentService = (ContentService) this.applicationContext.getBean("contentService");
|
||||
actionService = (ActionService) applicationContext.getBean("actionService");
|
||||
|
||||
// Create the store and get the root node
|
||||
this.testStoreRef = this.nodeService.createStore(
|
||||
@@ -111,11 +113,10 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
|
||||
this.nodeValue = this.rootNodeRef;
|
||||
|
||||
this.beforeDateValue = new Date();
|
||||
Thread.sleep(2000);
|
||||
this.dateValue = new Date();
|
||||
Thread.sleep(2000);
|
||||
this.afterDateValue = new Date();
|
||||
var now = Instant.now();
|
||||
this.beforeDateValue = Date.from(now.minusSeconds(4));
|
||||
this.dateValue = Date.from(now.minusSeconds(2));
|
||||
this.afterDateValue = Date.from(now);
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(PROP_TEXT, TEXT_VALUE);
|
||||
@@ -132,7 +133,7 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
TEST_TYPE_QNAME,
|
||||
props).getChildRef();
|
||||
|
||||
this.evaluator = (ComparePropertyValueEvaluator)this.applicationContext.getBean(ComparePropertyValueEvaluator.NAME);
|
||||
this.evaluator = (ComparePropertyValueEvaluator) this.applicationContext.getBean(ComparePropertyValueEvaluator.NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -226,11 +227,34 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
// Ensure other operators are invalid
|
||||
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.BEGINS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {exception.printStackTrace();};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.ENDS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.CONTAINS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,11 +333,34 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
// Ensure other operators are invalid
|
||||
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.BEGINS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {exception.printStackTrace();};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.ENDS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.CONTAINS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,13 +435,43 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
// Ensure other operators are invalid
|
||||
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.GREATER_THAN.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {exception.printStackTrace();};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.GREATER_THAN_EQUAL.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.LESS_THAN.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.LESS_THAN_EQUAL.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,19 +524,70 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
// Ensure other operators are invalid
|
||||
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.BEGINS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) { exception.printStackTrace();};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.ENDS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.CONTAINS.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.GREATER_THAN.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.GREATER_THAN_EQUAL.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.LESS_THAN.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.LESS_THAN_EQUAL.toString());
|
||||
try { this.evaluator.evaluate(condition, this.nodeRef); fail("An exception should have been raised here."); } catch (ActionServiceException exception) {};
|
||||
try
|
||||
{
|
||||
this.evaluator.evaluate(condition, this.nodeRef);
|
||||
fail("An exception should have been raised here.");
|
||||
}
|
||||
catch (ActionServiceException exception)
|
||||
{}
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -499,7 +627,6 @@ public class ComparePropertyValueEvaluatorTest extends BaseSpringTest
|
||||
condition.setParameterValue(ComparePropertyValueEvaluator.PARAM_VALUE, 2);
|
||||
assertFalse(this.evaluator.evaluate(condition, this.nodeRef));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -23,26 +23,23 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 2005 Jesper Steen M<>ller
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.action.executer;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.test.context.transaction.TestTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
@@ -63,17 +60,6 @@ import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.test_category.BaseSpringTestsCategory;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.test.context.transaction.TestTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Test of the ActionExecuter for extracting metadata.
|
||||
@@ -108,7 +94,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
registry = (MetadataExtracterRegistry) applicationContext.getBean("metadataExtracterRegistry");
|
||||
transactionService = (TransactionService) this.applicationContext.getBean("transactionService");
|
||||
|
||||
AuthenticationComponent authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
AuthenticationComponent authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
// Create the store and get the root node
|
||||
@@ -146,7 +132,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
props.remove(ContentModel.PROP_AUTHOR);
|
||||
props.put(ContentModel.PROP_TITLE, "");
|
||||
props.put(ContentModel.PROP_DESCRIPTION, null); // Wonder how this will
|
||||
// be handled
|
||||
// be handled
|
||||
this.nodeService.setProperties(this.nodeRef, props);
|
||||
|
||||
// Make the nodeRef visible to other transactions as it will need to be in async requests
|
||||
@@ -154,8 +140,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
TestTransaction.end();
|
||||
|
||||
// Execute the action
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
ActionImpl action = new ActionImpl(null, ID, SetPropertyValueActionExecuter.NAME, null);
|
||||
@@ -164,11 +149,13 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(3000); // Need to wait for the async extract
|
||||
// Need to wait for the async extract
|
||||
await().pollInSameThread()
|
||||
.atMost(MAX_ASYNC_TIMEOUT)
|
||||
.until(() -> nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), Objects::nonNull);
|
||||
|
||||
// Check that the properties have been set
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertEquals(QUICK_TITLE, nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE));
|
||||
@@ -181,6 +168,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
|
||||
private static final QName PROP_UNKNOWN_1 = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "unkown1");
|
||||
private static final QName PROP_UNKNOWN_2 = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "unkown2");
|
||||
|
||||
private static class TestUnknownMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
{
|
||||
public TestUnknownMetadataExtracter()
|
||||
@@ -190,12 +178,14 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
mappingProperties.put("unknown2", PROP_UNKNOWN_2.toString());
|
||||
setMappingProperties(mappingProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Set<QName>> getDefaultMapping()
|
||||
{
|
||||
// No need to give anything back as we have explicitly set the mapping already
|
||||
return new HashMap<String, Set<QName>>(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(String sourceMimetype)
|
||||
{
|
||||
@@ -242,12 +232,14 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
mappingProperties.put("description", ContentModel.PROP_DESCRIPTION.toString());
|
||||
setMappingProperties(mappingProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Set<QName>> getDefaultMapping()
|
||||
{
|
||||
// No need to give anything back as we have explicitly set the mapping already
|
||||
return new HashMap<String, Set<QName>>(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(String sourceMimetype)
|
||||
{
|
||||
@@ -264,9 +256,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that missing raw values result in node properties being removed
|
||||
* when running with {@link ContentMetadataExtracter#setCarryAspectProperties(boolean)}
|
||||
* set to <tt>false</tt>.
|
||||
* Ensure that missing raw values result in node properties being removed when running with {@link ContentMetadataExtracter#setCarryAspectProperties(boolean)} set to <tt>false</tt>.
|
||||
*/
|
||||
@Test
|
||||
public void testNullExtractedValues_ALF1823()
|
||||
@@ -335,8 +325,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
TestTransaction.end();
|
||||
|
||||
// Execute the action
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
ActionImpl action = new ActionImpl(null, ID, SetPropertyValueActionExecuter.NAME, null);
|
||||
@@ -345,11 +334,13 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(3000); // Need to wait for the async extract
|
||||
// Need to wait for the async extract
|
||||
await().pollInSameThread()
|
||||
.atMost(MAX_ASYNC_TIMEOUT)
|
||||
.until(() -> nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION), Objects::nonNull);
|
||||
|
||||
// Check that the properties have been preserved, but that description has been set
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertEquals(myTitle, nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE));
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,16 +25,27 @@
|
||||
*/
|
||||
package org.alfresco.repo.content.caching.cleanup;
|
||||
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.Duration;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import org.alfresco.repo.content.caching.CacheFileProps;
|
||||
import org.alfresco.repo.content.caching.CachingContentStore;
|
||||
import org.alfresco.repo.content.caching.ContentCacheImpl;
|
||||
@@ -43,12 +54,6 @@ import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.testing.category.LuceneTests;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests for the CachedContentCleanupJob
|
||||
@@ -58,22 +63,29 @@ import org.springframework.context.ApplicationContext;
|
||||
@Category(LuceneTests.class)
|
||||
public class CachedContentCleanupJobTest
|
||||
{
|
||||
private enum UrlSource { PROPS_FILE, REVERSE_CACHE_LOOKUP, NOT_PRESENT };
|
||||
|
||||
private static final Duration MAX_WAIT_TIMEOUT = Duration.ofSeconds(10);
|
||||
|
||||
private enum UrlSource
|
||||
{
|
||||
PROPS_FILE, REVERSE_CACHE_LOOKUP, NOT_PRESENT
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private static ApplicationContext ctx;
|
||||
private CachingContentStore cachingStore;
|
||||
private ContentCacheImpl cache;
|
||||
private File cacheRoot;
|
||||
private CachedContentCleaner cleaner;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass()
|
||||
{
|
||||
String cleanerConf = "classpath:cachingstore/test-cleaner-context.xml";
|
||||
ctx = ApplicationContextHelper.getApplicationContext(new String[] { cleanerConf });
|
||||
ctx = ApplicationContextHelper.getApplicationContext(new String[]{cleanerConf});
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException
|
||||
{
|
||||
@@ -89,7 +101,6 @@ public class CachedContentCleanupJobTest
|
||||
FileUtils.cleanDirectory(cacheRoot);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void filesNotInCacheAreDeleted() throws InterruptedException
|
||||
{
|
||||
@@ -112,11 +123,9 @@ public class CachedContentCleanupJobTest
|
||||
// Run cleaner
|
||||
cleaner.execute();
|
||||
|
||||
Thread.sleep(400);
|
||||
while (cleaner.isRunning())
|
||||
{
|
||||
Thread.sleep(200);
|
||||
}
|
||||
await().pollDelay(Duration.ofMillis(100))
|
||||
.atMost(MAX_WAIT_TIMEOUT)
|
||||
.until(() -> !cleaner.isRunning());
|
||||
|
||||
// check all files deleted
|
||||
for (File file : files)
|
||||
@@ -128,7 +137,6 @@ public class CachedContentCleanupJobTest
|
||||
assertEquals("Incorrect total size of files deleted", totalSize, cleaner.getSizeFilesDeleted());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void filesNewerThanMinFileAgeMillisAreNotDeleted() throws InterruptedException
|
||||
{
|
||||
@@ -154,21 +162,18 @@ public class CachedContentCleanupJobTest
|
||||
newFilesTotalSize += newFiles[i].length();
|
||||
}
|
||||
|
||||
|
||||
// The cleaner must finish before any of the newFiles are older than minFileAge. If the files are too
|
||||
// old the test will fail and it will be necessary to rethink how to test this.
|
||||
cleaner.execute();
|
||||
|
||||
Thread.sleep(400);
|
||||
while (cleaner.isRunning())
|
||||
{
|
||||
Thread.sleep(200);
|
||||
}
|
||||
await().pollDelay(Duration.ofMillis(100))
|
||||
.atMost(MAX_WAIT_TIMEOUT)
|
||||
.until(() -> !cleaner.isRunning());
|
||||
|
||||
if (cleaner.getDurationMillis() > minFileAge)
|
||||
{
|
||||
fail("Test unable to complete, since cleaner took " + cleaner.getDurationMillis() + "ms" +
|
||||
" which is longer than minFileAge [" + minFileAge + "ms]");
|
||||
" which is longer than minFileAge [" + minFileAge + "ms]");
|
||||
}
|
||||
|
||||
// check all 'old' files deleted
|
||||
@@ -224,14 +229,13 @@ public class CachedContentCleanupJobTest
|
||||
}
|
||||
}
|
||||
// How many were definitely deleted?
|
||||
assertEquals("Wrong number of files deleted", 7 , numDeleted);
|
||||
assertEquals("Wrong number of files deleted", 7, numDeleted);
|
||||
|
||||
// The cleaner should have recorded the correct number of deletions
|
||||
assertEquals("Incorrect number of deleted files", 7, cleaner.getNumFilesDeleted());
|
||||
assertEquals("Incorrect total size of files deleted", sevenFilesSize, cleaner.getSizeFilesDeleted());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void standardCleanAfterAggressiveFinished() throws InterruptedException
|
||||
{
|
||||
@@ -239,7 +243,6 @@ public class CachedContentCleanupJobTest
|
||||
final int numFiles = 30;
|
||||
File[] files = new File[numFiles];
|
||||
|
||||
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
Calendar calendar = new GregorianCalendar(2010, 11, 2, 17, i);
|
||||
@@ -286,7 +289,7 @@ public class CachedContentCleanupJobTest
|
||||
}
|
||||
}
|
||||
assertEquals("Incorrect number of deleted files", 11, cleaner.getNumFilesDeleted());
|
||||
assertEquals("Incorrect total size of files deleted", (11*fileSize), cleaner.getSizeFilesDeleted());
|
||||
assertEquals("Incorrect total size of files deleted", (11 * fileSize), cleaner.getSizeFilesDeleted());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -343,7 +346,6 @@ public class CachedContentCleanupJobTest
|
||||
checkFilesDeleted(file);
|
||||
}
|
||||
|
||||
|
||||
private void checkFilesDeleted(File file)
|
||||
{
|
||||
assertFalse("File should have been deleted: " + file, file.exists());
|
||||
@@ -351,7 +353,6 @@ public class CachedContentCleanupJobTest
|
||||
assertFalse("Properties file should have been deleted, cache file: " + file, props.exists());
|
||||
}
|
||||
|
||||
|
||||
private void checkWatchCountForCacheFile(File file, Integer expectedWatchCount)
|
||||
{
|
||||
assertTrue("File should still exist: " + file, file.exists());
|
||||
@@ -360,7 +361,6 @@ public class CachedContentCleanupJobTest
|
||||
assertEquals("File should contain correct deleteWatchCount", expectedWatchCount, props.getDeleteWatchCount());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void filesInCacheAreNotDeleted() throws InterruptedException
|
||||
{
|
||||
@@ -397,8 +397,8 @@ public class CachedContentCleanupJobTest
|
||||
return createCacheFile(calendar, urlSource, putInCache);
|
||||
}
|
||||
|
||||
private File createCacheFile(Calendar calendar, /*int year, int month, int day, int hour, int minute,*/
|
||||
UrlSource urlSource, boolean putInCache)
|
||||
private File createCacheFile(Calendar calendar, /* int year, int month, int day, int hour, int minute, */
|
||||
UrlSource urlSource, boolean putInCache)
|
||||
{
|
||||
File file = new File(cacheRoot, createNewCacheFilePath(calendar));
|
||||
file.getParentFile().mkdirs();
|
||||
@@ -410,58 +410,55 @@ public class CachedContentCleanupJobTest
|
||||
cache.putIntoLookup(Key.forUrl(contentUrl), file.getAbsolutePath());
|
||||
}
|
||||
|
||||
switch(urlSource)
|
||||
switch (urlSource)
|
||||
{
|
||||
case NOT_PRESENT:
|
||||
// cache won't be able to determine original content URL for the file
|
||||
break;
|
||||
case PROPS_FILE:
|
||||
// file with content URL in properties file
|
||||
CacheFileProps props = new CacheFileProps(file);
|
||||
props.setContentUrl(contentUrl);
|
||||
props.store();
|
||||
break;
|
||||
case REVERSE_CACHE_LOOKUP:
|
||||
// file with content URL in reverse lookup cache - but not 'in the cache' (forward lookup).
|
||||
cache.putIntoLookup(Key.forCacheFile(file), contentUrl);
|
||||
case NOT_PRESENT:
|
||||
// cache won't be able to determine original content URL for the file
|
||||
break;
|
||||
case PROPS_FILE:
|
||||
// file with content URL in properties file
|
||||
CacheFileProps props = new CacheFileProps(file);
|
||||
props.setContentUrl(contentUrl);
|
||||
props.store();
|
||||
break;
|
||||
case REVERSE_CACHE_LOOKUP:
|
||||
// file with content URL in reverse lookup cache - but not 'in the cache' (forward lookup).
|
||||
cache.putIntoLookup(Key.forCacheFile(file), contentUrl);
|
||||
}
|
||||
assertTrue("File should exist", file.exists());
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mimick functionality of ContentCacheImpl.createNewCacheFilePath()
|
||||
* but allowing a specific date (rather than 'now') to be used.
|
||||
* Mimick functionality of ContentCacheImpl.createNewCacheFilePath() but allowing a specific date (rather than 'now') to be used.
|
||||
*
|
||||
* @param calendar Calendar
|
||||
* @param calendar
|
||||
* Calendar
|
||||
* @return Path to use for cache file.
|
||||
*/
|
||||
private String createNewCacheFilePath(Calendar calendar)
|
||||
{
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
int month = calendar.get(Calendar.MONTH) + 1; // 0-based
|
||||
int month = calendar.get(Calendar.MONTH) + 1; // 0-based
|
||||
int day = calendar.get(Calendar.DAY_OF_MONTH);
|
||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = calendar.get(Calendar.MINUTE);
|
||||
// create the URL
|
||||
StringBuilder sb = new StringBuilder(20);
|
||||
sb.append(year).append('/')
|
||||
.append(month).append('/')
|
||||
.append(day).append('/')
|
||||
.append(hour).append('/')
|
||||
.append(minute).append('/')
|
||||
.append(GUID.generate()).append(".bin");
|
||||
.append(month).append('/')
|
||||
.append(day).append('/')
|
||||
.append(hour).append('/')
|
||||
.append(minute).append('/')
|
||||
.append(GUID.generate()).append(".bin");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private String makeContentUrl()
|
||||
{
|
||||
return "protocol://some/made/up/url/" + GUID.generate();
|
||||
}
|
||||
|
||||
|
||||
private void writeSampleContent(File file)
|
||||
{
|
||||
try
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,10 +25,19 @@
|
||||
*/
|
||||
package org.alfresco.repo.lock;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.secure;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.node.archive.NodeArchiveService;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
@@ -48,10 +57,6 @@ import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.TestWithUserUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* LockBehaviourImpl Unit Test.
|
||||
@@ -67,10 +72,10 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
*/
|
||||
private LockService lockService;
|
||||
|
||||
/**
|
||||
* The version service
|
||||
*/
|
||||
private VersionService versionService;
|
||||
/**
|
||||
* The version service
|
||||
*/
|
||||
private VersionService versionService;
|
||||
|
||||
/**
|
||||
* The node service
|
||||
@@ -109,7 +114,7 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
/**
|
||||
* User details
|
||||
*/
|
||||
private static final String PWD = "password";
|
||||
private static final String PWD = secure().nextAlphabetic(10);
|
||||
private static final String GOOD_USER_NAME = "goodUser";
|
||||
private static final String BAD_USER_NAME = "badUser";
|
||||
private static final String BAD_USER_WITH_ALL_PERMS_NAME = "badUserOwns";
|
||||
@@ -119,16 +124,16 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
this.nodeService = (NodeService)applicationContext.getBean("dbNodeService");
|
||||
this.lockService = (LockService)applicationContext.getBean("lockService");
|
||||
this.versionService = (VersionService)applicationContext.getBean("versionService");
|
||||
this.authenticationService = (MutableAuthenticationService)applicationContext.getBean("authenticationService");
|
||||
this.permissionService = (PermissionService)applicationContext.getBean("permissionService");
|
||||
this.copyService = (CopyService)applicationContext.getBean("copyService");
|
||||
this.nodeArchiveService = (NodeArchiveService)applicationContext.getBean("nodeArchiveService");
|
||||
this.nodeService = (NodeService) applicationContext.getBean("dbNodeService");
|
||||
this.lockService = (LockService) applicationContext.getBean("lockService");
|
||||
this.versionService = (VersionService) applicationContext.getBean("versionService");
|
||||
this.authenticationService = (MutableAuthenticationService) applicationContext.getBean("authenticationService");
|
||||
this.permissionService = (PermissionService) applicationContext.getBean("permissionService");
|
||||
this.copyService = (CopyService) applicationContext.getBean("copyService");
|
||||
this.nodeArchiveService = (NodeArchiveService) applicationContext.getBean("nodeArchiveService");
|
||||
|
||||
// Set the authentication
|
||||
AuthenticationComponent authComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
|
||||
AuthenticationComponent authComponent = (AuthenticationComponent) this.applicationContext.getBean("authenticationComponent");
|
||||
authComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
// Create the node properties
|
||||
@@ -144,7 +149,7 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
// Create node
|
||||
this.nodeRef = this.nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{}ParentNode"),
|
||||
ContentModel.TYPE_FOLDER,
|
||||
nodeProperties).getChildRef();
|
||||
@@ -163,13 +168,13 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
// Create a node with no lockAspect
|
||||
this.noAspectNode = this.nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{}noAspectNode"),
|
||||
ContentModel.TYPE_CONTAINER,
|
||||
nodeProperties).getChildRef();
|
||||
assertNotNull(this.noAspectNode);
|
||||
|
||||
// Create the users
|
||||
// Create the users
|
||||
TestWithUserUtils.createUser(GOOD_USER_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
|
||||
TestWithUserUtils.createUser(BAD_USER_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
|
||||
TestWithUserUtils.createUser(BAD_USER_WITH_ALL_PERMS_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
|
||||
@@ -292,7 +297,10 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
assertTrue(lockService.isLocked(nodeRef));
|
||||
assertTrue(lockService.isLockedAndReadOnly(nodeRef));
|
||||
|
||||
try {Thread.sleep(2*1000); } catch (Exception e) {};
|
||||
await().pollInSameThread()
|
||||
.pollDelay(Duration.ofMillis(500))
|
||||
.atMost(MAX_ASYNC_TIMEOUT)
|
||||
.until(() -> !lockService.isLocked(nodeRef));
|
||||
|
||||
// Should now have expired so the node should no longer appear to be locked
|
||||
this.lockService.checkForLock(this.nodeRef);
|
||||
@@ -370,66 +378,64 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the node service lock behaviour is as we expect
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Test that the node service lock behaviour is as we expect
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void testNodeServiceLockBehaviour()
|
||||
{
|
||||
public void testNodeServiceLockBehaviour()
|
||||
{
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
// Check that we can create a new node and set of it properties when no lock is present
|
||||
ChildAssociationRef childAssocRef = this.nodeService.createNode(
|
||||
this.nodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER);
|
||||
NodeRef nodeRef = childAssocRef.getChildRef();
|
||||
// Check that we can create a new node and set of it properties when no lock is present
|
||||
ChildAssociationRef childAssocRef = this.nodeService.createNode(
|
||||
this.nodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER);
|
||||
NodeRef nodeRef = childAssocRef.getChildRef();
|
||||
|
||||
// Lets lock the parent node and check that whether we can still create a new node
|
||||
this.lockService.lock(this.nodeRef, LockType.WRITE_LOCK);
|
||||
ChildAssociationRef childAssocRef2 = this.nodeService.createNode(
|
||||
this.nodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER);
|
||||
NodeRef nodeRef2 = childAssocRef.getChildRef();
|
||||
// Lets lock the parent node and check that whether we can still create a new node
|
||||
this.lockService.lock(this.nodeRef, LockType.WRITE_LOCK);
|
||||
ChildAssociationRef childAssocRef2 = this.nodeService.createNode(
|
||||
this.nodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER);
|
||||
NodeRef nodeRef2 = childAssocRef.getChildRef();
|
||||
|
||||
// Lets check that we can do other stuff with the node since we have it locked
|
||||
this.nodeService.setProperty(this.nodeRef, QName.createQName("{test}prop1"), "value1");
|
||||
Map<QName, Serializable> propMap = new HashMap<QName, Serializable>();
|
||||
propMap.put(QName.createQName("{test}prop2"), "value2");
|
||||
this.nodeService.setProperties(this.nodeRef, propMap);
|
||||
this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
// TODO there are various other calls that could be more vigirously checked
|
||||
// Lets check that we can do other stuff with the node since we have it locked
|
||||
this.nodeService.setProperty(this.nodeRef, QName.createQName("{test}prop1"), "value1");
|
||||
Map<QName, Serializable> propMap = new HashMap<QName, Serializable>();
|
||||
propMap.put(QName.createQName("{test}prop2"), "value2");
|
||||
this.nodeService.setProperties(this.nodeRef, propMap);
|
||||
this.nodeService.removeAspect(this.nodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
// TODO there are various other calls that could be more vigirously checked
|
||||
|
||||
// Lock the node as the 'bad' user
|
||||
this.lockService.unlock(this.nodeRef);
|
||||
// Lock the node as the 'bad' user
|
||||
this.lockService.unlock(this.nodeRef);
|
||||
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
this.lockService.lock(this.nodeRef, LockType.WRITE_LOCK);
|
||||
this.lockService.lock(this.nodeRef, LockType.WRITE_LOCK);
|
||||
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
// Lets check that we can't create a new child
|
||||
try
|
||||
{
|
||||
this.nodeService.createNode(
|
||||
this.nodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER);
|
||||
fail("The parent is locked so a new child should not have been created.");
|
||||
}
|
||||
catch(NodeLockedException exception)
|
||||
{
|
||||
}
|
||||
// Lets check that we can't create a new child
|
||||
try
|
||||
{
|
||||
this.nodeService.createNode(
|
||||
this.nodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER);
|
||||
fail("The parent is locked so a new child should not have been created.");
|
||||
}
|
||||
catch (NodeLockedException exception)
|
||||
{}
|
||||
|
||||
// TODO various other tests along these lines ...
|
||||
// TODO various other tests along these lines ...
|
||||
|
||||
// TODO check that delete is also working
|
||||
}
|
||||
// TODO check that delete is also working
|
||||
}
|
||||
|
||||
/**
|
||||
* ALF-5680: It is possible to cut/paste a locked file
|
||||
@@ -453,20 +459,20 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
|
||||
// Create the new container that we'll move the node to.
|
||||
NodeRef newParentRef = nodeService.createNode(
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
|
||||
// Now the bad user will try to move the node.
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
try
|
||||
{
|
||||
nodeService.moveNode(
|
||||
nodeRef,
|
||||
newParentRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"));
|
||||
nodeRef,
|
||||
newParentRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"));
|
||||
fail("Shouldn't have been able to move locked node.");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
@@ -506,17 +512,17 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
|
||||
// Create the new container that we'll move the node to.
|
||||
NodeRef newParentRefToMove = nodeService.createNode(
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
|
||||
// Create the new container that we'll copy the node to.
|
||||
NodeRef newParentRefToCopy = nodeService.createNode(
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -544,10 +550,10 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
|
||||
// Create the new container that we'll copy the node to.
|
||||
newParentRefToCopy = nodeService.createNode(
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName("{test}nodeServiceLockTest"),
|
||||
ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
|
||||
this.lockService.lock(nodeRef, LockType.WRITE_LOCK);
|
||||
|
||||
@@ -569,7 +575,7 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
fail("Should not have any locks.");
|
||||
fail("Should not have any locks.");
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -594,7 +600,7 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
{
|
||||
// Try to restore archived node by Not Lock Owner
|
||||
archivingBehaviorNodeRef = nodeService.restoreNode(archivedNode,
|
||||
this.inSpaceStoreNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{test}nodeServiceLockTest"));
|
||||
this.inSpaceStoreNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{test}nodeServiceLockTest"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -610,7 +616,7 @@ public class LockBehaviourImplTest extends BaseSpringTest
|
||||
try
|
||||
{
|
||||
archivingBehaviorNodeRef = nodeService.restoreNode(archivedNode,
|
||||
this.inSpaceStoreNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{test}nodeServiceLockTest"));
|
||||
this.inSpaceStoreNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{test}nodeServiceLockTest"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,16 +25,25 @@
|
||||
*/
|
||||
package org.alfresco.repo.lock;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.secure;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.test.context.transaction.TestTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.lock.mem.Lifetime;
|
||||
import org.alfresco.repo.lock.mem.LockState;
|
||||
@@ -66,11 +75,6 @@ import org.alfresco.test_category.BaseSpringTestsCategory;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.TestWithUserUtils;
|
||||
import org.alfresco.util.testing.category.RedundantTests;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.test.context.transaction.TestTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Simple lock service test
|
||||
@@ -100,14 +104,13 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
private static final String GOOD_USER_NAME = "goodUser";
|
||||
private static final String BAD_USER_NAME = "badUser";
|
||||
private static final String PWD = "password";
|
||||
private static final String PWD = secure().nextAlphabetic(10);
|
||||
|
||||
NodeRef rootNodeRef;
|
||||
private StoreRef storeRef;
|
||||
|
||||
private PolicyComponent policyComponent;
|
||||
|
||||
|
||||
public class LockServicePoliciesImpl implements LockServicePolicies.BeforeLock,
|
||||
LockServicePolicies.BeforeUnlock
|
||||
{
|
||||
@@ -131,24 +134,23 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
this.nodeService = (NodeService)applicationContext.getBean("dbNodeService");
|
||||
this.lockService = (LockService)applicationContext.getBean("lockService");
|
||||
this.nodeService = (NodeService) applicationContext.getBean("dbNodeService");
|
||||
this.lockService = (LockService) applicationContext.getBean("lockService");
|
||||
|
||||
this.securedLockService = (LockService)applicationContext.getBean("LockService");
|
||||
this.securedLockService = (LockService) applicationContext.getBean("LockService");
|
||||
PermissionService permissionService = (PermissionService) applicationContext.getBean("PermissionService");
|
||||
|
||||
this.authenticationService = (MutableAuthenticationService)applicationContext.getBean("authenticationService");
|
||||
this.authenticationService = (MutableAuthenticationService) applicationContext.getBean("authenticationService");
|
||||
CheckOutCheckInService cociService = (CheckOutCheckInService) applicationContext.getBean(
|
||||
"checkOutCheckInService");
|
||||
"checkOutCheckInService");
|
||||
|
||||
this.policyComponent = (PolicyComponent)applicationContext.getBean("policyComponent");
|
||||
this.policyComponent = (PolicyComponent) applicationContext.getBean("policyComponent");
|
||||
|
||||
// Set the authentication
|
||||
AuthenticationComponent authComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
|
||||
AuthenticationComponent authComponent = (AuthenticationComponent) this.applicationContext.getBean("authenticationComponent");
|
||||
authComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
// Create the node properties
|
||||
@@ -164,7 +166,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
// Create node
|
||||
this.parentNode = this.nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{}ParentNode"),
|
||||
ContentModel.TYPE_CONTAINER,
|
||||
nodeProperties).getChildRef();
|
||||
@@ -177,7 +179,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
// Add some children to the node
|
||||
this.childNode1 = this.nodeService.createNode(
|
||||
this.parentNode,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{}ChildNode1"),
|
||||
ContentModel.TYPE_CONTAINER,
|
||||
nodeProperties).getChildRef();
|
||||
@@ -185,7 +187,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
assertNotNull("childNode1 should not be null", this.childNode1);
|
||||
this.childNode2 = this.nodeService.createNode(
|
||||
this.parentNode,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{}ChildNode2"),
|
||||
ContentModel.TYPE_CONTAINER,
|
||||
nodeProperties).getChildRef();
|
||||
@@ -195,7 +197,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
// Create a node with no lockAspect
|
||||
this.noAspectNode = this.nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{}noAspectNode"),
|
||||
ContentModel.TYPE_CONTAINER,
|
||||
nodeProperties).getChildRef();
|
||||
@@ -216,8 +218,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
assertTrue("checkedOutNode should have checked out aspect", nodeService.hasAspect(checkedOutNode, ContentModel.ASPECT_CHECKED_OUT));
|
||||
assertTrue("checkedOutNode should have lockable aspect", nodeService.hasAspect(checkedOutNode, ContentModel.ASPECT_LOCKABLE));
|
||||
|
||||
|
||||
// Create the users
|
||||
// Create the users
|
||||
TestWithUserUtils.createUser(GOOD_USER_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
|
||||
TestWithUserUtils.createUser(BAD_USER_NAME, PWD, rootNodeRef, this.nodeService, this.authenticationService);
|
||||
|
||||
@@ -236,13 +237,11 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
{
|
||||
LockServicePoliciesImpl mockedLockServicePoliciesImpl = mock(LockServicePoliciesImpl.class);
|
||||
|
||||
BehaviourDefinition<ClassBehaviourBinding> lockDef =
|
||||
this.policyComponent.bindClassBehaviour(LockServicePolicies.BeforeLock.QNAME, ContentModel.TYPE_BASE,
|
||||
new JavaBehaviour(mockedLockServicePoliciesImpl, "beforeLock"));
|
||||
BehaviourDefinition<ClassBehaviourBinding> lockDef = this.policyComponent.bindClassBehaviour(LockServicePolicies.BeforeLock.QNAME, ContentModel.TYPE_BASE,
|
||||
new JavaBehaviour(mockedLockServicePoliciesImpl, "beforeLock"));
|
||||
|
||||
BehaviourDefinition<ClassBehaviourBinding> unlockDef =
|
||||
this.policyComponent.bindClassBehaviour(LockServicePolicies.BeforeUnlock.QNAME, ContentModel.TYPE_BASE,
|
||||
new JavaBehaviour(mockedLockServicePoliciesImpl, "beforeUnlock"));
|
||||
BehaviourDefinition<ClassBehaviourBinding> unlockDef = this.policyComponent.bindClassBehaviour(LockServicePolicies.BeforeUnlock.QNAME, ContentModel.TYPE_BASE,
|
||||
new JavaBehaviour(mockedLockServicePoliciesImpl, "beforeUnlock"));
|
||||
|
||||
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
|
||||
|
||||
@@ -305,7 +304,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
}
|
||||
catch (UnableToAquireLockException exception)
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(exception.getMessage());
|
||||
}
|
||||
@@ -443,8 +442,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
{
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, authenticationService);
|
||||
|
||||
IndexerAndSearcher indexerAndSearcher = (IndexerAndSearcher)
|
||||
applicationContext.getBean("indexerAndSearcherFactory");
|
||||
IndexerAndSearcher indexerAndSearcher = (IndexerAndSearcher) applicationContext.getBean("indexerAndSearcherFactory");
|
||||
SearcherComponent searcher = new SearcherComponent();
|
||||
searcher.setIndexerAndSearcherFactory(indexerAndSearcher);
|
||||
|
||||
@@ -498,7 +496,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -510,7 +508,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -525,7 +523,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -537,7 +535,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -545,11 +543,11 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
/* addAspect test */
|
||||
try
|
||||
{
|
||||
fullNodeService.addAspect(noAspectNode, ContentModel.ASPECT_AUTHOR , null);
|
||||
fullNodeService.addAspect(noAspectNode, ContentModel.ASPECT_AUTHOR, null);
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -561,7 +559,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -573,7 +571,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
|
||||
fail("node should be locked");
|
||||
}
|
||||
catch(NodeLockedException e)
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
// it's ok - node supposed to be locked
|
||||
}
|
||||
@@ -591,7 +589,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
@Test
|
||||
public void testExpiredEphemeralLockAndPersistentLock()
|
||||
{
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
// Check that the node is not currently locked
|
||||
assertEquals("noAspectNode should not be locked", LockStatus.NO_LOCK, securedLockService.getLockStatus(noAspectNode));
|
||||
@@ -611,8 +609,10 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
assertEquals("retrieved lock lifetime should be ephemeral", Lifetime.EPHEMERAL, lockState.getLifetime());
|
||||
assertNotNull("retrieved expire date should not be null", lockState.getExpires());
|
||||
|
||||
// Wait for 2 seconds to give the ephemeral lock time to expire
|
||||
try {Thread.sleep(2*1000);} catch (Exception exception){}
|
||||
// Wait to give the ephemeral lock time to expire
|
||||
await().pollInSameThread()
|
||||
.atMost(MAX_ASYNC_TIMEOUT)
|
||||
.until(() -> !securedLockService.isLocked(noAspectNode));
|
||||
|
||||
assertFalse("noAspectNode should not be locked", securedLockService.isLocked(noAspectNode));
|
||||
|
||||
@@ -687,7 +687,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
{
|
||||
this.lockService.unlock(this.parentNode);
|
||||
// This will pass in the open workd
|
||||
//fail("A user cannot unlock a node that is currently lock by another user.");
|
||||
// fail("A user cannot unlock a node that is currently lock by another user.");
|
||||
}
|
||||
catch (UnableToReleaseLockException exception)
|
||||
{
|
||||
@@ -710,7 +710,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
assertEquals(
|
||||
"parentNode should not be locked",
|
||||
"parentNode should not be locked",
|
||||
LockStatus.NO_LOCK,
|
||||
this.lockService.getLockStatus(this.parentNode));
|
||||
assertFalse("parentNode should not be locked", lockService.isLocked(parentNode));
|
||||
@@ -947,8 +947,10 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
assertEquals("lock status should be locked", LockStatus.LOCKED, this.lockService.getLockStatus(this.parentNode));
|
||||
assertTrue("parent node should be locked", lockService.isLocked(parentNode));
|
||||
|
||||
// Wait for 2 second before re-testing the status
|
||||
try {Thread.sleep(2*1000);} catch (Exception exception){}
|
||||
// Wait for lock to expire before re-testing the status
|
||||
await().pollInSameThread()
|
||||
.pollDelay(Duration.ofMillis(500))
|
||||
.atMost(MAX_ASYNC_TIMEOUT).until(() -> lockService.getLockStatus(parentNode), LockStatus.LOCK_EXPIRED::equals);
|
||||
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
assertEquals("lock status should be expired", LockStatus.LOCK_EXPIRED, this.lockService.getLockStatus(this.parentNode));
|
||||
@@ -981,8 +983,11 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
assertEquals("lock status should be locked", LockStatus.LOCKED, this.lockService.getLockStatus(this.parentNode));
|
||||
assertTrue("parent node should be locked", lockService.isLocked(parentNode));
|
||||
|
||||
// Wait for 2 second before re-testing the status
|
||||
try {Thread.sleep(2*1000);} catch (Exception exception){}
|
||||
// Wait for lock to expire before re-testing the status
|
||||
await().pollInSameThread()
|
||||
.pollDelay(Duration.ofMillis(500))
|
||||
.atMost(MAX_ASYNC_TIMEOUT)
|
||||
.until(() -> lockService.getLockStatus(parentNode), LockStatus.LOCK_EXPIRED::equals);
|
||||
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
assertEquals("lock status should be expired", LockStatus.LOCK_EXPIRED, this.lockService.getLockStatus(this.parentNode));
|
||||
@@ -997,7 +1002,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
public void testEphemeralExpiryThreshold()
|
||||
{
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
final int origThresh = ((LockServiceImpl)lockService).getEphemeralExpiryThreshold();
|
||||
final int origThresh = ((LockServiceImpl) lockService).getEphemeralExpiryThreshold();
|
||||
// Check the default situation is that the threshold does not apply.
|
||||
assertEquals("threshold should not apply", LockServiceImpl.MAX_EPHEMERAL_LOCK_SECONDS, origThresh);
|
||||
try
|
||||
@@ -1034,102 +1039,94 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
private void checkLifetimeForExpiry(Lifetime expectedLifetime, int expirySecs, Lifetime requestedLifetime)
|
||||
{
|
||||
lockService.unlock(parentNode);
|
||||
assertNotEquals("lock status should not be locked", LockStatus.LOCKED ,lockService.getLockStatus(parentNode));
|
||||
assertNotEquals("lock status should not be locked", LockStatus.LOCKED, lockService.getLockStatus(parentNode));
|
||||
lockService.lock(parentNode, LockType.WRITE_LOCK, expirySecs, requestedLifetime);
|
||||
LockState lock = lockService.getLockState(parentNode);
|
||||
assertEquals("lock lifetime should be the same", expectedLifetime, lock.getLifetime());
|
||||
|
||||
// Check that for any timeouts we test, a request for a persistent lock always yields a persistent lock.
|
||||
lockService.unlock(parentNode);
|
||||
assertNotEquals("lock status should not be locked", LockStatus.LOCKED ,lockService.getLockStatus(parentNode));
|
||||
assertNotEquals("lock status should not be locked", LockStatus.LOCKED, lockService.getLockStatus(parentNode));
|
||||
lockService.lock(parentNode, LockType.WRITE_LOCK, expirySecs, Lifetime.PERSISTENT);
|
||||
lock = lockService.getLockState(parentNode);
|
||||
assertEquals("lock lifetime should be persistent", Lifetime.PERSISTENT, lock.getLifetime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test to validate the behaviour of creating children of locked nodes.
|
||||
* No lock - can create children
|
||||
* READ_ONLY_LOCK - can't create children
|
||||
* WRITE_LOCK - owner can create children
|
||||
* non owner can't create children
|
||||
* NODE_LOCK non owner can create children
|
||||
* owner can create children
|
||||
* Unit test to validate the behaviour of creating children of locked nodes. No lock - can create children READ_ONLY_LOCK - can't create children WRITE_LOCK - owner can create children non owner can't create children NODE_LOCK non owner can create children owner can create children
|
||||
*/
|
||||
@Test
|
||||
public void testCreateChildrenOfLockedNodes() throws Exception
|
||||
{
|
||||
|
||||
/*
|
||||
* Check we can create a child of an unlocked node.
|
||||
*/
|
||||
assertEquals(
|
||||
"parent node should not be locked",
|
||||
LockStatus.NO_LOCK,
|
||||
this.lockService.getLockStatus(this.parentNode));
|
||||
assertFalse("parent node should not be locked", lockService.isLocked(parentNode));
|
||||
/* Check we can create a child of an unlocked node. */
|
||||
assertEquals(
|
||||
"parent node should not be locked",
|
||||
LockStatus.NO_LOCK,
|
||||
this.lockService.getLockStatus(this.parentNode));
|
||||
assertFalse("parent node should not be locked", lockService.isLocked(parentNode));
|
||||
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildA"), ContentModel.TYPE_FOLDER);
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildA"), ContentModel.TYPE_FOLDER);
|
||||
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
|
||||
this.lockService.lock(this.parentNode, LockType.WRITE_LOCK);
|
||||
|
||||
// Owner can create children
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildB"), ContentModel.TYPE_FOLDER);
|
||||
// Owner can create children
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildB"), ContentModel.TYPE_FOLDER);
|
||||
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
try
|
||||
{
|
||||
// Non owner can't create children with a write lock in place
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildB"), ContentModel.TYPE_FOLDER);
|
||||
fail("could create a child with a read only lock");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
logger.debug("exception while trying to create a child of a read only lock", e);
|
||||
}
|
||||
try
|
||||
{
|
||||
// Non owner can't create children with a write lock in place
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildB"), ContentModel.TYPE_FOLDER);
|
||||
fail("could create a child with a read only lock");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
logger.debug("exception while trying to create a child of a read only lock", e);
|
||||
}
|
||||
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
this.lockService.lock(this.parentNode, LockType.NODE_LOCK);
|
||||
this.lockService.lock(this.parentNode, LockType.NODE_LOCK);
|
||||
|
||||
// owner can create children with a node lock
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildD"), ContentModel.TYPE_FOLDER);
|
||||
// owner can create children with a node lock
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildD"), ContentModel.TYPE_FOLDER);
|
||||
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
// Non owner can create children with a node lock
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildC"), ContentModel.TYPE_FOLDER);
|
||||
// Non owner can create children with a node lock
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildC"), ContentModel.TYPE_FOLDER);
|
||||
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
this.lockService.lock(this.parentNode, LockType.READ_ONLY_LOCK);
|
||||
this.lockService.lock(this.parentNode, LockType.READ_ONLY_LOCK);
|
||||
|
||||
// owner should not be able to create children with a READ_ONLY_LOCK
|
||||
try
|
||||
{
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildD"), ContentModel.TYPE_FOLDER);
|
||||
fail("could create a child with a read only lock");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
logger.debug("exception while trying to create a child of a read only lock", e);
|
||||
}
|
||||
// owner should not be able to create children with a READ_ONLY_LOCK
|
||||
try
|
||||
{
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildD"), ContentModel.TYPE_FOLDER);
|
||||
fail("could create a child with a read only lock");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
logger.debug("exception while trying to create a child of a read only lock", e);
|
||||
}
|
||||
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
// Non owner should not be able to create children with READ_ONLY_LOCK
|
||||
try
|
||||
{
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildE"), ContentModel.TYPE_FOLDER);
|
||||
fail("could create a child with a read only lock");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
logger.debug("exception while trying to create a child of a read only lock", e);
|
||||
}
|
||||
// Non owner should not be able to create children with READ_ONLY_LOCK
|
||||
try
|
||||
{
|
||||
nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("ChildE"), ContentModel.TYPE_FOLDER);
|
||||
fail("could create a child with a read only lock");
|
||||
}
|
||||
catch (NodeLockedException e)
|
||||
{
|
||||
logger.debug("exception while trying to create a child of a read only lock", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1163,8 +1160,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService);
|
||||
|
||||
/* create node */
|
||||
final NodeRef testNode =
|
||||
this.nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{}testNode"), ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
final NodeRef testNode = this.nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{}testNode"), ContentModel.TYPE_CONTAINER).getChildRef();
|
||||
|
||||
// lock it as GOOD user
|
||||
this.securedLockService.lock(testNode, LockType.WRITE_LOCK, 2 * 86400, lt, null);
|
||||
@@ -1189,7 +1185,7 @@ public class LockServiceImplTest extends BaseSpringTest
|
||||
this.securedLockService.unlock(testNode);
|
||||
fail("BAD user shouldn't be able to unlock " + lt + " lock");
|
||||
}
|
||||
catch(AccessDeniedException e)
|
||||
catch (AccessDeniedException e)
|
||||
{
|
||||
// expected exception
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,6 +25,8 @@
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -38,10 +40,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
/**
|
||||
* Base test class providing Hibernate sessions.
|
||||
* <p>
|
||||
* By default this is auto-wired by type. If a this is going to
|
||||
* result in a conlict the use auto-wire by name. This can be done by
|
||||
* setting populateProtectedVariables to true in the constructor and
|
||||
* then adding protected members with the same name as the bean you require.
|
||||
* By default this is auto-wired by type. If a this is going to result in a conlict the use auto-wire by name. This can be done by setting populateProtectedVariables to true in the constructor and then adding protected members with the same name as the bean you require.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
@@ -50,6 +49,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
@ContextCustomizerFactories(factories = {}, mergeMode = ContextCustomizerFactories.MergeMode.REPLACE_DEFAULTS)
|
||||
public abstract class BaseSpringTest extends TestCase
|
||||
{
|
||||
protected static final Duration MAX_ASYNC_TIMEOUT = Duration.ofSeconds(10);
|
||||
public Log logger = LogFactory.getLog(getClass().getName());
|
||||
|
||||
@Autowired
|
||||
|
Reference in New Issue
Block a user