Skip to content

Commit

Permalink
Test case failure
Browse files Browse the repository at this point in the history
Fixing failure for the test

test.retryAnalyzer.RetryAnalyzerTest.ensureRetryDoesntRunEndlesslyForDataDrivenTests

Github actions failure on `master` branch: 

https://github.com/testng-team/testng/actions/runs/8307524777/job/22736819681

Gradle scan results link:

https://scans.gradle.com/s/wap5a5bvq3qgq/tests/task/:testng-core:test/details/test.retryAnalyzer.RetryAnalyzerTest/ensureRetryDoesntRunEndlesslyForDataDrivenTests?top-execution=1

Prerequisites for failure:

The below JVM arguments should be used:

* `-Duser.timezone="America/New_York”`
* `-Duser.country=RU`
* `-Duser.language=ru`
* `-XX:+UnlockExperimentalVMOptions`
* `-XX:hashCode=2`

Root cause: We are using hashCode() to create 
Key that is used to determine if a RetryAnalyzer
instance should be created or not.

When we run the tests using `-XX:hashCode=2` 
it causes the JVM to generate the same hashcode (value 1)
And this messes up the `RetryAnalyzer` object creation.

Fix:

Addressed this by wrapping the parameters into an 
object which will contain a unique id that can be used
to represent the same set of parameters.
  • Loading branch information
krmahadevan committed Mar 16, 2024
1 parent 15874ea commit 3505e4b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
15 changes: 10 additions & 5 deletions testng-core/src/main/java/org/testng/internal/BaseTestMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.testng.IClass;
Expand Down Expand Up @@ -832,7 +833,7 @@ private IRetryAnalyzer getRetryAnalyzerConsideringMethodParameters(ITestResult t
return this.m_retryAnalyzer;
}

final String keyAsString = getSimpleName() + "#" + hashParameters(tr);
final String keyAsString = getSimpleName() + "#" + parameterId(tr);
return m_testMethodToRetryAnalyzer.computeIfAbsent(
keyAsString,
key -> {
Expand All @@ -842,9 +843,13 @@ private IRetryAnalyzer getRetryAnalyzerConsideringMethodParameters(ITestResult t
});
}

private int hashParameters(ITestResult itr) {
Object[] parameters = itr.getParameters();
return Objects.hash(parameters);
private final Map<IObject.IdentifiableArrayObject, IObject.IdentifiableArrayObject> parameters =
new ConcurrentHashMap<>();

private String parameterId(ITestResult itr) {
IObject.IdentifiableArrayObject parameter =
new IObject.IdentifiableArrayObject(itr.getParameters());
return parameters.computeIfAbsent(parameter, Function.identity()).getInstanceId();
}

private static boolean isNotParameterisedTest(ITestResult tr) {
Expand Down
33 changes: 33 additions & 0 deletions testng-core/src/main/java/org/testng/internal/IObject.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.testng.internal;

import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
Expand Down Expand Up @@ -113,4 +114,36 @@ public int hashCode() {
return Objects.hash(instanceId);
}
}

/**
* A wrapper class that wraps around an array and associates a unique Id that can be used as a key
* for the array.
*/
class IdentifiableArrayObject {

private final String instanceId = UUID.randomUUID().toString();

private final Object[] parameters;

public IdentifiableArrayObject(Object[] parameters) {
this.parameters = parameters;
}

public String getInstanceId() {
return instanceId;
}

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
IdentifiableArrayObject that = (IdentifiableArrayObject) object;
return Arrays.equals(parameters, that.parameters);
}

@Override
public int hashCode() {
return Arrays.hashCode(parameters);
}
}
}

0 comments on commit 3505e4b

Please sign in to comment.