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