Share limited amount of resources between different threads - java

I write selenium tests and make it parallel via testng.
There are some tests which should use resource, and that resource cant be used in tests, while it using in another test.
So to make it clear let me describe in other words, I have 10 resources, and when some test start working with one of them, only 9 another resources should be available in another tests. If all 10 resources are busy, and another test attempts to get it, it should wait until one of test will finish execution and free it's resource.
Im trying to create provider which will control desired behaviour but it looks like I get deadlocks, because it hangs out some times at synchronized method call.
My plan is provider have 2 methods get() and remove()
get() called in test method to get resource
remove() called in method annotated with #AfterMethod annotation and this method is default method of specific interface which should be implemented in class, containing resource usage
Here is provider class:
public class ResourceProvider {
private static final Logger logger = LogManager.getLogger();
private static List<Resource> freeResources;
private static Map<String, List<Resource>> resourcesInUse;
static {
freeResources = new ArrayList<>();
//here is resource initialization to fill freeResources list
resourcesInUse = new HashMap<>();
}
public static synchronized Resource get() {
String testName = Thread.currentThread().getStackTrace()[2].getClassName()
+ "." + Thread.currentThread().getStackTrace()[2].getMethodName();
Resource resource = null;
logger.info(String.format("Attempt to get resource for %s test", testName));
for (int i = 0; i < 240; i++) {
if (freeResources.isEmpty()) {
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
resource = freeResources.get(0);
if (resourcesInUse.containsKey(testName)) {
resourcesInUse.get(testName).add(resource);
} else {
List<Resource> resources = new ArrayList<>();
resources.add(resource);
resourcesInUse.put(testName, resources);
}
freeResources.remove(resource);
break;
}
}
if (resource == null) {
throw new RuntimeException(String.format("There is no free resource for '%s' in 20 minutes", testName));
}
logger.info(String.format("Resource %s used in %s", resource, testName));
return resource;
}
public static synchronized boolean remove(ITestResult result) {
String testName = result.getMethod().getTestClass().getName() + "." + result.getMethod().getMethodName();
return remove(testName);
}
public static synchronized boolean remove(String testName) {
boolean isTestUseResource = resourcesInUse.containsKey(testName);
if (isTestUseResource) {
logger.info(String.format("Removing %s resources, used in %s", resourcesInUse.get(testName), testName));
freeResources.addAll(resourcesInUse.get(testName));
resourcesInUse.remove(testName);
}
return isTestUseResource;
}
Interface:
public interface RemoveResource {
#AfterMethod
default void removeResource(ITestResult result) {
ResourceProvider.remove(result);
}
But this code doesnt work good, it hangs out at remove() call sometimes.
May you help me to understand why I get hangs out and how to resolve it?

Related

JUnit testing / calling function few times

I am extracting concept from a single page and that page is being used in different functions, so i have created a function that assigns the value if value hasn't been assigned yet.
public String text() {
if (text.isPresent()) {
return text.get();
}
this.text = Optional.of(extractText(pdDocument));
return text.get();
}
I would like to create a test that checks that the function is being called once and the context is shared between the functions that doing some functionality in the same context
Here is an example when text() is being called twice
private Optional<String> packingListNet() {
return locatePattern(text(), PACKING_LIST_NET);
}
private Optional<String> packingListNumber() {
return locatePattern(text(), PACKING_LIST_NUMBER);
}
Would be grateful for any information, thank you
The technical answer: you could use a mocking library, such as PowerMockito, to create mocked instances of the Optional class. And when you have a mock object, you can instruct the mock how to react to method calls. Then you need to "get" the mocked Optional object into your class under test.
You could use that to cover the first if statement: you expect the mock to see the isPresent() call, to return true, and to then return a specific string. Your testcase could then check "that expected string came back". Similar for the other way round, when the mocked Optional "is empty", then you ensure another string is returned, and you check for that.
But honestly, it is doubtful if you should do that all.
You should focus on the public contract that your method there provides.
And that would mean:
Enable yourself that you can pass in a (real) Optional object into the class under test
When your Optional is not empty, your test expects ... what you put into it
When your Optional is empty, your test expects whatever extractText() will return
Of course, mocking is really problematic here: Optional is a final class. So you need to either use Mockito with "experimental support for final enabled", or you need to use PowerMock(ito) (which I strongly advise to never use).
So, as said: avoid mocking.
I think this method is badly conceived. It may rely on private, mutable state that will be a problem with multiple documents and threads accessing them.
A better approach would be to pass all the necessary information as method parameters. They are thread safe that way;
public static String getText(String textToSearchFor, Document pdfDocument) {
// extract here
}
Here's how I might write a JUnit test for a method like this:
public class TextMethodOwnerTest {
#Test
public void testGetText_Success() {
// setup
String expected = "text to find";
Document pdf; // Have to get this.
// exercise
String actual = TextMethodOwner.getText(expected, pdf);
// assert
Assert.assertEquals(expected, actual);
}
#Test
public void testGetText_PackingListNumber() {
// Add another case here
}
#Test
public void testGetText_PackingListNet() {
// Add another case here
}
}
I am not sure what are you trying to ask. Information is not clear but maybe this can help you:
Junit and mockito are mostly used togther. If you want to check any function gets called only one time we use verify() method of mockito with parameter atLeast(1)
For example: Example taken from (https://www.baeldung.com/mockito-verify)
List<String> mockedList = mock(MyList.class);
mockedList.clear();
mockedList.clear();
mockedList.clear();
verify(mockedList, atLeast(1)).clear();
Here is some pseudo code how you could achieve it:
public Class {
int counter = 0;
void test() {
counter++;
}
}
public ClassTest {
public Class class;
void shouldBeCalledOneTime() {
class.test();
AssertThat(class).hasFieldWithValue("counter", 1);
}
}
Since your question seemed to me mostly about reading the file only once, which is quite a genuine need for many, I wrote up this class using your code, but without JUnit.
This has a main method that calls the packingList*() method 100 times to different threads, but you will see that the extraction part is entered into only once in the beginning. For this, I have added a lock and used a synchronized block. I understand that this is basic, but thought I may share since it might help others.
Note the changes in the method public String text().
public class ReusedText{
private static final long PACKING_LIST_NET = 200;
private static final long PACKING_LIST_NUMBER = 120;
private Optional<String> text = Optional.ofNullable( null );
private Document pdDocument;
private static final Object LOCK = new Object();
private static final ExecutorService svc = Executors.newFixedThreadPool( 2 );
public ReusedText(Document pdDocument) {
super();
this.pdDocument = pdDocument;
}
public static void main( String[] args ){
ReusedText rt = new ReusedText( new Document( "/path/to/document/on/disk" ) );
for( int i = 0; i < 100; i++ ) {
svc.submit( () -> System.out.println( rt.packingListNet() ) );
svc.submit( () -> System.out.println( rt.packingListNumber() ) );
}
svc.shutdown();
}
public String text() {
if (text.isPresent()) {
return text.get();
}
else {
synchronized (LOCK) {
/* This repeated 'if' block is necessary because 'text' may have got populated while this thread was waiting for lock. */
if (text.isPresent()) return text.get();
else{
System.out.println( "Extracting text..." );
this.text = Optional.of( extractText( pdDocument ) );
return text.get();
}
}
}
}
private String extractText( Document doc ) {
//Read the file contents using some API like java.nio.file.Files or Apache Tika
return "file contents here!";
}
private Optional<String> packingListNet() {
return locatePattern(text(), PACKING_LIST_NET);
}
private Optional<String> packingListNumber() {
return locatePattern(text(), PACKING_LIST_NUMBER);
}
private Optional<String> locatePattern( String text, long packingListNumber ){
//Implement your logic with the text here.
return Optional.of( String.valueOf( packingListNumber ) );
}
private static class Document{
private String pathToText;
public Document(String pathToText) {
super();
this.pathToText = pathToText;
}
public String getPathToText(){
return pathToText;
}
}
}

Dynamically invoke the correct implementation in a factory

I have a library which parse URLs and extract some data. There is one class per URL. To know which class should handle the URL provided by the user, I have the code below.
public class HostExtractorFactory {
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
switch (host) {
case HostExtractorABC.HOST_NAME:
return HostExtractorAbc.getInstance();
case HostExtractorDEF.HOST_NAME:
return HostExtractorDef.getInstance();
case HostExtractorGHI.HOST_NAME:
return HostExtractorGhi.getInstance();
default:
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
}
The problem is users are requesting more URL to be parsed, which means my switch statement is growing. Every time someone comes up with a parser, I have to modify my code to include it.
To end this, I've decided to create a map and expose it to them, so that when their class is written, they can register themselves to the factory, by providing the host name, and the extractor to the factory. Below is the factory with this idea implemented.
public class HostExtractorFactory {
private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>();
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
if(EXTRACTOR_MAPPING.containsKey(host)) {
return EXTRACTOR_MAPPING.get(host);
} else {
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
public static void register(String hostname, HostExtractor extractor) {
if(StringUtils.isBlank(hostname) == false && extractor != null) {
EXTRACTOR_MAPPING.put(hostname, extractor);
}
}
}
And the user would use it that way:
public class HostExtractorABC extends HostExtractor {
public final static String HOST_NAME = "www.abc.com";
private static class HostPageExtractorLoader {
private static final HostExtractorABC INSTANCE = new HostExtractorABC();
}
private HostExtractorABC() {
if (HostPageExtractorLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
HostExtractorFactory.register(HOST_NAME, this);
}
public static HostExtractorABC getInstance() {
return HostPageExtractorLoader.INSTANCE;
}
...
}
I was patting my own back when I realized this will never work: the user classes are not loaded when I receive the URL, only the factory, which means their constructor never runs, and the map is always empty. So I am back to the drawing board, but would like some ideas around getting this to work or another approach to get rid of this pesky switch statement.
S
Another option is to use the Service Loader approach.
Having your implementers add something like the following in ./resources/META-INF/services/your.package.HostExtractor:
their.package1.HostExtractorABC
their.package2.HostExtractorDEF
their.package3.HostExtractorGHI
...
Then in your code, you can have something like:
HostExtractorFactory() {
final ServiceLoader<HostExtractor> loader
= ServiceLoader.load(your.package.HostExtractor.class);
for (final HostExtractor registeredExtractor : loader) {
// TODO - Perform pre-processing which is required.
// Add to Map? Extract some information and store? Etc.
}
}
I would advice for you to learn about dependency injection (I love spring implementation). You will then be able to write an interface like
public interface HostExtractorHandler {
public String getName();
public HostExtractor getInstance();
}
Than your code can "ask" for all classes that implements this interface, you then would be able to build your map in the initialization phase of your class.
I would use the Reflections library to locate the parsers. They all appear to derive from the HostExtractor class, so use the library to locate all subtypes:
Reflections reflections = new Reflections("base.package");
Set<Class<? extends HostExtractor>> extractorTypes =
reflections.getSubTypesOf(HostExtractor.class);
Use the results to create the instances in your factory:
for (Class<? extends HostExtractor> c : extractorTypes) {
HostExtractor he = c.newInstance();
EXTRACTOR_MAPPING.put(he.getHostName(), he);
}
I made up the getHostName method, but it should be trivial to add to the HostExtractor base class.

How to Monitor an existing Java class with JMX?

I have an existing Java class as follows and I want to monitor number of method invocations for each method in this class using JMX. How do I do it? I tried google but I can't see the big picture on how the whole thing is connected. It would be great if I can see see some code examples
Public class RPCServer {
public void storeSchema() { // want to count number of method invocations
System.out.println("storeSchema");
}
public void getSchema() { // want to count number of method invocations
System.out.println("getSchema");
}
public void storeRow() { // want to count number of method invocations
System.out.println("storeRow");
}
public void getRow() { //want to count number of method invocations
System.out.println("getRow");
}
}
I you want to see how many time some methods are executed through JMX, I propose this solution
First you need an interface for your class. Only the methods of this interface are visible for JMX:
public interface RPCServerInterface {
int countMethodInvocation(String method);
}
Then in the class you store how many time each function is call.
public class RPCServer implements RPCServerInterface{
private int row;
private Map<String,Integer> countByMethod = new HashMap<String,Integer>();
// +1 to the number of time of execution of this method
private void sumMethodInvocation(String method) {
if ( countByMethod.containsKey(method) ) {
int n = countByMethod.get(method);
countByMethod.put(method, n+1);
} else {
countByMethod.put(method,1);
}
}
// how many time the method has been invoked
#Override
public int countMethodInvocation(String method){
return countByMethod.containsKey(method)?countByMethod.get(method):0;
}
public void setRow(int i) {
// register each time is executed
this.sumMethodInvocation("setRow");
this.row = i;
}
public int getRow() {
// register each time is executed
this.sumMethodInvocation("getRow");
return row;
}
}}
}
Then you have to register your Bean:
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
RPCServer rpcServer = new RPCServer();
ObjectName objectName = new ObjectName("org.foo.RPCServer.jmx:type=RPCServerInterface");
StandardMBean standardMBean = new StandardMBean(rpcServer,RPCServerInterface.class);
mBeanServer.registerMBean(standardMBean, objectName);
The path org.foo.RPCServer.jmx is arbitrary.
Then your run jconsole and you find the process you are running.
Then you can run the command countMethodInvocation and you can get the number of execution time.
Like this:
This tutorial can be useful:
what-is-jmx-mbean-jconsole-tutorial

TestNG: RetryAnalyzer, dependent groups are skipped if a test succeeds upon retry

I have a RetryAnalyzer and RetryListener. In RetryListener onTestFailure, I check if the test is retryable, if yes I set the result to SUCCESS. I also do, testResult.getTestContext().getFailedMethods.removeResult(testResult) in this method.
I again remove failed results (with valid if conditions) in onFinish method in the listener.
Now the problem I am running into is, I made each test class into groups. One test class does the WRITES and one test class does the READS. So READs group depends on WRITES.
If a test case fails on 1st attempts and succeeds on retrying, then all the test cases in the dependent group are SKIPPED, despite removing failed result in onTestFailure method.
Is there a way to run dependent method if a test case succeeds on retrying? I am fine with the behavior if the test case fails in all attempts, so I am not looking to add "alwaysRun=true" on each dependent method.
On retry you should be removing the test from the Failed tests. And plz be sure to remove ITestResult object. (i.e, result but not result.getMethod())
#Override
public boolean retry(ITestResult result) {
if (currentCount < maxRetryCount) {
result.getTestContext().getFailedTests().removeResult(result);
currentCount++;
return true;
}
return false;
}
I was using TestNG 6.8.7, upgraded it to 6.9.5.
After that, upon retry, TestNG was marking test case as SKIPPED. I just had to create a Listener, which implemented TestListenerAdapter and override onTestSkipped, if there are retries available then remove the method from skippedTests.
result.getTestContext().getSkippedTests().removeResult(result.getMethod());
If not set test to FAILURE. Now it works as expected.
In retry file, add a mechanism to see if retry is left of the case.
In Custom Listener, override onTestSkipped() and check if RetryLeft, remove it from skippedResult and return
public class Retry implements IRetryAnalyzer {
private int count = 0;
private static final List retriedTests = new CopyOnWriteArrayList();
private static final ConcurrentHashMap<String, Boolean> retriedTestsMap = new ConcurrentHashMap();
#Override
public boolean retry(ITestResult iTestResult) {
int maxTry = 3;
if (!iTestResult.isSuccess()) { // Check if test not succeed
String name = getNameForTestResult(iTestResult);
if (count < maxTry) { // Check if maxTry count is reached
count++; // Increase the count count by 1
retriedTests.add(iTestResult);
retriedTestsMap.put(name, true);
RestApiUtil.println("**" + name + " retry count " + count + " **");
iTestResult.setStatus(ITestResult.FAILURE); // Mark test as failed
return true; // Tells TestNG to re-run the test
} else {
iTestResult.setStatus(ITestResult.FAILURE); // If maxCount reached,test marked as failed
retriedTestsMap.put(name, true);
}
} else {
iTestResult.setStatus(ITestResult.SUCCESS); // If test passes, TestNG marks it as passed
}
return false;
}
public static List getRetriedTests() {
return retriedTests;
}
public static boolean isRetryLeft(ITestResult tr) {
return retriedTestsMap.get(getNameForTestResult(tr));
}
private static String getNameForTestResult(ITestResult tr) {
return tr.getTestClass().getRealClass().getSimpleName() + "::" + tr.getName();
}
}
public class CustomTestNGListener extends TestListenerAdapter {
#Override
public void onTestSkipped(ITestResult tr) {
if (Retry.isRetryLeft(tr)) {
tr.getTestContext().getSkippedTests().removeResult(tr);
return;
}
super.onTestSkipped(tr);
}
}

Junit4 run a test class a fixed number of times and display results (eclipse)

I want to be able to run a Test class a specified number of times. The class looks like :
#RunWith(Parameterized.class)
public class TestSmithWaterman {
private static String[] args;
private static SmithWaterman sw;
private Double[][] h;
private String seq1aligned;
#Parameters
public static Collection<Object[]> configs() {
// h and seq1aligned values
}
public TestSmithWaterman(Double[][] h, String seq1aligned) {
this.h = h;
this.seq1aligned = seq1aligned;
}
#BeforeClass
public static void init() {
// run smith waterman once and for all
}
#Test
#Repeat(value = 20) // does nothing
// see http://codehowtos.blogspot.gr/2011/04/run-junit-test-repeatedly.html
public void testCalculateMatrices() {
assertEquals(h, sw.getH());
}
#Test
public void testAlignSeq1() {
assertEquals(seq1aligned, sw.getSeq1Aligned());
}
// etc
}
Any of the tests above may fail (concurrency bugs - EDIT : the failures provide useful debug info) so I want to be able to run the class multiple times and preferably have the results grouped somehow. Tried the Repeat annotation - but this is test specific (and did not really make it work - see above) and struggled with the RepeatedTest.class, which cannot seem to transfer to Junit 4 - the closest I found on SO is this - but apparently it is Junit3. In Junit4 my suite looks like :
#RunWith(Suite.class)
#SuiteClasses({ TestSmithWaterman.class })
public class AllTests {}
and I see no way to run this multiple times.
Parametrized with empty options is not an option really - as I need my params anyway
So I am stuck hitting Control + F11 in eclipse again and again
Help
EDIT (2017.01.25): someone went ahead and flagged this as duplicate of the question whose accepted answer I explicitly say does not apply here
As suggested by #MatthewFarwell in the comments I implemented a test rule as per his answer
public static class Retry implements TestRule {
private final int retryCount;
public Retry(int retryCount) {
this.retryCount = retryCount;
}
#Override
public Statement apply(final Statement base,
final Description description) {
return new Statement() {
#Override
#SuppressWarnings("synthetic-access")
public void evaluate() throws Throwable {
Throwable caughtThrowable = null;
int failuresCount = 0;
for (int i = 0; i < retryCount; i++) {
try {
base.evaluate();
} catch (Throwable t) {
caughtThrowable = t;
System.err.println(description.getDisplayName()
+ ": run " + (i + 1) + " failed:");
t.printStackTrace();
++failuresCount;
}
}
if (caughtThrowable == null) return;
throw new AssertionError(description.getDisplayName()
+ ": failures " + failuresCount + " out of "
+ retryCount + " tries. See last throwable as the cause.", caughtThrowable);
}
};
}
}
as a nested class in my test class - and added
#Rule
public Retry retry = new Retry(69);
before my test methods in the same class.
This indeed does the trick - it does repeat the test 69 times - in the case of some exception a new AssertionError, with an individual message containing some statistics plus the original Throwable as a cause, gets thrown. So the statistics will be also visible in the jUnit view of Eclipse.

Categories