View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.concurrent;
18  
19  import static org.junit.jupiter.api.Assertions.assertFalse;
20  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
21  import static org.junit.jupiter.api.Assertions.assertSame;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  import static org.junit.jupiter.api.Assertions.fail;
24  
25  import java.io.IOException;
26  import java.lang.reflect.Field;
27  import java.util.concurrent.ExecutorService;
28  
29  import org.apache.commons.lang3.function.FailableConsumer;
30  import org.apache.commons.lang3.function.FailableSupplier;
31  import org.junit.jupiter.api.Test;
32  
33  class BackgroundInitializerSupplierTest extends BackgroundInitializerTest {
34  
35      /**
36       * A concrete implementation of BackgroundInitializer. It is designed as a wrapper so the test can
37       * use the same builder pattern that real code will.
38       */
39      protected static final class SupplierBackgroundInitializerTestImpl extends AbstractBackgroundInitializerTestImpl {
40  
41          SupplierBackgroundInitializerTestImpl() {
42              setSupplierAndCloser((final CloseableCounter cc) -> cc.close());
43          }
44  
45          SupplierBackgroundInitializerTestImpl(final ExecutorService exec) {
46              super(exec);
47              setSupplierAndCloser((final CloseableCounter cc) -> cc.close());
48          }
49  
50          SupplierBackgroundInitializerTestImpl(final FailableConsumer<?, ?> consumer) {
51              setSupplierAndCloser(consumer);
52          }
53  
54          private void setSupplierAndCloser(final FailableConsumer<?, ?> consumer) {
55              try {
56                  // Use reflection here because the constructors we need are private
57                  final FailableSupplier<?, ?> supplier = this::initializeInternal;
58                  final Field initializer = AbstractConcurrentInitializer.class.getDeclaredField("initializer");
59                  initializer.setAccessible(true);
60                  initializer.set(this, supplier);
61  
62                  final Field closer = AbstractConcurrentInitializer.class.getDeclaredField("closer");
63                  closer.setAccessible(true);
64                  closer.set(this, consumer);
65              } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
66                  fail();
67              }
68          }
69      }
70  
71      @Override
72      protected AbstractBackgroundInitializerTestImpl getBackgroundInitializerTestImpl() {
73          return new SupplierBackgroundInitializerTestImpl();
74      }
75  
76      @Override
77      protected SupplierBackgroundInitializerTestImpl getBackgroundInitializerTestImpl(final ExecutorService exec) {
78          return new SupplierBackgroundInitializerTestImpl(exec);
79      }
80  
81      /**
82       * Tests that close() method closes the wrapped object
83       *
84       * @throws Exception
85       */
86      @Test
87      void testClose() throws Exception {
88          final AbstractBackgroundInitializerTestImpl init = getBackgroundInitializerTestImpl();
89          assertFalse(init.getCloseableCounter().isClosed(), "closed without close() call");
90          init.close();
91          assertFalse(init.getCloseableCounter().isClosed(), "closed() succeeded before start()");
92          init.start();
93          init.get(); //ensure the Future has completed.
94          assertFalse(init.getCloseableCounter().isClosed(), "closed() succeeded after start() but before close()");
95          init.close();
96          assertTrue(init.getCloseableCounter().isClosed(), "closed() did not succeed");
97      }
98  
99      /**
100      * Tests that close() wraps a checked exception in a ConcurrentException
101      *
102      * @throws Exception
103      */
104     @Test
105     void testCloseWithCheckedException() throws Exception {
106 
107         final IOException ioException = new IOException();
108         final FailableConsumer<?, ?> IOExceptionConsumer = (final CloseableCounter cc) -> {
109             throw ioException;
110         };
111 
112         final AbstractBackgroundInitializerTestImpl init = new SupplierBackgroundInitializerTestImpl(IOExceptionConsumer);
113         init.start();
114         init.get(); //ensure the Future has completed.
115         try {
116             init.close();
117             fail();
118         } catch (final Exception e) {
119             assertInstanceOf(ConcurrentException.class, e);
120             assertSame(ioException, e.getCause());
121         }
122     }
123 
124     /**
125      * Tests that close() throws a runtime exception
126      *
127      * @throws Exception
128      */
129     @Test
130     void testCloseWithRuntimeException() throws Exception {
131 
132         final NullPointerException npe = new NullPointerException();
133         final FailableConsumer<?, ?> NullPointerExceptionConsumer = (final CloseableCounter cc) -> {
134             throw npe;
135         };
136 
137         final AbstractBackgroundInitializerTestImpl init = new SupplierBackgroundInitializerTestImpl(NullPointerExceptionConsumer);
138         init.start();
139         init.get(); //ensure the Future has completed.
140         try {
141             init.close();
142             fail();
143         } catch (final Exception e) {
144             assertSame(npe, e);
145         }
146     }
147 }