Skip to content

Commit

Permalink
[pinpoint-apm#8965] Simplified thread flow control of SharedTestLifeC…
Browse files Browse the repository at this point in the history
…ycle
  • Loading branch information
emeroad committed Jun 30, 2022
1 parent 516b4b5 commit 56fa369
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 207 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

Expand All @@ -50,7 +49,7 @@
public class SharedPinpointPluginTest {
private static final TaggedLogger logger = TestLogger.getLogger();

public static void main(String[] args) throws Throwable {
public static void main(String[] args) throws Exception {
final String mavenDependencyResolverClassPaths = System.getProperty(SharedPluginTestConstants.MAVEN_DEPENDENCY_RESOLVER_CLASS_PATHS);
if (mavenDependencyResolverClassPaths == null) {
logger.error("mavenDependencyResolverClassPaths must not be empty");
Expand Down Expand Up @@ -202,7 +201,7 @@ private void logTestInformation() {
}
}

public void execute() throws Throwable {
public void execute() throws Exception {
logTestInformation();
ClassLoader mavenDependencyResolverClassLoader = new ChildFirstClassLoader(URLUtils.fileToUrls(mavenDependencyResolverClassPaths));
File testClazzLocation = new File(testLocation);
Expand All @@ -211,34 +210,24 @@ public void execute() throws Throwable {
executes(testInfos);
}

private void executes(List<TestInfo> testInfos) throws Throwable {
private void executes(List<TestInfo> testInfos) {
if (!CollectionUtils.hasLength(testInfos)) {
return;
}

TestInfo firstTestInfo = testInfos.get(0);
final ClassLoader testClassLoader = createTestClassLoader(firstTestInfo);
ExecuteSharedThread executeSharedThread = new ExecuteSharedThread(testClazzName, testClassLoader);

executeSharedThread.startBefore();
executeSharedThread.awaitBeforeCompleted(10, TimeUnit.MINUTES);
Throwable runnableError = executeSharedThread.getRunnableError();
if (runnableError != null) {
throw runnableError;
}
Properties properties = executeSharedThread.getProperties();
if (logger.isDebugEnabled()) {
logger.debug("sharedThread properties:{}", properties);
}
final ClassLoader sharedClassLoader = createTestClassLoader(firstTestInfo);
SharedTestExecutor sharedTestExecutor = new SharedTestExecutor(testClazzName, sharedClassLoader);

sharedTestExecutor.startBefore(10, TimeUnit.MINUTES);


final SharedTestLifeCycleWrapper sharedTestLifeCycleWrapper = executeSharedThread.getSharedClassWrapper();
final SharedTestLifeCycleWrapper sharedTestLifeCycleWrapper = sharedTestExecutor.getSharedClassWrapper();
for (TestInfo testInfo : testInfos) {
execute(testInfo, properties, sharedTestLifeCycleWrapper);
execute(testInfo, sharedTestLifeCycleWrapper);
}

executeSharedThread.startAfter();

executeSharedThread.join(TimeUnit.MINUTES.toMillis(5));
sharedTestExecutor.startAfter(5, TimeUnit.MINUTES);
}

private ClassLoader createTestClassLoader(TestInfo testInfo) {
Expand All @@ -249,11 +238,10 @@ private ClassLoader createTestClassLoader(TestInfo testInfo) {
}
}
URL[] urls = URLUtils.fileToUrls(dependencyFileList);
final ClassLoader testClassLoader = new ChildFirstClassLoader(urls, ProfilerClass.PINPOINT_PROFILER_CLASS);
return testClassLoader;
return new ChildFirstClassLoader(urls, ProfilerClass.PINPOINT_PROFILER_CLASS);
}

private void execute(final TestInfo testInfo, final Properties properties, SharedTestLifeCycleWrapper sharedTestLifeCycleWrapper) {
private void execute(final TestInfo testInfo, SharedTestLifeCycleWrapper sharedTestLifeCycleWrapper) {
try {
final ClassLoader testClassLoader = createTestClassLoader(testInfo);

Expand Down Expand Up @@ -294,7 +282,9 @@ private Class<?> loadClass() {
}
};
String threadName = testClazzName + " " + testInfo.getTestId() + " Thread";
Thread testThread = newThread(runnable, threadName, testClassLoader);

ThreadFactory threadFactory = new ThreadFactory(threadName, testClassLoader);
Thread testThread = threadFactory.newThread(runnable);
testThread.start();

testThread.join(TimeUnit.MINUTES.toMillis(5));
Expand All @@ -313,12 +303,4 @@ private void checkTerminatedState(Thread testThread, String testInfo) {
}
}

private Thread newThread(Runnable runnable, String threadName, ClassLoader testClassLoader) {
Thread testThread = new Thread(runnable);
testThread.setName(threadName);
testThread.setContextClassLoader(testClassLoader);
testThread.setDaemon(true);
return testThread;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright 2021 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.test.plugin.shared;

import com.navercorp.pinpoint.test.plugin.util.TestLogger;

import org.tinylog.TaggedLogger;

import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
* @author Taejin Koo
*/
public class SharedTestExecutor {

private static final TaggedLogger logger = TestLogger.getLogger();

private final ExecutorService executor;
private final String testClazzName;
private final ClassLoader testClassLoader;

private volatile SharedTestLifeCycleWrapper sharedTestLifeCycleWrapper;

public SharedTestExecutor(String testClazzName, ClassLoader testClassLoader) {
this.testClazzName = Objects.requireNonNull(testClazzName, "testClazzName");
this.testClassLoader = Objects.requireNonNull(testClassLoader, "testClassLoader");

ThreadFactory threadFactory = new ThreadFactory(testClazzName + "-Shared-Executor", testClassLoader);
this.executor = Executors.newSingleThreadExecutor(threadFactory);
}

void startBefore(long timeout, TimeUnit unit) {
Future<?> future = this.executor.submit(this::beforeAll);
awaitFuture("startBefore", future, timeout, unit);
}

private <V> V awaitFuture(String action, Future<V> future, long timeout, TimeUnit unit) {
try {
return future.get(timeout, unit);
} catch (ExecutionException | InterruptedException e) {
logger.warn("{} execution error {}", action, testClazzName, e);
throw new IllegalStateException(action + " execution error " + testClazzName, e);
} catch (TimeoutException e) {
future.cancel(true);
logger.warn("{} timeout {}", action, testClazzName);
throw new IllegalStateException(action + " timeout " + testClazzName);
}
}

public SharedTestLifeCycleWrapper getSharedClassWrapper() {
return sharedTestLifeCycleWrapper;
}


void startAfter(long timeout, TimeUnit unit) {
Future<?> future = this.executor.submit(this::afterAll);
awaitFuture("startAfter", future, timeout, unit);
}


private void beforeAll() {
Class<?> testClazz = loadClass();

logger.debug("Execute testClazz:{} cl:{}", testClazz.getName(), testClazz.getClassLoader());

sharedTestLifeCycleWrapper = SharedTestLifeCycleWrapper.newSharedTestLifeCycleWrapper(testClazz);
if (sharedTestLifeCycleWrapper != null) {
sharedTestLifeCycleWrapper.beforeAll();
}
}

private void afterAll() {
if (sharedTestLifeCycleWrapper != null) {
sharedTestLifeCycleWrapper.afterAll();
}
}

private Class<?> loadClass() {
try {
return testClassLoader.loadClass(testClazzName);
} catch (ClassNotFoundException e) {
logger.error(e, "testClazz:{} not found", testClazzName);
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit 56fa369

Please sign in to comment.