8221263: [TEST_BUG] RemotePrinterStatusRefresh test is hard to use

Reviewed-by: serb, prr
This commit is contained in:
Alexey Ivanov 2019-04-09 08:50:08 +01:00
parent 7a62c46781
commit 9972a6fdaa

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019, 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
@ -21,244 +21,480 @@
* questions.
*/
/**
/*
* @test
* @bug 8153732 8212202
* @bug 8153732 8212202 8221263 8221412
* @requires (os.family == "Windows")
* @summary Windows remote printer changes do not reflect in lookupPrintServices()
* @ignore Requires a new network printer installation\removal
* @run main/manual RemotePrinterStatusRefresh
*/
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.print.PrinterJob;
import javax.print.PrintService;
import javax.swing.Timer;
public class RemotePrinterStatusRefresh
{
private static TestUI test = null;
public static void main(String args[]) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
import static javax.swing.BorderFactory.createTitledBorder;
// Test UI creation
test = new TestUI(latch);
public class RemotePrinterStatusRefresh extends WindowAdapter {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
try {
test.createUI();
} catch (Exception e) {
throw new RuntimeException(e);
}
private static final long refreshTime = getRefreshTime();
private static final long TIMEOUT = refreshTime * 4 + 60;
private static final CountDownLatch latch = new CountDownLatch(1);
private static volatile RemotePrinterStatusRefresh test;
private volatile boolean testResult;
private volatile boolean testTimedOut;
private final JFrame frame;
private JButton refreshButton;
private JButton passButton;
private JButton failButton;
private final ServiceItemListModel beforeList;
private final ServiceItemListModel afterList;
private JTextField nextRefresh;
private JTextField timeLeft;
private final Timer timer;
private final long startTime;
private static class ServiceItem {
private enum State {
REMOVED, UNCHANGED, ADDED
}
final String name;
State state;
private ServiceItem(final String name) {
this.name = name;
state = State.UNCHANGED;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof ServiceItem)
&& ((ServiceItem) obj).name.equals(name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
private static class ServiceItemListModel extends AbstractListModel<ServiceItem> {
private final List<ServiceItem> list;
private ServiceItemListModel(List<ServiceItem> list) {
this.list = list;
}
@Override
public int getSize() {
return list.size();
}
@Override
public ServiceItem getElementAt(int index) {
return list.get(index);
}
private void refreshList(List<ServiceItem> newList) {
list.clear();
list.addAll(newList);
fireChanged();
}
private void fireChanged() {
fireContentsChanged(this, 0, list.size() - 1);
}
}
private static class ServiceItemListRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Component component =
super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
switch (((ServiceItem) value).state) {
case REMOVED:
component.setBackground(Color.RED);
component.setForeground(Color.WHITE);
break;
case ADDED:
component.setBackground(Color.GREEN);
component.setForeground(Color.BLACK);
break;
case UNCHANGED:
default:
break;
}
});
// RemotePrinterStatusRefresh creation
RemotePrinterStatusRefresh RemotePrinterStatusRefresh = new RemotePrinterStatusRefresh();
SwingUtilities.invokeAndWait(() -> {
collectPrintersList(test.resultsTextArea, true);
});
// 8 min = 480000 msec
if(waitForFlag(480000)) {
SwingUtilities.invokeAndWait(() -> {
collectPrintersList(test.resultsTextArea, false);
});
} else {
dispose();
throw new RuntimeException("No new network printer got added/removed!! Test timed out!!");
}
boolean status = latch.await(1, TimeUnit.MINUTES);
if (!status) {
dispose();
throw new RuntimeException("Test timed out.");
}
if (test.testResult == false) {
dispose();
throw new RuntimeException("Test Failed.");
}
dispose();
}
public static void dispose() throws Exception {
SwingUtilities.invokeAndWait(() -> {
test.disposeUI();
});
}
public static boolean waitForFlag (long maxTimeoutInMsec) throws Exception {
while(!test.isAdded && maxTimeoutInMsec > 0) {
maxTimeoutInMsec -= 100;
Thread.sleep(100);
}
if(maxTimeoutInMsec <= 0) {
return false;
} else {
return true;
return component;
}
}
private static void collectPrintersList(JTextArea textArea, boolean before) {
if(before) {
System.out.println("List of printers(before): ");
textArea.setText("List of printers(before): \n");
for (PrintService printServiceBefore : PrinterJob.lookupPrintServices()) {
System.out.println(printServiceBefore);
textArea.append(printServiceBefore.toString());
textArea.append("\n");
}
} else {
textArea.append("\n");
System.out.println("List of printers(after): ");
textArea.append("List of printers(after): \n");
for (PrintService printServiceAfter : PrinterJob.lookupPrintServices()) {
System.out.println(printServiceAfter);
textArea.append(printServiceAfter.toString());
textArea.append("\n");
}
private static final String INSTRUCTIONS_TEXT =
"Please follow the steps for this manual test:\n"
+ "Step 0: \"Before\" list is populated with currently "
+ "configured printers.\n"
+ "Step 1: Add or Remove a network printer using "
+ "Windows Control Panel.\n"
+ "Step 2: Wait for 4 minutes after adding or removing.\n"
+ " \"Next printer refresh in\" gives you a "
+ "rough estimation on when update will happen.\n"
+ "Step 3: Click Refresh."
+ "\"After\" list is populated with updated list "
+ "of printers.\n"
+ "Step 4: Compare the list of printers in \"Before\" and "
+ "\"After\" lists.\n"
+ " Added printers are highlighted with "
+ "green color, removed ones \u2014 with "
+ "red color.\n"
+ "Step 5: Click Pass if the list of printers is correctly "
+ "updated.\n"
+ "Step 6: If the list is not updated, wait for another "
+ "4 minutes, and then click Refresh again.\n"
+ "Step 7: If the list does not update, click Fail.\n"
+ "\n"
+ "You have to click Refresh to enable Pass and Fail buttons. "
+ "If no button is pressed,\n"
+ "the test will time out. "
+ "Closing the window also fails the test.";
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(RemotePrinterStatusRefresh::createUI);
latch.await();
if (!test.testResult) {
throw new RuntimeException("Test failed"
+ (test.testTimedOut ? " because of time out" : ""));
}
}
}
class TestUI {
private static JFrame mainFrame;
private static JPanel mainControlPanel;
private static JTextArea instructionTextArea;
private static JPanel resultButtonPanel;
private static JButton passButton;
private static JButton failButton;
private static JButton addedButton;
private static JPanel testPanel;
private static JButton testButton;
private static JLabel buttonPressCountLabel;
private static GridBagLayout layout;
private final CountDownLatch latch;
public boolean testResult = false;
public volatile Boolean isAdded = false;
public static JTextArea resultsTextArea;
public TestUI(CountDownLatch latch) throws Exception {
this.latch = latch;
private static long getRefreshTime() {
String refreshTime =
System.getProperty("sun.java2d.print.minRefreshTime", "240");
try {
long value = Long.parseLong(refreshTime);
return value < 240L ? 240L : value;
} catch (NumberFormatException e) {
return 240L;
}
}
public final void createUI() {
mainFrame = new JFrame("RemotePrinterStatusRefresh");
layout = new GridBagLayout();
mainControlPanel = new JPanel(layout);
resultButtonPanel = new JPanel(layout);
testPanel = new JPanel(layout);
GridBagConstraints gbc = new GridBagConstraints();
private static void createUI() {
test = new RemotePrinterStatusRefresh();
}
// Create Test instructions
String instructions
= "This test displays the current list of printers(before) attached to \n"
+ "this computer in the results panel.\n\n"
+ "Please follow the below steps for this manual test\n"
+ "--------------------------------------------------------------------\n"
+ "Step 1: Add/Remove a new network printer and Wait for 4 minutes after adding/removing\n"
+ "Step 2: Then click on 'Printer Added/Removed' button\n"
+ "Step 2: Once the new network printer is added/removed, see if it is \n"
+ " the same as displayed/not displayed in the results panel.\n"
+ "Step 3: If displayed/not displayed, then click 'Pass' else click on 'Fail' button";
private RemotePrinterStatusRefresh() {
frame = new JFrame("RemotePrinterStatusRefresh");
frame.addWindowListener(this);
instructionTextArea = new JTextArea();
instructionTextArea.setText(instructions);
instructionTextArea.setEditable(false);
instructionTextArea.setBorder(BorderFactory.
createTitledBorder("Test Instructions"));
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainControlPanel.add(instructionTextArea, gbc);
JPanel northPanel = new JPanel(new BorderLayout());
northPanel.add(createInfoPanel(), BorderLayout.NORTH);
northPanel.add(createInstructionsPanel(), BorderLayout.SOUTH);
gbc.gridx = 0;
gbc.gridy = 1;
testPanel.add(Box.createVerticalStrut(50));
mainControlPanel.add(testPanel);
addedButton = new JButton("Printer Added/Removed");
addedButton.setActionCommand("Added");
addedButton.addActionListener((ActionEvent e) -> {
System.out.println("Added Button pressed!");
isAdded = true;
});
beforeList = new ServiceItemListModel(
Collections.unmodifiableList(collectPrinterList()));
afterList = new ServiceItemListModel(new ArrayList<>());
logList("Before:", beforeList.list);
JPanel listPanel = new JPanel(new GridLayout(1, 2));
listPanel.setBorder(createTitledBorder("Print Services"));
listPanel.add(createListPanel(beforeList, "Before:", 'b'));
listPanel.add(createListPanel(afterList, "After:", 'a'));
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(northPanel, BorderLayout.NORTH);
mainPanel.add(listPanel, BorderLayout.CENTER);
mainPanel.add(createButtonPanel(), BorderLayout.SOUTH);
frame.add(mainPanel);
frame.pack();
refreshButton.requestFocusInWindow();
frame.setVisible(true);
timer = new Timer(1000, this::updateTimeLeft);
timer.start();
startTime = System.currentTimeMillis();
updateTimeLeft(null);
}
private JPanel createInfoPanel() {
JLabel javaLabel = new JLabel("Java version:");
JTextField javaVersion =
new JTextField(System.getProperty("java.runtime.version"));
javaVersion.setEditable(false);
javaLabel.setLabelFor(javaVersion);
JLabel refreshTimeLabel = new JLabel("Refresh interval:");
long minutes = refreshTime / 60;
long seconds = refreshTime % 60;
String interval = String.format("%1$d seconds%2$s",
refreshTime,
minutes > 0
? String.format(" (%1$d %2$s%3$s)",
minutes,
minutes > 1 ? "minutes" : "minute",
seconds > 0
? String.format(" %1$d %2$s",
seconds,
seconds > 1 ? "seconds" : "second")
: "")
: ""
);
JTextField refreshInterval = new JTextField(interval);
refreshInterval.setEditable(false);
refreshTimeLabel.setLabelFor(refreshInterval);
JLabel nextRefreshLabel = new JLabel("Next printer refresh in:");
nextRefresh = new JTextField();
nextRefresh.setEditable(false);
nextRefreshLabel.setLabelFor(nextRefresh);
JLabel timeoutLabel = new JLabel("Time left:");
timeLeft = new JTextField();
timeLeft.setEditable(false);
timeoutLabel.setLabelFor(timeLeft);
JPanel infoPanel = new JPanel();
GroupLayout layout = new GroupLayout(infoPanel);
infoPanel.setLayout(layout);
infoPanel.setBorder(BorderFactory.createTitledBorder("Info"));
layout.setAutoCreateGaps(true);
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(javaLabel)
.addComponent(refreshTimeLabel)
.addComponent(nextRefreshLabel)
.addComponent(timeoutLabel)
)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, true)
.addComponent(javaVersion)
.addComponent(refreshInterval)
.addComponent(nextRefresh)
.addComponent(timeLeft)
)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(javaLabel)
.addComponent(javaVersion)
)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(refreshTimeLabel)
.addComponent(refreshInterval))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(nextRefreshLabel)
.addComponent(nextRefresh))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(timeoutLabel)
.addComponent(timeLeft))
);
return infoPanel;
}
private JPanel createInstructionsPanel() {
JPanel instructionsPanel = new JPanel(new BorderLayout());
JTextArea instructionText = new JTextArea(INSTRUCTIONS_TEXT);
instructionText.setEditable(false);
instructionsPanel.setBorder(createTitledBorder("Test Instructions"));
instructionsPanel.add(new JScrollPane(instructionText));
return instructionsPanel;
}
private JPanel createListPanel(final ServiceItemListModel model,
final String title,
final char mnemonic) {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JList<ServiceItem> list = new JList<>(model);
list.setCellRenderer(new ServiceItemListRenderer());
JLabel label = new JLabel(title);
label.setLabelFor(list);
label.setDisplayedMnemonic(mnemonic);
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.X_AXIS));
labelPanel.add(label, BorderLayout.EAST);
labelPanel.add(Box.createHorizontalGlue());
panel.add(labelPanel);
panel.add(new JScrollPane(list));
return panel;
}
private JPanel createButtonPanel() {
refreshButton = new JButton("Refresh");
refreshButton.addActionListener(this::refresh);
// Create resultButtonPanel with Pass, Fail buttons
passButton = new JButton("Pass");
passButton.setActionCommand("Pass");
passButton.addActionListener((ActionEvent e) -> {
System.out.println("Pass Button pressed!");
testResult = true;
latch.countDown();
disposeUI();
});
passButton.addActionListener(this::pass);
passButton.setEnabled(false);
failButton = new JButton("Fail");
failButton.setActionCommand("Fail");
failButton.addActionListener((ActionEvent e) -> {
System.out.println("Fail Button pressed!");
testResult = false;
latch.countDown();
failButton.addActionListener(this::fail);
failButton.setEnabled(false);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
buttonPanel.add(Box.createHorizontalGlue());
buttonPanel.add(refreshButton);
buttonPanel.add(passButton);
buttonPanel.add(failButton);
buttonPanel.add(Box.createHorizontalGlue());
return buttonPanel;
}
private static List<ServiceItem> collectPrinterList() {
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
List<ServiceItem> list = new ArrayList<>(printServices.length);
for (PrintService service : printServices) {
list.add(new ServiceItem(service.getName()));
}
return list;
}
private static void logList(final String title, final List<ServiceItem> list) {
System.out.println(title);
for (ServiceItem item : list) {
System.out.println(item.name);
}
System.out.println();
}
private static void compareLists(final ServiceItemListModel before, final ServiceItemListModel after) {
boolean beforeUpdated = false;
boolean afterUpdated = false;
for (ServiceItem item : before.list) {
if (!after.list.contains(item)) {
item.state = ServiceItem.State.REMOVED;
beforeUpdated = true;
} else if (item.state != ServiceItem.State.UNCHANGED) {
item.state = ServiceItem.State.UNCHANGED;
beforeUpdated = true;
}
}
for (ServiceItem item : after.list) {
if (!before.list.contains(item)) {
item.state = ServiceItem.State.ADDED;
afterUpdated = true;
} else if (item.state != ServiceItem.State.UNCHANGED) {
item.state = ServiceItem.State.UNCHANGED;
afterUpdated = true;
}
}
if (beforeUpdated) {
before.fireChanged();
}
if (afterUpdated) {
after.fireChanged();
}
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("The window closed");
disposeUI();
}
private void disposeUI() {
timer.stop();
latch.countDown();
frame.dispose();
}
@SuppressWarnings("unused")
private void refresh(ActionEvent e) {
System.out.println("Refresh button pressed");
afterList.refreshList(collectPrinterList());
compareLists(beforeList, afterList);
passButton.setEnabled(true);
failButton.setEnabled(true);
logList("After:", afterList.list);
}
@SuppressWarnings("unused")
private void pass(ActionEvent e) {
System.out.println("Pass button pressed");
testResult = true;
disposeUI();
}
@SuppressWarnings("unused")
private void fail(ActionEvent e) {
System.out.println("Fail button pressed");
testResult = false;
disposeUI();
}
@SuppressWarnings("unused")
private void updateTimeLeft(ActionEvent e) {
long elapsed = (System.currentTimeMillis() - startTime) / 1000;
long left = TIMEOUT - elapsed;
if (left < 0) {
testTimedOut = true;
disposeUI();
});
gbc.gridx = 0;
gbc.gridy = 0;
resultButtonPanel.add(addedButton, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
resultButtonPanel.add(passButton, gbc);
gbc.gridx = 2;
gbc.gridy = 0;
resultButtonPanel.add(failButton, gbc);
resultsTextArea = new JTextArea();
resultsTextArea.setEditable(false);
resultsTextArea.setBorder(BorderFactory.
createTitledBorder("Results"));
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainControlPanel.add(resultsTextArea, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
mainControlPanel.add(resultButtonPanel, gbc);
mainFrame.add(mainControlPanel);
mainFrame.pack();
mainFrame.setVisible(true);
}
timeLeft.setText(formatTime(left));
nextRefresh.setText(formatTime(refreshTime - (elapsed % refreshTime)));
}
public void disposeUI() {
mainFrame.dispose();
private static String formatTime(final long seconds) {
long minutes = seconds / 60;
return String.format("%d:%02d", minutes, seconds - minutes * 60);
}
}