1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertNull;
26  import static org.junit.Assert.fail;
27  
28  import java.io.IOException;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.client.Get;
34  import org.apache.hadoop.hbase.client.HBaseAdmin;
35  import org.apache.hadoop.hbase.client.HConnection;
36  import org.apache.hadoop.hbase.client.HConnectionManager;
37  import org.apache.hadoop.hbase.client.HTable;
38  import org.apache.hadoop.hbase.client.Put;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.zookeeper.ZKConfig;
41  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
42  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
43  import org.apache.zookeeper.KeeperException;
44  import org.apache.zookeeper.ZooKeeper;
45  import org.apache.zookeeper.ZooKeeper.States;
46  import org.junit.AfterClass;
47  import org.junit.Assert;
48  import org.junit.Before;
49  import org.junit.BeforeClass;
50  import org.junit.Test;
51  
52  public class TestZooKeeper {
53    private final Log LOG = LogFactory.getLog(this.getClass());
54  
55    private final static HBaseTestingUtility
56        TEST_UTIL = new HBaseTestingUtility();
57  
58    /**
59     * @throws java.lang.Exception
60     */
61    @BeforeClass
62    public static void setUpBeforeClass() throws Exception {
63      // Test we can first start the ZK cluster by itself
64      TEST_UTIL.startMiniZKCluster();
65      TEST_UTIL.getConfiguration().setBoolean("dfs.support.append", true);
66      TEST_UTIL.startMiniCluster(2);
67    }
68  
69    /**
70     * @throws java.lang.Exception
71     */
72    @AfterClass
73    public static void tearDownAfterClass() throws Exception {
74      TEST_UTIL.shutdownMiniCluster();
75    }
76  
77    /**
78     * @throws java.lang.Exception
79     */
80    @Before
81    public void setUp() throws Exception {
82      TEST_UTIL.ensureSomeRegionServersAvailable(2);
83    }
84  
85    /**
86     * See HBASE-1232 and http://wiki.apache.org/hadoop/ZooKeeper/FAQ#4.
87     * @throws IOException
88     * @throws InterruptedException
89     */
90    @Test
91    public void testClientSessionExpired()
92    throws IOException, InterruptedException {
93      LOG.info("testClientSessionExpired");
94      Configuration c = new Configuration(TEST_UTIL.getConfiguration());
95      new HTable(c, HConstants.META_TABLE_NAME);
96      String quorumServers = ZKConfig.getZKQuorumServersString(c);
97      int sessionTimeout = 5 * 1000; // 5 seconds
98      HConnection connection = HConnectionManager.getConnection(c);
99      ZooKeeperWatcher connectionZK = connection.getZooKeeperWatcher();
100     long sessionID = connectionZK.getZooKeeper().getSessionId();
101     byte[] password = connectionZK.getZooKeeper().getSessionPasswd();
102     ZooKeeper zk = new ZooKeeper(quorumServers, sessionTimeout,
103         EmptyWatcher.instance, sessionID, password);
104     zk.close();
105 
106     Thread.sleep(sessionTimeout * 3L);
107 
108     // provoke session expiration by doing something with ZK
109     ZKUtil.dump(connectionZK);
110 
111     // Check that the old ZK conenction is closed, means we did expire
112     System.err.println("ZooKeeper should have timed out");
113     LOG.info("state=" + connectionZK.getZooKeeper().getState());
114     Assert.assertTrue(connectionZK.getZooKeeper().getState().equals(
115         States.CLOSED));
116 
117     // Check that the client recovered
118     ZooKeeperWatcher newConnectionZK = connection.getZooKeeperWatcher();
119     LOG.info("state=" + newConnectionZK.getZooKeeper().getState());
120     Assert.assertTrue(newConnectionZK.getZooKeeper().getState().equals(
121         States.CONNECTED));
122   }
123   
124   @Test
125   public void testRegionServerSessionExpired() throws Exception {
126     LOG.info("Starting testRegionServerSessionExpired");
127     int metaIndex = TEST_UTIL.getMiniHBaseCluster().getServerWithMeta();
128     TEST_UTIL.expireRegionServerSession(metaIndex);
129     testSanity();
130   }
131 
132   //@Test
133   public void disabledTestMasterSessionExpired() throws Exception {
134     LOG.info("Starting testMasterSessionExpired");
135     TEST_UTIL.expireMasterSession();
136     testSanity();
137   }
138 
139   /**
140    * Make sure we can use the cluster
141    * @throws Exception
142    */
143   public void testSanity() throws Exception{
144     HBaseAdmin admin =
145       new HBaseAdmin(new Configuration(TEST_UTIL.getConfiguration()));
146     String tableName = "test"+System.currentTimeMillis();
147     HTableDescriptor desc = new HTableDescriptor(tableName);
148     HColumnDescriptor family = new HColumnDescriptor("fam");
149     desc.addFamily(family);
150     LOG.info("Creating table " + tableName);
151     admin.createTable(desc);
152 
153     HTable table =
154       new HTable(new Configuration(TEST_UTIL.getConfiguration()), tableName);
155     Put put = new Put(Bytes.toBytes("testrow"));
156     put.add(Bytes.toBytes("fam"),
157         Bytes.toBytes("col"), Bytes.toBytes("testdata"));
158     LOG.info("Putting table " + tableName);
159     table.put(put);
160 
161   }
162 
163   @Test
164   public void testMultipleZK() {
165     try {
166       HTable localMeta =
167         new HTable(new Configuration(TEST_UTIL.getConfiguration()), HConstants.META_TABLE_NAME);
168       Configuration otherConf = new Configuration(TEST_UTIL.getConfiguration());
169       otherConf.set(HConstants.ZOOKEEPER_QUORUM, "127.0.0.1");
170       HTable ipMeta = new HTable(otherConf, HConstants.META_TABLE_NAME);
171 
172       // dummy, just to open the connection
173       localMeta.exists(new Get(HConstants.LAST_ROW));
174       ipMeta.exists(new Get(HConstants.LAST_ROW));
175 
176       // make sure they aren't the same
177       assertFalse(HConnectionManager.getConnection(localMeta.getConfiguration()).getZooKeeperWatcher()
178           == HConnectionManager.getConnection(otherConf).getZooKeeperWatcher());
179       assertFalse(HConnectionManager.getConnection(localMeta.getConfiguration())
180           .getZooKeeperWatcher().getQuorum().equals(HConnectionManager
181               .getConnection(otherConf).getZooKeeperWatcher().getQuorum()));
182     } catch (Exception e) {
183       e.printStackTrace();
184       fail();
185     }
186   }
187 
188   /**
189    * Create a bunch of znodes in a hierarchy, try deleting one that has childs
190    * (it will fail), then delete it recursively, then delete the last znode
191    * @throws Exception
192    */
193   @Test
194   public void testZNodeDeletes() throws Exception {
195     ZooKeeperWatcher zkw = new ZooKeeperWatcher(
196       new Configuration(TEST_UTIL.getConfiguration()), 
197       TestZooKeeper.class.getName(), null);
198     ZKUtil.createWithParents(zkw, "/l1/l2/l3/l4");
199     try {
200       ZKUtil.deleteNode(zkw, "/l1/l2");
201       fail("We should not be able to delete if znode has childs");
202     } catch (KeeperException ex) {
203       assertNotNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2/l3/l4", null));
204     }
205     ZKUtil.deleteNodeRecursively(zkw, "/l1/l2");
206     assertNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2/l3/l4", null));
207     ZKUtil.deleteNode(zkw, "/l1");
208     assertNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2", null));
209   }
210 
211   @Test
212   public void testClusterKey() throws Exception {
213     testKey("server", "2181", "hbase");
214     testKey("server1,server2,server3", "2181", "hbase");
215     try {
216       ZKUtil.transformClusterKey("2181:hbase");
217     } catch (IOException ex) {
218       // OK
219     }
220   }
221 
222   private void testKey(String ensemble, String port, String znode)
223       throws IOException {
224     Configuration conf = new Configuration();
225     String key = ensemble+":"+port+":"+znode;
226     String[] parts = ZKUtil.transformClusterKey(key);
227     assertEquals(ensemble, parts[0]);
228     assertEquals(port, parts[1]);
229     assertEquals(znode, parts[2]);
230     ZKUtil.applyClusterKeyToConf(conf, key);
231     assertEquals(parts[0], conf.get(HConstants.ZOOKEEPER_QUORUM));
232     assertEquals(parts[1], conf.get("hbase.zookeeper.property.clientPort"));
233     assertEquals(parts[2], conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT));
234     String reconstructedKey = ZKUtil.getZooKeeperClusterKey(conf);
235     assertEquals(key, reconstructedKey);
236   }
237 }