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.regionserver;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertNull;
023import static org.junit.Assert.assertTrue;
024
025import java.util.concurrent.Semaphore;
026import org.apache.hadoop.hbase.HBaseClassTestRule;
027import org.apache.hadoop.hbase.HBaseTestingUtility;
028import org.apache.hadoop.hbase.ServerName;
029import org.apache.hadoop.hbase.testclassification.MediumTests;
030import org.apache.hadoop.hbase.testclassification.RegionServerTests;
031import org.apache.hadoop.hbase.zookeeper.MasterAddressTracker;
032import org.apache.hadoop.hbase.zookeeper.ZKListener;
033import org.apache.hadoop.hbase.zookeeper.ZKUtil;
034import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
035import org.junit.AfterClass;
036import org.junit.BeforeClass;
037import org.junit.ClassRule;
038import org.junit.Rule;
039import org.junit.Test;
040import org.junit.experimental.categories.Category;
041import org.junit.rules.TestName;
042import org.slf4j.Logger;
043import org.slf4j.LoggerFactory;
044
045@Category({RegionServerTests.class, MediumTests.class})
046public class TestMasterAddressTracker {
047
048  @ClassRule
049  public static final HBaseClassTestRule CLASS_RULE =
050      HBaseClassTestRule.forClass(TestMasterAddressTracker.class);
051
052  private static final Logger LOG = LoggerFactory.getLogger(TestMasterAddressTracker.class);
053
054  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
055
056  @Rule
057  public TestName name = new TestName();
058
059  @BeforeClass
060  public static void setUpBeforeClass() throws Exception {
061    TEST_UTIL.startMiniZKCluster();
062  }
063
064  @AfterClass
065  public static void tearDownAfterClass() throws Exception {
066    TEST_UTIL.shutdownMiniZKCluster();
067  }
068
069  @Test
070  public void testDeleteIfEquals() throws Exception {
071    final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis());
072    final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772);
073    try {
074      assertFalse("shouldn't have deleted wrong master server.",
075          MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), "some other string."));
076    } finally {
077      assertTrue("Couldn't clean up master",
078          MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString()));
079    }
080  }
081
082  /**
083   * create an address tracker instance
084   * @param sn if not-null set the active master
085   * @param infoPort if there is an active master, set its info port.
086   */
087  private MasterAddressTracker setupMasterTracker(final ServerName sn, final int infoPort)
088      throws Exception {
089    ZKWatcher zk = new ZKWatcher(TEST_UTIL.getConfiguration(),
090        name.getMethodName(), null);
091    ZKUtil.createAndFailSilent(zk, zk.getZNodePaths().baseZNode);
092
093    // Should not have a master yet
094    MasterAddressTracker addressTracker = new MasterAddressTracker(zk, null);
095    addressTracker.start();
096    assertFalse(addressTracker.hasMaster());
097    zk.registerListener(addressTracker);
098
099    // Use a listener to capture when the node is actually created
100    NodeCreationListener listener = new NodeCreationListener(zk,
101            zk.getZNodePaths().masterAddressZNode);
102    zk.registerListener(listener);
103
104    if (sn != null) {
105      LOG.info("Creating master node");
106      MasterAddressTracker.setMasterAddress(zk, zk.getZNodePaths().masterAddressZNode,
107              sn, infoPort);
108
109      // Wait for the node to be created
110      LOG.info("Waiting for master address manager to be notified");
111      listener.waitForCreation();
112      LOG.info("Master node created");
113    }
114    return addressTracker;
115  }
116
117  /**
118   * Unit tests that uses ZooKeeper but does not use the master-side methods
119   * but rather acts directly on ZK.
120   * @throws Exception
121   */
122  @Test
123  public void testMasterAddressTrackerFromZK() throws Exception {
124    // Create the master node with a dummy address
125    final int infoPort = 1235;
126    final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis());
127    final MasterAddressTracker addressTracker = setupMasterTracker(sn, infoPort);
128    try {
129      assertTrue(addressTracker.hasMaster());
130      ServerName pulledAddress = addressTracker.getMasterAddress();
131      assertTrue(pulledAddress.equals(sn));
132      assertEquals(infoPort, addressTracker.getMasterInfoPort());
133    } finally {
134      assertTrue("Couldn't clean up master",
135          MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString()));
136    }
137  }
138
139
140  @Test
141  public void testParsingNull() throws Exception {
142    assertNull("parse on null data should return null.", MasterAddressTracker.parse(null));
143  }
144
145  @Test
146  public void testNoBackups() throws Exception {
147    final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis());
148    final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772);
149    try {
150      assertEquals("Should receive 0 for backup not found.", 0,
151          addressTracker.getBackupMasterInfoPort(
152              ServerName.valueOf("doesnotexist.example.com", 1234, System.currentTimeMillis())));
153    } finally {
154      assertTrue("Couldn't clean up master",
155          MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString()));
156    }
157  }
158
159  @Test
160  public void testNoMaster() throws Exception {
161    final MasterAddressTracker addressTracker = setupMasterTracker(null, 1772);
162    assertFalse(addressTracker.hasMaster());
163    assertNull("should get null master when none active.", addressTracker.getMasterAddress());
164    assertEquals("Should receive 0 for backup not found.", 0, addressTracker.getMasterInfoPort());
165  }
166
167  public static class NodeCreationListener extends ZKListener {
168    private static final Logger LOG = LoggerFactory.getLogger(NodeCreationListener.class);
169
170    private Semaphore lock;
171    private String node;
172
173    public NodeCreationListener(ZKWatcher watcher, String node) {
174      super(watcher);
175      lock = new Semaphore(0);
176      this.node = node;
177    }
178
179    @Override
180    public void nodeCreated(String path) {
181      if(path.equals(node)) {
182        LOG.debug("nodeCreated(" + path + ")");
183        lock.release();
184      }
185    }
186
187    public void waitForCreation() throws InterruptedException {
188      lock.acquire();
189    }
190  }
191
192}
193