/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.util.tap;
import org.junit.Before;
import org.junit.Test;
import static java.lang.Math.abs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class RecursiveTapTest
{
@Before
public void before()
{
Tap.DISPATCHES.clear();
createTaps();
}
@Test
public void testTapStructure()
{
assertTrue(a.internal() instanceof Dispatch);
assertTrue(b.internal() instanceof Dispatch);
}
@Test
public void testEnableRoot() throws InterruptedException
{
aba();
}
@Test
public void testEnableSubsidiary() throws InterruptedException
{
disableTaps();
Tap.setEnabled(SUBSIDIARY_TAP, true);
a.in();
sleep();
b.in();
sleep();
a.in();
sleep();
a.out();
sleep();
b.out();
sleep();
a.out();
expectNoReports();
}
@Test
public void testDisableRoot() throws InterruptedException
{
disableTaps();
a.in();
sleep();
b.in();
sleep();
a.in();
sleep();
a.out();
sleep();
b.out();
sleep();
a.out();
expectNoReports();
}
@Test
public void testSiblings() throws InterruptedException
{
Tap.DISPATCHES.clear(); // Different set of taps from other tests
// Tap structure:
// r
// i
// j
// x
// y
// k
InOutTap r = Tap.createRecursiveTimer("r");
InOutTap i = r.createSubsidiaryTap("i");
InOutTap j = r.createSubsidiaryTap("j");
InOutTap k = r.createSubsidiaryTap("k");
InOutTap x = r.createSubsidiaryTap("x");
InOutTap y = r.createSubsidiaryTap("y");
Tap.setEnabled("r", true);
r.in();
sleep();
i.in();
sleep();
j.in();
sleep();
x.in();
sleep();
x.out();
sleep();
y.in();
sleep();
y.out();
sleep();
j.out();
sleep();
k.in();
sleep();
k.out();
sleep();
i.out();
sleep();
r.out();
TapReport[] tapReports = Tap.getReport("r");
assertEquals(6, tapReports.length);
for (TapReport report : tapReports) {
if (report.getName().equals("r")) {
assertEquals(1, report.getInCount());
// assertTrue(checkTicks(report, 2));
} else if (report.getName().equals("i")) {
assertEquals(1, report.getInCount());
// assertTrue(checkTicks(report, 3));
} else if (report.getName().equals("j")) {
assertEquals(1, report.getInCount());
// assertTrue(checkTicks(report, 3));
} else if (report.getName().equals("k")) {
assertEquals(1, report.getInCount());
// assertTrue(checkTicks(report, 1));
} else if (report.getName().equals("x")) {
assertEquals(1, report.getInCount());
// assertTrue(checkTicks(report, 1));
} else if (report.getName().equals("y")) {
assertEquals(1, report.getInCount());
// assertTrue(checkTicks(report, 1));
} else {
fail();
}
assertEquals(report.getOutCount(), report.getInCount());
}
}
// The following tests enable/disable taps at all combinations of points with respect to the ABA
// tap pattern:
//
// 1
// in A
// 2
// in B
// 3
// in A
// 4
// out A
// 5
// out B
// 6
// out A
// 7
//
// testEnableDisable_XY starts with taps enabled. The root tap is disabled at position X and enabled it at Y,
// X = 1..7, Y = 1..7, X <= Y. Then, after making sure that results are correct, the standard aba test is run
// to see that that still works after the disabling/enabling.
@Test
public void testEnableDisable_11() throws InterruptedException
{
/* 1 */ disableTaps(); enableTaps();
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 2, 3, 1, 2);
enableTaps();
aba();
}
@Test
public void testEnableDisable_12() throws InterruptedException
{
/* 1 */ disableTaps();
a.in();
/* 2 */ enableTaps();
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 1, 1, 1, 2);
enableTaps();
aba();
}
@Test
public void testEnableDisable_13() throws InterruptedException
{
/* 1 */ disableTaps();
a.in();
/* 2 */
sleep();
b.in();
/* 3 */ enableTaps();
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 1, 1, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_14() throws InterruptedException
{
/* 1 */ disableTaps();
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */ enableTaps();
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_15() throws InterruptedException
{
/* 1 */ disableTaps();
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */ enableTaps();
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_16() throws InterruptedException
{
/* 1 */ disableTaps();
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */ enableTaps();
sleep();
a.out();
/* 7 */
expect(1, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_17() throws InterruptedException
{
/* 1 */ disableTaps();
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */ enableTaps();
expect(1, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_22() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */ disableTaps(); enableTaps();
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 1, 1, 1, 2);
enableTaps();
aba();
}
@Test
public void testEnableDisable_23() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */ disableTaps();
sleep();
b.in();
/* 3 */ enableTaps();
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 1, 1, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_24() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */ disableTaps();
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */ enableTaps();
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_25() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */ disableTaps();
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */ enableTaps();
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_26() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */ disableTaps();
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */ enableTaps();
sleep();
a.out();
/* 7 */
expect(1, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_27() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */ disableTaps();
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */ enableTaps();
expect(1, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_33() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */ disableTaps(); enableTaps();
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 1, 1, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_34() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */ disableTaps();
sleep();
a.in();
/* 4 */ enableTaps();
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_35() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */ disableTaps();
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */ enableTaps();
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_36() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */ disableTaps();
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */ enableTaps();
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_37() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */ disableTaps();
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */ enableTaps();
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_44() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */ disableTaps(); enableTaps();
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_45() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */ disableTaps();
sleep();
a.out();
/* 5 */ enableTaps();
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_46() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */ disableTaps();
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */ enableTaps();
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_47() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */ disableTaps();
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */ enableTaps();
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_55() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */ disableTaps(); enableTaps();
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_56() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */ disableTaps();
sleep();
b.out();
/* 6 */ enableTaps();
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_57() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */ disableTaps();
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */ enableTaps();
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_66() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */ disableTaps(); enableTaps();
sleep();
a.out();
/* 7 */
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_67() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */ disableTaps();
sleep();
a.out();
/* 7 */ enableTaps();
expect(2, 0, 0, 0, 0);
enableTaps();
aba();
}
@Test
public void testEnableDisable_77() throws InterruptedException
{
/* 1 */
a.in();
/* 2 */
sleep();
b.in();
/* 3 */
sleep();
a.in();
/* 4 */
sleep();
a.out();
/* 5 */
sleep();
b.out();
/* 6 */
sleep();
a.out();
/* 7 */ disableTaps(); enableTaps();
expect(2, 0, 0, 0, 0);
}
private void aba() throws InterruptedException
{
a.in();
sleep();
b.in();
sleep();
a.in();
sleep();
a.out();
sleep();
b.out();
sleep();
a.out();
expect(2, 2, 3, 1, 2);
}
private void createTaps()
{
a = Tap.createRecursiveTimer("a");
b = a.createSubsidiaryTap("b");
enableTaps();
}
// nTaps: number of taps touched (via in or out) while taps are enabled. The root tap (a) is enabled even if
// not touched.
private void expect(int nTaps, int aCount, int aTicks, int bCount, int bTicks)
{
TapReport[] tapReports = Tap.getReport(ROOT_TAP);
assertEquals(nTaps, tapReports.length);
for (TapReport report : tapReports) {
if (report.getName().equals("a")) {
assertEquals(
String.format("aCount = %s", report.getInCount()),
aCount,
report.getInCount());
/*
assertTrue(
String.format("aCount = %s, aTime = %s",
report.getInCount(),
report.getCumulativeTime() / MILLION),
checkTicks(report, aTicks));
*/
} else if (report.getName().equals("b")) {
assertEquals(
String.format("bCount = %s", report.getInCount()),
bCount,
report.getInCount());
/*
assertTrue(
String.format("bCount = %s, bTime = %s",
report.getInCount(),
report.getCumulativeTime() / MILLION),
checkTicks(report, bTicks));
*/
} else {
fail();
}
assertEquals(report.getOutCount(), report.getInCount());
}
}
private void expectNoReports()
{
assertEquals(0, Tap.getReport(ROOT_TAP).length);
}
private void enableTaps()
{
Tap.setEnabled(ROOT_TAP, true);
}
private void disableTaps()
{
Tap.setEnabled(ROOT_TAP, false);
}
private void sleep() throws InterruptedException
{
Thread.sleep(TICK_LENGTH_MSEC);
}
private boolean checkTicks(TapReport tapReport, int ticks)
{
return abs(tapReport.getCumulativeTime() / MILLION - ticks * TICK_LENGTH_MSEC) < CLOCK_IMPRECISION_MSEC;
}
private static final String ROOT_TAP = "a";
private static final String SUBSIDIARY_TAP = "b";
private static final int MILLION = 1000000;
private static final int TICK_LENGTH_MSEC = 20;
private static final int CLOCK_IMPRECISION_MSEC = 10;
private InOutTap a;
private InOutTap b;
}