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 import static org.junit.Assert.assertThrows; 21 22 import com.google.common.testing.NullPointerTester; 23 import java.lang.Thread.UncaughtExceptionHandler; 24 import java.util.Locale; 25 import java.util.concurrent.Executors; 26 import java.util.concurrent.ThreadFactory; 27 import junit.framework.TestCase; 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 = 37 new Runnable() { 38 @Override 39 public void run() { 40 completed = true; 41 } 42 }; 43 44 private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER = 45 new UncaughtExceptionHandler() { 46 @Override 47 public void uncaughtException(Thread t, Throwable e) { 48 // No-op 49 } 50 }; 51 52 private ThreadFactoryBuilder builder; 53 private volatile boolean completed = false; 54 55 @Override setUp()56 public void setUp() { 57 builder = new ThreadFactoryBuilder(); 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 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(rootLocaleFormat(format, i), factory.newThread(monitoredRunnable).getName()); 101 } 102 } 103 testNameFormatWithPercentD_custom()104 public void testNameFormatWithPercentD_custom() { 105 String format = "super-duper-thread-%d"; 106 ThreadFactory factory = builder.setNameFormat(format).build(); 107 for (int i = 0; i < 11; i++) { 108 assertEquals(rootLocaleFormat(format, i), factory.newThread(monitoredRunnable).getName()); 109 } 110 } 111 testDaemon_false()112 public void testDaemon_false() { 113 ThreadFactory factory = builder.setDaemon(false).build(); 114 Thread thread = factory.newThread(monitoredRunnable); 115 assertFalse(thread.isDaemon()); 116 } 117 testDaemon_true()118 public void testDaemon_true() { 119 ThreadFactory factory = builder.setDaemon(true).build(); 120 Thread thread = factory.newThread(monitoredRunnable); 121 assertTrue(thread.isDaemon()); 122 } 123 testPriority_custom()124 public void testPriority_custom() { 125 for (int i = Thread.MIN_PRIORITY; i <= Thread.MAX_PRIORITY; i++) { 126 ThreadFactory factory = builder.setPriority(i).build(); 127 Thread thread = factory.newThread(monitoredRunnable); 128 assertEquals(i, thread.getPriority()); 129 } 130 } 131 testPriority_tooLow()132 public void testPriority_tooLow() { 133 assertThrows( 134 IllegalArgumentException.class, () -> builder.setPriority(Thread.MIN_PRIORITY - 1)); 135 } 136 testPriority_tooHigh()137 public void testPriority_tooHigh() { 138 assertThrows( 139 IllegalArgumentException.class, () -> builder.setPriority(Thread.MAX_PRIORITY + 1)); 140 } 141 testUncaughtExceptionHandler_custom()142 public void testUncaughtExceptionHandler_custom() { 143 assertEquals( 144 UNCAUGHT_EXCEPTION_HANDLER, 145 builder 146 .setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER) 147 .build() 148 .newThread(monitoredRunnable) 149 .getUncaughtExceptionHandler()); 150 } 151 testBuildMutateBuild()152 public void testBuildMutateBuild() { 153 ThreadFactory factory1 = builder.setPriority(1).build(); 154 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 155 156 ThreadFactory factory2 = builder.setPriority(2).build(); 157 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 158 assertEquals(2, factory2.newThread(monitoredRunnable).getPriority()); 159 } 160 testBuildTwice()161 public void testBuildTwice() { 162 ThreadFactory unused; 163 unused = builder.build(); // this is allowed 164 unused = builder.build(); // this is *also* allowed 165 } 166 testBuildMutate()167 public void testBuildMutate() { 168 ThreadFactory factory1 = builder.setPriority(1).build(); 169 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 170 171 builder.setPriority(2); // change the state of the builder 172 assertEquals(1, factory1.newThread(monitoredRunnable).getPriority()); 173 } 174 testThreadFactory()175 public void testThreadFactory() throws InterruptedException { 176 final String THREAD_NAME = "ludicrous speed"; 177 final int THREAD_PRIORITY = 1; 178 final boolean THREAD_DAEMON = false; 179 ThreadFactory backingThreadFactory = 180 new ThreadFactory() { 181 @Override 182 public Thread newThread(Runnable r) { 183 Thread thread = new Thread(r); 184 thread.setName(THREAD_NAME); 185 thread.setPriority(THREAD_PRIORITY); 186 thread.setDaemon(THREAD_DAEMON); 187 thread.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER); 188 return thread; 189 } 190 }; 191 192 Thread thread = 193 builder.setThreadFactory(backingThreadFactory).build().newThread(monitoredRunnable); 194 195 assertEquals(THREAD_NAME, thread.getName()); 196 assertEquals(THREAD_PRIORITY, thread.getPriority()); 197 assertEquals(THREAD_DAEMON, thread.isDaemon()); 198 assertSame(UNCAUGHT_EXCEPTION_HANDLER, thread.getUncaughtExceptionHandler()); 199 assertSame(Thread.State.NEW, thread.getState()); 200 201 assertFalse(completed); 202 thread.start(); 203 thread.join(); 204 assertTrue(completed); 205 } 206 testNulls()207 public void testNulls() { 208 NullPointerTester npTester = new NullPointerTester(); 209 npTester.testAllPublicConstructors(ThreadFactoryBuilder.class); 210 npTester.testAllPublicStaticMethods(ThreadFactoryBuilder.class); 211 npTester.testAllPublicInstanceMethods(builder); 212 } 213 rootLocaleFormat(String format, Object... args)214 private static String rootLocaleFormat(String format, Object... args) { 215 return String.format(Locale.ROOT, format, args); 216 } 217 } 218