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.rng.simple;
18  
19  import org.apache.commons.rng.UniformRandomProvider;
20  import org.junit.jupiter.api.Assertions;
21  import org.junit.jupiter.api.BeforeAll;
22  import org.junit.jupiter.api.Test;
23  
24  import java.util.EnumSet;
25  import java.util.concurrent.ExecutionException;
26  import java.util.concurrent.ExecutorService;
27  import java.util.concurrent.Executors;
28  import java.util.concurrent.Future;
29  import java.util.concurrent.TimeUnit;
30  import java.util.concurrent.TimeoutException;
31  
32  /**
33   * Tests for {@link ThreadLocalRandomSource}.
34   */
35  class ThreadLocalRandomSourceTest {
36      /**
37       * A set of all the RandomSource options that requires arguments. This should be
38       * ignored in certain tests since they are not supported.
39       */
40      private static EnumSet<RandomSource> toIgnore;
41  
42      @BeforeAll
43      public static void createToIgnoreSet() {
44          toIgnore = EnumSet.of(RandomSource.TWO_CMRES_SELECT);
45      }
46  
47      @Test
48      void testCurrentThrowsForNullRandomSource() {
49          Assertions.assertThrows(IllegalArgumentException.class, () -> ThreadLocalRandomSource.current(null));
50      }
51  
52      @Test
53      void testCurrentThrowsForRandomSourceWithDataArguments() {
54          Assertions.assertThrows(IllegalArgumentException.class,
55              () -> ThreadLocalRandomSource.current(RandomSource.TWO_CMRES_SELECT));
56      }
57  
58      @Test
59      void testCurrentForAllRandomSources()
60              throws InterruptedException, ExecutionException, TimeoutException {
61          final RandomSource[] sources = RandomSource.values();
62          final UniformRandomProvider[] rngs = new UniformRandomProvider[sources.length];
63  
64          for (int i = 0; i < sources.length; i++) {
65              final RandomSource source = sources[i];
66              if (toIgnore.contains(source)) {
67                  continue;
68              }
69              final UniformRandomProvider rng = getCurrent(source);
70              Assertions.assertNotNull(rng, () -> "Failed to create source: " + source);
71              rngs[i] = rng;
72          }
73          for (int i = 0; i < sources.length; i++) {
74              final RandomSource source = sources[i];
75              if (toIgnore.contains(source)) {
76                  continue;
77              }
78              final UniformRandomProvider rng = getCurrent(source);
79              Assertions.assertSame(rngs[i], rng, () -> "Failed to return same source: " + source);
80          }
81  
82          // Build on a new thread
83          final UniformRandomProvider[] rngs2 = new UniformRandomProvider[rngs.length];
84          final ExecutorService executor = Executors.newFixedThreadPool(1);
85          final Future<?> future = executor.submit(
86              new Runnable() {
87                  @Override
88                  public void run() {
89                      for (int i = 0; i < sources.length; i++) {
90                          if (toIgnore.contains(sources[i])) {
91                              continue;
92                          }
93                          rngs2[i] = getCurrent(sources[i]);
94                      }
95                  }
96              });
97  
98          // Shutdown and wait for task to end
99          executor.shutdown();
100         future.get(30, TimeUnit.SECONDS);
101 
102         // The RNG from the new thread should be different
103         for (int i = 0; i < sources.length; i++) {
104             final RandomSource source = sources[i];
105             if (toIgnore.contains(source)) {
106                 continue;
107             }
108             Assertions.assertNotSame(rngs[i], rngs2[i], () -> "Failed to return different source: " + source);
109         }
110     }
111 
112     private static UniformRandomProvider getCurrent(RandomSource source) {
113         try {
114             return ThreadLocalRandomSource.current(source);
115         } catch (final RuntimeException ex) {
116             throw new RuntimeException("Failed to get current: " + source, ex);
117         }
118     }
119 }