001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.ipc;
019
020import static org.apache.hadoop.hbase.HBaseTestingUtility.fam1;
021import static org.junit.Assert.assertTrue;
022
023import java.io.IOException;
024import java.net.Socket;
025import java.net.SocketAddress;
026import java.util.List;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.TableName;
032import org.apache.hadoop.hbase.client.Connection;
033import org.apache.hadoop.hbase.client.ConnectionFactory;
034import org.apache.hadoop.hbase.client.Get;
035import org.apache.hadoop.hbase.client.MetricsConnection;
036import org.apache.hadoop.hbase.client.RetriesExhaustedException;
037import org.apache.hadoop.hbase.client.Table;
038import org.apache.hadoop.hbase.testclassification.MediumTests;
039import org.apache.hadoop.hbase.util.Bytes;
040import org.junit.AfterClass;
041import org.junit.BeforeClass;
042import org.junit.ClassRule;
043import org.junit.Rule;
044import org.junit.Test;
045import org.junit.experimental.categories.Category;
046import org.junit.rules.ExpectedException;
047import org.junit.rules.TestName;
048import org.slf4j.Logger;
049import org.slf4j.LoggerFactory;
050
051import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
052
053@Category(MediumTests.class)
054public class TestRpcClientLeaks {
055
056  @ClassRule
057  public static final HBaseClassTestRule CLASS_RULE =
058      HBaseClassTestRule.forClass(TestRpcClientLeaks.class);
059
060  @Rule
061  public TestName name = new TestName();
062
063  public static class MyRpcClientImpl extends BlockingRpcClient {
064    public static List<Socket> savedSockets = Lists.newArrayList();
065    @Rule public ExpectedException thrown = ExpectedException.none();
066
067    public MyRpcClientImpl(Configuration conf) {
068      super(conf);
069    }
070
071    public MyRpcClientImpl(Configuration conf, String clusterId, SocketAddress address,
072        MetricsConnection metrics) {
073      super(conf, clusterId, address, metrics);
074    }
075
076    @Override
077    protected BlockingRpcConnection createConnection(ConnectionId remoteId) throws IOException {
078      return new BlockingRpcConnection(this, remoteId) {
079        @Override
080        protected synchronized void setupConnection() throws IOException {
081          super.setupConnection();
082          synchronized (savedSockets) {
083            savedSockets.add(socket);
084          }
085          throw new IOException("Sample exception for " +
086            "verifying socket closure in case of exceptions.");
087        }
088      };
089    }
090  }
091
092  private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
093
094  @BeforeClass
095  public static void setup() throws Exception {
096    UTIL.startMiniCluster();
097  }
098
099  @AfterClass
100  public static void teardown() throws Exception {
101    UTIL.shutdownMiniCluster();
102  }
103
104  public static final Logger LOG = LoggerFactory.getLogger(TestRpcClientLeaks.class);
105
106  @Test(expected=RetriesExhaustedException.class)
107  public void testSocketClosed() throws IOException, InterruptedException {
108    TableName tableName = TableName.valueOf(name.getMethodName());
109    UTIL.createTable(tableName, fam1).close();
110
111    Configuration conf = new Configuration(UTIL.getConfiguration());
112    conf.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY,
113      MyRpcClientImpl.class.getName());
114    conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2);
115    Connection connection = ConnectionFactory.createConnection(conf);
116    Table table = connection.getTable(TableName.valueOf(name.getMethodName()));
117    table.get(new Get(Bytes.toBytes("asd")));
118    connection.close();
119    for (Socket socket : MyRpcClientImpl.savedSockets) {
120      assertTrue("Socket + " +  socket + " is not closed", socket.isClosed());
121    }
122  }
123}