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