提交 a16723ac 编写于 作者: oldratlee's avatar oldratlee 🔥

unify agent test

上级 22f32567
......@@ -145,6 +145,17 @@ getClasspath() {
echo "$(getTtlJarPath):$(getClasspathWithoutTtlJar)"
}
junit_test_case() {
(
cd target/test-classes &&
find . -iname '*Test.class' | sed '
s%^\./%%
s/\.class$//
s%/%.%g
'
)
}
#################################################################################
# maven actions
#################################################################################
......
......@@ -3,10 +3,11 @@
cd "$(dirname "$(readlink -f "$0")")"
source ./common.sh
# Run agent check for ExecutorService, ForkJoinPool
# Run unit test under ttl agent, include check for ExecutorService, ForkJoinPool
runCmd "${JAVA_CMD[@]}" -cp "$(getClasspathWithoutTtlJar)" \
"-javaagent:$(getTtlJarPath)=ttl.agent.logger:STDOUT" \
com.alibaba.ttl.threadpool.agent.check.AgentCheckMain
-Drun-ttl-test-under-agent=true \
org.junit.runner.JUnitCore $(junit_test_case | grep -vE '\.TtlAgentTest$')
# Run agent check for Timer/TimerTask
runCmd "${JAVA_CMD[@]}" -cp "$(getClasspathWithoutTtlJar)" \
......
......@@ -3,16 +3,5 @@
cd "$(dirname "$(readlink -f "$0")")"
source ./common.sh
junit_test_case() {
(
cd target/test-classes &&
find . -iname '*Test.class' | sed '
s%^\./%%
s/\.class$//
s%/%.%g
'
)
}
runCmd "${JAVA_CMD[@]}" -cp "$(getClasspath)" \
org.junit.runner.JUnitCore $(junit_test_case)
......@@ -50,10 +50,6 @@ import java.util.logging.Level;
* @since 0.9.0
*/
public final class TtlAgent {
private TtlAgent() {
throw new InstantiationError("Must not instantiate this class");
}
/**
* Entrance method of TTL Java Agent.
*
......@@ -114,6 +110,8 @@ public final class TtlAgent {
logger.info("[TtlAgent.premain] addTransformer " + transformer.getClass() + " success");
logger.info("[TtlAgent.premain] end");
ttlAgentLoaded = true;
} catch (Exception e) {
String msg = "Fail to load TtlAgent , cause: " + e.toString();
logger.log(Level.SEVERE, msg, e);
......@@ -155,4 +153,14 @@ public final class TtlAgent {
return ret;
}
public static boolean isTtlAgentLoaded() {
return ttlAgentLoaded;
}
private static boolean ttlAgentLoaded = false;
private TtlAgent() {
throw new InstantiationError("Must not instantiate this class");
}
}
......@@ -3,6 +3,7 @@
package com.alibaba
import com.alibaba.ttl.TransmittableThreadLocal
import com.alibaba.ttl.threadpool.agent.TtlAgent
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import java.lang.Thread.sleep
......@@ -159,3 +160,9 @@ fun <T> assertParentTtlValues(values: TtlValues<T>) {
values
)
}
fun noTtlAgentRun(): Boolean = TtlAgent.isTtlAgentLoaded().let {
val isUnderAgentSet = System.getProperties().containsKey("run-ttl-test-under-agent")
assertEquals(isUnderAgentSet, it)
!it
}
package com.alibaba.support.junit.conditional
import com.alibaba.noTtlAgentRun
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.IgnoreCondition
/**
* @see [Getting Java version at runtime](https://stackoverflow.com/a/23706899/922688)
*/
class IsAgentRun : IgnoreCondition {
override fun isSatisfied(): Boolean = !noTtlAgentRun()
}
......@@ -16,7 +16,6 @@ class ExecutorsTest {
val futures = (0..size * 2).map {
threadPool.submit {
println("run $it")
Thread.sleep(10)
}
}
......
package com.alibaba.ttl
import com.alibaba.*
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.ConditionalIgnore
import com.alibaba.support.junit.conditional.IsAgentRun
import com.alibaba.ttl.testmodel.Call
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.instanceOf
import org.junit.AfterClass
import org.junit.Assert.*
import org.junit.Rule
import org.junit.Test
import java.util.*
import java.util.concurrent.Callable
......@@ -18,12 +22,18 @@ import java.util.concurrent.TimeUnit
* @author Jerry Lee (oldratlee at gmail dot com)
*/
class TtlCallableTest {
@Rule
@JvmField
val rule = ConditionalIgnoreRule()
@Test
@ConditionalIgnore(condition = IsAgentRun::class)
fun test_TtlCallable_runInCurrentThread() {
val ttlInstances = createParentTtlInstances()
val call = Call("1", ttlInstances)
val ttlCallable = TtlCallable.get(call)
// create after new Task, won't see parent value in in task!
......@@ -46,13 +56,18 @@ class TtlCallableTest {
val ttlInstances = createParentTtlInstances()
val call = Call("1", ttlInstances)
val ttlCallable = TtlCallable.get(call)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
val ttlCallable = if (noTtlAgentRun()) TtlCallable.get(call) else call
if (noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
val future = executorService.submit(ttlCallable)
if (!noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
assertEquals("ok", future.get())
......@@ -72,13 +87,19 @@ class TtlCallableTest {
newTtlInstanceAndPut("add and removed!", ttlInstances).remove()
val call = Call("1", ttlInstances)
val ttlCallable = TtlCallable.get(call)
val ttlCallable = if (noTtlAgentRun()) TtlCallable.get(call) else call
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
if (noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
val future = executorService.submit(ttlCallable)
if (!noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
assertEquals("ok", future.get())
......@@ -90,6 +111,7 @@ class TtlCallableTest {
}
@Test
@ConditionalIgnore(condition = IsAgentRun::class)
fun test_releaseTtlValueReferenceAfterCall() {
val ttlInstances = createParentTtlInstances()
......
package com.alibaba.ttl
import com.alibaba.*
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.ConditionalIgnore
import com.alibaba.support.junit.conditional.IsAgentRun
import com.alibaba.ttl.testmodel.DeepCopyFooTransmittableThreadLocal
import com.alibaba.ttl.testmodel.FooPojo
import com.alibaba.ttl.testmodel.FooTask
......@@ -9,6 +12,7 @@ import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.instanceOf
import org.junit.AfterClass
import org.junit.Assert.*
import org.junit.Rule
import org.junit.Test
import java.util.*
import java.util.concurrent.ConcurrentHashMap
......@@ -22,8 +26,12 @@ import java.util.concurrent.atomic.AtomicInteger
* @author Jerry Lee (oldratlee at gmail dot com)
*/
class TtlRunnableTest {
@Rule
@JvmField
val rule = ConditionalIgnoreRule()
@Test
@ConditionalIgnore(condition = IsAgentRun::class)
fun test_ttlRunnable_runInCurrentThread() {
val ttlInstances = createParentTtlInstances()
......@@ -72,13 +80,19 @@ class TtlRunnableTest {
val ttlInstances = createParentTtlInstances()
val task = Task("1", ttlInstances)
val ttlRunnable = TtlRunnable.get(task)
val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
if (noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
val submit = executorService.submit(ttlRunnable)
if (!noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
val submit = executorService.submit(ttlRunnable)
submit.get()
......@@ -98,12 +112,17 @@ class TtlRunnableTest {
val task = Task("1", ttlInstances)
val ttlRunnable = TtlRunnable.get(task)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task
if (noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
val submit = executorService.submit(ttlRunnable)
if (!noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
}
submit.get()
......@@ -141,34 +160,38 @@ class TtlRunnableTest {
counterTtl.set("Foo")
// do copy when decorate runnable
val ttlRunnable1 = TtlRunnable.get { /* do nothing Runnable */ }
assertEquals(1, counterTtl.copyCounter.get().toLong())
assertEquals(0, counterTtl.beforeExecuteCounter.get().toLong())
assertEquals(0, counterTtl.afterExecuteCounter.get().toLong())
val ttlRunnable1 = if (noTtlAgentRun()) TtlRunnable.get { /* do nothing Runnable */ } else Runnable { /* do nothing Runnable */ }
assertEquals(if (noTtlAgentRun()) 1 else 0, counterTtl.copyCounter.get())
assertEquals(0, counterTtl.beforeExecuteCounter.get())
assertEquals(0, counterTtl.afterExecuteCounter.get())
// do before/after when run
executorService.submit(ttlRunnable1).get()
assertEquals(1, counterTtl.copyCounter.get().toLong())
assertEquals(1, counterTtl.beforeExecuteCounter.get().toLong())
assertEquals(1, counterTtl.afterExecuteCounter.get().toLong())
assertEquals(1, counterTtl.copyCounter.get())
assertEquals(1, counterTtl.beforeExecuteCounter.get())
Thread.sleep(1)
assertEquals(1, counterTtl.afterExecuteCounter.get())
// do before/after when run
executorService.submit(ttlRunnable1).get()
assertEquals(1, counterTtl.copyCounter.get().toLong())
assertEquals(2, counterTtl.beforeExecuteCounter.get().toLong())
assertEquals(2, counterTtl.afterExecuteCounter.get().toLong())
assertEquals(if (noTtlAgentRun()) 1 else 2, counterTtl.copyCounter.get())
assertEquals(2, counterTtl.beforeExecuteCounter.get())
Thread.sleep(1)
assertEquals(2, counterTtl.afterExecuteCounter.get())
// do copy when decorate runnable
val ttlRunnable2 = TtlRunnable.get { /* do nothing Runnable */ }
assertEquals(2, counterTtl.copyCounter.get().toLong())
assertEquals(2, counterTtl.beforeExecuteCounter.get().toLong())
assertEquals(2, counterTtl.afterExecuteCounter.get().toLong())
val ttlRunnable2 = if (noTtlAgentRun()) TtlRunnable.get { /* do nothing Runnable */ } else Runnable { /* do nothing Runnable */ }
assertEquals(if (noTtlAgentRun()) 2 else 2, counterTtl.copyCounter.get())
assertEquals(2, counterTtl.beforeExecuteCounter.get())
Thread.sleep(1)
assertEquals(2, counterTtl.afterExecuteCounter.get())
// do before/after when run
executorService.submit(ttlRunnable2).get()
assertEquals(2, counterTtl.copyCounter.get().toLong())
assertEquals(3, counterTtl.beforeExecuteCounter.get().toLong())
assertEquals(3, counterTtl.afterExecuteCounter.get().toLong())
assertEquals(if (noTtlAgentRun()) 2 else 3, counterTtl.copyCounter.get())
assertEquals(3, counterTtl.beforeExecuteCounter.get())
Thread.sleep(1)
assertEquals(3, counterTtl.afterExecuteCounter.get())
}
@Test
......@@ -184,14 +207,22 @@ class TtlRunnableTest {
ttlInstances[PARENT_CREATE_MODIFIED_IN_CHILD] = p
val task = FooTask("1", ttlInstances)
val ttlRunnable = TtlRunnable.get(task)
// create after new Task, won't see parent value in in task!
val after = DeepCopyFooTransmittableThreadLocal()
after.set(FooPojo(PARENT_CREATE_AFTER_CREATE_CHILD, 4))
ttlInstances[PARENT_CREATE_AFTER_CREATE_CHILD] = after
val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task
if (noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
val after = DeepCopyFooTransmittableThreadLocal()
after.set(FooPojo(PARENT_CREATE_AFTER_CREATE_CHILD, 4))
ttlInstances[PARENT_CREATE_AFTER_CREATE_CHILD] = after
}
val submit = executorService.submit(ttlRunnable)
if (!noTtlAgentRun()) {
// create after new Task, won't see parent value in in task!
val after = DeepCopyFooTransmittableThreadLocal()
after.set(FooPojo(PARENT_CREATE_AFTER_CREATE_CHILD, 4))
ttlInstances[PARENT_CREATE_AFTER_CREATE_CHILD] = after
}
submit.get()
// child Inheritable
......@@ -209,6 +240,7 @@ class TtlRunnableTest {
}
@Test
@ConditionalIgnore(condition = IsAgentRun::class)
fun test_releaseTtlValueReferenceAfterRun() {
val ttlInstances = createParentTtlInstances()
......
......@@ -11,9 +11,7 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.TimeUnit
import java.util.concurrent.*
private val pool = ForkJoinPool()
private val singleThreadPool = ForkJoinPool(1)
......@@ -57,7 +55,7 @@ private fun run_test_with_pool(forkJoinPool: ForkJoinPool) {
val ttlInstances = createParentTtlInstances()
val numbers = 0..42
val sumTask = SumTask(numbers, ttlInstances)
val sumTask: ForkJoinTask<Int> = if (noTtlAgentRun()) TtlSumTask(numbers, ttlInstances) else SumTask(numbers, ttlInstances)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
......@@ -66,26 +64,25 @@ private fun run_test_with_pool(forkJoinPool: ForkJoinPool) {
val future = forkJoinPool.submit(sumTask)
assertEquals(numbers.sum(), future.get())
// child Inheritable
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/),
sumTask.copied
(sumTask as Getter).getcopied()
)
// left grand Task Inheritable, changed value
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + SumTask.CHANGE_POSTFIX /* CHANGED */),
sumTask.leftSubTask.copied
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + CHANGE_POSTFIX /* CHANGED */),
sumTask.getLeftSubTask().getcopied()
)
// right grand Task Inheritable, not change value
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/),
sumTask.rightSubTask.copied
sumTask.getRightSubTask().getcopied()
)
// child do not effect parent
......@@ -98,14 +95,64 @@ private fun run_test_with_pool(forkJoinPool: ForkJoinPool) {
}
private interface Getter {
fun getcopied(): Map<String, Any>
fun getLeftSubTask(): Getter
fun getRightSubTask(): Getter
}
/**
* A test demo class
*
* @author LNAmp
* @see com.alibaba.ttl.TtlRecursiveTask
*/
private open class TtlSumTask(private val numbers: IntRange,
private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>, private val changeTtlValue: Boolean = false) : TtlRecursiveTask<Int>(), Getter {
lateinit var copied: Map<String, Any>
lateinit var leftSubTask: TtlSumTask
lateinit var rightSubTask: TtlSumTask
override fun compute(): Int {
if (changeTtlValue) {
modifyParentTtlInstances(CHANGE_POSTFIX, ttlMap)
}
try {
return if (numbers.count() <= 10) {
numbers.sum()
} else {
val mid = numbers.start + numbers.count() / 2
// left -> change! right -> not change.
val left = TtlSumTask(numbers.start until mid, ttlMap, true)
val right = TtlSumTask(mid..numbers.endInclusive, ttlMap, false)
this.leftSubTask = left
this.rightSubTask = right
left.fork()
right.fork()
left.join() + right.join()
}
} finally {
this.copied = copyTtlValues(this.ttlMap)
}
}
override fun getcopied(): Map<String, Any> = copied
override fun getLeftSubTask(): Getter = leftSubTask
override fun getRightSubTask(): Getter = rightSubTask
}
/**
* A test demo class
*/
private class SumTask(private val numbers: IntRange,
private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>, private val changeTtlValue: Boolean = false) : TtlRecursiveTask<Int>() {
private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>, private val changeTtlValue: Boolean = false) : RecursiveTask<Int>(), Getter {
lateinit var copied: Map<String, Any>
lateinit var leftSubTask: SumTask
......@@ -137,7 +184,11 @@ private class SumTask(private val numbers: IntRange,
}
}
companion object {
const val CHANGE_POSTFIX = " + 1"
}
override fun getcopied(): Map<String, Any> = copied
override fun getLeftSubTask(): Getter = leftSubTask
override fun getRightSubTask(): Getter = rightSubTask
}
const val CHANGE_POSTFIX = " + 1"
package com.alibaba.ttl.reported_bugs
import com.alibaba.noTtlAgentRun
import com.alibaba.ttl.TransmittableThreadLocal
import com.alibaba.ttl.TtlRunnable
import org.junit.Assert.assertEquals
......@@ -23,14 +24,16 @@ class Bug70_Test {
assertEquals(hello, threadLocal.get())
FutureTask<String> { threadLocal.get() }.also {
executorService.submit(TtlRunnable.get(it))
val runnable = if (noTtlAgentRun()) TtlRunnable.get(it) else it
executorService.submit(runnable)
assertEquals(hello, it.get())
}
val taskRef = AtomicReference<FutureTask<String>>()
thread(name = "the thread for run executor action") {
FutureTask<String> { threadLocal.get() }.also {
executorService.submit(TtlRunnable.get(it, false, false))
val runnable = if (noTtlAgentRun()) TtlRunnable.get(it, false, false) else it
executorService.submit(runnable)
taskRef.set(it)
}
}.join()
......
package com.alibaba.ttl.threadpool;
import com.alibaba.*
import com.alibaba.ttl.TtlRunnable
import com.alibaba.ttl.testmodel.Task
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test;
import java.util.concurrent.*
private const val POOL_SIZE = 3
val threadFactory = ThreadFactory { Thread(it).apply { isDaemon = true } }
val executorService = ThreadPoolExecutor(POOL_SIZE, POOL_SIZE,
10L, TimeUnit.SECONDS,
LinkedBlockingQueue(), threadFactory)
val scheduledExecutorService = ScheduledThreadPoolExecutor(POOL_SIZE, threadFactory)
class ExecutorClassesTest {
@Test
fun checkThreadPoolExecutorForRemoveMethod() {
val futures = (0 until POOL_SIZE * 2).map {
executorService.submit { Thread.sleep(10) }
}
Runnable {
println("Task should be removed!")
}.let {
if (noTtlAgentRun()) TtlRunnable.get(it)
else it
}.let {
executorService.execute(it)
// Does ThreadPoolExecutor#remove method take effect?
assertTrue(executorService.remove(it))
assertFalse(executorService.remove(it))
}
// wait sleep task finished.
futures.forEach { it.get(100, TimeUnit.MILLISECONDS) }
}
@Test
fun checkScheduledExecutorService() {
val ttlInstances = createParentTtlInstances(ConcurrentHashMap())
val tag = "2"
val task = Task(tag, ttlInstances)
val future = scheduledExecutorService.schedule(if (noTtlAgentRun()) TtlRunnable.get(task) else task, 100, TimeUnit.MILLISECONDS)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
future.get(200, TimeUnit.MILLISECONDS)
// child Inheritable
assertChildTtlValues(tag, task.copied)
// child do not effect parent
assertParentTtlValues(copyTtlValues(ttlInstances))
}
}
package com.alibaba.ttl.threadpool
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule
import com.alibaba.support.junit.conditional.ConditionalIgnoreRule.ConditionalIgnore
import com.alibaba.support.junit.conditional.IsAgentRun
import com.alibaba.ttl.threadpool.TtlExecutors.*
import org.junit.Assert.*
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.Executors.newScheduledThreadPool
......@@ -9,7 +13,12 @@ import java.util.concurrent.Executors.newScheduledThreadPool
* @author Jerry Lee (oldratlee at gmail dot com)
*/
class TtlExecutorsTest {
@Rule
@JvmField
val rule = ConditionalIgnoreRule()
@Test
@ConditionalIgnore(condition = IsAgentRun::class)
fun test_common() {
val newScheduledThreadPool = newScheduledThreadPool(3)
......@@ -35,8 +44,8 @@ class TtlExecutorsTest {
@Test
fun test_null() {
assertNull(TtlExecutors.getTtlExecutor(null))
assertNull(TtlExecutors.getTtlExecutorService(null))
assertNull(getTtlExecutor(null))
assertNull(getTtlExecutorService(null))
assertNull(getTtlScheduledExecutorService(null))
assertFalse(isTtlWrapper(null))
......
@file:JvmName("AgentCheckMain")
package com.alibaba.ttl.threadpool.agent.check
import com.alibaba.support.junit.conditional.BelowJava7
fun main(args: Array<String>) {
com.alibaba.ttl.threadpool.agent.check.executor.main(args)
if (!BelowJava7().isSatisfied)
com.alibaba.ttl.threadpool.agent.check.forkjoin.main(args)
}
@file:JvmName("ExecutorClassesAgentCheck")
package com.alibaba.ttl.threadpool.agent.check.executor
import com.alibaba.*
import com.alibaba.ttl.testmodel.Task
import org.junit.Assert.*
import java.util.concurrent.*
private const val POOL_SIZE = 3
/**
* @author Jerry Lee (oldratlee at gmail dot com)
* @author wuwen5 (wuwen.55 at aliyun dot com)
* @see com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlExecutorTransformlet
*/
fun main(args: Array<String>) {
val threadFactory = ThreadFactory { Thread(it).apply { isDaemon = true } }
val executorService = ThreadPoolExecutor(POOL_SIZE, POOL_SIZE,
10L, TimeUnit.SECONDS,
LinkedBlockingQueue(), threadFactory)
val scheduledExecutorService = ScheduledThreadPoolExecutor(POOL_SIZE, threadFactory)
expandThreadPool(executorService)
expandThreadPool(scheduledExecutorService)
checkExecutorService(executorService)
checkThreadPoolExecutorForRemoveMethod(executorService)
checkScheduledExecutorService(scheduledExecutorService)
executorService.shutdown()
scheduledExecutorService.shutdown()
if (!executorService.awaitTermination(100, TimeUnit.MILLISECONDS)) fail("Fail to shutdown thread pool")
if (!scheduledExecutorService.awaitTermination(100, TimeUnit.MILLISECONDS))
fail("Fail to shutdown thread pool")
printHead("ExecutorClassesAgentCheck OK!")
}
private fun checkExecutorService(executorService: ExecutorService) {
printHead("checkExecutorService")
val ttlInstances = createParentTtlInstances(ConcurrentHashMap())
val tag = "1"
val task = Task(tag, ttlInstances)
val future = executorService.submit(task)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
future.get(100, TimeUnit.MILLISECONDS)
// child Inheritable
assertChildTtlValues(tag, task.copied)
// child do not effect parent
assertParentTtlValues(copyTtlValues(ttlInstances))
}
private fun checkThreadPoolExecutorForRemoveMethod(executor: ThreadPoolExecutor) {
printHead("checkThreadPoolExecutorForRemoveMethod")
val futures = (0 until POOL_SIZE * 2).map {
executor.submit { Thread.sleep(10) }
}
Runnable {
println("Task should be removed!")
}.let {
executor.execute(it)
// Does ThreadPoolExecutor#remove method take effect?
assertTrue(executor.remove(it))
assertFalse(executor.remove(it))
}
// wait sleep task finished.
futures.forEach { it.get(100, TimeUnit.MILLISECONDS) }
}
private fun checkScheduledExecutorService(scheduledExecutorService: ScheduledExecutorService) {
printHead("checkScheduledExecutorService")
val ttlInstances = createParentTtlInstances(ConcurrentHashMap())
val tag = "2"
val task = Task(tag, ttlInstances)
val future = scheduledExecutorService.schedule(task, 100, TimeUnit.MILLISECONDS)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
future.get(200, TimeUnit.MILLISECONDS)
// child Inheritable
assertChildTtlValues(tag, task.copied)
// child do not effect parent
assertParentTtlValues(copyTtlValues(ttlInstances))
}
@file:JvmName("ForkJoinTaskClassAgentCheck")
package com.alibaba.ttl.threadpool.agent.check.forkjoin
import com.alibaba.*
import com.alibaba.ttl.TransmittableThreadLocal
import org.junit.Assert.assertEquals
import org.junit.Assert.fail
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.RecursiveTask
import java.util.concurrent.TimeUnit
private val pool = ForkJoinPool()
private val singleThreadPool = ForkJoinPool(1)
/**
* !! Quick and dirty: copy code from [com.alibaba.ttl.forkjoin.recursive_task.TtlRecursiveTaskTest] !!
*
* @author Jerry Lee (oldratlee at gmail dot com)
* @author wuwen5 (wuwen.55 at aliyun dot com)
* @see com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlForkJoinTransformlet
*/
fun main(args: Array<String>) {
check_TtlRecursiveTask_asyncWith_ForkJoinPool()
check_TtlRecursiveTask_asyncWith_SingleThreadForkJoinPool()
pool.shutdown()
if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS)) fail("Fail to shutdown thread pool")
singleThreadPool.shutdown()
if (!singleThreadPool.awaitTermination(100, TimeUnit.MILLISECONDS)) fail("Fail to shutdown thread pool")
printHead("ForkJoinTaskClassAgentCheck OK!")
}
private fun check_TtlRecursiveTask_asyncWith_ForkJoinPool() {
printHead("check_TtlRecursiveTask_asyncWith_ForkJoinPool")
run_test_with_pool(pool)
}
private fun check_TtlRecursiveTask_asyncWith_SingleThreadForkJoinPool() {
printHead("check_TtlRecursiveTask_asyncWith_SingleThreadForkJoinPool")
run_test_with_pool(singleThreadPool)
}
private fun run_test_with_pool(forkJoinPool: ForkJoinPool) {
val ttlInstances = createParentTtlInstances()
val numbers = 0..42
val sumTask = SumTask(numbers, ttlInstances)
// create after new Task, won't see parent value in in task!
createParentTtlInstancesAfterCreateChild(ttlInstances)
val future = forkJoinPool.submit(sumTask)
assertEquals(numbers.sum(), future.get())
// child Inheritable
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/
),
sumTask.copied
)
// left grand Task Inheritable, changed value
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + SumTask.CHANGE_POSTFIX /* CHANGED */
),
sumTask.leftSubTask.copied
)
// right grand Task Inheritable, not change value
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/),
sumTask.rightSubTask.copied
)
// child do not effect parent
assertTtlValues(
mapOf(PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,
PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD,
PARENT_CREATE_AFTER_CREATE_CHILD to PARENT_CREATE_AFTER_CREATE_CHILD),
copyTtlValues(ttlInstances)
)
}
/**
* A test demo class
*
* @author LNAmp
* @see com.alibaba.ttl.TtlRecursiveTask
*/
private class SumTask(private val numbers: IntRange,
private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>,
private val changeTtlValue: Boolean = false) : RecursiveTask<Int>() {
lateinit var copied: Map<String, Any>
lateinit var leftSubTask: SumTask
lateinit var rightSubTask: SumTask
override fun compute(): Int {
if (changeTtlValue) {
modifyParentTtlInstances(CHANGE_POSTFIX, ttlMap)
}
try {
return if (numbers.count() <= 10) {
numbers.sum()
} else {
val mid = numbers.start + numbers.count() / 2
// left -> change! right -> not change.
val left = SumTask(numbers.start until mid, ttlMap, true)
val right = SumTask(mid..numbers.endInclusive, ttlMap, false)
this.leftSubTask = left
this.rightSubTask = right
left.fork()
right.fork()
left.join() + right.join()
}
} finally {
this.copied = copyTtlValues(this.ttlMap)
}
}
companion object {
const val CHANGE_POSTFIX = " + 1"
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册