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.znodePaths.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, zk.znodePaths.masterAddressZNode);
100    zk.registerListener(listener);
101
102    if (sn != null) {
103      LOG.info("Creating master node");
104      MasterAddressTracker.setMasterAddress(zk, zk.znodePaths.masterAddressZNode, sn, infoPort);
105
106      // Wait for the node to be created
107      LOG.info("Waiting for master address manager to be notified");
108      listener.waitForCreation();
109      LOG.info("Master node created");
110    }
111    return addressTracker;
112  }
113
114  /**
115   * Unit tests that uses ZooKeeper but does not use the master-side methods
116   * but rather acts directly on ZK.
117   * @throws Exception
118   */
119  @Test
120  public void testMasterAddressTrackerFromZK() throws Exception {
121    // Create the master node with a dummy address
122    final int infoPort = 1235;
123    final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis());
124    final MasterAddressTracker addressTracker = setupMasterTracker(sn, infoPort);
125    try {
126      assertTrue(addressTracker.hasMaster());
127      ServerName pulledAddress = addressTracker.getMasterAddress();
128      assertTrue(pulledAddress.equals(sn));
129      assertEquals(infoPort, addressTracker.getMasterInfoPort());
130    } finally {
131      assertTrue("Couldn't clean up master",
132          MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString()));
133    }
134  }
135
136
137  @Test
138  public void testParsingNull() throws Exception {
139    assertNull("parse on null data should return null.", MasterAddressTracker.parse(null));
140  }
141
142  @Test
143  public void testNoBackups() throws Exception {
144    final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis());
145    final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772);
146    try {
147      assertEquals("Should receive 0 for backup not found.", 0,
148          addressTracker.getBackupMasterInfoPort(
149              ServerName.valueOf("doesnotexist.example.com", 1234, System.currentTimeMillis())));
150    } finally {
151      assertTrue("Couldn't clean up master",
152          MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString()));
153    }
154  }
155
156  @Test
157  public void testNoMaster() throws Exception {
158    final MasterAddressTracker addressTracker = setupMasterTracker(null, 1772);
159    assertFalse(addressTracker.hasMaster());
160    assertNull("should get null master when none active.", addressTracker.getMasterAddress());
161    assertEquals("Should receive 0 for backup not found.", 0, addressTracker.getMasterInfoPort());
162  }
163
164  public static class NodeCreationListener extends ZKListener {
165    private static final Logger LOG = LoggerFactory.getLogger(NodeCreationListener.class);
166
167    private Semaphore lock;
168    private String node;
169
170    public NodeCreationListener(ZKWatcher watcher, String node) {
171      super(watcher);
172      lock = new Semaphore(0);
173      this.node = node;
174    }
175
176    @Override
177    public void nodeCreated(String path) {
178      if(path.equals(node)) {
179        LOG.debug("nodeCreated(" + path + ")");
180        lock.release();
181      }
182    }
183
184    public void waitForCreation() throws InterruptedException {
185      lock.acquire();
186    }
187  }
188
189}
190