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.zookeeper; 019 020import static org.junit.Assert.assertNotNull; 021import static org.junit.Assert.assertNull; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.util.List; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.Abortable; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseZKTestingUtility; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.testclassification.ZKTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.hbase.util.Threads; 035import org.apache.zookeeper.CreateMode; 036import org.apache.zookeeper.KeeperException; 037import org.apache.zookeeper.ZooDefs; 038import org.apache.zookeeper.ZooKeeper; 039import org.apache.zookeeper.data.ACL; 040import org.apache.zookeeper.data.Stat; 041import org.junit.AfterClass; 042import org.junit.BeforeClass; 043import org.junit.ClassRule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 050 051@Category({ ZKTests.class, MediumTests.class }) 052public class TestZKUtil { 053 @ClassRule 054 public static final HBaseClassTestRule CLASS_RULE = 055 HBaseClassTestRule.forClass(TestZKUtil.class); 056 057 private static final Logger LOG = LoggerFactory.getLogger(TestZKUtil.class); 058 059 private static HBaseZKTestingUtility UTIL = new HBaseZKTestingUtility(); 060 061 private static ZKWatcher ZKW; 062 063 @BeforeClass 064 public static void setUp() throws Exception { 065 UTIL.startMiniZKCluster().getClientPort(); 066 ZKW = new ZKWatcher(new Configuration(UTIL.getConfiguration()), TestZKUtil.class.getName(), 067 new WarnOnlyAbortable()); 068 } 069 070 @AfterClass 071 public static void tearDown() throws IOException { 072 Closeables.close(ZKW, true); 073 UTIL.shutdownMiniZKCluster(); 074 UTIL.cleanupTestDir(); 075 } 076 077 /** 078 * Create a znode with data 079 */ 080 @Test 081 public void testCreateWithParents() throws KeeperException, InterruptedException { 082 byte[] expectedData = new byte[] { 1, 2, 3 }; 083 ZKUtil.createWithParents(ZKW, "/l1/l2/l3/l4/testCreateWithParents", expectedData); 084 byte[] data = ZKUtil.getData(ZKW, "/l1/l2/l3/l4/testCreateWithParents"); 085 assertTrue(Bytes.equals(expectedData, data)); 086 ZKUtil.deleteNodeRecursively(ZKW, "/l1"); 087 088 ZKUtil.createWithParents(ZKW, "/testCreateWithParents", expectedData); 089 data = ZKUtil.getData(ZKW, "/testCreateWithParents"); 090 assertTrue(Bytes.equals(expectedData, data)); 091 ZKUtil.deleteNodeRecursively(ZKW, "/testCreateWithParents"); 092 } 093 094 /** 095 * Create a bunch of znodes in a hierarchy, try deleting one that has childs (it will fail), then 096 * delete it recursively, then delete the last znode 097 */ 098 @Test 099 public void testZNodeDeletes() throws Exception { 100 ZKUtil.createWithParents(ZKW, "/l1/l2/l3/l4"); 101 try { 102 ZKUtil.deleteNode(ZKW, "/l1/l2"); 103 fail("We should not be able to delete if znode has childs"); 104 } catch (KeeperException ex) { 105 assertNotNull(ZKUtil.getDataNoWatch(ZKW, "/l1/l2/l3/l4", null)); 106 } 107 ZKUtil.deleteNodeRecursively(ZKW, "/l1/l2"); 108 // make sure it really is deleted 109 assertNull(ZKUtil.getDataNoWatch(ZKW, "/l1/l2/l3/l4", null)); 110 111 // do the same delete again and make sure it doesn't crash 112 ZKUtil.deleteNodeRecursively(ZKW, "/l1/l2"); 113 114 ZKUtil.deleteNode(ZKW, "/l1"); 115 assertNull(ZKUtil.getDataNoWatch(ZKW, "/l1/l2", null)); 116 } 117 118 /** 119 * A test for HBASE-3238 120 * @throws IOException A connection attempt to zk failed 121 * @throws InterruptedException One of the non ZKUtil actions was interrupted 122 * @throws KeeperException Any of the zookeeper connections had a KeeperException 123 */ 124 @Test 125 public void testCreateSilentIsReallySilent() 126 throws InterruptedException, KeeperException, IOException { 127 Configuration c = UTIL.getConfiguration(); 128 129 String aclZnode = "/aclRoot"; 130 String quorumServers = ZKConfig.getZKQuorumServersString(c); 131 int sessionTimeout = 5 * 1000; // 5 seconds 132 ZooKeeper zk = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance); 133 zk.addAuthInfo("digest", "hbase:rox".getBytes()); 134 135 // Save the previous ACL 136 Stat s; 137 List<ACL> oldACL; 138 while (true) { 139 try { 140 s = new Stat(); 141 oldACL = zk.getACL("/", s); 142 break; 143 } catch (KeeperException e) { 144 switch (e.code()) { 145 case CONNECTIONLOSS: 146 case SESSIONEXPIRED: 147 case OPERATIONTIMEOUT: 148 LOG.warn("Possibly transient ZooKeeper exception", e); 149 Threads.sleep(100); 150 break; 151 default: 152 throw e; 153 } 154 } 155 } 156 157 // I set this acl after the attempted creation of the cluster home node. 158 // Add retries in case of retryable zk exceptions. 159 while (true) { 160 try { 161 zk.setACL("/", ZooDefs.Ids.CREATOR_ALL_ACL, -1); 162 break; 163 } catch (KeeperException e) { 164 switch (e.code()) { 165 case CONNECTIONLOSS: 166 case SESSIONEXPIRED: 167 case OPERATIONTIMEOUT: 168 LOG.warn("Possibly transient ZooKeeper exception: " + e); 169 Threads.sleep(100); 170 break; 171 default: 172 throw e; 173 } 174 } 175 } 176 177 while (true) { 178 try { 179 zk.create(aclZnode, null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT); 180 break; 181 } catch (KeeperException e) { 182 switch (e.code()) { 183 case CONNECTIONLOSS: 184 case SESSIONEXPIRED: 185 case OPERATIONTIMEOUT: 186 LOG.warn("Possibly transient ZooKeeper exception: " + e); 187 Threads.sleep(100); 188 break; 189 default: 190 throw e; 191 } 192 } 193 } 194 zk.close(); 195 ZKUtil.createAndFailSilent(ZKW, aclZnode); 196 197 // Restore the ACL 198 ZooKeeper zk3 = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance); 199 zk3.addAuthInfo("digest", "hbase:rox".getBytes()); 200 try { 201 zk3.setACL("/", oldACL, -1); 202 } finally { 203 zk3.close(); 204 } 205 } 206 207 /** 208 * Test should not fail with NPE when getChildDataAndWatchForNewChildren invoked with wrongNode 209 */ 210 @Test 211 @SuppressWarnings("deprecation") 212 public void testGetChildDataAndWatchForNewChildrenShouldNotThrowNPE() throws Exception { 213 ZKUtil.getChildDataAndWatchForNewChildren(ZKW, "/wrongNode"); 214 } 215 216 private static class WarnOnlyAbortable implements Abortable { 217 218 @Override 219 public void abort(String why, Throwable e) { 220 LOG.warn("ZKWatcher received abort, ignoring. Reason: " + why); 221 if (LOG.isDebugEnabled()) { 222 LOG.debug(e.toString(), e); 223 } 224 } 225 226 @Override 227 public boolean isAborted() { 228 return false; 229 } 230 } 231}