8253543: sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java failed with "AssertionError: All pixels are not black"

Reviewed-by: serb
This commit is contained in:
Alexandre Iline 2020-09-30 01:27:30 +00:00
parent 5310d85809
commit ffc97ba585
4 changed files with 121 additions and 44 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -22,6 +22,7 @@
*/ */
import com.sun.swingset3.demos.button.ButtonDemo; import com.sun.swingset3.demos.button.ButtonDemo;
import org.jemmy2ext.JemmyExt;
import org.jtregext.GuiTestListener; import org.jtregext.GuiTestListener;
import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.ClassReference;
import org.netbeans.jemmy.ComponentChooser; import org.netbeans.jemmy.ComponentChooser;
@ -33,7 +34,11 @@ import org.testng.annotations.Listeners;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.awt.Component; import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot; import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import javax.swing.UIManager; import javax.swing.UIManager;
@ -72,10 +77,24 @@ public class ButtonDemoScreenshotTest {
UIManager.setLookAndFeel(lookAndFeel); UIManager.setLookAndFeel(lookAndFeel);
Robot rob = new Robot(); Robot rob = new Robot();
//capture some of the background
Dimension screeSize = Toolkit.getDefaultToolkit().getScreenSize();
Point screenCenter = new Point(screeSize.width / 2, screeSize.height / 2);
Rectangle center = new Rectangle(
screenCenter.x - 50, screenCenter.y - 50,
screenCenter.x + 50, screenCenter.y + 50);
BufferedImage background = rob.createScreenCapture(center);
new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication(); new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication();
JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE); JFrameOperator mainFrame = new JFrameOperator(DEMO_TITLE);
waitImageIsStill(rob, mainFrame); mainFrame.waitComponentShowing(true);
//make sure the frame is already painted
waitChangedImage(rob, () -> rob.createScreenCapture(center),
background, mainFrame.getTimeouts(), "background.png");
//make sure the frame is painted completely
waitStillImage(rob, mainFrame, "frame.png");
// Check all the buttons // Check all the buttons
for (int i : BUTTONS) { for (int i : BUTTONS) {
@ -83,7 +102,7 @@ public class ButtonDemoScreenshotTest {
} }
} }
private void checkButton(JFrameOperator jfo, int i, Robot rob) { private void checkButton(JFrameOperator jfo, int i, Robot rob) throws InterruptedException {
JButtonOperator button = new JButtonOperator(jfo, i); JButtonOperator button = new JButtonOperator(jfo, i);
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed //additional instrumentation for JDK-8198920. To be removed after the bug is fixed
@ -93,9 +112,8 @@ public class ButtonDemoScreenshotTest {
button.moveMouse(button.getCenterX(), button.getCenterY()); button.moveMouse(button.getCenterX(), button.getCenterY());
BufferedImage initialButtonImage = capture(rob, button); BufferedImage notPressed, pressed = null;
assertNotBlack(initialButtonImage); notPressed = waitStillImage(rob, button, "not-pressed-" + i + ".png");
save(initialButtonImage, "button" + i + ".png");
BufferedImage[] pressedImage = new BufferedImage[1]; BufferedImage[] pressedImage = new BufferedImage[1];
@ -108,22 +126,15 @@ public class ButtonDemoScreenshotTest {
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed //additional instrumentation for JDK-8198920. To be removed after the bug is fixed
button.getOutput().printTrace("JDK-8198920: Button press confirmed by " + System.currentTimeMillis()); button.getOutput().printTrace("JDK-8198920: Button press confirmed by " + System.currentTimeMillis());
//end of instrumentation for JDK-8198920 //end of instrumentation for JDK-8198920
button.waitState(new ComponentChooser() { waitChangedImage(rob, () -> capture(rob, button), notPressed,
public boolean checkComponent(Component c) { button.getTimeouts(), "pressed-" + i + ".png");
pressedImage[0] = capture(rob, button); pressed = waitStillImage(rob, button, "pressed.png");
assertNotBlack(pressedImage[0]);
return !sComparator.compare(initialButtonImage, pressedImage[0]);
}
public String getDescription() {
return "Button with new image";
}
});
} finally { } finally {
if (pressedImage[0] != null) {
save(pressedImage[0], "button" + i + "_pressed.png");
}
button.releaseMouse(); button.releaseMouse();
if(pressed != null) {
waitChangedImage(rob, () -> capture(rob, button), pressed,
button.getTimeouts(), "released-" + i + ".png");
}
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed //additional instrumentation for JDK-8198920. To be removed after the bug is fixed
button.getOutput().printTrace("JDK-8198920: Button released at " + System.currentTimeMillis()); button.getOutput().printTrace("JDK-8198920: Button released at " + System.currentTimeMillis());
try { try {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,8 +23,8 @@
import static com.sun.swingset3.demos.editorpane.EditorPaneDemo.DEMO_TITLE; import static com.sun.swingset3.demos.editorpane.EditorPaneDemo.DEMO_TITLE;
import static com.sun.swingset3.demos.editorpane.EditorPaneDemo.SOURCE_FILES; import static com.sun.swingset3.demos.editorpane.EditorPaneDemo.SOURCE_FILES;
import static org.jemmy2ext.JemmyExt.EXACT_STRING_COMPARATOR; import static org.jemmy2ext.JemmyExt.*;
import static org.jemmy2ext.JemmyExt.assertNotBlack; import static org.testng.Assert.assertFalse;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
@ -149,7 +149,8 @@ public class EditorPaneDemoTest {
final int xGap = 100, yGap = 40, columns = 2, rows = 5; final int xGap = 100, yGap = 40, columns = 2, rows = 5;
editorPaneOperator.waitState(comp -> { editorPaneOperator.waitState(comp -> {
BufferedImage capturedImage = ImageTool.getImage(imageRect); BufferedImage capturedImage = ImageTool.getImage(imageRect);
assertNotBlack(capturedImage); save(capturedImage, "editor.png");
assertFalse(isBlack(capturedImage), "image blackness");
int x = 0, y = 0, i = 0, j; int x = 0, y = 0, i = 0, j;
for (; i < columns; i++) { for (; i < columns; i++) {
x += xGap; x += xGap;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -56,9 +57,11 @@ import org.netbeans.jemmy.ComponentChooser;
import org.netbeans.jemmy.DefaultCharBindingMap; import org.netbeans.jemmy.DefaultCharBindingMap;
import org.netbeans.jemmy.QueueTool; import org.netbeans.jemmy.QueueTool;
import org.netbeans.jemmy.TimeoutExpiredException; import org.netbeans.jemmy.TimeoutExpiredException;
import org.netbeans.jemmy.Timeouts;
import org.netbeans.jemmy.Waitable; import org.netbeans.jemmy.Waitable;
import org.netbeans.jemmy.Waiter; import org.netbeans.jemmy.Waiter;
import org.netbeans.jemmy.drivers.scrolling.JSpinnerDriver; import org.netbeans.jemmy.drivers.scrolling.JSpinnerDriver;
import org.netbeans.jemmy.image.ImageComparator;
import org.netbeans.jemmy.image.StrictImageComparator; import org.netbeans.jemmy.image.StrictImageComparator;
import org.netbeans.jemmy.operators.ComponentOperator; import org.netbeans.jemmy.operators.ComponentOperator;
import org.netbeans.jemmy.operators.ContainerOperator; import org.netbeans.jemmy.operators.ContainerOperator;
@ -89,17 +92,13 @@ public class JemmyExt {
DefaultCharBindingMap.class DefaultCharBindingMap.class
}; };
public static void assertNotBlack(BufferedImage image) { /**
int w = image.getWidth(); * Checks if the image is complitely black.
int h = image.getHeight(); */
try { public static boolean isBlack(BufferedImage image) {
assertFalse("All pixels are not black", IntStream.range(0, w).parallel().allMatch(x return IntStream.range(0, image.getWidth()).parallel()
-> IntStream.range(0, h).allMatch(y -> (image.getRGB(x, y) & 0xffffff) == 0) .allMatch(x-> IntStream.range(0, image.getHeight())
)); .allMatch(y -> (image.getRGB(x, y) & 0xffffff) == 0));
} catch (Throwable t) {
save(image, "allPixelsAreBlack.png");
throw t;
}
} }
public static void waitArmed(JButtonOperator button) { public static void waitArmed(JButtonOperator button) {
@ -184,18 +183,46 @@ public class JemmyExt {
} }
} }
public static void waitImageIsStill(Robot rob, ComponentOperator operator) { /**
operator.waitState(new ComponentChooser() { * Waits for a screen area taken by a component to not be completely black rectangle.
* @return last (non-black) image
* @throws TimeoutExpiredException if the waiting is unsuccessful
*/
public static BufferedImage waitNotBlack(Robot rob, ComponentOperator operator, String imageName) {
class NonBlackImageChooser implements ComponentChooser {
private BufferedImage image = null;
@Override
public boolean checkComponent(Component comp) {
image = capture(rob, operator);
save(image, imageName);
return !isBlack(image);
}
@Override
public String getDescription() {
return "A non-black Image of " + operator;
}
}
NonBlackImageChooser chooser = new NonBlackImageChooser();
operator.waitState(chooser);
return chooser.image;
}
/**
* Waits for the displayed image to be still.
* @return last still image
* @throws TimeoutExpiredException if the waiting is unsuccessful
*/
public static BufferedImage waitStillImage(Robot rob, ComponentOperator operator, String imageName) {
operator.getTimeouts().setTimeout("Waiter.TimeDelta", 1000);
class StillImageChooser implements ComponentChooser {
private BufferedImage previousImage = null; private BufferedImage previousImage = null;
private int index = 0;
private final StrictImageComparator sComparator = new StrictImageComparator(); private final StrictImageComparator sComparator = new StrictImageComparator();
@Override @Override
public boolean checkComponent(Component comp) { public boolean checkComponent(Component comp) {
BufferedImage currentImage = capture(rob, operator); BufferedImage currentImage = capture(rob, operator);
save(currentImage, "waitImageIsStill" + index + ".png"); save(currentImage, imageName);
index++;
boolean compareResult = previousImage == null ? false : sComparator.compare(currentImage, previousImage); boolean compareResult = previousImage == null ? false : sComparator.compare(currentImage, previousImage);
previousImage = currentImage; previousImage = currentImage;
return compareResult; return compareResult;
@ -203,9 +230,46 @@ public class JemmyExt {
@Override @Override
public String getDescription() { public String getDescription() {
return "Image of " + operator + " is still"; return "A still image of " + operator;
} }
}); }
StillImageChooser chooser = new StillImageChooser();
operator.waitState(chooser);
return chooser.previousImage;
}
/**
* Waits for the displayed image to change.
* @param reference image to compare to
* @return last (changed) image
* @throws TimeoutExpiredException if the waiting is unsuccessful
*/
public static BufferedImage waitChangedImage(Robot rob,
Supplier<BufferedImage> supplier,
BufferedImage reference,
Timeouts timeouts,
String imageName) throws InterruptedException {
ImageComparator comparator = new StrictImageComparator();
class ImageWaitable implements Waitable {
BufferedImage image;
@Override
public Object actionProduced(Object obj) {
image = supplier.get();
save(image, imageName);
return comparator.compare(reference, image) ? null : image;
}
@Override
public String getDescription() {
return "Waiting screen image to change";
}
}
ImageWaitable waitable = new ImageWaitable();
Waiter waiter = new Waiter(waitable);
waiter.setTimeouts(timeouts);
waiter.waitAction(null);
return waitable.image;
} }
private static class ThrowableHolder { private static class ThrowableHolder {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -218,6 +218,7 @@ public final class ButtonDemo extends JPanel {
JFrame frame = new JFrame(DEMO_TITLE); JFrame frame = new JFrame(DEMO_TITLE);
frame.add(buttonDemo); frame.add(buttonDemo);
frame.pack(); frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true); frame.setVisible(true);
}); });
} }