001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.junit.viewer.client;
017:
018: import com.google.gwt.core.client.EntryPoint;
019: import com.google.gwt.core.client.GWT;
020: import com.google.gwt.http.client.URL;
021: import com.google.gwt.user.client.DOM;
022: import com.google.gwt.user.client.Element;
023: import com.google.gwt.user.client.rpc.AsyncCallback;
024: import com.google.gwt.user.client.rpc.ServiceDefTarget;
025: import com.google.gwt.user.client.ui.Button;
026: import com.google.gwt.user.client.ui.CellPanel;
027: import com.google.gwt.user.client.ui.ClickListener;
028: import com.google.gwt.user.client.ui.FlexTable;
029: import com.google.gwt.user.client.ui.HTML;
030: import com.google.gwt.user.client.ui.HasHorizontalAlignment;
031: import com.google.gwt.user.client.ui.HasVerticalAlignment;
032: import com.google.gwt.user.client.ui.HorizontalPanel;
033: import com.google.gwt.user.client.ui.Image;
034: import com.google.gwt.user.client.ui.Label;
035: import com.google.gwt.user.client.ui.RootPanel;
036: import com.google.gwt.user.client.ui.VerticalPanel;
037: import com.google.gwt.user.client.ui.Widget;
038: import com.google.gwt.user.client.ui.TableListener;
039: import com.google.gwt.user.client.ui.SourcesTableEvents;
040:
041: import java.util.ArrayList;
042: import java.util.Collections;
043: import java.util.Comparator;
044: import java.util.List;
045: import java.util.Map;
046:
047: /**
048: * The application for viewing benchmark reports. In order for the ReportViewer
049: * to operate correctly, you must have both the {@link ReportServer} RPC and
050: * {@link com.google.gwt.junit.viewer.server.ReportImageServer} servlets up and
051: * running within a servlet container.
052: *
053: * <code>ReportViewer's</code> GWT XML module is configured to start these
054: * servlets by default. Just start <code>ReportViewer</code> in hosted mode,
055: * and GWT will run them within its own embedded servlet engine. For example,
056: *
057: * <pre>java -cp <classpath> com.google.gwt.dev.GWTShell -out
058: * ReportViewerShell/www
059: * com.google.gwt.junit.viewer.ReportViewer/ReportViewer.html</pre>
060: *
061: * You can configure the location where ReportServer reads the benchmark reports
062: * from by setting the system property named in
063: * {@link com.google.gwt.junit.client.Benchmark#REPORT_PATH}.
064: */
065: public class ReportViewer implements EntryPoint {
066:
067: private static class MutableBool {
068:
069: boolean value;
070:
071: MutableBool(boolean value) {
072: this .value = value;
073: }
074: }
075:
076: private class SummariesTableListener implements TableListener {
077:
078: private FlexTable summariesTable;
079:
080: SummariesTableListener(FlexTable summariesTable) {
081: this .summariesTable = summariesTable;
082: }
083:
084: public void onCellClicked(SourcesTableEvents sender, int row,
085: int col) {
086: if (currentSelectedRow != -1) {
087: summariesTable.getRowFormatter().removeStyleName(
088: currentSelectedRow, "viewer-SelectedRow");
089: }
090: currentSelectedRow = row;
091: summariesTable.getRowFormatter().addStyleName(row,
092: "viewer-SelectedRow");
093: ReportSummary summary = (ReportSummary) summaries
094: .get(row - 1);
095: getReportDetails(summary.getId());
096: }
097: }
098:
099: private static final String baseUrl = GWT.getModuleBaseURL();
100:
101: private static final String imageServer = baseUrl + "test_images/";
102:
103: HTML detailsLabel;
104:
105: Report report;
106:
107: VerticalPanel reportPanel;
108:
109: ReportServerAsync reportServer;
110:
111: FlexTable reportTable;
112:
113: HTML statusLabel;
114:
115: List/* <ReportSummary> */summaries;
116:
117: VerticalPanel summariesPanel;
118:
119: FlexTable summariesTable;
120:
121: CellPanel topPanel;
122:
123: private int currentSelectedRow = -1;
124:
125: public void onModuleLoad() {
126:
127: init();
128:
129: // Asynchronously load the summaries
130: ServiceDefTarget target = (ServiceDefTarget) GWT
131: .create(ReportServer.class);
132: target.setServiceEntryPoint(GWT.getModuleBaseURL()
133: + "test_reports");
134: reportServer = (ReportServerAsync) target;
135:
136: reportServer.getReportSummaries(new AsyncCallback() {
137: public void onFailure(Throwable caught) {
138: String msg = "<p>" + caught.toString() + "</p>"
139: + "<p>Is your path to the reports correct?</p>";
140: statusLabel.setHTML(msg);
141: }
142:
143: public void onSuccess(Object result) {
144: summaries = (List/* <ReportSummary> */) result;
145: if (summaries != null) {
146: if (summaries.size() == 0) {
147: statusLabel
148: .setText("There are no benchmark reports available in this folder.");
149: }
150: Collections.sort(summaries, new Comparator() {
151: public int compare(Object o1, Object o2) {
152: ReportSummary r1 = (ReportSummary) o1;
153: ReportSummary r2 = (ReportSummary) o2;
154: return r2.getDate().compareTo(r1.getDate()); // most recent first
155: }
156: });
157: displaySummaries();
158: }
159: }
160: });
161: }
162:
163: private FlexTable createReportTable() {
164:
165: FlexTable topTable = new FlexTable();
166:
167: FlexTable tempReportTable = new FlexTable();
168: tempReportTable.setBorderWidth(1);
169: tempReportTable.setCellPadding(5);
170: tempReportTable.setWidget(0, 0, new Label("Date Created"));
171: tempReportTable.setWidget(0, 1, new Label("GWT Version"));
172:
173: if (report == null) {
174: tempReportTable.setWidget(1, 0, new Label(
175: "No currently selected report."));
176: tempReportTable.getFlexCellFormatter().setColSpan(1, 0, 3);
177: return tempReportTable;
178: }
179:
180: detailsLabel
181: .setHTML("<h3>" + report.getId() + " details </h3>");
182: tempReportTable.setWidget(1, 0, new Label(report
183: .getDateString()));
184: tempReportTable.setWidget(1, 1, new Label(report
185: .getGwtVersion()));
186:
187: // topTable.setWidget( 0, 0, tempReportTable );
188: int currentRow = 1;
189:
190: Collections.sort(report.getCategories(), new Comparator() {
191: public int compare(Object o1, Object o2) {
192: Category c1 = (Category) o1;
193: Category c2 = (Category) o2;
194: return c1.getName().compareTo(c2.getName());
195: }
196: }); // Should be done once in the RPC
197:
198: for (int i = 0; i < report.getCategories().size(); ++i) {
199: Category c = (Category) report.getCategories().get(i);
200:
201: if (!c.getName().equals("")) {
202: FlexTable categoryTable = new FlexTable();
203: categoryTable.setBorderWidth(0);
204: categoryTable.setCellPadding(5);
205: categoryTable.setText(0, 0, c.getName());
206: categoryTable.getFlexCellFormatter().setStyleName(0, 0,
207: "benchmark-category");
208:
209: categoryTable.setWidget(0, 1, new Label("Description"));
210: categoryTable.setWidget(1, 0, new Label(c.getName()));
211: categoryTable.setWidget(1, 1, new Label(c
212: .getDescription()));
213:
214: topTable.setWidget(currentRow++, 0, categoryTable);
215: }
216:
217: Collections.sort(c.getBenchmarks(), new Comparator() {
218: public int compare(Object o1, Object o2) {
219: Benchmark b1 = (Benchmark) o1;
220: Benchmark b2 = (Benchmark) o2;
221: return b1.getName().compareTo(b2.getName());
222: }
223: }); // Should be done once in the RPC
224:
225: for (int j = 0; j < c.getBenchmarks().size(); ++j) {
226: Benchmark benchmark = (Benchmark) c.getBenchmarks()
227: .get(j);
228:
229: FlexTable benchmarkTable = new FlexTable();
230: benchmarkTable.setBorderWidth(0);
231: benchmarkTable.setCellPadding(5);
232: benchmarkTable.setText(0, 0, benchmark.getName());
233: // benchmarkTable.setText(0, 1, benchmark.getDescription());
234: String codeHtml;
235: String sourceText = benchmark.getSourceCode();
236: if (sourceText != null) {
237: Element tempElem = DOM.createDiv();
238: DOM.setInnerText(tempElem, sourceText);
239: String escapedCodeHtml = DOM.getInnerHTML(tempElem);
240: codeHtml = "<pre>" + escapedCodeHtml + "</pre>";
241: } else {
242: codeHtml = "<i>(source not available)</i>";
243: }
244: benchmarkTable.setWidget(1, 0, new HTML(codeHtml));
245: benchmarkTable.getFlexCellFormatter().setStyleName(0,
246: 0, "benchmark-name");
247: // benchmarkTable.getFlexCellFormatter().setStyleName( 0, 1,
248: // "benchmark-description" );
249: benchmarkTable.getFlexCellFormatter().setStyleName(1,
250: 0, "benchmark-code");
251:
252: // TODO(tobyr) Provide detailed benchmark information.
253: // Following bits of commented code are steps in that direction.
254: /*
255: * benchmarkTable.setWidget( 0, 1, new Label( "Description"));
256: * benchmarkTable.setWidget( 0, 2, new Label( "Class Name"));
257: * benchmarkTable.setWidget( 0, 3, new Label( "Source Code"));
258: * benchmarkTable.setWidget( 1, 0, new Label( benchmark.getName()));
259: * benchmarkTable.setWidget( 1, 1, new Label(
260: * benchmark.getDescription())); benchmarkTable.setWidget( 1, 2, new
261: * Label( benchmark.getClassName())); benchmarkTable.setWidget( 1, 3,
262: * new HTML( "<pre>" + benchmark.getSourceCode() + "</pre>"));
263: */
264: topTable.setWidget(currentRow++, 0, benchmarkTable);
265:
266: FlexTable resultsTable = new FlexTable();
267: resultsTable.setBorderWidth(0);
268: resultsTable.setCellPadding(5);
269: FlexTable.FlexCellFormatter resultsFormatter = resultsTable
270: .getFlexCellFormatter();
271: topTable.setWidget(currentRow++, 0, resultsTable);
272:
273: Collections.sort(benchmark.getResults(),
274: new Comparator() {
275: public int compare(Object o1, Object o2) {
276: Result r1 = (Result) o1;
277: Result r2 = (Result) o2;
278: return r1.getAgent().compareTo(
279: r2.getAgent());
280: }
281: }); // Should be done once in the RPC
282:
283: final List trialsTables = new ArrayList();
284:
285: Result sampleResult = (Result) benchmark.getResults()
286: .get(0);
287: Trial sampleTrial = (Trial) sampleResult.getTrials()
288: .get(0);
289: int numVariables = sampleTrial.getVariables().size();
290: final MutableBool isVisible = new MutableBool(
291: numVariables > 2);
292: String buttonName = isVisible.value ? "Hide Data"
293: : "Show Data";
294:
295: Button visibilityButton = new Button(buttonName,
296: new ClickListener() {
297: public void onClick(Widget sender) {
298: isVisible.value = !isVisible.value;
299: for (int i = 0; i < trialsTables.size(); ++i) {
300: Widget w = (Widget) trialsTables
301: .get(i);
302: w.setVisible(isVisible.value);
303: }
304: String name = isVisible.value ? "Hide Data"
305: : "Show Data";
306: ((Button) sender).setText(name);
307: }
308: });
309:
310: for (int k = 0; k < benchmark.getResults().size(); ++k) {
311: Result result = (Result) benchmark.getResults()
312: .get(k);
313: List trials = result.getTrials();
314:
315: // Currently only support graphs for results of 2 variables or less
316: if (numVariables <= 2) {
317: resultsTable.setWidget(0, k, new Image(
318: getImageUrl(report.getId(),
319: c.getName(), benchmark
320: .getClassName(),
321: benchmark.getName(), result
322: .getAgent())));
323: } else {
324: if (k == 0) {
325: resultsTable
326: .setHTML(
327: 0,
328: k,
329: "<b>"
330: + BrowserInfo
331: .getBrowser(result
332: .getAgent())
333: + "</b><br><font size=\"-1\">(Graphs are not yet available "
334: + "for benchmarks with more than two parameters)</font>");
335: }
336: }
337:
338: /*
339: * FlexTable allTrialsTable = new FlexTable();
340: * allTrialsTable.setBorderWidth(1); allTrialsTable.setCellPadding(5);
341: * FlexTable.CellFormatter allTrialsFormatter = allTrialsTable
342: * .getFlexCellFormatter(); topTable.setWidget(currentRow++, 0,
343: * allTrialsTable); allTrialsTable.setWidget(0, k, trialsTable);
344: * allTrialsFormatter .setAlignment(0, k,
345: * HasHorizontalAlignment.ALIGN_CENTER,
346: * HasVerticalAlignment.ALIGN_TOP);
347: */
348:
349: resultsFormatter.setAlignment(2, k,
350: HasHorizontalAlignment.ALIGN_LEFT,
351: HasVerticalAlignment.ALIGN_TOP);
352:
353: // A table of straight data for all trials for an agent
354: FlexTable trialsTable = new FlexTable();
355: trialsTable.setVisible(isVisible.value);
356: trialsTables.add(trialsTable);
357: trialsTable.setBorderWidth(1);
358: trialsTable.setCellPadding(5);
359:
360: if (k == 0) {
361: resultsTable.setWidget(1, k, visibilityButton);
362: resultsFormatter.setColSpan(1, k, benchmark
363: .getResults().size());
364: resultsFormatter.setAlignment(1, k,
365: HasHorizontalAlignment.ALIGN_LEFT,
366: HasVerticalAlignment.ALIGN_MIDDLE);
367: }
368:
369: resultsTable.setWidget(2, k, trialsTable);
370:
371: int numTrials = trials.size();
372:
373: Map variables = sampleTrial.getVariables();
374: List variableNames = new ArrayList(variables
375: .keySet());
376: Collections.sort(variableNames);
377:
378: // Write out the variable column headers
379: for (int varIndex = 0; varIndex < numVariables; ++varIndex) {
380: String varName = (String) variableNames
381: .get(varIndex);
382: trialsTable.setHTML(0, varIndex, varName);
383: }
384:
385: // Timing header
386: trialsTable.setHTML(0, numVariables, "Timing (ms)");
387:
388: // Write out all the trial data
389: for (int l = 0; l < numTrials; ++l) {
390: Trial trial = (Trial) trials.get(l);
391:
392: // Write the variable values
393: for (int varIndex = 0; varIndex < numVariables; ++varIndex) {
394: String varName = (String) variableNames
395: .get(varIndex);
396: String varValue = (String) trial
397: .getVariables().get(varName);
398: trialsTable.setHTML(l + 1, varIndex,
399: varValue);
400: }
401:
402: // Write out the timing data
403: String data = null;
404: if (trial.getException() != null) {
405: data = trial.getException();
406: } else {
407: data = trial.getRunTimeMillis() + "";
408: }
409: trialsTable.setHTML(l + 1, numVariables, data);
410: }
411: }
412: }
413: }
414:
415: return topTable;
416: }
417:
418: private FlexTable createSummariesTable() {
419:
420: FlexTable tempSummariesTable = new FlexTable();
421: tempSummariesTable.addStyleName("viewer-List");
422: tempSummariesTable.setCellPadding(5);
423: tempSummariesTable.setBorderWidth(1);
424: tempSummariesTable.setCellSpacing(0);
425: tempSummariesTable.setWidget(0, 0, new Label("Report"));
426: tempSummariesTable.setWidget(0, 1, new Label("Date Created"));
427: tempSummariesTable.setWidget(0, 2, new Label("Tests"));
428: tempSummariesTable.getRowFormatter().addStyleName(0,
429: "viewer-ListHeader");
430:
431: if (summaries == null) {
432: tempSummariesTable.setWidget(1, 0, new Label(
433: "Fetching reports..."));
434: tempSummariesTable.getFlexCellFormatter().setColSpan(1, 0,
435: 4);
436: return tempSummariesTable;
437: }
438:
439: for (int i = 0; i < summaries.size(); ++i) {
440: ReportSummary summary = (ReportSummary) summaries.get(i);
441: int index = i + 1;
442: tempSummariesTable.setHTML(index, 0,
443: "<a href=\"javascript:void(0)\">" + summary.getId()
444: + "</a>");
445: tempSummariesTable.setWidget(index, 1, new Label(summary
446: .getDateString()));
447: tempSummariesTable.setWidget(index, 2, new Label(String
448: .valueOf(summary.getNumTests())));
449: }
450:
451: tempSummariesTable.addTableListener(new SummariesTableListener(
452: tempSummariesTable));
453:
454: return tempSummariesTable;
455: }
456:
457: private void displayReport() {
458: FlexTable table = createReportTable();
459: reportPanel.remove(reportTable);
460: reportTable = table;
461: reportPanel.insert(reportTable, 1);
462: }
463:
464: private void displaySummaries() {
465: FlexTable table = createSummariesTable();
466: summariesPanel.remove(summariesTable);
467: summariesTable = table;
468: summariesPanel.insert(summariesTable, 1);
469: }
470:
471: private String encode(String str) {
472: if (str.equals("")) {
473: return str;
474: }
475: return URL.encodeComponent(str);
476: }
477:
478: private String getImageUrl(String report, String category,
479: String testClass, String testMethod, String agent) {
480: return imageServer + encode(report) + "/" + encode(category)
481: + "/" + encode(testClass) + "/" + encode(testMethod)
482: + "/" + encode(agent);
483: }
484:
485: /**
486: * Loads report details asynchronously for a given report.
487: *
488: * @param id the non-null id of the report
489: */
490: private void getReportDetails(String id) {
491: statusLabel.setText("Retrieving the report...");
492: reportServer.getReport(id, new AsyncCallback() {
493: public void onFailure(Throwable caught) {
494: statusLabel.setText(caught.toString());
495: }
496:
497: public void onSuccess(Object result) {
498: report = (Report) result;
499: statusLabel
500: .setText("Finished fetching report details.");
501: displayReport();
502: }
503: });
504: }
505:
506: private void init() {
507: topPanel = new VerticalPanel();
508:
509: summariesPanel = new VerticalPanel();
510: summariesPanel.add(new HTML("<h3>Benchmark Reports</h3>"));
511: summariesTable = createSummariesTable();
512: summariesPanel.add(summariesTable);
513:
514: reportPanel = new VerticalPanel();
515: detailsLabel = new HTML("<h3>Report Details</h3>");
516: reportPanel.add(detailsLabel);
517: reportTable = createReportTable();
518: // reportPanel.add( reportTable );
519:
520: topPanel.add(summariesPanel);
521: CellPanel spacerPanel = new HorizontalPanel();
522: spacerPanel.setSpacing(10);
523: spacerPanel.add(new Label());
524: topPanel.add(spacerPanel);
525: topPanel.add(reportPanel);
526: final RootPanel root = RootPanel.get();
527:
528: root.add(topPanel);
529:
530: statusLabel = new HTML("Select a report.");
531: root.add(statusLabel);
532: }
533: }
|