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    *      http://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.hamcrest.CoreMatchers.instanceOf;
20  import static org.hamcrest.MatcherAssert.assertThat;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertSame;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  import static org.junit.jupiter.api.Assertions.fail;
25  
26  import java.io.IOException;
27  import java.lang.reflect.Field;
28  import java.util.concurrent.ExecutorService;
29  
30  import org.apache.commons.lang3.function.FailableConsumer;
31  import org.apache.commons.lang3.function.FailableSupplier;
32  import org.junit.jupiter.api.Test;
33  
34  public class BackgroundInitializerSupplierTest extends BackgroundInitializerTest {
35  
36      /**
37       * A concrete implementation of BackgroundInitializer. It is designed as a warpper so the test can
38       * use the same builder pattern that real code will.
39       */
40      protected static final class SupplierBackgroundInitializerTestImpl extends AbstractBackgroundInitializerTestImpl {
41  
42          SupplierBackgroundInitializerTestImpl() {
43              super();
44              setSupplierAndCloser((CloseableCounter cc) -> cc.close());
45          }
46  
47          SupplierBackgroundInitializerTestImpl(final ExecutorService exec) {
48              super(exec);
49              setSupplierAndCloser((CloseableCounter cc) -> cc.close());
50          }
51  
52          SupplierBackgroundInitializerTestImpl(FailableConsumer<?, ?> consumer) {
53              super();
54              setSupplierAndCloser(consumer);
55          }
56  
57          private void setSupplierAndCloser(FailableConsumer<?, ?> consumer) {
58              try {
59                  // Use reflection here because the constructors we need are private
60                  FailableSupplier<?, ?> supplier = () -> initializeInternal();
61                  Field initializer = AbstractConcurrentInitializer.class.getDeclaredField("initializer");
62                  initializer.setAccessible(true);
63                  initializer.set(this, supplier);
64  
65                  Field closer = AbstractConcurrentInitializer.class.getDeclaredField("closer");
66                  closer.setAccessible(true);
67                  closer.set(this, consumer);
68              } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
69                  fail();
70              }
71          }
72      }
73  
74      protected AbstractBackgroundInitializerTestImpl getBackgroundInitializerTestImpl() {
75          return new SupplierBackgroundInitializerTestImpl();
76      }
77  
78      protected SupplierBackgroundInitializerTestImpl getBackgroundInitializerTestImpl(final ExecutorService exec) {
79          return new SupplierBackgroundInitializerTestImpl(exec);
80      }
81  
82      /**
83       * Tests that close() method closes the wrapped object
84       *
85       * @throws Exception
86       */
87      @Test
88      public void testClose() throws Exception {
89          final AbstractBackgroundInitializerTestImpl init = getBackgroundInitializerTestImpl();
90          assertFalse(init.getCloseableCounter().isClosed(), "closed without close() call");
91          init.close();
92          assertFalse(init.getCloseableCounter().isClosed(), "closed() succeeded before start()");
93          init.start();
94          init.get(); //ensure the Future has completed.
95          assertFalse(init.getCloseableCounter().isClosed(), "closed() succeeded after start() but before close()");
96          init.close();
97          assertTrue(init.getCloseableCounter().isClosed(), "closed() did not succeed");
98      }
99  
100     /**
101      * Tests that close() wraps a checked exception in a ConcurrentException
102      *
103      * @throws Exception
104      */
105     @Test
106     public void testCloseWithCheckedException() throws Exception {
107 
108         final IOException ioException = new IOException();
109         final FailableConsumer<?, ?> IOExceptionConsumer = (CloseableCounter cc) -> {
110             throw ioException;
111         };
112 
113         final AbstractBackgroundInitializerTestImpl init = new SupplierBackgroundInitializerTestImpl(IOExceptionConsumer);
114         init.start();
115         init.get(); //ensure the Future has completed.
116         try {
117             init.close();
118             fail();
119         } catch (Exception e) {
120             assertThat(e, instanceOf(ConcurrentException.class));
121             assertSame(ioException, e.getCause());
122         }
123     }
124 
125     /**
126      * Tests that close() throws a runtime exception
127      *
128      * @throws Exception
129      */
130     @Test
131     public void testCloseWithRuntimeException() throws Exception {
132 
133         final NullPointerException npe = new NullPointerException();
134         final FailableConsumer<?, ?> NullPointerExceptionConsumer = (CloseableCounter cc) -> {
135             throw npe;
136         };
137 
138         final AbstractBackgroundInitializerTestImpl init = new SupplierBackgroundInitializerTestImpl(NullPointerExceptionConsumer);
139         init.start();
140         init.get(); //ensure the Future has completed.
141         try {
142             init.close();
143             fail();
144         } catch (Exception e) {
145             assertSame(npe, e);
146         }
147     }
148 }