/* * RHQ Management Platform * Copyright (C) 2005-2010 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.helpers.perftest.support.reporting; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.rhq.helpers.perftest.support.testng.PerformanceReporting; import org.testng.ITestResult; import java.io.*; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Comparator; import java.util.Date; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; /** * Export data to an excel sheet * * @author Heiko W. Rupp */ public class ExcelExporter implements PerformanceReportExporter { private static final String DOT_XLS = ".xls"; static final String TARGET = "target/"; String baseFileName ; PerformanceReporting.Rolling rolling; CellStyle integerStyle; CellStyle boldText; @Override public void setBaseFile(String fileName) { baseFileName = fileName; if (baseFileName.startsWith(TARGET)) baseFileName = TARGET + baseFileName; } @Override public void setRolling(PerformanceReporting.Rolling rolling) { this.rolling = rolling; } @Override public void export(Map<String, Long> timings, ITestResult result) { Workbook wb; InputStream inp = null; String fileName = getFileName(); // Check if Workbook is present - otherwise create it try { inp = new FileInputStream(fileName); wb = new HSSFWorkbook(inp); } catch (Exception e) { wb = new HSSFWorkbook(); } finally { if (inp!=null) try { inp.close(); } catch (IOException e) { e.printStackTrace(); // TODO: Customise this generated block } } // Now write to it FileOutputStream fileOut = null; try { // Check if we have our sheet, otherwise create if (wb.getNumberOfSheets()==0) { wb.createSheet("Overview"); } Sheet sheet = wb.getSheetAt(0); DataFormat df = wb.createDataFormat(); integerStyle = wb.createCellStyle(); integerStyle.setDataFormat(df.getFormat("#######0")); Font boldFont = wb.createFont(); boldFont.setBoldweight(Font.BOLDWEIGHT_BOLD); boldText = wb.createCellStyle(); boldText.setFont(boldFont); createOverviewHeaderIfNeeded(sheet); long time = getTotalTime(timings); createOverviewEntry(sheet, time, result); createDetailsSheet(wb,timings,result); // Write the output to a file File outFile = new File(fileName); System.out.println("ExcelExporter, writing to " + outFile.getAbsolutePath()); fileOut = new FileOutputStream(outFile); wb.write(fileOut); fileOut.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (fileOut!=null) fileOut.close(); } catch (IOException e) { System.err.println("Failed to close the workbook: " + e.getMessage()); } } } /** * Create a sheet per test to show the individual timings we recorded * @param wb Workbook to attach the new sheet to * @param timings The map with timings from the test * @param result TestNG results of the test */ private void createDetailsSheet(Workbook wb, Map<String,Long> timings, ITestResult result) { String name = result.getTestClass().getName(); if (name.contains(".")) name = name.substring(name.lastIndexOf(".")+1); name += "." + result.getName(); Sheet sheet = wb.getSheet(name); if (sheet ==null) sheet = wb.createSheet(name); Row row = appendRow(sheet); Cell cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Class"); name = result.getTestClass().getName(); if (name.contains(".")) name = name.substring(name.lastIndexOf(".")+1); row.createCell(1).setCellValue(name); row = appendRow(sheet); cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Method"); row.createCell(1).setCellValue(result.getName()); cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Success:"); row.createCell(1).setCellValue(result.isSuccess()); row = appendRow(sheet); cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("TestNG timing"); row.createCell(1).setCellValue(result.getEndMillis()-result.getStartMillis()); row = appendRow(sheet); cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Perf test timing"); row.createCell(1).setCellValue(getTotalTime(timings)); row = appendRow(sheet); // Empty row row = appendRow(sheet); cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Individual Timings"); // Now the timings row = appendRow(sheet); cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Name"); cell = row.createCell(1); cell.setCellStyle(boldText); cell.setCellValue("Duration"); Set<Map.Entry<String,Long>> data = timings.entrySet(); SortedSet<Map.Entry<String,Long>> sorted = new TreeSet<Map.Entry<String,Long>>(new Comparator<Map.Entry<String,Long>>() { public int compare(Map.Entry<String,Long> item1, Map.Entry<String,Long> item2) { return item1.getKey().compareTo(item2.getKey()); } }); sorted.addAll(data); for (Map.Entry<String,Long> entry: sorted) { row = appendRow(sheet); cell = row.createCell(0); cell.setCellValue(entry.getKey()); cell = row.createCell(1); cell.setCellStyle(integerStyle); cell.setCellValue(entry.getValue()); } sheet.autoSizeColumn(0); sheet.autoSizeColumn(1); } /** * Create a row on the overview sheet * @param sheet sheet to use * @param testTime time this test took within the perf biz logic * @param result the TestNG result object */ private void createOverviewEntry(Sheet sheet, long testTime, ITestResult result) { // Test name Row row = appendRow(sheet); Cell cell = row.createCell(0); cell.setCellType(Cell.CELL_TYPE_STRING); String name = result.getTestClass().getName(); if (name.contains(".")) name = name.substring(name.lastIndexOf(".")+1); name += "." + result.getName(); cell.setCellValue(name); // success ? cell = row.createCell(1); cell.setCellType(Cell.CELL_TYPE_BOOLEAN); cell.setCellValue(result.isSuccess()); // timing from TestNG cell = row.createCell(2); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(integerStyle); cell.setCellValue(result.getEndMillis()-result.getStartMillis()); // timing of our business logic cell = row.createCell(3); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(integerStyle); cell.setCellValue(testTime); } /** * Create a header row that describes the columns on the overview sheet * @param sheet sheet to write to. */ private void createOverviewHeaderIfNeeded(Sheet sheet) { Row row = sheet.getRow(0); if (row==null) row = sheet.createRow(0); Cell cell = row.createCell(0); cell.setCellStyle(boldText); cell.setCellValue("Name"); cell = row.createCell(1); cell.setCellStyle(boldText); cell.setCellValue("Success"); cell = row.createCell(2); cell.setCellStyle(boldText); cell.setCellValue("TestNG timing"); cell.setCellStyle(boldText); cell = row.createCell(3); cell.setCellValue("Perf timing"); cell.setCellStyle(boldText); sheet.autoSizeColumn(0); sheet.autoSizeColumn(2); sheet.autoSizeColumn(3); } /** * Get the accumulated time from all the perf test biz logic of the test * @param timings Map with timings and 'sub tests' * @return summary time */ private long getTotalTime(Map<String, Long> timings) { long summaryTime = 0L; for (Map.Entry<String,Long> item : timings.entrySet()) { summaryTime += item.getValue(); } return summaryTime; } /** * Append a row to the sheet * @param sheet Sheet to append a new empty row to * @return the newly created row */ private Row appendRow(Sheet sheet) { int lastRow = sheet.getLastRowNum(); Row ret = sheet.createRow(lastRow+1); return ret; } /** * Return the filename to use based on the baseFileName and * the the rolling argument of the @PerformanceReporting annotation * @return filename for the excel file ending on .xls */ private String getFileName() { String fileName = baseFileName; DateFormat df ; String suffix = ""; switch (rolling) { case HOURLY: df = new SimpleDateFormat("yyMMdd-kk"); suffix = "-" + df.format(new Date()); break; case DAILY: df = new SimpleDateFormat("yyMMdd"); suffix = "-" + df.format(new Date()); default: break; } fileName = fileName + suffix + DOT_XLS; return fileName; } }