/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Cloudera, Inc. licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudera.flume.master;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.thrift.TException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.cloudera.flume.conf.FlumeConfiguration;
import com.cloudera.flume.conf.FlumeSpecException;
import com.cloudera.flume.master.StatusManager.NodeStatus;
import com.cloudera.flume.reporter.ReportEvent;
import com.cloudera.flume.reporter.ReportManager;
import com.cloudera.flume.reporter.Reportable;
import com.cloudera.flume.util.MockClock;
import com.cloudera.util.Clock;
import com.cloudera.util.FileUtil;
import com.cloudera.util.NetUtils;
/**
* Tests the logic behind the MasterClientServer class. RPC-specific type
* conversion is already covered in TestRPCMechanisms, so we don't test that
* here.
*/
public class TestMasterServers {
FlumeMaster master = null;
File tmpdir = null;
FlumeConfiguration cfg;
@Before
public void createZKDirs() throws IOException {
cfg = FlumeConfiguration.createTestableConfiguration();
cfg.set(FlumeConfiguration.WEBAPPS_PATH, "build/webapps");
tmpdir = FileUtil.mktempdir();
FlumeConfiguration.get().set(FlumeConfiguration.MASTER_ZK_LOGDIR,
tmpdir.getAbsolutePath());
}
@After
public void stopMaster() throws IOException {
if (master != null) {
master.shutdown();
master = null;
}
if (tmpdir != null) {
FileUtil.rmr(tmpdir);
tmpdir = null;
}
}
@Test
public void testMasterClientServerThrift() throws TException, IOException {
master = new FlumeMaster(cfg);
master.serve();
MasterClientServer delegate = new MasterClientServer(master, cfg);
delegate.heartbeat("foo", "phys-node", NetUtils.localhost(),
StatusManager.NodeState.HELLO, 0);
delegate.acknowledge("foo");
delegate.checkAck("foo");
Map<String, NodeStatus> statuses = master.getStatMan().getNodeStatuses();
assertEquals(1, statuses.size());
NodeStatus s = statuses.get("foo");
assertNotNull(s);
assertEquals("phys-node", s.physicalNode);
delegate.getConfig("host");
delegate.getLogicalNodes("host");
}
@Test
public void testInvalidRPCSpec() {
cfg.set(FlumeConfiguration.MASTER_HEARBEAT_RPC, "INVALID");
assertEquals("THRIFT", cfg.getMasterHeartbeatRPC());
}
@Test(expected = IllegalArgumentException.class)
public void testNullMasterClient() throws IOException {
new MasterClientServer(null, cfg);
}
@Test
public void testMasterAdminServer() throws TException, IOException,
FlumeSpecException {
master = new FlumeMaster(cfg);
master.serve();
MasterAdminServer mas = new MasterAdminServer(master, cfg);
MockClock mclk = new MockClock(0);
Clock.setClock(mclk);
// populate status
MasterClientServer delegate = new MasterClientServer(master, cfg);
master.getSpecMan().setConfig("foo", "my-test-flow", "null", "null"); // set
// at
// time
// 0
long cfgtime = Clock.unixTime();
boolean changed1, changed2, changed3, changed4;
mclk.forward(250);
// make the first stamp in the "past" to force an update
changed1 = delegate.heartbeat("foo", "foo", NetUtils.localhost(),
StatusManager.NodeState.HELLO, cfgtime); // new
// node
assertTrue(changed1);
mclk.forward(500);
changed2 = delegate.heartbeat("foo", "foo", NetUtils.localhost(),
StatusManager.NodeState.HELLO, cfgtime);
assertFalse(changed2);
master.getSpecMan().setConfig("foo", "my-test-flow", "null", "null");
long oldcfgtime = cfgtime;
cfgtime = Clock.unixTime();
mclk.forward(500);
// "check with the last version we had"
changed3 = delegate.heartbeat("foo", "foo", NetUtils.localhost(),
StatusManager.NodeState.HELLO, oldcfgtime);
assertTrue(changed3);
mclk.forward(500);
// "ok, we did a config update on the node"
changed4 = delegate.heartbeat("foo", "foo", NetUtils.localhost(),
StatusManager.NodeState.HELLO, cfgtime);
assertFalse(changed4);
mclk.forward(500);
mas.getNodeStatuses();
// calls
mas.getConfigs();
mas.isFailure(0);
mas.isSuccess(0);
mas.submit(new Command("noop", new String[0]));
}
@Test(expected = IllegalArgumentException.class)
public void testNullMasterAdmin() {
try {
new MasterAdminServer(null, cfg);
} catch (IOException e) {
}
}
@Test
public void testReports() throws TException, IOException {
FlumeConfiguration.createTestableConfiguration();
ReportManager rptMan = ReportManager.get();
rptMan.clear();
FlumeConfiguration.get().set(FlumeConfiguration.WEBAPPS_PATH,
"build/webapps");
FlumeConfiguration.get().set(FlumeConfiguration.MASTER_STORE, "memory");
FlumeConfiguration.get().setInt(FlumeConfiguration.MASTER_HEARTBEAT_PORT, 55556);
FlumeMaster master = new FlumeMaster(new CommandManager(),
new ConfigManager(), new StatusManager(), new MasterAckManager(),
FlumeConfiguration.get());
MasterClientServer delegate = new MasterClientServer(master, cfg);
delegate.masterRPC.serve();
ReportEvent r = new ReportEvent("foo");
r.setStringMetric("bar", "baz");
Map<String, ReportEvent> rptMap = new HashMap<String, ReportEvent>();
rptMap.put("test-report", r);
delegate.putReports(rptMap);
Map<String, Reportable> reportables = rptMan.getReportables();
delegate.stop();
assertEquals(1, reportables.size());
assertNotNull(reportables.get("test-report"));
assertEquals("baz", reportables.get("test-report").getReport().getStringMetric("bar"));
}
}