BackgroundInitializerSupplierTest.java
/*
* 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
*
* https://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.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import org.apache.commons.lang3.function.FailableConsumer;
import org.apache.commons.lang3.function.FailableSupplier;
import org.junit.jupiter.api.Test;
class BackgroundInitializerSupplierTest extends BackgroundInitializerTest {
/**
* A concrete implementation of BackgroundInitializer. It is designed as a wrapper so the test can
* use the same builder pattern that real code will.
*/
protected static final class SupplierBackgroundInitializerTestImpl extends AbstractBackgroundInitializerTestImpl {
SupplierBackgroundInitializerTestImpl() {
setSupplierAndCloser((final CloseableCounter cc) -> cc.close());
}
SupplierBackgroundInitializerTestImpl(final ExecutorService exec) {
super(exec);
setSupplierAndCloser((final CloseableCounter cc) -> cc.close());
}
SupplierBackgroundInitializerTestImpl(final FailableConsumer<?, ?> consumer) {
setSupplierAndCloser(consumer);
}
private void setSupplierAndCloser(final FailableConsumer<?, ?> consumer) {
try {
// Use reflection here because the constructors we need are private
final FailableSupplier<?, ?> supplier = this::initializeInternal;
final Field initializer = AbstractConcurrentInitializer.class.getDeclaredField("initializer");
initializer.setAccessible(true);
initializer.set(this, supplier);
final Field closer = AbstractConcurrentInitializer.class.getDeclaredField("closer");
closer.setAccessible(true);
closer.set(this, consumer);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
fail();
}
}
}
@Override
protected AbstractBackgroundInitializerTestImpl getBackgroundInitializerTestImpl() {
return new SupplierBackgroundInitializerTestImpl();
}
@Override
protected SupplierBackgroundInitializerTestImpl getBackgroundInitializerTestImpl(final ExecutorService exec) {
return new SupplierBackgroundInitializerTestImpl(exec);
}
/**
* Tests that close() method closes the wrapped object
*
* @throws Exception
*/
@Test
void testClose() throws Exception {
final AbstractBackgroundInitializerTestImpl init = getBackgroundInitializerTestImpl();
assertFalse(init.getCloseableCounter().isClosed(), "closed without close() call");
init.close();
assertFalse(init.getCloseableCounter().isClosed(), "closed() succeeded before start()");
init.start();
init.get(); //ensure the Future has completed.
assertFalse(init.getCloseableCounter().isClosed(), "closed() succeeded after start() but before close()");
init.close();
assertTrue(init.getCloseableCounter().isClosed(), "closed() did not succeed");
}
/**
* Tests that close() wraps a checked exception in a ConcurrentException
*
* @throws Exception
*/
@Test
void testCloseWithCheckedException() throws Exception {
final IOException ioException = new IOException();
final FailableConsumer<?, ?> IOExceptionConsumer = (final CloseableCounter cc) -> {
throw ioException;
};
final AbstractBackgroundInitializerTestImpl init = new SupplierBackgroundInitializerTestImpl(IOExceptionConsumer);
init.start();
init.get(); //ensure the Future has completed.
try {
init.close();
fail();
} catch (final Exception e) {
assertInstanceOf(ConcurrentException.class, e);
assertSame(ioException, e.getCause());
}
}
/**
* Tests that close() throws a runtime exception
*
* @throws Exception
*/
@Test
void testCloseWithRuntimeException() throws Exception {
final NullPointerException npe = new NullPointerException();
final FailableConsumer<?, ?> NullPointerExceptionConsumer = (final CloseableCounter cc) -> {
throw npe;
};
final AbstractBackgroundInitializerTestImpl init = new SupplierBackgroundInitializerTestImpl(NullPointerExceptionConsumer);
init.start();
init.get(); //ensure the Future has completed.
try {
init.close();
fail();
} catch (final Exception e) {
assertSame(npe, e);
}
}
}