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