package org.radargun.reporting.html; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import org.radargun.config.Cluster; import org.radargun.config.Configuration; import org.radargun.config.MasterConfig; import org.radargun.logging.Log; import org.radargun.logging.LogFactory; import org.radargun.reporting.Report; /** * The main document in HTML report. * Shows benchmark configuration and links to timeline & test results. * * @author Radim Vansa <rvansa@redhat.com> */ public class IndexDocument extends HtmlDocument { private static final Log log = LogFactory.getLog(IndexDocument.class); private Map<Report, Map<String, Set<OriginalConfig>>> configs = new HashMap<>(); private Set<String> normalized = new HashSet<>(); private MasterConfig masterConfig; public IndexDocument(String directory) { super(directory, "index.html", "RadarGun benchmark"); } public void writeMasterConfig(MasterConfig masterConfig) { this.masterConfig = masterConfig; String configFile = "master-config.xml"; String scenarioFile = "scenario-file.xml"; try (FileOutputStream mainFileWriter = new FileOutputStream(directory + File.separator + configFile); FileOutputStream scenarioWriter = new FileOutputStream(directory + File.separator + scenarioFile) ) { mainFileWriter.write(masterConfig.getMasterConfigBytes()); if (masterConfig.getScenarioBytes() != null) { scenarioWriter.write(masterConfig.getScenarioBytes()); } } catch (FileNotFoundException e) { log.error("Failed to open " + configFile, e); } catch (IOException e) { log.error("Failed to write " + configFile, e); } } /** * Used from freemarker template to decide whether to provide a link to an external scenario file. * @return true if there's an external scenario file imported into the main RG benchmark */ public boolean isExternalScenario() { return masterConfig.getScenarioBytes() != null; } private void writeConfig(Cluster cluster, Configuration.Setup setup, OriginalConfig config) { String configFile = String.format("original_%s_%s_%d_%s", setup.getConfiguration().name, setup.group, cluster.getClusterIndex(), config.filename).replace(File.separator, "_"); try (FileOutputStream contentWriter = new FileOutputStream(directory + File.separator + configFile)) { contentWriter.write(config.content); } catch (FileNotFoundException e) { log.error("Failed to open " + configFile, e); } catch (IOException e) { log.error("Failed to write " + configFile, e); } } private void addToConfigs(Map<String, Set<OriginalConfig>> configs, String group, int slave, String filename, byte[] content) { boolean found = false; for (OriginalConfig config : configs.get(group)) { if (config.filename.equals(filename) && Arrays.equals(config.content, content)) { config.slaves.add(slave); found = true; break; } } if (!found) { configs.get(group).add(new OriginalConfig(slave, filename, content)); } } /** * Prepares configuration files for report * * @param reports to be parsed */ public void prepareServiceConfigs(Collection<Report> reports) { for (Report report : reports) { Map<String, Set<OriginalConfig>> configs = new HashMap<>(); for (Configuration.Setup setup : report.getConfiguration().getSetups()) { Set<Integer> slaves = report.getCluster().getSlaves(setup.group); if (configs.get(setup.group) == null) { configs.put(setup.group, new HashSet<>()); } for (Map.Entry<Integer, Map<String, Properties>> entry : report.getNormalizedServiceConfigs().entrySet()) { if (slaves.contains(entry.getKey()) && entry.getValue() != null) { normalized.addAll(entry.getValue().keySet()); } } for (Map.Entry<Integer, Map<String, byte[]>> entry : report.getOriginalServiceConfig().entrySet()) { if (slaves.contains(entry.getKey()) && entry.getValue() != null) { for (Map.Entry<String, byte[]> file : entry.getValue().entrySet()) { addToConfigs(configs, setup.group, entry.getKey(), file.getKey(), file.getValue()); } } } this.configs.put(report, configs); for (OriginalConfig config : configs.get(setup.group)) { writeConfig(report.getCluster(), setup, config); } } } } /** * The following methods are used in Freemarker templates * e.g. method getPercentiles() can be used as getPercentiles() or percentiles in template */ public Set<OriginalConfig> getConfigs(Report report, String groupName) { return configs.get(report).get(groupName); } public String getFilename(String configName, String groupName, Cluster cluster, String config) { return String.format("normalized_%s_%s_%d_%s.html", configName, groupName, cluster.getClusterIndex(), config); } public Set<String> getNormalized() { return normalized; } public String removeFileSeparator(String string) { return string.replace(File.separator, "_"); } public static class OriginalConfig { private Set<Integer> slaves = new HashSet<>(); private String filename; private byte[] content; public OriginalConfig(int slave, String filename, byte[] content) { slaves.add(slave); this.filename = filename; this.content = content; } /** * The following methods are used in Freemarker templates * e.g. method getPercentiles() can be used as getPercentiles() or percentiles in template */ public Set<Integer> getSlaves() { return slaves; } public String getFilename() { return filename; } public byte[] getContent() { return content; } } }