1 /* 2 * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 4607272 26 * @summary Unit test for AsynchronousChannelGroup 27 * @key randomness 28 */ 29 30 import java.nio.ByteBuffer; 31 import java.nio.channels.*; 32 import java.net.*; 33 import java.util.*; 34 import java.util.concurrent.*; 35 import java.io.IOException; 36 37 public class Basic { 38 static final Random rand = new Random(); 39 static final ThreadFactory threadFactory = (Runnable r) -> { 40 return new Thread(r); 41 }; 42 43 public static void main(String[] args) throws Exception { 44 shutdownTests(); 45 shutdownNowTests(); 46 afterShutdownTests(); 47 miscTests(); 48 } 49 50 static void awaitTermination(AsynchronousChannelGroup group) throws InterruptedException { 51 boolean terminated = group.awaitTermination(20, TimeUnit.SECONDS); 52 if (!terminated) 53 throw new RuntimeException("Group should have terminated"); 54 } 55 56 static void testShutdownWithNoChannels(ExecutorService pool, 57 AsynchronousChannelGroup group) 58 throws Exception 59 { 60 group.shutdown(); 61 if (!group.isShutdown()) 62 throw new RuntimeException("Group should be shutdown"); 63 // group should terminate quickly 64 awaitTermination(group); 65 if (pool != null && !pool.isTerminated()) 66 throw new RuntimeException("Executor should have terminated"); 67 } 68 69 static void testShutdownWithChannels(ExecutorService pool, 70 AsynchronousChannelGroup group) 71 throws Exception 72 { 73 74 // create channel that is bound to group 75 AsynchronousChannel ch; 76 switch (rand.nextInt(2)) { 77 case 0 : ch = AsynchronousSocketChannel.open(group); break; 78 case 1 : ch = AsynchronousServerSocketChannel.open(group); break; 79 default : throw new AssertionError(); 80 } 81 group.shutdown(); 82 if (!group.isShutdown()) 83 throw new RuntimeException("Group should be shutdown"); 84 85 // last channel so should terminate after this channel is closed 86 ch.close(); 87 88 // group should terminate quickly 89 awaitTermination(group); 90 if (pool != null && !pool.isTerminated()) 91 throw new RuntimeException("Executor should have terminated"); 92 } 93 94 static void shutdownTests() throws Exception { 95 System.out.println("-- test shutdown --"); 96 97 // test shutdown with no channels in groups 98 for (int i = 0; i < 100; i++) { 99 ExecutorService pool = Executors.newCachedThreadPool(); 100 AsynchronousChannelGroup group = AsynchronousChannelGroup 101 .withCachedThreadPool(pool, rand.nextInt(5)); 102 testShutdownWithNoChannels(pool, group); 103 } 104 for (int i = 0; i < 100; i++) { 105 int nThreads = 1 + rand.nextInt(8); 106 AsynchronousChannelGroup group = AsynchronousChannelGroup 107 .withFixedThreadPool(nThreads, threadFactory); 108 testShutdownWithNoChannels(null, group); 109 } 110 for (int i = 0; i < 100; i++) { 111 ExecutorService pool = Executors.newCachedThreadPool(); 112 AsynchronousChannelGroup group = AsynchronousChannelGroup 113 .withThreadPool(pool); 114 testShutdownWithNoChannels(pool, group); 115 } 116 117 // test shutdown with channel in group 118 for (int i = 0; i < 100; i++) { 119 ExecutorService pool = Executors.newCachedThreadPool(); 120 AsynchronousChannelGroup group = AsynchronousChannelGroup 121 .withCachedThreadPool(pool, rand.nextInt(10)); 122 testShutdownWithChannels(pool, group); 123 } 124 for (int i = 0; i < 100; i++) { 125 int nThreads = 1 + rand.nextInt(8); 126 AsynchronousChannelGroup group = AsynchronousChannelGroup 127 .withFixedThreadPool(nThreads, threadFactory); 128 testShutdownWithChannels(null, group); 129 } 130 for (int i = 0; i < 100; i++) { 131 ExecutorService pool = Executors.newCachedThreadPool(); 132 AsynchronousChannelGroup group = AsynchronousChannelGroup 133 .withThreadPool(pool); 134 testShutdownWithChannels(pool, group); 135 } 136 } 137 138 static void testShutdownNow(ExecutorService pool, 139 AsynchronousChannelGroup group) 140 throws Exception 141 { 142 // I/O in progress 143 AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel 144 .open(group).bind(new InetSocketAddress(0)); 145 ch.accept(); 146 147 // forceful shutdown 148 group.shutdownNow(); 149 150 // shutdownNow is required to close all channels 151 if (ch.isOpen()) 152 throw new RuntimeException("Channel should be closed"); 153 154 awaitTermination(group); 155 156 if (pool != null && !pool.isTerminated()) 157 throw new RuntimeException("Executor should have terminated"); 158 } 159 160 static void shutdownNowTests() throws Exception { 161 System.out.println("-- test shutdownNow --"); 162 163 for (int i = 0; i < 10; i++) { 164 ExecutorService pool = pool = Executors.newCachedThreadPool(); 165 AsynchronousChannelGroup group = AsynchronousChannelGroup 166 .withCachedThreadPool(pool, rand.nextInt(5)); 167 testShutdownNow(pool, group); 168 } 169 for (int i = 0; i < 10; i++) { 170 int nThreads = 1 + rand.nextInt(8); 171 AsynchronousChannelGroup group = AsynchronousChannelGroup 172 .withFixedThreadPool(nThreads, threadFactory); 173 testShutdownNow(null, group); 174 } 175 for (int i = 0; i < 10; i++) { 176 ExecutorService pool = Executors.newCachedThreadPool(); 177 AsynchronousChannelGroup group = AsynchronousChannelGroup 178 .withThreadPool(pool); 179 testShutdownNow(pool, group); 180 } 181 } 182 183 // test creating channels in group after group is shutdown 184 static void afterShutdownTests() throws Exception { 185 System.out.println("-- test operations after group is shutdown --"); 186 AsynchronousChannelGroup group = 187 AsynchronousChannelGroup.withFixedThreadPool(1, threadFactory); 188 189 AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group); 190 AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(group); 191 192 // initiate accept 193 listener.bind(new InetSocketAddress(0)); 194 Future<AsynchronousSocketChannel> result = listener.accept(); 195 196 // shutdown group 197 group.shutdown(); 198 if (!group.isShutdown()) 199 throw new RuntimeException("Group should be shutdown"); 200 201 // attempt to create another channel 202 try { 203 AsynchronousSocketChannel.open(group); 204 throw new RuntimeException("ShutdownChannelGroupException expected"); 205 } catch (ShutdownChannelGroupException x) { 206 } 207 try { 208 AsynchronousServerSocketChannel.open(group); 209 throw new RuntimeException("ShutdownChannelGroupException expected"); 210 } catch (ShutdownChannelGroupException x) { 211 } 212 213 // attempt to create another channel by connecting. This should cause 214 // the accept operation to fail. 215 InetAddress lh = InetAddress.getLocalHost(); 216 int port = ((InetSocketAddress)listener.getLocalAddress()).getPort(); 217 InetSocketAddress isa = new InetSocketAddress(lh, port); 218 ch.connect(isa).get(); 219 try { 220 result.get(); 221 throw new RuntimeException("Connection was accepted"); 222 } catch (ExecutionException x) { 223 Throwable cause = x.getCause(); 224 if (!(cause instanceof IOException)) 225 throw new RuntimeException("Cause should be IOException"); 226 cause = cause.getCause(); 227 if (!(cause instanceof ShutdownChannelGroupException)) 228 throw new RuntimeException("IOException cause should be ShutdownChannelGroupException"); 229 } 230 231 // initiate another accept even though channel group is shutdown. 232 Future<AsynchronousSocketChannel> res = listener.accept(); 233 try { 234 res.get(3, TimeUnit.SECONDS); 235 throw new RuntimeException("TimeoutException expected"); 236 } catch (TimeoutException x) { 237 } 238 // connect to the listener which should cause the accept to complete 239 AsynchronousSocketChannel.open().connect(isa); 240 try { 241 res.get(); 242 throw new RuntimeException("Connection was accepted"); 243 } catch (ExecutionException x) { 244 Throwable cause = x.getCause(); 245 if (!(cause instanceof IOException)) 246 throw new RuntimeException("Cause should be IOException"); 247 cause = cause.getCause(); 248 if (!(cause instanceof ShutdownChannelGroupException)) 249 throw new RuntimeException("IOException cause should be ShutdownChannelGroupException"); 250 } 251 252 // group should *not* terminate as channels are open 253 boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS); 254 if (terminated) 255 throw new RuntimeException("Group should not have terminated"); 256 257 // close channel; group should terminate quickly 258 ch.close(); 259 listener.close(); 260 awaitTermination(group); 261 } 262 263 static void miscTests() throws Exception { 264 System.out.println("-- miscellenous tests --"); 265 try { 266 AsynchronousChannelGroup.withFixedThreadPool(1, null); 267 throw new RuntimeException("NPE expected"); 268 } catch (NullPointerException x) { 269 } 270 try { 271 AsynchronousChannelGroup.withFixedThreadPool(0, threadFactory); 272 throw new RuntimeException("IAE expected"); 273 } catch (IllegalArgumentException e) { 274 } 275 try { 276 AsynchronousChannelGroup.withCachedThreadPool(null, 0); 277 throw new RuntimeException("NPE expected"); 278 } catch (NullPointerException x) { 279 } 280 try { 281 AsynchronousChannelGroup.withThreadPool(null); 282 throw new RuntimeException("NPE expected"); 283 } catch (NullPointerException e) { 284 } 285 } 286 }