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