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