RFR: 8283712 : Create a manual test framework class [v4]

Alexey Ivanov aivanov at openjdk.java.net
Tue Apr 5 21:01:45 UTC 2022


On Mon, 28 Mar 2022 17:06:41 GMT, lawrence.andrews <duke at openjdk.java.net> wrote:

>> We need a common manual test framework code that can be shared across all the client manual test. This framework class should have the following
>> 1) Frame which contains test instruction .
>> 2) Pass & Fail button so that user can mark the test pass or fail
>> 3) Upon failing the test user should be able to elaborate why the test failed and this can be added to the test failure. 
>> 4) Disposing of all the frames.
>> 
>> @aivanov-jdk
>
> lawrence.andrews has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Dispose the Frame based in EDT

The ability to have instructions as HTML text (hosted in `JEditorPane`) would make the solution more flexible. Obviously, we shouldn't implement everything we can think of. Yet we should still think about possible advanced features.

test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java line 48:

> 46:     static PrintLatinCJKTest testInstance = new PrintLatinCJKTest();
> 47:     static String info =
> 48:        "To test 8022536, if a remote printer is the system default, \n"+

It's unclear to me whether a remote printer is required for the test.

We should probably clarify the test instructions. Yet I haven't looked into the bug for which the test was written.

test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java line 91:

> 89:     public static void main(String[] args) throws InterruptedException, InvocationTargetException {
> 90:         PassFailJFrame passFailJFrame = new PassFailJFrame("Test Instruction" +
> 91:                 "Frame", info, 7, 30, 3);

This already breaks the threading rules of Swing: every access to Swing components must be done on EDT.

The thing is `PassFailJFrame` extends `JFrame`, thus super constructor (the inherited one from `JFrame`) will be called on main thread. It's not what we want, isn't it?

I'd suggest not to extend `JFrame` at all. We're not developing new functionality to `JFrame` but build UI using Swing components.

As a benefit, you'll be able to initialise GUI on EDT if the constructor is called on another thread.

I support Phil that the framework should document threading and mark methods which are allowed to be called on any thread. Probably all the methods should allow for it.

test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java line 93:

> 91:                 "Frame", info, 7, 30, 3);
> 92:         PrintLatinCJKTest.showFrame();
> 93:         passFailJFrame.awaitAndCheck();

I believe `awaitAndCheck()` is the method that must be called from the main thread. It waits until the test is completed.

If it was called on EDT, it would block the event queue.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 42:

> 40:     private final CountDownLatch latch = new CountDownLatch(1);
> 41:     private boolean failed = false;
> 42:     private String testFailedReason;

These two are accessed by EDT and main thread. The boolean field should be declared `volatile` or use `AtomicBoolean`. The same applies for `testFailedReason`.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 45:

> 43:     private JTextArea instructionsText;
> 44:     private final int maxRowLength;
> 45:     private final int maxStringLength;

These aren't needed as fields, they're used only to create instruction text.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 65:

> 63:      * @throws HeadlessException
> 64:      * @throws InterruptedException
> 65:      * @throws InvocationTargetException

I suggest adding generic descriptions of exceptions to avoid IDE warnings.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 78:

> 76:         invokeAndWait(() -> {
> 77:             setLayout(new BorderLayout());
> 78:             instructionsText = new JTextArea(instructions, maxRowLength, maxStringLength);

You could use line wrap functionality of JTextArea to avoid adding `\n` to the instructions.

Consider placing it into JScrollPane for flexibility, though not required.

`maxRowLength` is actually the number of rows (lines), and `maxStringLength` is the number of columns. These parameters are used to calculate the preferred size of the text area, they don't limit the text the component can store.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 80:

> 78:             instructionsText = new JTextArea(instructions, maxRowLength, maxStringLength);
> 79:             instructionsText.setEditable(false);
> 80:             instructionsText.setFocusable(false);

I think leaving the instructions focusable won't hurt. It would allow selecting text (and copying it) if the tester needs it for whatever reason.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 95:

> 93:             add(buttonsPanel, BorderLayout.SOUTH);
> 94:             pack();
> 95:             setLocation(10, 10);

The instruction window should probably be placed around the centre of the screen.

The class should provide a method to position a secondary frame near the instruction frame so that both frames don't overlap.

A possibility to include test UI to the instructions could be beneficial in some cases: dealing with one window is easier than with several ones. It's just a suggestion for further improvement though.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 96:

> 94:             pack();
> 95:             setLocation(10, 10);
> 96:             setVisible(true);

Closing the window with Close button should also fail the test, now it doesn't.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 125:

> 123:     public void getFailureReason() {
> 124:         final JDialog dialog = new JDialog();
> 125:         dialog.setTitle("Failure reason");

I suggest making the dialog Toolkit-modal so that only the dialog can be interacted with.


        final JDialog dialog = new JDialog(this, "Failure reason", TOOLKIT_MODAL);


At this time, I can click Fail again several times and I'll have several dialogs open. I can also click Pass which completes the test and disposes of the dialogs.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 135:

> 133:             dialog.dispose();
> 134:             latch.countDown();
> 135:         });

This doesn't handle closing the dialog via Close button or Esc. I believe it should also do everything but copying the entered text.

test/jdk/java/awt/regtesthelpers/PassFailJFrame.java line 144:

> 142:         jPanel.add(okayBtnPanel, BorderLayout.SOUTH);
> 143:         dialog.add(jPanel);
> 144:         dialog.setLocationRelativeTo(null);

We should probably position the dialog relatively to the frame or the Fail button.

Now the frame is displayed on the left edge of the screen but the dialog is in the centre of the screen as if they're unrelated.

-------------

PR: https://git.openjdk.java.net/jdk/pull/7966



More information about the client-libs-dev mailing list