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 import java.lang.Thread.UncaughtExceptionHandler; 23 import java.util.Locale; 24 import java.util.concurrent.Executors; 25 import java.util.concurrent.ThreadFactory; 26 import junit.framework.TestCase; 27 28 /** 29 * Tests for ThreadFactoryBuilder. 30 * 31 * @author Kurt Alfred Kluever 32 * @author Martin Buchholz 33 */ 34 public class ThreadFactoryBuilderTest extends TestCase { 35 private final Runnable monitoredRunnable = 36 new Runnable() { 37 @Override 38 public void run() { 39 completed = true; 40 } 41 }; 42 43 private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER = 44 new UncaughtExceptionHandler() { 45 @Override 46 public void uncaughtException(Thread t, Throwable e) { 47 // No-op 48 } 49 }; 50 51 private ThreadFactoryBuilder builder; 52 private volatile boolean completed = false; 53 54 @Override setUp()55 public void setUp() { 56 builder = new ThreadFactoryBuilder(); 57 } 58 59 testThreadFactoryBuilder_defaults()60 public void testThreadFactoryBuilder_defaults() throws InterruptedException { 61 ThreadFactory threadFactory = builder.build(); 62 Thread thread = threadFactory.newThread(monitoredRunnable); 63 checkThreadPoolName(thread, 1); 64 65 Thread defaultThread = Executors.defaultThreadFactory().newThread(monitoredRunnable); 66 assertEquals(defaultThread.isDaemon(), thread.isDaemon()); 67 assertEquals(defaultThread.getPriority(), thread.getPriority()); 68 assertSame(defaultThread.getThreadGroup(), thread.getThreadGroup()); 69 assertSame(defaultThread.getUncaughtExceptionHandler(), thread.getUncaughtExceptionHandler()); 70 71 assertFalse(completed); 72 thread.start(); 73 thread.join(); 74 assertTrue(completed); 75 76 // Creating a new thread from the same ThreadFactory will have the same 77 // pool ID but a thread ID of 2. 78 Thread thread2 = threadFactory.newThread(monitoredRunnable); 79 checkThreadPoolName(thread2, 2); 80 assertEquals( 81 thread.getName().substring(0, thread.getName().lastIndexOf('-')), 82 thread2.getName().substring(0, thread.getName().lastIndexOf('-'))); 83 84 // Building again should give us a different pool ID. 85 ThreadFactory threadFactory2 = builder.build(); 86 Thread thread3 = threadFactory2.newThread(monitoredRunnable); 87 checkThreadPoolName(thread3, 1); 88 assertThat(thread2.getName().substring(0, thread.getName().lastIndexOf('-'))) 89 .isNotEqualTo(thread3.getName().substring(0, thread.getName().lastIndexOf('-'))); 90 } 91 checkThreadPoolName(Thread thread, int threadId)92 private static void checkThreadPoolName(Thread thread, int threadId) { 93 assertThat(thread.getName()).matches("^pool-\\d+-thread-" + threadId + "$"); 94 } 95 96 testNameFormatWithPercentS_custom()97 public void testNameFormatWithPercentS_custom() { 98 String format = "super-duper-thread-%s"; 99 ThreadFactory factory = builder.setNameFormat(format).build(); 100 for (int i = 0; i < 11; i++) { 101 assertEquals(rootLocaleFormat(format, i), factory.newThread(monitoredRunnable).getName()); 102 } 103 } 104 105 testNameFormatWithPercentD_custom()106 public void testNameFormatWithPercentD_custom() { 107 String format = "super-duper-thread-%d"; 108 ThreadFactory factory = builder.setNameFormat(format).build(); 109 for (int i = 0; i < 11; i++) { 110 assertEquals(rootLocaleFormat(format, i), factory.newThread(monitoredRunnable).getName()); 111 } 112 } 113 114 testDaemon_false()115 public void testDaemon_false() { 116 ThreadFactory factory = builder.setDaemon(false).build(); 117 Thread thread = factory.newThread(monitoredRunnable); 118 assertFalse(thread.isDaemon()); 119 } 120 121 testDaemon_true()122 public void testDaemon_true() { 123 ThreadFactory factory = builder.setDaemon(true).build(); 124 Thread thread = factory.newThread(monitoredRunnable); 125 assertTrue(thread.isDaemon()); 126 } 127 128 testPriority_custom()129 public void testPriority_custom() { 130 for (int i = Thread.MIN_PRIORITY; i <= Thread.MAX_PRIORITY; i++) { 131 ThreadFactory factory = builder.setPriority(i).build(); 132 Thread thread = factory.newThread(monitoredRunnable); 133 assertEquals(i, thread.getPriority()); 134 } 135 } 136 testPriority_tooLow()137 public void testPriority_tooLow() { 138 try { 139 builder.setPriority(Thread.MIN_PRIORITY - 1); 140 fail(); 141 } catch (IllegalArgumentException expected) { 142 } 143 } 144 testPriority_tooHigh()145 public void testPriority_tooHigh() { 146 try { 147 builder.setPriority(Thread.MAX_PRIORITY + 1); 148 fail(); 149 } catch (IllegalArgumentException expected) { 150 } 151 } 152 153 testUncaughtExceptionHandler_custom()154 public void testUncaughtExceptionHandler_custom() { 155 assertEquals( 156 UNCAUGHT_EXCEPTION_HANDLER, 157 builder 158 .setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER) 159 .build() 160 .newThread(monitoredRunnable) 161 .getUncaughtExceptionHandler()); 162 } 163 164 testBuildMutateBuild()165 public void testBuildMutateBuild() { 166 ThreadFactory factory1 = builder.setPriority(1).build(); 167 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 168 169 ThreadFactory factory2 = builder.setPriority(2).build(); 170 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 171 assertEquals(2, factory2.newThread(monitoredRunnable).getPriority()); 172 } 173 testBuildTwice()174 public void testBuildTwice() { 175 ThreadFactory unused; 176 unused = builder.build(); // this is allowed 177 unused = builder.build(); // this is *also* allowed 178 } 179 180 testBuildMutate()181 public void testBuildMutate() { 182 ThreadFactory factory1 = builder.setPriority(1).build(); 183 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 184 185 builder.setPriority(2); // change the state of the builder 186 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 187 } 188 189 testThreadFactory()190 public void testThreadFactory() throws InterruptedException { 191 final String THREAD_NAME = "ludicrous speed"; 192 final int THREAD_PRIORITY = 1; 193 final boolean THREAD_DAEMON = false; 194 ThreadFactory backingThreadFactory = 195 new ThreadFactory() { 196 @Override 197 public Thread newThread(Runnable r) { 198 Thread thread = new Thread(r); 199 thread.setName(THREAD_NAME); 200 thread.setPriority(THREAD_PRIORITY); 201 thread.setDaemon(THREAD_DAEMON); 202 thread.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER); 203 return thread; 204 } 205 }; 206 207 Thread thread = 208 builder.setThreadFactory(backingThreadFactory).build().newThread(monitoredRunnable); 209 210 assertEquals(THREAD_NAME, thread.getName()); 211 assertEquals(THREAD_PRIORITY, thread.getPriority()); 212 assertEquals(THREAD_DAEMON, thread.isDaemon()); 213 assertSame(UNCAUGHT_EXCEPTION_HANDLER, thread.getUncaughtExceptionHandler()); 214 assertSame(Thread.State.NEW, thread.getState()); 215 216 assertFalse(completed); 217 thread.start(); 218 thread.join(); 219 assertTrue(completed); 220 } 221 testNulls()222 public void testNulls() { 223 NullPointerTester npTester = new NullPointerTester(); 224 npTester.testAllPublicConstructors(ThreadFactoryBuilder.class); 225 npTester.testAllPublicStaticMethods(ThreadFactoryBuilder.class); 226 npTester.testAllPublicInstanceMethods(builder); 227 } 228 rootLocaleFormat(String format, Object... args)229 private static String rootLocaleFormat(String format, Object... args) { 230 return String.format(Locale.ROOT, format, args); 231 } 232 } 233