/*
* Copyright 2014 OCTO Technology
*
* Licensed 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.octo.reactive.audit;
import com.octo.reactive.audit.lib.TolerateLatency;
import com.octo.reactive.audit.lib.FileReactiveAuditException;
import com.octo.reactive.audit.lib.Latency;
import com.octo.reactive.audit.lib.ReactiveAuditException;
import org.junit.Test;
import java.io.File;
import java.lang.reflect.Field;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import static com.octo.reactive.audit.ReactiveAudit.auditPackageName;
import static com.octo.reactive.audit.lib.Latency.*;
import static org.junit.Assert.*;
@SuppressWarnings({"MethodOnlyUsedFromInnerClass", "ResultOfMethodCallIgnored"})
public class ReactiveAuditTest
{
// Because the Aspectj must use the config singleton,
// it's not possible to inject a specific config instance
private final ReactiveAudit config = ReactiveAudit.config;
private final int[] log = new int[1];
private final Handler handler = new Handler()
{
@Override
public void publish(LogRecord record)
{
if (record.getLevel() != Level.FINE)
++log[0];
}
@Override
public void flush()
{
}
@Override
public void close()
{
}
};
@Test
public void currentThread_test()
{
TestTools.strict.commit();
assertTrue(config.isThreadNameMatch(Thread.currentThread().getName()));
}
@Test
public void currentThread_nothing()
{
config.begin().threadPattern("(?!)").commit();
assertFalse(config.isThreadNameMatch(Thread.currentThread().getName()));
}
@Test
public void setAllParams()
{
config.reset();
config.begin()
.throwExceptions(true)
.threadPattern("")
.latencyFile("high")
.latencyNetwork("medium")
.latencyCPU("low")
.bootStrapDelay(10)
.commit();
assertEquals(true, config.isThrow());
assertEquals("", config.getThreadPattern());
assertEquals(Latency.HIGH, config.getFileLatency());
assertEquals(Latency.MEDIUM, config.getNetworkLatency());
assertEquals(LOW, config.getCPULatency());
assertEquals(10, config.getBootstrapDelay());
config.begin()
.throwExceptions(false)
.threadPattern("abc")
.latencyFile("")
.latencyNetwork("")
.latencyCPU("")
.bootStrapDelay(0)
.commit();
assertEquals(false, config.isThrow());
assertEquals("abc", config.getThreadPattern());
assertNull(config.getFileLatency());
assertNull(config.getNetworkLatency());
assertNull(config.getCPULatency());
assertEquals(0, config.getBootstrapDelay());
}
@Test(expected = IllegalArgumentException.class)
public void lockTransaction()
{
config.reset();
config.begin()
.seal()
.threadPattern("abc");
}
@Test
@TolerateLatency // For accept join
public void logIfNewThread()
throws InterruptedException
{
config.reset();
config.begin()
.threadPattern(".*")
.latencyFile("LOW")
.throwExceptions(false)
.commit();
try
{
addHandler();
Thread t;
log[0] = 0;
Runnable rctx1 = new Runnable()
{
@Override
public void run()
{
latencyCall1();
}
};
// First turn, invoke log.
t = new Thread(rctx1);
t.setDaemon(true);
t.start();
t.join();
assertEquals(1, log[0]);
// Second turn, invoke log.
log[0] = 0;
Runnable rctx2 = new Runnable()
{
@Override
public void run()
{
latencyCall2();
}
};
t = new Thread(rctx2);
t.setDaemon(true);
t.start();
t.join();
assertEquals(1, log[0]);
// Third turn, same context, no invoke log.
log[0] = 0;
t = new Thread(rctx1);
t.setDaemon(true);
t.start();
t.join();
assertEquals(0, log[0]);
log[0] = 0;
Runnable rctx3 = new Runnable()
{
@Override
public void run()
{
latencyCall3();
}
};
t = new Thread(rctx3);
t.setDaemon(true);
t.start();
t.join();
assertEquals(1, log[0]);
log[0] = 0;
Runnable rctx4 = new Runnable()
{
@Override
public void run()
{
latencyCall4();
}
};
t = new Thread(rctx4);
t.setDaemon(true);
t.start();
t.join();
assertEquals(2, log[0]);
log[0] = 0;
t = new Thread(rctx3);
t.setDaemon(true);
t.start();
t.join();
assertEquals(0, log[0]);
log[0] = 0;
t = new Thread(rctx4);
t.setDaemon(true);
t.start();
t.join();
assertEquals(0, log[0]);
}
finally
{
removeHandler();
}
}
@Test
public void logIfNewLoop()
{
config.reset();
config.begin()
.threadPattern(".*")
.logOutput(LoadParams.DEFAULT_LOG_OUTPUT,LoadParams.DEFAULT_LOG_FORMAT,LoadParams.DEFAULT_LOG_SIZE)
.latencyFile("LOW")
.throwExceptions(false)
.commit();
try
{
addHandler();
for (int i = 0; i < 5; ++i)
{
log[0] = 0;
latencyCall1();
if (i == 0) assertEquals(1, log[0]);
else assertEquals(0, log[0]);
}
}
finally
{
removeHandler();
}
}
@Test
public void logIfLevel()
{
config.reset();
config.begin()
.latencyFile("")
.commit();
try
{
addHandler();
log[0] = 0;
config.logIfNew(LOW, new FileReactiveAuditException(LOW, ""));
assertEquals(0, log[0]);
log[0] = 0;
config.logIfNew(MEDIUM, new FileReactiveAuditException(MEDIUM, ""));
assertEquals(0, log[0]);
log[0] = 0;
config.logIfNew(HIGH, new FileReactiveAuditException(HIGH, ""));
assertEquals(0, log[0]);
}
finally
{
removeHandler();
}
config.begin()
.latencyFile("LOW")
.commit();
try
{
addHandler();
log[0] = 0;
config.logIfNew(LOW, new FileReactiveAuditException(LOW, ""));
assertEquals(1, log[0]);
log[0] = 0;
config.logIfNew(MEDIUM, new FileReactiveAuditException(MEDIUM, ""));
assertEquals(1, log[0]);
log[0] = 0;
config.logIfNew(HIGH, new FileReactiveAuditException(HIGH, ""));
assertEquals(1, log[0]);
}
finally
{
removeHandler();
}
config.begin()
.latencyFile("MEDIUM")
.commit();
try
{
addHandler();
log[0] = 0;
config.logIfNew(LOW, new FileReactiveAuditException(LOW, ""));
assertEquals(0, log[0]);
log[0] = 0;
config.logIfNew(MEDIUM, new FileReactiveAuditException(MEDIUM, ""));
assertEquals(1, log[0]);
log[0] = 0;
config.logIfNew(HIGH, new FileReactiveAuditException(HIGH, ""));
assertEquals(1, log[0]);
}
finally
{
removeHandler();
}
config.begin()
.latencyFile("HIGH")
.commit();
try
{
addHandler();
log[0] = 0;
config.logIfNew(LOW, new FileReactiveAuditException(LOW, ""));
assertEquals(0, log[0]);
log[0] = 0;
config.logIfNew(MEDIUM, new FileReactiveAuditException(MEDIUM, ""));
assertEquals(0, log[0]);
log[0] = 0;
config.logIfNew(HIGH, new FileReactiveAuditException(HIGH, ""));
assertEquals(1, log[0]);
}
finally
{
removeHandler();
}
}
private void removeHandler()
{
config.logger.removeHandler(handler);
}
@SuppressWarnings("ConstantConditions")
private void addHandler()
{
//noinspection ConstantIfStatement
if (true) // Remove log on console
{
for (Handler h : config.logger.getHandlers())
{
config.logger.removeHandler(h);
}
}
config.logger.addHandler(handler);
}
private void latencyCall1()
{
new File("/").getFreeSpace();
}
private void latencyCall2()
{
new File("/").getFreeSpace();
}
private void latencyCall3()
{
latencyCall1();
}
private void latencyCall4()
{
latencyCall1();
latencyCall2();
}
@SuppressWarnings("PointlessBooleanExpression")
@Test
public void testPurgeStackTrace()
throws NoSuchFieldException, IllegalAccessException
{
// If debug mode, test nothing
Field field = ReactiveAuditException.class.getDeclaredField("debug");
field.setAccessible(true);
if (((Boolean) field.get(null)) == true) return;
TestTools.strict.commit();
try
{
latencyCall1();
fail();
}
catch (ReactiveAuditException e)
{
StackTraceElement[] stack = e.getStackTrace();
for (StackTraceElement traceElement : stack)
{
assertFalse((traceElement.getClassName().startsWith(auditPackageName)
&& !traceElement.getClassName().endsWith("Test"))); // For inner unit test
}
}
}
}