Refactor AbstractConcurrentInitializerTest to add non-Object test

This commit is contained in:
Gary Gregory 2024-05-23 09:58:53 -04:00
parent 84abc1181c
commit c8f5b0c001
3 changed files with 111 additions and 40 deletions

View File

@ -28,23 +28,49 @@ import org.junit.jupiter.api.Test;
/**
* <p>
* An abstract base class for tests of concrete {@code ConcurrentInitializer}
* implementations.
* An abstract base class for tests of concrete {@code ConcurrentInitializer} implementations.
* </p>
* <p>
* This class provides some basic tests for initializer implementations. Derived
* class have to create a {@link ConcurrentInitializer} object on which the
* tests are executed.
* This class provides some basic tests for initializer implementations. Derived class have to create a {@link ConcurrentInitializer} object on which the tests
* are executed.
* </p>
*
* @param <T> Domain type.
*/
public abstract class AbstractConcurrentInitializerTest extends AbstractLangTest {
public abstract class AbstractConcurrentInitializerTest<T> extends AbstractLangTest {
static final class GetThread extends Thread {
private Object object;
private final CountDownLatch startLatch;
private final ConcurrentInitializer<?> initializer;
GetThread(final CountDownLatch startLatch, final ConcurrentInitializer<?> initializer) {
this.startLatch = startLatch;
this.initializer = initializer;
}
@Override
public void run() {
try {
// wait until all threads are ready for maximum parallelism
startLatch.await();
// access the initializer
object = initializer.get();
} catch (final InterruptedException iex) {
// ignore
} catch (final ConcurrentException cex) {
object = cex;
}
}
}
/**
* Creates the {@link ConcurrentInitializer} object to be tested. This
* method is called whenever the test fixture needs to be obtained.
* Creates the {@link ConcurrentInitializer} object to be tested. This method is called whenever the test fixture needs to be obtained.
*
* @return the initializer object to be tested
*/
protected abstract ConcurrentInitializer<Object> createInitializer();
protected abstract ConcurrentInitializer<T> createInitializer();
/**
* Tests a simple invocation of the get() method.
@ -57,39 +83,19 @@ public abstract class AbstractConcurrentInitializerTest extends AbstractLangTest
}
/**
* Tests whether get() can be invoked from multiple threads concurrently.
* Always the same object should be returned.
* Tests whether get() can be invoked from multiple threads concurrently. Always the same object should be returned.
*
* @throws org.apache.commons.lang3.concurrent.ConcurrentException because the object under test may throw it.
* @throws InterruptedException because the threading API my throw it.
* @throws InterruptedException because the threading API my throw it.
*/
@Test
public void testGetConcurrent() throws ConcurrentException,
InterruptedException {
final ConcurrentInitializer<Object> initializer = createInitializer();
public void testGetConcurrent() throws ConcurrentException, InterruptedException {
final ConcurrentInitializer<T> initializer = createInitializer();
final int threadCount = 20;
final CountDownLatch startLatch = new CountDownLatch(1);
final class GetThread extends Thread {
Object object;
@Override
public void run() {
try {
// wait until all threads are ready for maximum parallelism
startLatch.await();
// access the initializer
object = initializer.get();
} catch (final InterruptedException iex) {
// ignore
} catch (final ConcurrentException cex) {
object = cex;
}
}
}
final GetThread[] threads = new GetThread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new GetThread();
threads[i] = new GetThread(startLatch, initializer);
threads[i].start();
}
@ -107,14 +113,13 @@ public abstract class AbstractConcurrentInitializerTest extends AbstractLangTest
}
/**
* Tests whether sequential get() invocations always return the same
* instance.
* Tests whether sequential get() invocations always return the same instance.
*
* @throws org.apache.commons.lang3.concurrent.ConcurrentException because the object under test may throw it.
*/
@Test
public void testGetMultipleTimes() throws ConcurrentException {
final ConcurrentInitializer<Object> initializer = createInitializer();
final ConcurrentInitializer<T> initializer = createInitializer();
final Object obj = initializer.get();
for (int i = 0; i < 10; i++) {
assertEquals(obj, initializer.get(), "Got different object at " + i);
@ -123,12 +128,15 @@ public abstract class AbstractConcurrentInitializerTest extends AbstractLangTest
/**
* Tests a simple invocation of the isInitialized() method.
*
* @throws Throwable on test failure.
*/
@Test
public void testisInitialized() throws Throwable {
final ConcurrentInitializer<Object> initializer = createInitializer();
final ConcurrentInitializer<T> initializer = createInitializer();
if (initializer instanceof AbstractConcurrentInitializer) {
final AbstractConcurrentInitializer castedInitializer = (AbstractConcurrentInitializer) initializer;
@SuppressWarnings("unchecked")
final AbstractConcurrentInitializer<T, Exception> castedInitializer = (AbstractConcurrentInitializer<T, Exception>) initializer;
assertFalse(castedInitializer.isInitialized(), "was initialized before get()");
assertNotNull(castedInitializer.get(), "No managed object");
assertTrue(castedInitializer.isInitialized(), "was not initialized after get()");

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.lang3.concurrent;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
/**
* Test class for {@code AtomicInitializer}.
*/
public class AtomicInitializerNonObjectTest extends AbstractConcurrentInitializerTest<Integer> {
/**
* Returns the initializer to be tested.
*
* @return the {@code AtomicInitializer}
*/
@Override
protected ConcurrentInitializer<Integer> createInitializer() {
return new AtomicInitializer<Integer>() {
@Override
protected Integer initialize() {
return new Integer(0);
}
};
}
@Test
public void testGetThatReturnsNullFirstTime() throws ConcurrentException {
final AtomicInitializer<Integer> initializer = new AtomicInitializer<Integer>() {
final AtomicInteger firstRun = new AtomicInteger(1);
@Override
protected Integer initialize() {
if (firstRun.getAndSet(0) == 1) {
return null;
}
return new Integer(0);
}
};
assertNull(initializer.get());
assertNull(initializer.get());
}
}

View File

@ -25,7 +25,8 @@ import org.junit.jupiter.api.Test;
/**
* Test class for {@code AtomicInitializer}.
*/
public class AtomicInitializerTest extends AbstractConcurrentInitializerTest {
public class AtomicInitializerObjectTest extends AbstractConcurrentInitializerTest<Object> {
/**
* Returns the initializer to be tested.
*