/*********************************************************************************** * * Copyright (c) 2015 Kamil Baczkowicz * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * * Kamil Baczkowicz - initial API and implementation and/or initial documentation * */ package pl.baczkowicz.mqttspy.ui; import java.io.File; import java.net.URL; import java.util.Date; import java.util.ResourceBundle; import javafx.beans.property.ReadOnlyStringWrapper; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.MenuButton; import javafx.scene.control.MenuItem; import javafx.scene.control.TitledPane; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeTableCell; import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.stage.DirectoryChooser; import javafx.util.Callback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.baczkowicz.mqttspy.connectivity.MqttAsyncConnection; import pl.baczkowicz.mqttspy.ui.scripts.InteractiveScriptManager; import pl.baczkowicz.mqttspy.ui.testcases.InteractiveTestCaseManager; import pl.baczkowicz.spy.eventbus.IKBus; import pl.baczkowicz.spy.testcases.TestCaseManager; import pl.baczkowicz.spy.testcases.TestCaseStatus; import pl.baczkowicz.spy.ui.panes.PaneVisibilityStatus; import pl.baczkowicz.spy.ui.panes.TitledPaneController; import pl.baczkowicz.spy.ui.properties.TestCaseProperties; /** * Controller for the test cases execution window. */ public class TestCasesExecutionController extends AnchorPane implements Initializable, TitledPaneController { /** Initial and minimal scene/stage width. */ public final static int WIDTH = 780; /** Initial and minimal scene/stage height. */ public final static int HEIGHT = 550; final static Logger logger = LoggerFactory.getLogger(TestCasesExecutionController.class); private TitledPane pane; private AnchorPane paneTitle; @FXML private TreeTableView<TestCaseProperties> scriptTree; private TreeItem<TestCaseProperties> root = new TreeItem<>(); /** * The name of this field needs to be set to the name of the pane + * Controller (i.e. <fx:id>Controller). */ @FXML private TestCaseExecutionController testCaseExecutionPaneController; @FXML private TreeTableColumn<TestCaseProperties, String> nameColumn; @FXML private TreeTableColumn<TestCaseProperties, String> lastRunColumn; @FXML private TreeTableColumn<TestCaseProperties, TestCaseStatus> statusColumn; @FXML private ContextMenu scriptTreeContextMenu; @FXML private MenuItem setLocationMenu; @FXML private MenuItem enqueueAllMenu; @FXML private MenuItem enqueueSelectedMenu; @FXML private MenuItem enqueueNotRunMenu; @FXML private MenuItem enqueueFailedMenu; @FXML private MenuItem clearEnqueuedMenu; @FXML private Label enqueuedLabel; @FXML private Label passesLabel; @FXML private Label failuresLabel; @FXML private Label runLabel; @FXML private Label totalLabel; @FXML private Label skippedLabel; private String scriptsLocation; // private EventManager<FormattedMqttMessage> eventManager; private IKBus eventBus; private InteractiveScriptManager scriptManager; private InteractiveTestCaseManager testCaseManager; private MqttAsyncConnection connection; private MenuButton settingsButton; private ConnectionController connectionController; private Label titleLabel; public void initialize(URL location, ResourceBundle resources) { // Set location setLocationMenu.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { final DirectoryChooser fileChooser = new DirectoryChooser(); fileChooser.setTitle("Select test cases location"); final File selectedFile = fileChooser.showDialog(scriptTree.getScene().getWindow()); if (selectedFile != null) { scriptsLocation = selectedFile.getAbsolutePath(); testCaseManager.loadTestCases(scriptsLocation); root.getChildren().clear(); for (final TestCaseProperties properties : testCaseManager.getTestCasesProperties()) { root.getChildren().add(new TreeItem<TestCaseProperties>(properties)); } scriptTree.getSelectionModel().clearSelection(); refreshInfo(); scriptTree.getSortOrder().clear(); scriptTree.getSortOrder().add(nameColumn); // TODO: get all dirs and subdirs? } } }); enqueueAllMenu.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { testCaseManager.enqueueAllTestCases(); // TODO: start final TreeItem<TestCaseProperties> selected = scriptTree.getSelectionModel().getSelectedItem(); if (selected != null && selected.getValue() != null) { final TestCaseProperties testCaseProperties = selected.getValue(); testCaseManager.runTestCase(testCaseProperties); refreshInfo(); } } }); enqueueSelectedMenu.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { final TreeItem<TestCaseProperties> selected = scriptTree.getSelectionModel().getSelectedItem(); if (selected != null && selected.getValue() != null) { final TestCaseProperties testCaseProperties = selected.getValue(); testCaseManager.enqueueTestCase(testCaseProperties); refreshInfo(); } } }); enqueueNotRunMenu.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { testCaseManager.enqueueAllNotRun(); refreshInfo(); } }); enqueueFailedMenu.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { testCaseManager.enqueueAllFailed(); refreshInfo(); } }); clearEnqueuedMenu.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { testCaseManager.clearEnqueued(); refreshInfo(); } }); scriptTree.setRoot(root); scriptTree.setShowRoot(false); scriptTree.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { showSelected(); refreshInfo(); } }); nameColumn.setCellValueFactory ( (TreeTableColumn.CellDataFeatures<TestCaseProperties, String> param) -> new ReadOnlyStringWrapper(param.getValue().getValue().getName()) ); lastRunColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<TestCaseProperties, String>, ObservableValue<String>>() { @Override public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<TestCaseProperties, String> p) { return p.getValue().getValue().lastUpdatedProperty(); } }); lastRunColumn.setCellFactory(new Callback<TreeTableColumn<TestCaseProperties, String>, TreeTableCell<TestCaseProperties, String>>() { public TreeTableCell<TestCaseProperties, String> call(TreeTableColumn<TestCaseProperties, String> param) { final TreeTableCell<TestCaseProperties, String> cell = new TreeTableCell<TestCaseProperties, String>() { @Override public void updateItem(String item, boolean empty) { super.updateItem(item, empty); setText(item); } }; cell.setAlignment(Pos.CENTER); return cell; } }); statusColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<TestCaseProperties, TestCaseStatus>, ObservableValue<TestCaseStatus>>() { @Override public ObservableValue<TestCaseStatus> call(TreeTableColumn.CellDataFeatures<TestCaseProperties, TestCaseStatus> p) { return p.getValue().getValue().statusProperty(); } }); statusColumn.setCellFactory(new Callback<TreeTableColumn<TestCaseProperties,TestCaseStatus>, TreeTableCell<TestCaseProperties,TestCaseStatus>>() { public TreeTableCell<TestCaseProperties, TestCaseStatus> call( TreeTableColumn<TestCaseProperties, TestCaseStatus> param) { final TreeTableCell<TestCaseProperties, TestCaseStatus> cell = new TreeTableCell<TestCaseProperties, TestCaseStatus>() { @Override public void updateItem(TestCaseStatus item, boolean empty) { super.updateItem(item, empty); if (!isEmpty()) { setGraphic(testCaseExecutionPaneController.getIconForStatus(item)); } else { setGraphic(null); } } }; cell.setAlignment(Pos.CENTER); cell.setPadding(new Insets(0, 0, 0, 0)); return cell; } }); // Note: important - without that, cell height goes nuts with progress indicator scriptTree.setFixedCellSize(24); scriptTree.setPlaceholder(new Label("Right click to load test cases...")); } public void init() { titleLabel = new Label(pane.getText()); scriptManager = new InteractiveScriptManager(eventBus, connection); testCaseManager = new InteractiveTestCaseManager(scriptManager, this, testCaseExecutionPaneController); testCaseExecutionPaneController.setTestCaseManager(testCaseManager); if (connectionController != null) { paneTitle = new AnchorPane(); settingsButton = ViewManager.createTitleButtons(this, paneTitle, connectionController); } } public void refreshInfo() { totalLabel.setText(totalLabel.getText().substring(0, totalLabel.getText().indexOf(" ") + 1) + testCaseManager.getTotalCount()); enqueuedLabel.setText(enqueuedLabel.getText().substring(0, enqueuedLabel.getText().indexOf(" ") + 1) + testCaseManager.getEnqueuedCount()); int passes = 0; int failures = 0; int skipped = 0; int run = 0; enqueueAllMenu.setDisable(true); enqueueSelectedMenu.setDisable(true); enqueueNotRunMenu.setDisable(true); enqueueFailedMenu.setDisable(true); clearEnqueuedMenu.setDisable(testCaseManager.getEnqueuedCount() == 0 ? true : false); if (root.getChildren().size() > 0 && testCaseManager.getTotalCount() > 0) { enqueueAllMenu.setDisable(false); final TreeItem<TestCaseProperties> selected = scriptTree.getSelectionModel().getSelectedItem(); if (selected != null && selected.getValue() != null) { enqueueSelectedMenu.setDisable(false); } for (final TestCaseProperties testCase : testCaseManager.getTestCasesProperties()) { if (TestCaseStatus.PASSED.equals(testCase.statusProperty().getValue())) { passes++; } else if (TestCaseStatus.FAILED.equals(testCase.statusProperty().getValue())) { failures++; } else if (TestCaseStatus.SKIPPED.equals(testCase.statusProperty().getValue())) { skipped++; } run = passes + failures + skipped; } enqueueNotRunMenu.setDisable(run != testCaseManager.getTotalCount() ? false : true); enqueueFailedMenu.setDisable(failures > 0 ? false : true); } passesLabel.setText(passesLabel.getText().substring(0, passesLabel.getText().indexOf(" ") + 1) + passes); failuresLabel.setText(failuresLabel.getText().substring(0, failuresLabel.getText().indexOf(" ") + 1) + failures); skippedLabel.setText(skippedLabel.getText().substring(0, skippedLabel.getText().indexOf(" ") + 1) + skipped); runLabel.setText(runLabel.getText().substring(0, runLabel.getText().indexOf(" ") + 1) + run); if (scriptsLocation != null) { final String parentDir = scriptsLocation + System.getProperty("file.separator"); testCaseManager.exportTestCasesResultsAsCSV(new File(parentDir+ "results_" + TestCaseManager.testCasesFileSdf.format(new Date()) + ".csv")); } } public void showSelected() { final TreeItem<TestCaseProperties> selected = scriptTree.getSelectionModel().getSelectedItem(); if (selected != null && selected.getValue() != null) { final TestCaseProperties testCaseProperties = selected.getValue(); logger.info("About to display selected test case - " + testCaseProperties.getName()); testCaseExecutionPaneController.display(testCaseProperties, testCaseProperties.getSteps()); } else { logger.warn("No test case selected"); } } // =============================== // === Setters and getters ======= // =============================== public void setEventBus(final IKBus eventBus) { this.eventBus = eventBus; } @Override public TitledPane getTitledPane() { return pane; } @Override public void setTitledPane(TitledPane pane) { this.pane = pane; } public void setConnection(MqttAsyncConnection connection) { this.connection = connection; } public void setConnectionController(final ConnectionController connectionController) { this.connectionController = connectionController; } @Override public void updatePane(PaneVisibilityStatus status) { if (PaneVisibilityStatus.ATTACHED.equals(status)) { settingsButton.setVisible(true); } else { settingsButton.setVisible(false); } } @Override public Label getTitleLabel() { return titleLabel; } }