/**
* 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.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.zookeeper.KeeperException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cloudera.flume.conf.FlumeConfiguration;
import com.cloudera.util.FileUtil;
/**
* Unit tests for ZooKeeperCounter
*/
public class ZooKeeperCounterTest {
static final Logger LOG = LoggerFactory.getLogger(ZooKeeperCounterTest.class);
static ZooKeeperService svc;
static File tmp;
@BeforeClass
static public void setupZK() throws IOException, InterruptedException {
tmp = FileUtil.mktempdir();
FlumeConfiguration.get().set(FlumeConfiguration.MASTER_ZK_LOGDIR,
tmp.getAbsolutePath());
svc = ZooKeeperService.getAndInit();
}
@AfterClass
static public void tearDownZK() throws IOException {
svc.shutdown();
FileUtil.rmr(tmp);
}
/**
* Test that counter by default returns monotonically increasing sequence.
*/
@Test
public void testMonotonicity() throws IOException, InterruptedException,
KeeperException {
ZooKeeperCounter seq = new ZooKeeperCounter(svc, "/seq-generator-test");
for (long i = 0; i < 1024; ++i) {
assertEquals(i, seq.incrementAndGet());
}
seq.shutdown();
}
/**
* Test that changing the increment size changes the step in counter values
* returned.
*/
@Test
public void testIncrementSize() throws IOException, InterruptedException,
KeeperException {
ZooKeeperCounter seq = new ZooKeeperCounter(svc, "/seq-generator-incr-test");
for (long i = 0; i < 1024; ++i) {
assertEquals(i * 4, seq.incrementAndGetBy(4L));
}
seq.shutdown();
}
/**
* Test that we can reset the counter to a range of values
*/
@Test
public void testReset() throws IOException, InterruptedException, KeeperException {
ZooKeeperCounter seq = new ZooKeeperCounter(svc, "/seq-generator-reset-test");
for (long i=0; i < 1024; ++i) {
seq.resetTo(i);
assertEquals(i, seq.incrementAndGet());
}
seq.shutdown();
}
final static int LOOP_COUNT = 200;
public class CounterThread extends Thread {
private ZooKeeperCounter seq;
public ArrayList<Long> counts = new ArrayList<Long>();
public CounterThread(ZooKeeperCounter seq) {
this.seq = seq;
}
public void run() {
for (int i = 0; i < LOOP_COUNT; ++i) {
try {
counts.add(seq.incrementAndGet());
} catch (Exception e) {
// Just log - missing counter value will fail the test
LOG.error("CounterThread saw exception",e);
}
}
}
}
/**
* Test that running two threads accessing the same counter together both see
* a sequentially consistent view of the counter.
*/
@Test
public void testConcurrency() throws IOException, KeeperException,
InterruptedException {
ZooKeeperCounter seq = new ZooKeeperCounter(svc, "/seq-generator-conc-test");
CounterThread t1 = new CounterThread(seq);
CounterThread t2 = new CounterThread(seq);
t1.start();
t2.start();
t1.join();
t2.join();
long last = -1;
for (Long l : t1.counts) {
assertTrue("Expected increasing counts", last < l);
last = l;
}
last = -1;
for (Long l : t2.counts) {
assertTrue("Expected increasing counts", last < l);
last = l;
}
ArrayList<Long> counts = t1.counts;
counts.addAll(t2.counts);
Collections.sort(counts);
for (long i = 0; i < LOOP_COUNT * 2; ++i) {
assertEquals("Missing counter value", i, (long) counts.get((int) i));
}
seq.shutdown();
}
}