-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support suite level thread pools for data provider #2982
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package org.testng.internal; | ||
|
||
import java.io.Closeable; | ||
import java.io.IOException; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.UUID; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.function.Supplier; | ||
import org.testng.ISuite; | ||
import org.testng.log4testng.Logger; | ||
|
||
/** | ||
* A simple bean bag that is intended to help share objects during the lifetime of TestNG without | ||
* needing it to be a singleton. | ||
*/ | ||
public final class ObjectBag { | ||
|
||
private static final Logger logger = Logger.getLogger(ObjectBag.class); | ||
private final Map<Class<?>, Object> bag = new ConcurrentHashMap<>(); | ||
|
||
private static final Map<UUID, ObjectBag> instances = new ConcurrentHashMap<>(); | ||
|
||
public static ObjectBag getInstance(ISuite suite) { | ||
return instances.computeIfAbsent(suite.getXmlSuite().SUITE_ID, k -> new ObjectBag()); | ||
} | ||
|
||
public static void cleanup(ISuite suite) { | ||
UUID uid = suite.getXmlSuite().SUITE_ID; | ||
Optional.ofNullable(instances.get(uid)).ifPresent(ObjectBag::cleanup); | ||
instances.remove(uid); | ||
} | ||
|
||
/** | ||
* @param type - The type of the object to be created | ||
* @param supplier - A {@link Supplier} that should be used to produce a new instance | ||
* @return - Either the newly produced instance or the existing instance. | ||
*/ | ||
public Object createIfRequired(Class<?> type, Supplier<Object> supplier) { | ||
return bag.computeIfAbsent(type, t -> supplier.get()); | ||
} | ||
|
||
public void cleanup() { | ||
bag.values().stream() | ||
.filter(it -> it instanceof Closeable) | ||
.map(it -> (Closeable) it) | ||
.forEach( | ||
it -> { | ||
try { | ||
it.close(); | ||
} catch (IOException e) { | ||
logger.debug("Could not clean-up " + it, e); | ||
} | ||
}); | ||
bag.clear(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
import org.testng.ITestResult; | ||
import org.testng.collections.CollectionUtils; | ||
import org.testng.collections.Lists; | ||
import org.testng.internal.ObjectBag; | ||
import org.testng.internal.Parameters; | ||
import org.testng.internal.PoolService; | ||
import org.testng.internal.invokers.ITestInvoker.FailureContext; | ||
|
@@ -129,7 +130,18 @@ public List<ITestResult> runInParallel( | |
// testng387: increment the param index in the bag. | ||
parametersIndex += 1; | ||
} | ||
PoolService<List<ITestResult>> ps = new PoolService<>(suite.getDataProviderThreadCount()); | ||
|
||
ObjectBag objectBag = ObjectBag.getInstance(context.getSuite()); | ||
boolean sharedThreadPool = context.getSuite().getXmlSuite().isShareThreadPoolForDataProviders(); | ||
|
||
@SuppressWarnings("unchecked") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why the warning cannot be fixed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any suggestions on how to fix this? I am basically trying to figure out how to push in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try replacing the diamond operators with the real value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still seing it 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
PoolService<List<ITestResult>> ps = | ||
sharedThreadPool | ||
? (PoolService<List<ITestResult>>) | ||
objectBag.createIfRequired( | ||
PoolService.class, | ||
() -> new PoolService<>(suite.getDataProviderThreadCount(), false)) | ||
: new PoolService<>(suite.getDataProviderThreadCount()); | ||
List<List<ITestResult>> r = ps.submitTasksAndWait(workers); | ||
for (List<ITestResult> l2 : r) { | ||
result.addAll(l2); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,11 +56,13 @@ Cedric Beust & Alexandru Popescu | |
@attr skipfailedinvocationcounts Whether to skip failed invocations. | ||
@attr data-provider-thread-count An integer giving the size of the thread pool to use | ||
for parallel data providers. | ||
@attr share-thread-pool-for-data-providers - Whether TestNG should use a common thread pool | ||
for running parallel data providers. (Works only with TestNG versions 7.9.0 or higher) | ||
@attr object-factory A class that implements IObjectFactory that will be used to | ||
instantiate the test objects. | ||
@attr allow-return-values If true, tests that return a value will be run as well | ||
--> | ||
<!ATTLIST suite | ||
<!ATTLIST suite | ||
name CDATA #REQUIRED | ||
junit (true | false) "false" | ||
verbose CDATA #IMPLIED | ||
|
@@ -73,6 +75,7 @@ Cedric Beust & Alexandru Popescu | |
time-out CDATA #IMPLIED | ||
skipfailedinvocationcounts (true | false) "false" | ||
data-provider-thread-count CDATA "10" | ||
share-thread-pool-for-data-providers (true | false) "false" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should release a new version of the dtd. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Can you please guide me on the following?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DTD (or XSD) is a contract like an interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @juherr - Sure. I understand the intent of the DTD/XSD. But what purpose does this solve for TestNG is what I am trying to understand. Our users are mostly going to be on the same XSD (asking them to go update all the suite files with pointing it to a newer version is kind of like a sub-optimal user experience for me). The XSD exists only because we would like to validate our xml schema and it really doesn't serve any functional purpose from the user's perspective. So why would they want to update. So eventually what benefit does TestNG have by doing this? On the other hand, if we just go and update the same XSD with newer attributes, a user would just need to update to the newer TestNG version that is aware of the newer attributes and this will just work for a user. This is what my concern is. |
||
object-factory CDATA #IMPLIED | ||
group-by-instances (true | false) "false" | ||
preserve-order (true | false) "true" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As not static, in camelCase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted this to stand out as if it is a constant. That was why I intentionally broke the naming conventions and used all CAPS