Skip to content

Commit

Permalink
8316017: Refactor timeout handler in PassFailJFrame
Browse files Browse the repository at this point in the history
Backport-of: 3abd772672a4dfd984459283235f3b1d8fb28a49
  • Loading branch information
Andrew Lu committed Apr 18, 2024
1 parent 85d891b commit 583477f
Showing 1 changed file with 116 additions and 57 deletions.
173 changes: 116 additions & 57 deletions test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
Expand Down Expand Up @@ -159,14 +161,26 @@ public final class PassFailJFrame {
* Prefix for the user-provided failure reason.
*/
private static final String FAILURE_REASON = "Failure Reason:\n";
/**
* The failure reason message when the user didn't provide one.
*/
private static final String EMPTY_REASON = "(no reason provided)";

private static final List<Window> windowList = new ArrayList<>();
private static final Timer timer = new Timer(0, null);

private static final CountDownLatch latch = new CountDownLatch(1);

private static volatile boolean failed;
private static volatile boolean timeout;
private static volatile String testFailedReason;
private static TimeoutHandler timeoutHandler;

/**
* The description of why the test fails.
* <p>
* Note: <strong>do not use</strong> this field directly,
* use the {@link #setFailureReason(String) setFailureReason} and
* {@link #getFailureReason() getFailureReason} methods to modify and
* to read its value.
*/
private static String failureReason;

private static final AtomicInteger imgCounter = new AtomicInteger(0);

Expand Down Expand Up @@ -327,42 +341,27 @@ private static void createUI(String title, String instructions,
frame = new JFrame(title);
frame.setLayout(new BorderLayout());

JLabel testTimeoutLabel = new JLabel("", JLabel.CENTER);
timeoutHandler = new TimeoutHandler(testTimeoutLabel, testTimeOut);
frame.add(testTimeoutLabel, BorderLayout.NORTH);

JTextComponent text = instructions.startsWith("<html>")
? configureHTML(instructions, rows, columns)
: configurePlainText(instructions, rows, columns);
text.setEditable(false);

long tTimeout = TimeUnit.MINUTES.toMillis(testTimeOut);

final JLabel testTimeoutLabel = new JLabel(String.format("Test " +
"timeout: %s", convertMillisToTimeStr(tTimeout)), JLabel.CENTER);
final long startTime = System.currentTimeMillis();
timer.setDelay(1000);
timer.addActionListener((e) -> {
long leftTime = tTimeout - (System.currentTimeMillis() - startTime);
if ((leftTime < 0) || failed) {
timer.stop();
testFailedReason = FAILURE_REASON
+ "Timeout User did not perform testing.";
timeout = true;
latch.countDown();
}
testTimeoutLabel.setText(String.format("Test timeout: %s", convertMillisToTimeStr(leftTime)));
});
timer.start();
frame.add(testTimeoutLabel, BorderLayout.NORTH);
frame.add(new JScrollPane(text), BorderLayout.CENTER);

JButton btnPass = new JButton("Pass");
btnPass.addActionListener((e) -> {
latch.countDown();
timer.stop();
timeoutHandler.stop();
});

JButton btnFail = new JButton("Fail");
btnFail.addActionListener((e) -> {
getFailureReason();
timer.stop();
requestFailureReason();
timeoutHandler.stop();
});

JPanel buttonsPanel = new JPanel();
Expand Down Expand Up @@ -506,12 +505,58 @@ public interface InstructionUI {
}


private static final class TimeoutHandler implements ActionListener {
private final long endTime;

private final Timer timer;

private final JLabel label;

public TimeoutHandler(final JLabel label, final long testTimeOut) {
endTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(testTimeOut);

this.label = label;

timer = new Timer(1000, this);
timer.start();
updateTime(testTimeOut);
}

@Override
public void actionPerformed(ActionEvent e) {
long leftTime = endTime - System.currentTimeMillis();
if (leftTime < 0) {
timer.stop();
setFailureReason(FAILURE_REASON
+ "Timeout - User did not perform testing.");
latch.countDown();
}
updateTime(leftTime);
}

private void updateTime(final long leftTime) {
if (leftTime < 0) {
label.setText("Test timeout: 00:00:00");
return;
}
long hours = leftTime / 3_600_000;
long minutes = (leftTime - hours * 3_600_000) / 60_000;
long seconds = (leftTime - hours * 3_600_000 - minutes * 60_000) / 1_000;
label.setText(String.format("Test timeout: %02d:%02d:%02d",
hours, minutes, seconds));
}

public void stop() {
timer.stop();
}
}


private static final class WindowClosingHandler extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
testFailedReason = FAILURE_REASON
+ "User closed a window";
failed = true;
setFailureReason(FAILURE_REASON
+ "User closed a window");
latch.countDown();
}
}
Expand Down Expand Up @@ -605,14 +650,28 @@ private static void captureScreen(CaptureType type) {
JOptionPane.INFORMATION_MESSAGE);
}

private static String convertMillisToTimeStr(long millis) {
if (millis < 0) {
return "00:00:00";
/**
* Sets the failure reason which describes why the test fails.
* This method ensures the {@code failureReason} field does not change
* after it's set to a non-{@code null} value.
* @param reason the description of why the test fails
* @throws IllegalArgumentException if the {@code reason} parameter
* is {@code null}
*/
private static synchronized void setFailureReason(final String reason) {
if (reason == null) {
throw new IllegalArgumentException("The failure reason must not be null");
}
long hours = millis / 3_600_000;
long minutes = (millis - hours * 3_600_000) / 60_000;
long seconds = (millis - hours * 3_600_000 - minutes * 60_000) / 1_000;
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
if (failureReason == null) {
failureReason = reason;
}
}

/**
* {@return the description of why the test fails}
*/
private static synchronized String getFailureReason() {
return failureReason;
}

/**
Expand All @@ -633,38 +692,28 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti
latch.await();
invokeAndWait(PassFailJFrame::disposeWindows);

if (timeout) {
throw new RuntimeException(testFailedReason);
}

if (failed) {
throw new RuntimeException("Test failed! : " + testFailedReason);
String failure = getFailureReason();
if (failure != null) {
throw new RuntimeException(failure);
}

System.out.println("Test passed!");
}

/**
* Disposes of all the windows. It disposes of the test instruction frame
* and all other windows added via {@link #addTestWindow(Window)}.
*/
private static synchronized void disposeWindows() {
windowList.forEach(Window::dispose);
}

/**
* Read the test failure reason and add the reason to the test result
* example in the jtreg .jtr file.
* Requests the description of the test failure reason from the tester.
*/
private static void getFailureReason() {
private static void requestFailureReason() {
final JDialog dialog = new JDialog(frame, "Test Failure ", true);
dialog.setTitle("Failure reason");
JPanel jPanel = new JPanel(new BorderLayout());
JTextArea jTextArea = new JTextArea(5, 20);

JButton okButton = new JButton("OK");
okButton.addActionListener((ae) -> {
testFailedReason = FAILURE_REASON + jTextArea.getText();
String text = jTextArea.getText();
setFailureReason(FAILURE_REASON
+ (!text.isEmpty() ? text : EMPTY_REASON));
dialog.setVisible(false);
});

Expand All @@ -679,11 +728,22 @@ private static void getFailureReason() {
dialog.pack();
dialog.setVisible(true);

failed = true;
// Ensure the test fails even if the dialog is closed
// without clicking the OK button
setFailureReason(FAILURE_REASON + EMPTY_REASON);

dialog.dispose();
latch.countDown();
}

/**
* Disposes of all the windows. It disposes of the test instruction frame
* and all other windows added via {@link #addTestWindow(Window)}.
*/
private static synchronized void disposeWindows() {
windowList.forEach(Window::dispose);
}

private static void positionInstructionFrame(final Position position) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

Expand Down Expand Up @@ -876,8 +936,7 @@ public static void forceFail() {
* @param reason the reason why the test is failed
*/
public static void forceFail(String reason) {
failed = true;
testFailedReason = FAILURE_REASON + reason;
setFailureReason(FAILURE_REASON + reason);
latch.countDown();
}

Expand Down

1 comment on commit 583477f

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.