/*
* Copyright 2008-2014 by Emeric Vernat
*
* This file is part of Java Melody.
*
* 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 net.bull.javamelody;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
/**
* Test unitaire de la classe PdfReport.
* @author Emeric Vernat
*/
//CHECKSTYLE:OFF
public class TestPdfReport {
private static final String TEST_APP = "test app";
/** Before.
* @throws IOException e */
@Before
public void setUp() throws IOException {
Utils.initialize();
JRobin.initBackendFactory(new Timer(getClass().getSimpleName(), true));
}
/** After. */
@After
public void tearDown() {
JRobin.stop();
}
/** Test.
* @throws IOException e
* @throws SchedulerException e
* @throws DocumentException e */
@Test
public void testToPdf() throws IOException, SchedulerException, DocumentException {
//CHECKSTYLE:ON
final Counter sqlCounter = new Counter("sql", "db.png");
sqlCounter.setDisplayed(true);
// counterName doit être http, sql ou ejb pour que les libellés de graph soient trouvés dans les traductions
final Counter counter = new Counter("http", "db.png", sqlCounter);
final Counter errorCounter = new Counter(Counter.ERROR_COUNTER_NAME, null);
final Counter jobCounter = JobGlobalListener.getJobCounter();
final List<Counter> counters = new ArrayList<Counter>();
counters.add(counter);
counters.add(sqlCounter);
counters.add(errorCounter);
counters.add(jobCounter);
counter.addRequest("test1", 0, 0, false, 1000);
counter.addRequest("test2", 1000, 500, false, 1000);
counter.addRequest("test3", 10000, 500, true, 10000);
final Collector collector = new Collector("test", counters);
final JavaInformations javaInformations = new JavaInformations(null, true);
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final List<JavaInformations> javaInformationsList = Collections
.singletonList(javaInformations);
counter.addRequest("test1", 0, 0, false, 1000);
collector.collectWithoutErrors(javaInformationsList);
counter.clear();
collector.collectWithoutErrors(javaInformationsList);
PdfReport pdfReport = new PdfReport(collector, true, javaInformationsList, Period.TOUT,
output);
pdfReport.toPdf();
pdfReport.close();
assertNotEmptyAndClear(output);
final JRobin jrobin = collector.getCounterJRobins().iterator().next();
final byte[] graph = jrobin.graph(Period.JOUR.getRange(), 50, 50);
final Map<String, byte[]> graphs = new HashMap<String, byte[]>();
graphs.put("1", graph);
graphs.put("2", graph);
graphs.put("3", graph);
graphs.put("4", graph);
pdfReport = new PdfReport(collector, true, javaInformationsList, Period.TOUT, output);
pdfReport.preInitGraphs(graphs, graphs, graphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
// pour les PDFs suivants, inutile de regénérer toutes les images,
// ce qui prendrait beaucoup de temps, donc on utilise preInitGraphs
final Map<String, byte[]> emptyGraphs = Collections.emptyMap();
counter.bindContext("test 1", "complete test 1", null, -1);
sqlCounter.bindContext("sql1", "sql 1", null, -1);
sqlCounter.addRequest("sql1", 100, 100, false, -1);
counter.addRequest("test 1", 0, 0, false, 1000);
counter.addRequest("test2", 1000, 500, false, 1000);
counter.addRequest(buildLongRequestName(), 10000, 5000, true, 10000);
collector.collectWithoutErrors(javaInformationsList);
pdfReport = new PdfReport(collector, true, javaInformationsList, Period.TOUT, output);
pdfReport.preInitGraphs(emptyGraphs, emptyGraphs, emptyGraphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
pdfReport = new PdfReport(collector, false, javaInformationsList, Period.TOUT, output);
pdfReport.preInitGraphs(emptyGraphs, emptyGraphs, emptyGraphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
// errorCounter
errorCounter.addRequestForSystemError("error", -1, -1, null);
errorCounter.addRequestForSystemError("error2", -1, -1, "ma stack-trace");
pdfReport = new PdfReport(collector, false, javaInformationsList, Period.TOUT, output);
pdfReport.preInitGraphs(emptyGraphs, emptyGraphs, emptyGraphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
rootContexts(counter, collector, javaInformations, output);
cache(collector, output);
job(collector, output);
Utils.setProperty(Parameter.NO_DATABASE, Boolean.TRUE.toString());
pdfReport = new PdfReport(collector, false, javaInformationsList, Period.TOUT, output);
pdfReport.preInitGraphs(emptyGraphs, emptyGraphs, emptyGraphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
Utils.setProperty(Parameter.NO_DATABASE, Boolean.FALSE.toString());
I18N.bindLocale(Locale.CHINA);
try {
pdfReport = new PdfReport(collector, false, javaInformationsList, Period.TOUT, output);
pdfReport.preInitGraphs(emptyGraphs, emptyGraphs, emptyGraphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
} finally {
I18N.unbindLocale();
}
}
private void cache(Collector collector, ByteArrayOutputStream output) throws IOException {
final String cacheName = "testcache";
final CacheManager cacheManager = CacheManager.getInstance();
cacheManager.addCache(cacheName);
try {
cacheManager.getCache(cacheName).put(new Element(1, Math.random()));
cacheManager.getCache(cacheName).get(1);
cacheManager.getCache(cacheName).get(0);
cacheManager.addCache("testcache2");
// JavaInformations doit être réinstancié pour récupérer les caches
final List<JavaInformations> javaInformationsList = Collections
.singletonList(new JavaInformations(null, true));
final PdfReport pdfReport = new PdfReport(collector, false, javaInformationsList,
Period.TOUT, output);
final Map<String, byte[]> graphs = Collections.emptyMap();
pdfReport.preInitGraphs(graphs, graphs, graphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
} finally {
cacheManager.removeCache(cacheName);
cacheManager.removeCache("testcache2");
}
}
private void job(Collector collector, ByteArrayOutputStream output) throws IOException,
SchedulerException {
// job quartz
JobGlobalListener.initJobGlobalListener();
JobGlobalListener.getJobCounter().clear();
//Grab the Scheduler instance from the Factory
final Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
try {
// and start it off
scheduler.start();
//Define job instance
final Random random = new Random();
//Define a Trigger that will fire "later"
final JobDetail job2 = new JobDetail("job" + random.nextInt(), null, JobTestImpl.class);
final SimpleTrigger trigger2 = new SimpleTrigger("trigger" + random.nextInt(), null,
new Date(System.currentTimeMillis() + random.nextInt(60000)));
trigger2.setRepeatInterval(2 * 24L * 60 * 60 * 1000);
scheduler.scheduleJob(job2, trigger2);
scheduler.pauseJob(job2.getName(), job2.getGroup());
try {
final JobDetail job3 = new JobDetail("job" + random.nextInt(), null,
JobTestImpl.class);
final Trigger trigger3 = new CronTrigger("trigger" + random.nextInt(), null,
"0 0 0 * * ? 2030");
scheduler.scheduleJob(job3, trigger3);
} catch (final ParseException e) {
throw new IllegalStateException(e);
}
// JavaInformations doit être réinstancié pour récupérer les jobs
// (mais "Aucun job" dans le counter)
final List<JavaInformations> javaInformationsList = Collections
.singletonList(new JavaInformations(null, true));
final PdfReport pdfReport = new PdfReport(collector, false, javaInformationsList,
Period.TOUT, output);
final Map<String, byte[]> graphs = Collections.emptyMap();
pdfReport.preInitGraphs(graphs, graphs, graphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
//Define a Trigger that will fire "now"
final JobDetail job = new JobDetail("job" + random.nextInt(), null, JobTestImpl.class);
job.setDescription("description");
final SimpleTrigger trigger = new SimpleTrigger("trigger" + random.nextInt(), null,
new Date());
//Schedule the job with the trigger
scheduler.scheduleJob(job, trigger);
// JobTestImpl fait un sleep de 2s au plus, donc on l'attend pour le compter
try {
Thread.sleep(2100);
} catch (final InterruptedException e) {
throw new IllegalStateException(e);
}
// et on le relance pour qu'il soit en cours
trigger.setRepeatInterval(60000);
scheduler.scheduleJob(job, trigger);
// JavaInformations doit être réinstancié pour récupérer les jobs
final List<JavaInformations> javaInformationsList2 = Collections
.singletonList(new JavaInformations(null, true));
final PdfReport pdfReport2 = new PdfReport(collector, false, javaInformationsList2,
Period.TOUT, output);
pdfReport2.preInitGraphs(graphs, graphs, graphs);
pdfReport2.toPdf();
assertNotEmptyAndClear(output);
} finally {
scheduler.shutdown();
JobGlobalListener.getJobCounter().clear();
JobGlobalListener.destroyJobGlobalListener();
}
}
private void rootContexts(Counter counter, Collector collector,
JavaInformations javaInformations, ByteArrayOutputStream output) throws IOException,
DocumentException {
PdfReport pdfReport;
TestCounter.bindRootContexts("first request", counter, 3);
pdfReport = new PdfReport(collector, false, Collections.singletonList(javaInformations),
Period.TOUT, output);
final Map<String, byte[]> graphs = Collections.emptyMap();
pdfReport.preInitGraphs(graphs, graphs, graphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
final Counter myCounter = new Counter("http", null);
final Collector collector2 = new Collector("test 2", Arrays.asList(myCounter));
myCounter.bindContext("my context", "my context", null, -1);
pdfReport = new PdfReport(collector2, false, Collections.singletonList(javaInformations),
Period.TOUT, output);
pdfReport.preInitGraphs(graphs, graphs, graphs);
pdfReport.toPdf();
assertNotEmptyAndClear(output);
final PdfDocumentFactory pdfDocumentFactory = new PdfDocumentFactory(
collector.getApplication(), null, output);
final Document document = pdfDocumentFactory.createDocument();
document.open();
final PdfCounterRequestContextReport pdfCounterRequestContextReport = new PdfCounterRequestContextReport(
collector2.getRootCurrentContexts(collector2.getCounters()),
new ArrayList<PdfCounterReport>(), new ArrayList<ThreadInformations>(), false,
pdfDocumentFactory, document);
pdfCounterRequestContextReport.toPdf();
document.close();
assertNotEmptyAndClear(output);
}
private void assertNotEmptyAndClear(ByteArrayOutputStream output) {
assertTrue("rapport vide", output.size() > 0);
output.reset();
}
private static String buildLongRequestName() {
// plus de 1000 caractères
final StringBuilder sb = new StringBuilder(1100);
for (int i = 0; i < 1100 / 2; i++) {
sb.append("a ");
}
return sb.toString();
}
/** Test.
* @throws IOException e
* @throws DocumentException e */
@Test
public void testPdfCounterReportWithIncludeGraph() throws IOException, DocumentException {
// counterName doit être http, sql ou ejb pour que les libellés de graph soient trouvés dans les traductions
final Counter counter = new Counter("http", "db.png");
final Counter errorCounter = new Counter(Counter.ERROR_COUNTER_NAME, null);
final List<Counter> counters = Arrays.asList(counter, errorCounter);
final Collector collector = new Collector(TEST_APP, counters);
final JavaInformations javaInformations = new JavaInformations(null, true);
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final List<JavaInformations> javaInformationsList = Collections
.singletonList(javaInformations);
counter.addRequest("test include graph", 1, 1, false, 1000);
errorCounter.addRequestForSystemError("error", 1, 1, null);
collector.collectWithoutErrors(javaInformationsList);
counter.addRequest("test include graph", 1, 1, false, 1000);
errorCounter.addRequestForSystemError("error", 1, 1, null);
collector.collectWithoutErrors(javaInformationsList);
final Document document = new PdfDocumentFactory(TEST_APP, null, output).createDocument();
document.open();
final PdfCounterReport pdfCounterReport = new PdfCounterReport(collector, counter,
Period.TOUT.getRange(), true, document);
pdfCounterReport.toPdf();
pdfCounterReport.writeRequestDetails();
final PdfCounterReport pdfErrorCounterReport = new PdfCounterReport(collector,
errorCounter, Period.TOUT.getRange(), true, document);
pdfErrorCounterReport.writeRequestDetails();
document.close();
assertNotEmptyAndClear(output);
}
/** Test.
* @throws IOException e
* @throws DocumentException e */
@Test
public void testEmptyPdfCounterRequestContext() throws IOException, DocumentException {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final PdfDocumentFactory pdfDocumentFactory = new PdfDocumentFactory(TEST_APP, null, output);
final Document document = pdfDocumentFactory.createDocument();
document.open();
final PdfCounterRequestContextReport report = new PdfCounterRequestContextReport(
Collections.<CounterRequestContext> emptyList(),
Collections.<PdfCounterReport> emptyList(),
Collections.<ThreadInformations> emptyList(), true, pdfDocumentFactory, document);
report.toPdf();
report.writeContextDetails();
// on ne peut fermer le document car on n'a rien écrit normalement
assertNotNull("PdfCounterRequestContextReport", report);
}
/** Test.
* @throws IOException e
* @throws DocumentException e */
@Test
public void testPdfThreadInformationsReport() throws IOException, DocumentException {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final PdfDocumentFactory pdfDocumentFactory = new PdfDocumentFactory(TEST_APP, null, output);
final Document document = pdfDocumentFactory.createDocument();
document.open();
boolean stackTraceEnabled = true;
final PdfThreadInformationsReport report = new PdfThreadInformationsReport(
JavaInformations.buildThreadInformationsList(), stackTraceEnabled,
pdfDocumentFactory, document);
report.toPdf();
document.close();
assertNotEmptyAndClear(output);
final Document document2 = pdfDocumentFactory.createDocument();
document2.open();
stackTraceEnabled = false;
final PdfThreadInformationsReport report2 = new PdfThreadInformationsReport(
JavaInformations.buildThreadInformationsList(), stackTraceEnabled,
pdfDocumentFactory, document2);
report2.toPdf();
document2.close();
assertNotEmptyAndClear(output);
// writeDeadlocks
final List<ThreadInformations> threads = new ArrayList<ThreadInformations>();
final Thread thread = Thread.currentThread();
threads.add(new ThreadInformations(thread, null, 10, 10, false, Parameters.getHostAddress()));
threads.add(new ThreadInformations(thread, null, 10, 10, true, Parameters.getHostAddress()));
final Document document3 = pdfDocumentFactory.createDocument();
document3.open();
stackTraceEnabled = false;
final PdfThreadInformationsReport report3 = new PdfThreadInformationsReport(threads,
stackTraceEnabled, pdfDocumentFactory, document3);
report3.writeDeadlocks();
document3.close();
assertNotEmptyAndClear(output);
final Document document4 = pdfDocumentFactory.createDocument();
document4.open();
final PdfThreadInformationsReport report4 = new PdfThreadInformationsReport(
new ArrayList<ThreadInformations>(), stackTraceEnabled, pdfDocumentFactory,
document4);
report4.toPdf();
report4.writeDeadlocks();
document4.close();
assertNotEmptyAndClear(output);
}
/** Test. */
@Test
public void testGetFileName() {
assertNotNull("filename", PdfReport.getFileName("test"));
}
}