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 */ 28 29 import java.nio.ByteBuffer; 30 import java.nio.channels.*; 31 import java.net.*; 32 import java.util.*; 33 import java.util.concurrent.*; 34 import java.io.IOException; 35 36 public class Basic { 37 static final Random rand = new Random(); 38 static final ThreadFactory threadFactory = (Runnable r) -> { 39 return new Thread(r); 40 }; 41 42 public static void main(String[] args) throws Exception { 43 shutdownTests(); 44 shutdownNowTests(); 45 afterShutdownTests(); 46 miscTests(); 47 } 48 49 static void awaitTermination(AsynchronousChannelGroup group) throws InterruptedException { 50 boolean terminated = group.awaitTermination(20, TimeUnit.SECONDS); 51 if (!terminated) 52 throw new RuntimeException("Group should have terminated"); 53 } 54 55 static void testShutdownWithNoChannels(ExecutorService pool, 56 AsynchronousChannelGroup group) 57 throws Exception 58 { 59 group.shutdown(); 60 if (!group.isShutdown()) 61 throw new RuntimeException("Group should be shutdown"); 62 // group should terminate quickly 63 awaitTermination(group); 64 if (pool != null && !pool.isTerminated()) 65 throw new RuntimeException("Executor should have terminated"); 66 } 67 68 static void testShutdownWithChannels(ExecutorService pool, 69 AsynchronousChannelGroup group) 70 throws Exception 71 { 72 73 // create channel that is bound to group 74 AsynchronousChannel ch; 75 switch (rand.nextInt(2)) { 76 case 0 : ch = AsynchronousSocketChannel.open(group); break; 77 case 1 : ch = AsynchronousServerSocketChannel.open(group); break; 78 default : throw new AssertionError(); 79 } 80 group.shutdown(); 81 if (!group.isShutdown()) 82 throw new RuntimeException("Group should be shutdown"); 83 84 // last channel so should terminate after this channel is closed 85 ch.close(); 86 87 // group should terminate quickly 88 awaitTermination(group); 89 if (pool != null && !pool.isTerminated()) 90 throw new RuntimeException("Executor should have terminated"); 91 } 92 93 static void shutdownTests() throws Exception { 94 System.out.println("-- test shutdown --"); 95 96 // test shutdown with no channels in groups 97 for (int i = 0; i < 100; i++) { 98 ExecutorService pool = Executors.newCachedThreadPool(); 99 AsynchronousChannelGroup group = AsynchronousChannelGroup 100 .withCachedThreadPool(pool, rand.nextInt(5)); 101 testShutdownWithNoChannels(pool, group); 102 } 103 for (int i = 0; i < 100; i++) { 104 int nThreads = 1 + rand.nextInt(8); 105 AsynchronousChannelGroup group = AsynchronousChannelGroup 106 .withFixedThreadPool(nThreads, threadFactory); 107 testShutdownWithNoChannels(null, group); 108 } 109 for (int i = 0; i < 100; i++) { 110 ExecutorService pool = Executors.newCachedThreadPool(); 111 AsynchronousChannelGroup group = AsynchronousChannelGroup 112 .withThreadPool(pool); 113 testShutdownWithNoChannels(pool, group); 114 } 115 116 // test shutdown with channel in group 117 for (int i = 0; i < 100; i++) { 118 ExecutorService pool = Executors.newCachedThreadPool(); 119 AsynchronousChannelGroup group = AsynchronousChannelGroup 120 .withCachedThreadPool(pool, rand.nextInt(10)); 121 testShutdownWithChannels(pool, group); 122 } 123 for (int i = 0; i < 100; i++) { 124 int nThreads = 1 + rand.nextInt(8); 125 AsynchronousChannelGroup group = AsynchronousChannelGroup 126 .withFixedThreadPool(nThreads, threadFactory); 127 testShutdownWithChannels(null, group); 128 } 129 for (int i = 0; i < 100; i++) { 130 ExecutorService pool = Executors.newCachedThreadPool(); 131 AsynchronousChannelGroup group = AsynchronousChannelGroup 132 .withThreadPool(pool); 133 testShutdownWithChannels(pool, group); 134 } 135 } 136 137 static void testShutdownNow(ExecutorService pool, 138 AsynchronousChannelGroup group) 139 throws Exception 140 { 141 // I/O in progress 142 AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel 143 .open(group).bind(new InetSocketAddress(0)); 144 ch.accept(); 145 146 // forceful shutdown 147 group.shutdownNow(); 148 149 // shutdownNow is required to close all channels 150 if (ch.isOpen()) 151 throw new RuntimeException("Channel should be closed"); 152 153 awaitTermination(group); 154 155 if (pool != null && !pool.isTerminated()) 156 throw new RuntimeException("Executor should have terminated"); 157 } 158 159 static void shutdownNowTests() throws Exception { 160 System.out.println("-- test shutdownNow --"); 161 162 for (int i = 0; i < 10; i++) { 163 ExecutorService pool = pool = Executors.newCachedThreadPool(); 164 AsynchronousChannelGroup group = AsynchronousChannelGroup 165 .withCachedThreadPool(pool, rand.nextInt(5)); 166 testShutdownNow(pool, group); 167 } 168 for (int i = 0; i < 10; i++) { 169 int nThreads = 1 + rand.nextInt(8); 170 AsynchronousChannelGroup group = AsynchronousChannelGroup 171 .withFixedThreadPool(nThreads, threadFactory); 172 testShutdownNow(null, group); 173 } 174 for (int i = 0; i < 10; i++) { 175 ExecutorService pool = Executors.newCachedThreadPool(); 176 AsynchronousChannelGroup group = AsynchronousChannelGroup 177 .withThreadPool(pool); 178 testShutdownNow(pool, group); 179 } 180 } 181 182 // test creating channels in group after group is shutdown 183 static void afterShutdownTests() throws Exception { 184 System.out.println("-- test operations after group is shutdown --"); 185 AsynchronousChannelGroup group = 186 AsynchronousChannelGroup.withFixedThreadPool(1, threadFactory); 187 188 AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group); 189 AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(group); 190 191 // initiate accept 192 listener.bind(new InetSocketAddress(0)); 193 Future<AsynchronousSocketChannel> result = listener.accept(); 194 195 // shutdown group 196 group.shutdown(); 197 if (!group.isShutdown()) 198 throw new RuntimeException("Group should be shutdown"); 199 200 // attempt to create another channel 201 try { 202 AsynchronousSocketChannel.open(group); 203 throw new RuntimeException("ShutdownChannelGroupException expected"); 204 } catch (ShutdownChannelGroupException x) { 205 } 206 try { 207 AsynchronousServerSocketChannel.open(group); 208 throw new RuntimeException("ShutdownChannelGroupException expected"); 209 } catch (ShutdownChannelGroupException x) { 210 } 211 212 // attempt to create another channel by connecting. This should cause 213 // the accept operation to fail. 214 InetAddress lh = InetAddress.getLocalHost(); 215 int port = ((InetSocketAddress)listener.getLocalAddress()).getPort(); 216 InetSocketAddress isa = new InetSocketAddress(lh, port); 217 ch.connect(isa).get(); 218 try { 219 result.get(); 220 throw new RuntimeException("Connection was accepted"); 221 } catch (ExecutionException x) { 222 Throwable cause = x.getCause(); 223 if (!(cause instanceof IOException)) 224 throw new RuntimeException("Cause should be IOException"); 225 cause = cause.getCause(); 226 if (!(cause instanceof ShutdownChannelGroupException)) 227 throw new RuntimeException("IOException cause should be ShutdownChannelGroupException"); 228 } 229 230 // initiate another accept even though channel group is shutdown. 231 Future<AsynchronousSocketChannel> res = listener.accept(); 232 try { 233 res.get(3, TimeUnit.SECONDS); 234 throw new RuntimeException("TimeoutException expected"); 235 } catch (TimeoutException x) { 236 } 237 // connect to the listener which should cause the accept to complete 238 AsynchronousSocketChannel.open().connect(isa); 239 try { 240 res.get(); 241 throw new RuntimeException("Connection was accepted"); 242 } catch (ExecutionException x) { 243 Throwable cause = x.getCause(); 244 if (!(cause instanceof IOException)) 245 throw new RuntimeException("Cause should be IOException"); 246 cause = cause.getCause(); 247 if (!(cause instanceof ShutdownChannelGroupException)) 248 throw new RuntimeException("IOException cause should be ShutdownChannelGroupException"); 249 } 250 251 // group should *not* terminate as channels are open 252 boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS); 253 if (terminated) 254 throw new RuntimeException("Group should not have terminated"); 255 256 // close channel; group should terminate quickly 257 ch.close(); 258 listener.close(); 259 awaitTermination(group); 260 } 261 262 static void miscTests() throws Exception { 263 System.out.println("-- miscellenous tests --"); 264 try { 265 AsynchronousChannelGroup.withFixedThreadPool(1, null); 266 throw new RuntimeException("NPE expected"); 267 } catch (NullPointerException x) { 268 } 269 try { 270 AsynchronousChannelGroup.withFixedThreadPool(0, threadFactory); 271 throw new RuntimeException("IAE expected"); 272 } catch (IllegalArgumentException e) { 273 } 274 try { 275 AsynchronousChannelGroup.withCachedThreadPool(null, 0); 276 throw new RuntimeException("NPE expected"); 277 } catch (NullPointerException x) { 278 } 279 try { 280 AsynchronousChannelGroup.withThreadPool(null); 281 throw new RuntimeException("NPE expected"); 282 } catch (NullPointerException e) { 283 } 284 } 285 }