1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  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
17package org.apache.harmony.tests.java.nio.channels;
18
19import java.io.IOException;
20import java.net.ServerSocket;
21import java.net.SocketAddress;
22import java.nio.ByteBuffer;
23import java.nio.channels.ClosedChannelException;
24import java.nio.channels.ClosedSelectorException;
25import java.nio.channels.Pipe;
26import java.nio.channels.SelectionKey;
27import java.nio.channels.Selector;
28import java.nio.channels.ServerSocketChannel;
29import java.nio.channels.SocketChannel;
30import java.nio.channels.spi.SelectorProvider;
31import java.util.concurrent.atomic.AtomicBoolean;
32import java.util.concurrent.atomic.AtomicReference;
33import java.util.Set;
34import junit.framework.TestCase;
35
36/*
37 * Tests for Selector and its default implementation
38 */
39public class SelectorTest extends TestCase {
40    private static final int WAIT_TIME = 100;
41
42    private SocketAddress localAddress;
43
44    private Selector selector;
45
46    private ServerSocketChannel ssc;
47
48    private enum SelectType {
49        NULL, TIMEOUT, NOW
50    };
51
52    protected void setUp() throws Exception {
53        super.setUp();
54        ssc = ServerSocketChannel.open();
55        ssc.configureBlocking(false);
56        ServerSocket ss = ssc.socket();
57        ss.bind(null);
58        localAddress = ss.getLocalSocketAddress();
59        selector = Selector.open();
60    }
61
62    protected void tearDown() throws Exception {
63        try {
64            ssc.close();
65        } catch (Exception e) {
66            // do nothing
67        }
68        try {
69            selector.close();
70        } catch (Exception e) {
71            // do nothing
72        }
73        super.tearDown();
74    }
75
76    /**
77     * @tests java.nio.channels.Selector#open()
78     */
79    public void test_open() throws IOException {
80        assertNotNull(selector);
81    }
82
83    /**
84     * @tests Selector#isOpen()
85     */
86    public void test_isOpen() throws IOException {
87        assertTrue(selector.isOpen());
88        selector.close();
89        assertFalse(selector.isOpen());
90    }
91
92    /**
93     * @tests java.nio.channels.Selector#provider()
94     */
95    public void test_provider() throws IOException {
96        // should be system default provider
97        assertNotNull(selector.provider());
98        assertSame(SelectorProvider.provider(), selector.provider());
99    }
100
101    /**
102     * @tests java.nio.channels.Selector#keys()
103     */
104    public void test_keys() throws IOException {
105        SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
106
107        Set<SelectionKey> keySet = selector.keys();
108        Set<SelectionKey> keySet2 = selector.keys();
109
110        assertSame(keySet, keySet2);
111        assertEquals(1,keySet.size());
112        SelectionKey key2 = keySet.iterator().next();
113        assertEquals(key,key2);
114
115        // Any attempt to modify keys will cause UnsupportedOperationException
116        SocketChannel sc = SocketChannel.open();
117        sc.configureBlocking(false);
118        SelectionKey key3 = sc.register(selector, SelectionKey.OP_READ);
119        try {
120            keySet2.add(key3);
121            fail("should throw UnsupportedOperationException");
122        } catch (UnsupportedOperationException e) {
123            // expected
124        }
125        try {
126            keySet2.remove(key3);
127            fail("should throw UnsupportedOperationException");
128        } catch (UnsupportedOperationException e) {
129            // expected
130        }
131        try {
132            keySet2.clear();
133            fail("should throw UnsupportedOperationException");
134        } catch (UnsupportedOperationException e) {
135            // expected
136        }
137
138        selector.close();
139        try {
140            selector.keys();
141            fail("should throw ClosedSelectorException");
142        } catch (ClosedSelectorException e) {
143            // expected
144        }
145    }
146
147    /**
148     * @tests java.nio.channels.Selector#keys()
149     */
150    public void test_selectedKeys() throws IOException {
151        SocketChannel sc = SocketChannel.open();
152        ssc.register(selector, SelectionKey.OP_ACCEPT);
153        try {
154            int count = 0;
155            sc.connect(localAddress);
156            count = blockingSelect(SelectType.NULL, 0);
157            assertEquals(1, count);
158            Set<SelectionKey> selectedKeys = selector.selectedKeys();
159            Set<SelectionKey> selectedKeys2 = selector.selectedKeys();
160            assertSame(selectedKeys, selectedKeys2);
161
162            assertEquals(1, selectedKeys.size());
163            assertEquals(ssc.keyFor(selector), selectedKeys.iterator().next());
164            // add one key into selectedKeys
165            try {
166                selectedKeys.add(ssc.keyFor(selector));
167                fail("Should throw UnsupportedOperationException");
168            } catch (UnsupportedOperationException e) {
169                // expected
170            }
171
172            // no exception should be thrown
173            selectedKeys.clear();
174
175            Set<SelectionKey> selectedKeys3 = selector.selectedKeys();
176            assertSame(selectedKeys, selectedKeys3);
177
178            ssc.keyFor(selector).cancel();
179            assertEquals(0, selectedKeys.size());
180            selector.close();
181            try {
182                selector.selectedKeys();
183                fail("should throw ClosedSelectorException");
184            } catch (ClosedSelectorException e) {
185                // expected
186            }
187        } finally {
188            sc.close();
189        }
190    }
191
192    /**
193     * @tests java.nio.channel.Selector#selectNow()
194     */
195    public void test_selectNow() throws IOException {
196        assert_select_OP_ACCEPT(SelectType.NOW, 0);
197        assert_select_OP_CONNECT(SelectType.NOW, 0);
198        assert_select_OP_READ(SelectType.NOW, 0);
199        assert_select_OP_WRITE(SelectType.NOW, 0);
200    }
201
202    /**
203     * @tests java.nio.channel.Selector#selectNow()
204     */
205    public void test_selectNow_SelectorClosed() throws IOException {
206        assert_select_SelectorClosed(SelectType.NOW, 0);
207    }
208
209    public void test_selectNow_Timeout() throws IOException {
210        // make sure selectNow doesn't block
211        selector.selectNow();
212    }
213
214    /**
215     * @tests java.nio.channel.Selector#select()
216     */
217    public void test_select() throws IOException {
218        assert_select_OP_ACCEPT(SelectType.NULL, 0);
219        assert_select_OP_CONNECT(SelectType.NULL, 0);
220        assert_select_OP_READ(SelectType.NULL, 0);
221        assert_select_OP_WRITE(SelectType.NULL, 0);
222    }
223
224    /**
225     * @tests java.nio.channel.Selector#select()
226     */
227    public void test_select_SelectorClosed() throws IOException {
228        assert_select_SelectorClosed(SelectType.NULL, 0);
229    }
230
231    /**
232     * @tests java.nio.channel.Selector#select(long)
233     */
234    public void test_selectJ() throws IOException {
235        assert_select_OP_ACCEPT(SelectType.TIMEOUT, 0);
236        assert_select_OP_CONNECT(SelectType.TIMEOUT, 0);
237        assert_select_OP_READ(SelectType.TIMEOUT, 0);
238        assert_select_OP_WRITE(SelectType.TIMEOUT, 0);
239
240        assert_select_OP_ACCEPT(SelectType.TIMEOUT, WAIT_TIME);
241        assert_select_OP_CONNECT(SelectType.TIMEOUT, WAIT_TIME);
242        assert_select_OP_READ(SelectType.TIMEOUT, WAIT_TIME);
243        assert_select_OP_WRITE(SelectType.TIMEOUT, WAIT_TIME);
244    }
245
246    /**
247     * @tests java.nio.channel.Selector#select(long)
248     */
249    public void test_selectJ_SelectorClosed() throws IOException {
250        assert_select_SelectorClosed(SelectType.TIMEOUT, 0);
251        selector = Selector.open();
252        assert_select_SelectorClosed(SelectType.TIMEOUT, WAIT_TIME);
253    }
254
255    /**
256     * @tests java.nio.channel.Selector#select(long)
257     */
258    public void test_selectJ_Exception() throws IOException {
259        try {
260            selector.select(-1);
261        } catch (IllegalArgumentException e) {
262            // expected
263        }
264    }
265
266    public void test_selectJ_Timeout() throws IOException {
267        // make sure select(timeout) doesn't block
268        selector.select(WAIT_TIME);
269    }
270
271    public void test_selectJ_Empty_Keys() throws IOException {
272        // regression test, see HARMONY-3888.
273        // make sure select(long) does wait for specified amount of
274        // time if keys.size() == 0 (initial state of selector).
275
276        final long SELECT_TIMEOUT_MS = 2000;
277
278        long t0 = System.nanoTime();
279        selector.select(SELECT_TIMEOUT_MS);
280        long t1 = System.nanoTime();
281
282        long waitMs = (t1 - t0) / 1000L / 1000L;
283        assertTrue(waitMs >= SELECT_TIMEOUT_MS);
284        assertTrue(waitMs < 5*SELECT_TIMEOUT_MS);
285    }
286
287    /**
288     * @tests java.nio.channels.Selector#wakeup()
289     */
290    public void test_wakeup() throws IOException {
291        /*
292         * make sure the test does not block on select
293         */
294        selector.wakeup();
295        selectOnce(SelectType.NULL, 0);
296        selector.wakeup();
297        selectOnce(SelectType.TIMEOUT, 0);
298
299        // try to wakeup select. The invocation sequence of wakeup and select
300        // doesn't affect test result.
301        new Thread() {
302            public void run() {
303
304                try {
305                    Thread.sleep(WAIT_TIME);
306                } catch (InterruptedException e) {
307                    // ignore
308                }
309                selector.wakeup();
310            }
311        }.start();
312        selectOnce(SelectType.NULL, 0);
313
314        // try to wakeup select. The invocation sequence of wakeup and select
315        // doesn't affect test result.
316        new Thread() {
317            public void run() {
318
319                try {
320                    Thread.sleep(WAIT_TIME);
321                } catch (InterruptedException e) {
322                    // ignore
323                }
324                selector.wakeup();
325            }
326        }.start();
327        selectOnce(SelectType.TIMEOUT, 0);
328    }
329
330    public void test_keySetViewsModifications() throws IOException {
331        Set<SelectionKey> keys = selector.keys();
332
333        SelectionKey key1 = ssc.register(selector, SelectionKey.OP_ACCEPT);
334
335        assertTrue(keys.contains(key1));
336
337        SocketChannel sc = SocketChannel.open();
338        sc.configureBlocking(false);
339        SelectionKey key2 = sc.register(selector, SelectionKey.OP_READ);
340
341        assertTrue(keys.contains(key1));
342        assertTrue(keys.contains(key2));
343
344        key1.cancel();
345        assertTrue(keys.contains(key1));
346
347        selector.selectNow();
348        assertFalse(keys.contains(key1));
349        assertTrue(keys.contains(key2));
350     }
351
352    /**
353     * This test cancels a key while selecting to verify that the cancelled
354     * key set is processed both before and after the call to the underlying
355     * operating system.
356     */
357    public void test_cancelledKeys() throws Exception {
358        final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
359        final AtomicBoolean complete = new AtomicBoolean();
360
361        final Pipe pipe = Pipe.open();
362        pipe.source().configureBlocking(false);
363        final SelectionKey key = pipe.source().register(selector, SelectionKey.OP_READ);
364
365        Thread thread = new Thread() {
366            public void run() {
367                try {
368                    // make sure to call key.cancel() while the main thread is selecting
369                    Thread.sleep(500);
370                    key.cancel();
371                    assertFalse(key.isValid());
372                    pipe.sink().write(ByteBuffer.allocate(4)); // unblock select()
373                } catch (Throwable e) {
374                    failure.set(e);
375                } finally {
376                    complete.set(true);
377                }
378            }
379        };
380        assertTrue(key.isValid());
381
382        thread.start();
383        do {
384            assertEquals(0, selector.select(5000)); // blocks
385            assertEquals(0, selector.selectedKeys().size());
386        } while (!complete.get()); // avoid spurious interrupts
387        assertFalse(key.isValid());
388
389        thread.join();
390        assertNull(failure.get());
391    }
392
393    public void testOpChange() throws Exception {
394        SocketChannel sc = SocketChannel.open();
395        sc.configureBlocking(false);
396        sc.register(selector, SelectionKey.OP_CONNECT);
397        try {
398            sc.connect(localAddress);
399            int count = blockingSelect(SelectType.TIMEOUT, 100);
400            assertEquals(1, count);
401            Set<SelectionKey> selectedKeys = selector.selectedKeys();
402            assertEquals(1, selectedKeys.size());
403            SelectionKey key = selectedKeys.iterator().next();
404            assertEquals(sc.keyFor(selector), key);
405            assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
406            // select again, it should return 0
407            count = selectOnce(SelectType.TIMEOUT, 100);
408            assertEquals(0, count);
409            // but selectedKeys remains the same as previous
410            assertSame(selectedKeys, selector.selectedKeys());
411            sc.finishConnect();
412
413            // same selector, but op is changed
414            SelectionKey key1 = sc.register(selector, SelectionKey.OP_WRITE);
415            assertEquals(key, key1);
416            count = blockingSelect(SelectType.TIMEOUT, 100);
417            assertEquals(1, count);
418            selectedKeys = selector.selectedKeys();
419            assertEquals(1, selectedKeys.size());
420            key = selectedKeys.iterator().next();
421            assertEquals(key, key1);
422            assertEquals(SelectionKey.OP_WRITE, key.readyOps());
423
424            selectedKeys.clear();
425        } finally {
426            try {
427                ssc.accept().close();
428            } catch (Exception e) {
429                // do nothing
430            }
431            try {
432                sc.close();
433            } catch (IOException e) {
434                // do nothing
435            }
436        }
437    }
438
439    public void test_nonBlockingConnect() throws IOException {
440        SocketChannel channel = null;
441        try {
442            channel = SocketChannel.open();
443            channel.configureBlocking(false);
444            Selector selector = Selector.open();
445            channel.register(selector, SelectionKey.OP_CONNECT);
446            channel.connect(localAddress);
447            channel.finishConnect();
448            selector.select();
449            assertEquals(0, selector.selectedKeys().size());
450        } finally {
451            channel.close();
452        }
453    }
454
455    private void assert_select_SelectorClosed(SelectType type, int timeout)
456            throws IOException {
457        // selector is closed
458        selector.close();
459        try {
460            selectOnce(type, timeout);
461            fail("should throw ClosedSelectorException");
462        } catch (ClosedSelectorException e) {
463            // expected
464        }
465    }
466
467    private void assert_select_OP_ACCEPT(SelectType type, int timeout)
468            throws IOException, ClosedChannelException {
469        SocketChannel sc = SocketChannel.open();
470        SocketChannel client = null;
471        try {
472            ssc.register(selector, SelectionKey.OP_ACCEPT);
473            sc.connect(localAddress);
474            int count = blockingSelect(type, timeout);
475            assertEquals(1, count);
476            Set<SelectionKey> selectedKeys = selector.selectedKeys();
477            assertEquals(1, selectedKeys.size());
478            SelectionKey key = selectedKeys.iterator().next();
479            assertEquals(ssc.keyFor(selector), key);
480            assertEquals(SelectionKey.OP_ACCEPT, key.readyOps());
481            // select again, it should return 0
482            count = selectOnce(type, timeout);
483            assertEquals(0,count);
484            // but selectedKeys remains the same as previous
485            assertSame(selectedKeys, selector.selectedKeys());
486            client = ssc.accept();
487            selectedKeys.clear();
488        } finally {
489            try {
490                sc.close();
491            } catch (IOException e) {
492                // do nothing
493            }
494            if (null != client) {
495                client.close();
496            }
497        }
498        ssc.keyFor(selector).cancel();
499    }
500
501    private void assert_select_OP_CONNECT(SelectType type, int timeout)
502            throws IOException, ClosedChannelException {
503        SocketChannel sc = SocketChannel.open();
504        sc.configureBlocking(false);
505        sc.register(selector, SelectionKey.OP_CONNECT);
506        try {
507            sc.connect(localAddress);
508            int count = blockingSelect(type, timeout);
509            assertEquals(1, count);
510            Set<SelectionKey> selectedKeys = selector.selectedKeys();
511            assertEquals(1, selectedKeys.size());
512            SelectionKey key = selectedKeys.iterator().next();
513            assertEquals(sc.keyFor(selector), key);
514            assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
515            // select again, it should return 0
516            count = selectOnce(type, timeout);
517            assertEquals(0, count);
518            // but selectedKeys remains the same as previous
519            assertSame(selectedKeys, selector.selectedKeys());
520            sc.finishConnect();
521            selectedKeys.clear();
522        } finally {
523            try {
524                ssc.accept().close();
525            } catch (Exception e) {
526                // do nothing
527            }
528
529            try {
530                sc.close();
531            } catch (IOException e) {
532                // do nothing
533            }
534        }
535    }
536
537    private void assert_select_OP_READ(SelectType type, int timeout)
538            throws IOException {
539        SocketChannel sc = SocketChannel.open();
540        SocketChannel client = null;
541        SocketChannel sc2 = SocketChannel.open();
542        SocketChannel client2 = null;
543        try {
544            ssc.configureBlocking(true);
545            sc.connect(localAddress);
546            client = ssc.accept();
547            sc.configureBlocking(false);
548            sc.register(selector, SelectionKey.OP_READ);
549            client.configureBlocking(true);
550
551            sc2.connect(localAddress);
552            client2 = ssc.accept();
553            sc2.configureBlocking(false);
554            sc2.register(selector, SelectionKey.OP_READ);
555            client2.configureBlocking(true);
556
557            client.write(ByteBuffer.wrap("a".getBytes()));
558            int count = blockingSelect(type, timeout);
559            assertEquals(1, count);
560            Set<SelectionKey> selectedKeys = selector.selectedKeys();
561            assertEquals(1, selectedKeys.size());
562            SelectionKey key = selectedKeys.iterator().next();
563            assertEquals(sc.keyFor(selector), key);
564            assertEquals(SelectionKey.OP_READ, key.readyOps());
565            // select again, it should return 0
566            count = selectOnce(type, timeout);
567            assertEquals(0, count);
568            // but selectedKeys remains the same as previous
569            assertSame(selectedKeys, selector.selectedKeys());
570
571            sc.read(ByteBuffer.allocate(8));
572
573            // the second SocketChannel should be selected this time
574            client2.write(ByteBuffer.wrap("a".getBytes()));
575            count = blockingSelect(type, timeout);
576            assertEquals(1, count);
577            // selectedKeys still includes the key of sc, because the key of sc
578            // is not removed last time.
579            selectedKeys = selector.selectedKeys();
580            assertEquals(2, selectedKeys.size());
581        } finally {
582            if (null != client) {
583                try {
584                    client.close();
585                } catch (Exception e) {
586                    // ignore
587                }
588            }
589            if (null != client2) {
590                try {
591                    client2.close();
592                } catch (Exception e) {
593                    // ignore
594                }
595            }
596            try {
597                sc.close();
598            } catch (Exception e) {
599                // ignore
600            }
601            try {
602                sc2.close();
603            } catch (Exception e) {
604                // ignore
605            }
606            ssc.configureBlocking(false);
607        }
608    }
609
610    private void assert_select_OP_WRITE(SelectType type, int timeout)
611            throws IOException {
612        SocketChannel sc = SocketChannel.open();
613        SocketChannel client = null;
614        try {
615            sc.connect(localAddress);
616            ssc.configureBlocking(true);
617            client = ssc.accept();
618            sc.configureBlocking(false);
619            sc.register(selector, SelectionKey.OP_WRITE);
620            int count = blockingSelect(type, timeout);
621            assertEquals(1, count);
622            Set<SelectionKey> selectedKeys = selector.selectedKeys();
623            assertEquals(1, selectedKeys.size());
624            SelectionKey key = selectedKeys.iterator().next();
625            assertEquals(sc.keyFor(selector), key);
626            assertEquals(SelectionKey.OP_WRITE, key.readyOps());
627            // select again, it should return 0
628            count = selectOnce(type, timeout);
629            assertEquals(0, count);
630            // but selectedKeys remains the same as previous
631            assertSame(selectedKeys, selector.selectedKeys());
632        } finally {
633            if (null != client) {
634                client.close();
635            }
636            try {
637                sc.close();
638            } catch (IOException e) {
639                // do nothing
640            }
641            ssc.configureBlocking(false);
642        }
643    }
644
645    private int blockingSelect(SelectType type, int timeout) throws IOException {
646        int ret = 0;
647        do {
648            ret = selectOnce(type, timeout);
649            if (ret > 0) {
650                return ret;
651            }
652            try {
653                Thread.sleep(100);
654            } catch (InterruptedException e) {
655                // ignore
656            }
657        } while (true);
658    }
659
660    private int selectOnce(SelectType type, int timeout) throws IOException {
661        int ret = 0;
662        switch (type) {
663        case NULL:
664            ret = selector.select();
665            break;
666        case TIMEOUT:
667            ret = selector.select(timeout);
668            break;
669        case NOW:
670            ret = selector.selectNow();
671            break;
672        }
673        return ret;
674    }
675
676}
677