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