Home | History | Annotate | Download | only in channels
      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 
     17 package org.apache.harmony.tests.java.nio.channels;
     18 
     19 import java.io.IOException;
     20 import java.net.ServerSocket;
     21 import java.net.SocketAddress;
     22 import java.nio.ByteBuffer;
     23 import java.nio.channels.ClosedChannelException;
     24 import java.nio.channels.ClosedSelectorException;
     25 import java.nio.channels.Pipe;
     26 import java.nio.channels.SelectionKey;
     27 import java.nio.channels.Selector;
     28 import java.nio.channels.ServerSocketChannel;
     29 import java.nio.channels.SocketChannel;
     30 import java.nio.channels.spi.SelectorProvider;
     31 import java.util.concurrent.atomic.AtomicBoolean;
     32 import java.util.concurrent.atomic.AtomicReference;
     33 import java.util.Set;
     34 import junit.framework.TestCase;
     35 
     36 /*
     37  * Tests for Selector and its default implementation
     38  */
     39 public 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