Equalsverifier fails when run with quarkus:dev - quarkus

When running equalsverfier in quarkus dev mode, equalsverfier tests fail.
I tried to test a class with equalsverifier. This works in my IDE.
I tried to use it in quarkus dev mode (by running ./mvnw quarkus:dev), but then it fails with the following exception:
ERROR [io.qua.test] (Test runner thread) Test DingetjeTest#implementsEquals() failed
: java.lang.AssertionError: EqualsVerifier found a problem in class a.Dingetje.
-> Can not set final java.lang.String field a.Dingetje.text to a.Dingetje
For more information, go to: http://www.jqno.nl/equalsverifier/errormessages
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:308)
at a.DingetjeTest.implementsEquals(DingetjeTest.java:11)
Caused by: java.lang.IllegalArgumentException: Can not set final java.lang.String field a.Dingetje.text to a.Dingetje
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38)
at java.base/java.lang.reflect.Field.get(Field.java:418)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$copyTo$1(FieldModifier.java:79)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$change$3(FieldModifier.java:113)
at nl.jqno.equalsverifier.internal.util.Rethrow.lambda$rethrow$0(Rethrow.java:47)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:30)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:45)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:55)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.change(FieldModifier.java:113)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.copyTo(FieldModifier.java:79)
at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.copyInto(InPlaceObjectAccessor.java:43)
at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.copy(InPlaceObjectAccessor.java:24)
at nl.jqno.equalsverifier.internal.checkers.ExamplesChecker.checkSingle(ExamplesChecker.java:84)
at nl.jqno.equalsverifier.internal.checkers.ExamplesChecker.check(ExamplesChecker.java:47)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verifyWithExamples(SingleTypeEqualsVerifierApi.java:413)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.performVerification(SingleTypeEqualsVerifierApi.java:369)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:304)
... 1 more
Here's the class under test:
package a;
import java.util.Objects;
public class Dingetje {
private final String text;
public Dingetje(String text) {
this.text = text;
}
#Override
public final boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Dingetje)) {
return false;
}
Dingetje other = (Dingetje) o;
return text.equals(other.text);
}
#Override
public final int hashCode() {
return Objects.hash(text);
}
}
And the test:
package a;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
class DingetjeTest {
#Test
void implementsEquals() {
EqualsVerifier.forClass(Dingetje.class)
.withNonnullFields("text")
.verify();
}
}
What am I missing here?

EqualsVerifier uses Objenesis to create instances of classes, and it keeps the same reference of the objenesis object around for performance reasons. It caches all the objects it has created before, so that makes things quicker when you want to create the same object over and over again, which EqualsVerifier tends to do.
However, EqualsVerifier keeps a static reference to objenesis, which means that it lives as long as the JVM does. It turns out that the Quarkus test runner can re-run the same tests again and again, and it creates a new class loader each time. But part of the equality of java.lang.Class is that the classloader that created the class, must also be the same. So it couldn't retrieve these objects from its cache anymore and returnd instances with classloaders that are now different from the other objects created in the test, and this caused the exceptions that you saw.
In version 3.8 of EqualsVerifier (created as a result of this StackOverflow post), this issue can be avoided by adding #withResetCaches() like this:
EqualsVerifier.forClass(Dingetje.class)
.withResetCaches()
.withNonnullFields("text")
.verify();
That fixes the problem.

Related

DataMongoTest using embeddedMongo fails due to program blocked by group policy (Windows 10)

Executing a simple unit test over a Mongo Repository fails in Windows 10 due to
java.io.IOException: Cannot run program
"C:\Users\myuser\AppData\Local\Temp\extract-88ea18ed-75d4-420f-be7f-623baeeb5c70extractmongod.exe":
CreateProcess error=1260, This program is blocked by group policy. For
more information, contact your system administrator
This had worked until a few days ago, but failing now probably due to some recent Windows update.
Example of a failing test
#ExtendWith(SpringExtension.class)
#DataMongoTest
#AutoConfigureDataJpa
#AutoConfigureTestDatabase
#ExtendWith(LogbackSuppressorExtension.class)
#Import(TestConfiguration.class)
class AnnexContentRepositoryTest {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private AnnexContentRepository annexContentRepository;
#Test
public void findAllByParentCodeAndParentType() {
AnnexContent annexContent = addAnnexContent();
Page<AnnexContent> annexContentResult = annexContentRepository
.findAllByParentCodeAndParentType(annexContent.getParentCode(), ParentType.THE_ONE,
Pageable.unpaged());
Assertions.assertEquals(1, annexContentResult.getTotalElements());
}
private AnnexContent addAnnexContent() {
AnnexContent annexContent = AnnexContentBuilder.buildDefault();
return mongoTemplate.save(annexContent);
}
}
The solution that I've found is to add two system variables that embedded mongo reads ("de.flapdoodle.embed.io.tmpdir" and "EMBEDDED_MONGO_ARTIFACTS") in test configuration (the same applies in running the application with embedded mongo, where these two system variables can be set also).
#Configuration
public class TestConfiguration {
public TestConfiguration(Environment environment) {
if (SystemUtils.IS_OS_WINDOWS) {
System.setProperty("de.flapdoodle.embed.io.tmpdir", environment.getProperty("mongo-embedded.windows.temp-dir"));
System.setProperty("EMBEDDED_MONGO_ARTIFACTS", environment.getProperty("mongo-embedded.windows.temp-dir"));
}
}
}
By changing the location from the embedded mongo default ("c:\myuser\appdata\local\temp") to, for example, "c:\temp", the problem disappears.
Pringi's solution works. Here it is, simplified with an actual Windows path in c:\temp\mongotemp
First manually create directory c:\temp\mongotemp
Add a new MongoConfig.java file:
import org.apache.commons.lang3.SystemUtils;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MongoConfig {
public MongoConfig() {
if (SystemUtils.IS_OS_WINDOWS) {
System.setProperty("de.flapdoodle.embed.io.tmpdir", "c:\\temp\\mongotemp");
}
}
}
App should run now.
You can then inspect the contents of c:\temp\mongotemp , it's the executable that was previously being blocked by the system policy.

How to write script in gradle that execute particular methods?

I am writing a gradle script that runs all tests before making a build.
test {
filter {
includeTestsMatching "*TestAll*"
includeTestsMatching "*ExtensionValidatorTest*"
........
}
}
I have three tests of different versions(v1,v2,v3).
TestAll.java
package .....v1;//v2 for version 2 and v3 for version 3
#RunWith(Suite.class)
#Suite.SuiteClasses({
A.class,
B.class,
......
})
public class TestAll {
#BeforeClass
public static void setUp() {//connection to database
........
}
#AfterClass
public static void tearDown() {//close database connection
........
}
}
When I run gradle test connection to database is broken after execution of a particular TestAll. I do not want to change the TestAll files of any version as they can be run and tested independently. How can I make gradle run only setUp once(of any version)which establishes connection, then run all the TestAll method in v1,v2 and v3 and finally teardown(of any version) which terminates database connection.
Gradle won't help you with this. There are following methods in Gradle DSL:
test {
beforeSuite{...}
afterSuite{...}
}
However, they execute outside of the test runtime scope and intended for logging. You only can achieve this using a testing framework.
TestNG provides a simple solution - #BeforeSuite and #AfterSuite annotations, that are actually run once before and after the entire suite.
Unfortunately, JUnit doesn't have a built-in solution for that, since test isolation is its core concept. Nevertheless, you still can make your own. You need to encapsulate database-related API into a singleton class:
public class DbContainer() {
private static DbContainer container;
private DbContaner() {}
public DbContainer getInstance() {
if (container == null) {
container = new DbContainer()
}
return container;
}
public void openConnection() {
// ...
}
public void closeConnection() {
// ...
}
// here is your database API methods
}
Then you can share this instance between test methods and classes using #ClassRule annotation:
#ClassRule
public static DbContainer db = DbContainer.getInstance();
#Test
public void someTest() {
db.query(...)
}
Note: provided solution is not thread-safe and doesn't suit the parallel execution. Some additional effort is required to achieve it.

junit5: howto introspect if a test is actually augmented with #Before/AfterEach methods

I'm writing a little extension that tells me in my log when a test starts, so i know which logs are related to which tests:
public class LoggingExtension implements Extension, BeforeEachCallback, AfterTestExecutionCallback {
protected final Logger log = LoggerFactory.getLogger(getClass());
#Override
public void beforeEach(final ExtensionContext context) throws Exception {
log.info("-- Test #before: {}::{} ----------------------------------------",
context.getDisplayName(),
context.getTestClass().map(x -> x.getSimpleName()).orElse("no test class available"));
}
/**
* (non-Javadoc) ${see_to_overridden}
*/
#Override
public void afterTestExecution(final ExtensionContext context) throws Exception {
context.getExecutionException()
.ifPresent(ex -> {
log.error("-- Test #after: {}::{} ----------------------------------------",
context.getDisplayName(),
context.getTestClass().map(x -> x.getSimpleName()).orElse("no test class available"),
ex);
// log.error("", ex);
});
}
}
I wanted to change this like so:
log -- Test #start: ... when the test itself starts (ie. use BeforeTestExecutionCallback)
and use the BeforeEachCallback to mark the start of #BeforeEach execution(s) but only iff there is actually before-code being executed, as to avoid cluttering.
So the question is: How can i tell if there are actually 1..n #BeforeEach methods that are being executed?
I investigated the the ExtensionContext but came up empty.
So the question is: How can i tell if there are actually 1..n #BeforeEach methods that are being executed?
As of JUnit Jupiter 5.4, there is no official way to find that out. That information is not exposed in any user-facing API: it's internal to the JUnit Jupiter TestEngine.
However, the new InvocationInterceptor extension API coming in JUnit Jupiter 5.5 will provide a way to determine if a #BeforeEach method is about to be executed.

NullPointerException thrown from ESIntegTestCase

I am using Elasticsearch version 2.4.4.
Then I had created test case derived from ESIntegTestCase, something like:
public class ELSTest extends ESIntegTestCase {
#Override
protected Settings nodeSettings ( int nodeOrdinal ) {
return Settings.builder().put( super.nodeSettings( nodeOrdinal ) )
.put( super.nodeSettings( nodeOrdinal ) )
.put( IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1 )
.put( IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1 )
.put( Node.HTTP_ENABLED, true )
.build();
}
#BeforeClass
public void setup () throws Exception {
createIndex( "idx" ); // line 57
ensureGreen( "idx" );
}
}
After resolving "jar hell" problem and reading bunch of pages about ESIntegTestCase I got new one.
java.lang.NullPointerException
at org.elasticsearch.test.ESIntegTestCase.client(ESIntegTestCase.java:657)
at org.elasticsearch.test.ESIntegTestCase.client(ESIntegTestCase.java:650)
at org.elasticsearch.test.ESIntegTestCase.prepareCreate(ESIntegTestCase.java:763)
at com.company.ELSTest.setup(ELSTest.java:57)
What can be the reason for it? I mean the one where ESIntegTestCase class throws NPE in the line:
Client client = cluster().client();
It seems like cluster is not initialized. What is the proper very basic class setup, to start elasticsearch in tests?
Answering myself :-)
The documentation is located at: integration tests
There are the following extentions needed:
Important limitation is that ESIntegTestCase class will work only with JUnit. There is no easy way to get it working with e.g. TestNG - explanation follows.
Start JUnit with additional parameters:
-Dtests.jarhell.check=false
to avoid jar hell
-Dtests.security.manager=false
to avoid java.security.AccessControlException: access denied
Class is declared as following:
#RunWith( com.carrotsearch.randomizedtesting.RandomizedRunner.class )
public class ELSTest extends ESIntegTestCase {
#Before
public void setup () throws Exception {
beforeClass(); // against NullPointerException in ESIntegTestCase
createIndex( "idx" );
ensureGreen( "idx" );
// ...
}
}
Remarks:
#RunWith is needed to avoid java.lang.IllegalStateException: No context information for thread:
and this is a reason why e.g. TestNG cannot be used - TestNG has no RunWith annotation.
#Before cannot be changed to #BeforeClass as beforeClass() method cannot be called from static context.
The method nodeSettings ( int nodeOrdinal ) is not mandatory.

What could cause a class implementing "ApplicationListener<ContextRefreshedEvent>" not to be notified of a "ContextRefreshedEvent"

I have a Spring application listener implementing ApplicationListener<ContextRefreshedEvent> as follows:
#Profile({ Profiles.DEFAULT, Profiles.CLOUD, Profiles.TEST, Profiles.DEV })
#Component
public class BootstrapLoaderListener implements ApplicationListener<ContextRefreshedEvent>, ResourceLoaderAware, Ordered {
private static final Logger log = Logger.getLogger(BootstrapLoaderListener.class);
#Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
#Autowired
private DayToTimeSlotRepository dayToTimeSlotRepository;
#Autowired
private LanguageRepository languageRepository;
private ResourceLoader resourceLoader;
#Override
#Transactional
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
initApplication();
}
private void initApplication() {
if (dayToTimeSlotRepository.count() == 0) {
initDayToTimeSlots();
}
if (languageRepository.count() == 0) {
initLanguages();
}
}
private void initDayToTimeSlots() {
for (Day day : Day.values()) {
for (TimeSlot timeSlot : TimeSlot.values()) {
DayToTimeSlot dayToTimeSlot = new DayToTimeSlot();
dayToTimeSlot.setDay(day);
dayToTimeSlot.setTimeSlot(timeSlot);
dayToTimeSlot.setDisabled(isDayToTimeSlotDisabled(timeSlot, day));
dayToTimeSlotRepository.save(dayToTimeSlot);
}
}
}
...
I rely on this listener class to insert reference data that is not updated nor deleted and I have a number of Spring integration tests that use this class, one of which fails because the listener is not notified (initDayToTimeSlots is not invoked).
I am trying to pinpoint where the problem comes from by debugging the tests and I noticed that when I run the problematic test class on its own, the tests contained in the class pass (indicating that the listener is notified) but when I run all of my application test classes together, the listener is not notified causing the test to fail (indicating that some other test changes/dirties the context).
Here is the problematic test class:
#ActiveProfiles({ Profiles.TEST })
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
public class RegularDayToTimeSlotsTest {
private static int NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK = 25;
#Before
public void setup() {
//org.hsqldb.util.DatabaseManagerSwing.main(new String[] { "--url", "jdbc:hsqldb:mem:bignibou", "--noexit" });
}
#Autowired
private AdvertisementService advertisementService;
#Test
public void shouldNotContainSaturdayNorSunday() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).onProperty("day").excludes(Day.SATURDAY, Day.SUNDAY);
assertThat(regularDayToTimeSlots).onProperty("day").contains(Day.MONDAY, Day.THUESDAY);
}
#Test
public void shouldNotContainEveningNorNighttime() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).onProperty("timeSlot").excludes(TimeSlot.EVENING, TimeSlot.NIGHTTIME);
assertThat(regularDayToTimeSlots).onProperty("timeSlot").contains(TimeSlot.MORNING, TimeSlot.LUNCHTIME);
}
#Test
public void shouldContainCorrectNumberOfDayToTimeSlots() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).hasSize(NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK);
}
}
I am puzzled to see that both the prepareRefresh() and finishRefresh() methods within AbstractApplicationContext.refresh method are indeed called but that my listener is not notified...
Has anyone got any clue?
P.S. I know I could use #DirtiesContext in order to get a fresh context and I also know it would be preferable not to rely on an application listener for my tests but I am very anxious to understand what is going wrong here. Hence this post.
edit 1: When I debug the problematic test class in isolation, I notice that the event source is of type GenericApplicationContext and as explained above the test passes OK because the listener is notified. However when all test classes are run together, the event source is, oddly enough, of type GenericWebApplicationContext and no listener is found here in SimpleApplicationEventMulticaster:
#Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
#Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
edit 2: my comments in edit 1 make me asks myself what is responsible for determining the uniqueness of context configuration...
For instance, I have only two test classes with the following context configuration:
#ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
I guess they both will use the same cached context, won't they? Now can a third class use the same cached context even though it does not have exactly the same context configuration?
Why does my test get a GenericWebApplicationContext above?
my comments in edit 1 make me asks myself what is responsible for
determining the uniqueness of context configuration...
The elements that make up the context cache key are described in the Context caching section of the "Testing" chapter in the reference manual.
For instance, I have only two test classes with the following context
configuration:
#ContextConfiguration(classes = {
FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
I guess they both will use the same cached context, won't they?
If they declare only those two configuration classes in that exact order, then yes.
Now can a third class use the same cached context even though it does not
have exactly the same context configuration?
No.
Why does my test get a GenericWebApplicationContext above?
A GenericWebApplicationContext is only loaded if your test class (or one of its superclasses) is annotated with #WebAppConfiguration.
If you are experiencing behavior that contradicts this, then you have discovered a bug in which case we would appreciate it if you could produce a scaled down test project in the issue repository and create a corresponding JIRA issue against the "Spring Framework" and its "Test" component.
Thanks,
Sam (author of the Spring TestContext Framework)

Resources