8374754: jtreg failure handler - replace inline javascript and inline event handlers with same origin javascript files

Reviewed-by: erikj
This commit is contained in:
Jaikiran Pai 2026-01-10 02:17:37 +00:00
parent 0537a3fae9
commit 657d5f77f4
4 changed files with 121 additions and 62 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,19 +23,50 @@
package jdk.test.failurehandler;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
public class HtmlPage implements AutoCloseable {
static final String STYLE_SHEET_FILENAME = "failure-handler-style.css";
static final String SCRIPT_FILENAME = "failure-handler-script.js";
private final PrintWriter writer;
private final HtmlSection rootSection;
public HtmlPage(PrintWriter writer) {
Objects.requireNonNull(writer, "writer cannot be null");
this.writer = writer;
/**
* Constructs a {@code HtmlPage}
*
* @param dir The directory into which the HTML file and related resources will be created
* @param htmlFileName The HTML file name
* @param append if {@code true} then the content will be appended to the file represented
* by the {@code htmlFileName}, else the {@code htmlFileName} will be overwritten
* with the new content
* @throws IllegalArgumentException if {@code dir} is not a directory or if the
* {@code htmlFileName} is {@linkplain String#isBlank() blank}
* @throws IOException if there is an error constructing file resource(s) for this HTML page
*/
public HtmlPage(final Path dir, final String htmlFileName, final boolean append)
throws IOException {
Objects.requireNonNull(dir, "directory cannot be null");
Objects.requireNonNull(htmlFileName, "HTML file name cannot be null");
if (!Files.isDirectory(dir)) {
throw new IllegalArgumentException(dir + " is not a directory");
}
if (htmlFileName.isBlank()) {
throw new IllegalArgumentException("HTML file name cannot be blank");
}
final FileWriter fileWriter = new FileWriter(dir.resolve(htmlFileName).toFile(), append);
this.writer = new PrintWriter(fileWriter, true);
createScriptFile(dir);
createStyleSheetFile(dir);
rootSection = new HtmlSection(writer);
}
@Override
public void close() {
writer.close();
@ -44,4 +75,71 @@ public class HtmlPage implements AutoCloseable {
public HtmlSection getRootSection() {
return rootSection;
}
private static void createStyleSheetFile(final Path destDir) throws IOException {
final Path styleSheet = destDir.resolve(STYLE_SHEET_FILENAME);
if (Files.exists(styleSheet)) {
return;
}
final String content = """
div { display:none;}
""";
Files.writeString(styleSheet, content);
}
private static void createScriptFile(final Path destDir) throws IOException {
final Path script = destDir.resolve(SCRIPT_FILENAME);
if (Files.exists(script)) {
return;
}
final String content = """
function doShow(e) {
while (e != null) {
if (e.tagName == 'DIV') {
e.style.display = 'block';
}
e = e.parentNode;
}
}
function showHandler(event) {
elementId = this.dataset.show;
elementToShow = document.getElementById(elementId);
doShow(elementToShow);
}
function toggleHandler(event) {
toggleElementId = this.dataset.toggle;
elementToToggle = document.getElementById(toggleElementId);
d = elementToToggle.style.display;
if (d == 'block') {
elementToToggle.style.display = 'none';
} else {
doShow(elementToToggle);
}
}
function bodyLoadHandler() {
const index = location.href.indexOf("#");
if (index != -1) {
doShow(document.getElementById(location.href.substring(index + 1)));
}
// elements that require the "toggleHandler" function to be registered
// as an event handler for the onclick event
const requiringToggleHandler = document.querySelectorAll("[data-toggle]");
for (const e of requiringToggleHandler) {
e.addEventListener("click", toggleHandler);
}
// elements that require the "showHandler" function to be registered
// as an event handler for the onclick event
const requiringShowHandler = document.querySelectorAll("[data-show]");
for (const e of requiringShowHandler) {
e.addEventListener("click", showHandler);
}
}
// register a onload event handler
window.addEventListener("DOMContentLoaded", bodyLoadHandler);
""";
Files.writeString(script, content);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -57,41 +57,15 @@ public class HtmlSection {
if (rootSection == null) {
this.rootSection = this;
this.pw.println("<html>");
this.pw.println("<style>\n"
+ "div { display:none;}\n"
+ "</style>\n"
+ "\n"
+ "<script>\n"
+ "function show(e) {\n"
+ " while (e != null) {\n"
+ " if (e.tagName == 'DIV') {\n"
+ " e.style.display = 'block';\n"
+ " }\n"
+ " e = e.parentNode;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "function toggle(id) {\n"
+ " e = document.getElementById(id);\n"
+ " d = e.style.display;\n"
+ " if (d == 'block') {\n"
+ " e.style.display = 'none';\n"
+ " } else {\n"
+ " show(e);\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "function main() {\n"
+ " index = location.href.indexOf(\"#\");"
+ " if (index != -1) {\n"
+ " show(document.getElementById(location.href.substring(index + 1)));\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "</script>\n"
+ "</head>");
this.pw.println("<body onload='main()'>");
this.pw.println("<head>");
this.pw.println(
"<link href=\"" + HtmlPage.STYLE_SHEET_FILENAME + "\" rel=\"stylesheet\" type=\"text/css\" />");
this.pw.println(
"<script src=\"" + HtmlPage.SCRIPT_FILENAME + "\" type=\"text/javascript\" ></script>");
this.pw.println("</head>");
this.pw.println("<body>");
} else {
this.rootSection = rootSection;
this.pw.print("<ul>");
@ -146,7 +120,7 @@ public class HtmlSection {
} else if (child != null) {
path = String.format("%s.%s", path, child);
}
pw.printf("<a href=\"#%1$s\" onclick=\"show(document.getElementById('%1$s')); return true;\">%2$s</a>%n",
pw.printf("<a href=\"#%1$s\" data-show=\"%1$s\" >%2$s</a>%n",
path, name);
}
@ -188,7 +162,7 @@ public class HtmlSection {
: String.format("%s.%s", parent.id, name),
name, rootSection);
this.parent = parent;
pw.printf("<li><a name='%1$s'/><a href='#%1$s' onclick=\"toggle('%1$s'); return false;\">%2$s</a><div id='%1$s'><code><pre>",
pw.printf("<li><a name='%1$s'/><a href='#%1$s' data-toggle=\"%1$s\" >%2$s</a><div id='%1$s'><code><pre>",
id, name);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -105,9 +105,7 @@ public class GatherDiagnosticInfoObserver implements Harness.Observer {
private void gatherCoreInfo(Path workDir, String name, Path core, PrintWriter log,
CoreInfoGatherer gatherer) {
File output = workDir.resolve(CORES_OUTPUT).toFile();
try (HtmlPage html = new HtmlPage(new PrintWriter(
new FileWriter(output, true), true))) {
try (HtmlPage html = new HtmlPage(workDir, CORES_OUTPUT, true)) {
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
gatherer.gatherCoreInfo(html.getRootSection(), core);
@ -121,9 +119,7 @@ public class GatherDiagnosticInfoObserver implements Harness.Observer {
private void gatherEnvInfo(Path workDir, String name, PrintWriter log,
EnvironmentInfoGatherer gatherer) {
File output = workDir.resolve(ENVIRONMENT_OUTPUT).toFile();
try (HtmlPage html = new HtmlPage(new PrintWriter(
new FileWriter(output, true), true))) {
try (HtmlPage html = new HtmlPage(workDir, ENVIRONMENT_OUTPUT, true)) {
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
gatherer.gatherEnvironmentInfo(html.getRootSection());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -69,16 +69,7 @@ public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
}
try {
actionsLog.printf("%s ---%n", name);
File output = workDir.resolve(OUTPUT_FILENAME).toFile();
try {
PrintWriter pw = new PrintWriter(new FileWriter(output, true), true);
runGatherer(name, workDir, actionsLog, pw, pid);
} catch (IOException e) {
actionsLog.printf("IOException: cannot open output file[%s] : %s",
output, e.getMessage());
e.printStackTrace(actionsLog);
}
runGatherer(name, actionsLog, pid);
} finally {
actionsLog.printf("--- %s%n", name);
// don't close jtreg log
@ -90,9 +81,9 @@ public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
}
}
private void runGatherer(String name, Path workDir, PrintWriter log,
PrintWriter out, long pid) {
try (HtmlPage html = new HtmlPage(out)) {
private void runGatherer(String name, PrintWriter log, long pid) {
Path workDir = outputDir.toPath();
try (HtmlPage html = new HtmlPage(workDir, OUTPUT_FILENAME, true)) {
ProcessInfoGatherer gatherer = new GathererFactory(
OS.current().family,
workDir, log, testJdk.toPath()).getProcessInfoGatherer();