1 /*
2  * Copyright (C) 2010 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.util.concurrent;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.common.testing.NullPointerTester;
22 
23 import junit.framework.TestCase;
24 
25 import java.lang.Thread.UncaughtExceptionHandler;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.ThreadFactory;
28 
29 /**
30  * Tests for ThreadFactoryBuilder.
31  *
32  * @author Kurt Alfred Kluever
33  * @author Martin Buchholz
34  */
35 public class ThreadFactoryBuilderTest extends TestCase {
36   private final Runnable monitoredRunnable = new Runnable() {
37     @Override public void run() {
38       completed = true;
39     }
40   };
41 
42   private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER =
43       new UncaughtExceptionHandler() {
44         @Override public void uncaughtException(Thread t, Throwable e) {
45           // No-op
46         }
47       };
48 
49   private ThreadFactoryBuilder builder;
50   private volatile boolean completed = false;
51 
setUp()52   @Override public void setUp() {
53     builder = new ThreadFactoryBuilder();
54   }
55 
testThreadFactoryBuilder_defaults()56   public void testThreadFactoryBuilder_defaults() throws InterruptedException {
57     ThreadFactory threadFactory = builder.build();
58     Thread thread = threadFactory.newThread(monitoredRunnable);
59     checkThreadPoolName(thread, 1);
60 
61     Thread defaultThread =
62         Executors.defaultThreadFactory().newThread(monitoredRunnable);
63     assertEquals(defaultThread.isDaemon(), thread.isDaemon());
64     assertEquals(defaultThread.getPriority(), thread.getPriority());
65     assertSame(defaultThread.getThreadGroup(), thread.getThreadGroup());
66     assertSame(defaultThread.getUncaughtExceptionHandler(),
67         thread.getUncaughtExceptionHandler());
68 
69     assertFalse(completed);
70     thread.start();
71     thread.join();
72     assertTrue(completed);
73 
74     // Creating a new thread from the same ThreadFactory will have the same
75     // pool ID but a thread ID of 2.
76     Thread thread2 = threadFactory.newThread(monitoredRunnable);
77     checkThreadPoolName(thread2, 2);
78     assertEquals(
79         thread.getName().substring(0, thread.getName().lastIndexOf('-')),
80         thread2.getName().substring(0, thread.getName().lastIndexOf('-')));
81 
82     // Building again should give us a different pool ID.
83     ThreadFactory threadFactory2 = builder.build();
84     Thread thread3 = threadFactory2.newThread(monitoredRunnable);
85     checkThreadPoolName(thread3, 1);
86     assertThat(
87         thread2.getName().substring(0, thread.getName().lastIndexOf('-')))
88         .isNotEqualTo(
89             thread3.getName().substring(0, thread.getName().lastIndexOf('-')));
90   }
91 
checkThreadPoolName(Thread thread, int threadId)92   private static void checkThreadPoolName(Thread thread, int threadId) {
93     assertTrue(thread.getName().matches("^pool-\\d+-thread-" + threadId + "$"));
94   }
95 
testNameFormatWithPercentS_custom()96   public void testNameFormatWithPercentS_custom() {
97     String format = "super-duper-thread-%s";
98     ThreadFactory factory = builder.setNameFormat(format).build();
99     for (int i = 0; i < 11; i++) {
100       assertEquals(String.format(format, i),
101           factory.newThread(monitoredRunnable).getName());
102     }
103   }
104 
testNameFormatWithPercentD_custom()105   public void testNameFormatWithPercentD_custom() {
106     String format = "super-duper-thread-%d";
107     ThreadFactory factory = builder.setNameFormat(format).build();
108     for (int i = 0; i < 11; i++) {
109       assertEquals(String.format(format, i),
110           factory.newThread(monitoredRunnable).getName());
111     }
112   }
113 
testDaemon_false()114   public void testDaemon_false() {
115     ThreadFactory factory = builder.setDaemon(false).build();
116     Thread thread = factory.newThread(monitoredRunnable);
117     assertFalse(thread.isDaemon());
118   }
119 
testDaemon_true()120   public void testDaemon_true() {
121     ThreadFactory factory = builder.setDaemon(true).build();
122     Thread thread = factory.newThread(monitoredRunnable);
123     assertTrue(thread.isDaemon());
124   }
125 
testPriority_custom()126   public void testPriority_custom() {
127     for (int i = Thread.MIN_PRIORITY; i <= Thread.MAX_PRIORITY; i++) {
128       ThreadFactory factory = builder.setPriority(i).build();
129       Thread thread = factory.newThread(monitoredRunnable);
130       assertEquals(i, thread.getPriority());
131     }
132   }
133 
testPriority_tooLow()134   public void testPriority_tooLow() {
135     try {
136       builder.setPriority(Thread.MIN_PRIORITY - 1);
137       fail();
138     } catch (IllegalArgumentException expected) {
139     }
140   }
141 
testPriority_tooHigh()142   public void testPriority_tooHigh() {
143     try {
144       builder.setPriority(Thread.MAX_PRIORITY + 1);
145       fail();
146     } catch (IllegalArgumentException expected) {
147     }
148   }
149 
testUncaughtExceptionHandler_custom()150   public void testUncaughtExceptionHandler_custom() {
151     assertEquals(UNCAUGHT_EXCEPTION_HANDLER,
152         builder.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER).build()
153         .newThread(monitoredRunnable).getUncaughtExceptionHandler());
154   }
155 
testBuildMutateBuild()156   public void testBuildMutateBuild() {
157     ThreadFactory factory1 = builder.setPriority(1).build();
158     assertEquals(1, factory1.newThread(monitoredRunnable).getPriority());
159 
160     ThreadFactory factory2 = builder.setPriority(2).build();
161     assertEquals(1, factory1.newThread(monitoredRunnable).getPriority());
162     assertEquals(2, factory2.newThread(monitoredRunnable).getPriority());
163   }
164 
testBuildTwice()165   public void testBuildTwice() {
166     builder.build();  // this is allowed
167     builder.build();  // this is *also* allowed
168   }
169 
testBuildMutate()170   public void testBuildMutate() {
171     ThreadFactory factory1 = builder.setPriority(1).build();
172     assertEquals(1, factory1.newThread(monitoredRunnable).getPriority());
173 
174     builder.setPriority(2);  // change the state of the builder
175     assertEquals(1, factory1.newThread(monitoredRunnable).getPriority());
176   }
177 
testThreadFactory()178   public void testThreadFactory() throws InterruptedException {
179     final String THREAD_NAME = "ludicrous speed";
180     final int THREAD_PRIORITY = 1;
181     final boolean THREAD_DAEMON = false;
182     ThreadFactory backingThreadFactory = new ThreadFactory() {
183       @Override public Thread newThread(Runnable r) {
184         Thread thread = new Thread(r);
185         thread.setName(THREAD_NAME);
186         thread.setPriority(THREAD_PRIORITY);
187         thread.setDaemon(THREAD_DAEMON);
188         thread.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
189         return thread;
190       }
191     };
192 
193     Thread thread = builder.setThreadFactory(backingThreadFactory).build()
194         .newThread(monitoredRunnable);
195 
196     assertEquals(THREAD_NAME, thread.getName());
197     assertEquals(THREAD_PRIORITY, thread.getPriority());
198     assertEquals(THREAD_DAEMON, thread.isDaemon());
199     assertSame(UNCAUGHT_EXCEPTION_HANDLER,
200         thread.getUncaughtExceptionHandler());
201     assertSame(Thread.State.NEW, thread.getState());
202 
203     assertFalse(completed);
204     thread.start();
205     thread.join();
206     assertTrue(completed);
207   }
208 
testNulls()209   public void testNulls() {
210     NullPointerTester npTester = new NullPointerTester();
211     npTester.testAllPublicConstructors(ThreadFactoryBuilder.class);
212     npTester.testAllPublicStaticMethods(ThreadFactoryBuilder.class);
213     npTester.testAllPublicInstanceMethods(builder);
214   }
215 }
216