All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.tapirtest.execution.gui.application.views.MainViewModel.xtend Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * MIT License
 * 
 * Copyright (c) 2018 b+m Informatik AG
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package io.tapirtest.execution.gui.application.views

import de.bmiag.tapir.bootstrap.TapirBootstrapper
import de.bmiag.tapir.execution.TapirExecutor
import de.bmiag.tapir.execution.TapirExecutor.TapirExecutorFactory
import de.bmiag.tapir.execution.model.ExecutionPlan
import de.bmiag.tapir.execution.model.Identifiable
import de.bmiag.tapir.execution.model.TestClass
import de.bmiag.tapir.execution.model.TestStep
import de.bmiag.tapir.execution.model.TestSuite
import io.tapirtest.execution.gui.application.components.AbstractCheckBoxTreeItem
import io.tapirtest.execution.gui.application.components.ExecutionPlanTreeItem
import io.tapirtest.execution.gui.application.components.TestStepTreeItem
import io.tapirtest.execution.gui.application.data.Property
import io.tapirtest.execution.gui.application.filter.GUIStepExecutionInvocationHandler
import io.tapirtest.execution.gui.application.listener.GUIExecutionListener
import java.util.List
import javafx.application.Application.Parameters
import javafx.application.Platform
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleListProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.scene.control.Alert
import javafx.scene.control.Alert.AlertType
import javafx.scene.control.CheckBoxTreeItem
import javafx.scene.control.TreeItem
import org.apache.logging.log4j.LogManager
import org.eclipse.xtend.lib.annotations.Accessors
import org.springframework.context.ConfigurableApplicationContext
import io.tapirtest.execution.gui.application.data.ExecutionStatus
import de.saxsys.mvvmfx.ViewModel
import de.saxsys.mvvmfx.utils.commands.DelegateCommand
import de.saxsys.mvvmfx.utils.commands.Action

/**
 * The view model of the main page.
 * 
 * @author Nils Christian Ehmke
 * 
 * @since 1.0.0 
 */
@Accessors
class MainViewModel implements ViewModel {

	static val logger = LogManager.getLogger(MainViewModel)

	val reinitializeExecutionPlanCommand = createCommand[performReinitializeExecutionPlan]
	val selectAllCommand = createCommand[performSelectAll]
	val deselectAllCommand = createCommand[performDeselectAll]
	val startTestsCommand = createCommand[performStartTests]
	val addPropertyCommand = createCommand[performAddProperty]
	val deletePropertyCommand = createCommand[performDeleteProperty]

	val refreshTableObservable = new SimpleObjectProperty
	val executionPlanRoot = new SimpleObjectProperty>()
	val propertiesContent = new SimpleListProperty(FXCollections.observableArrayList())
	val selectedProperty = new SimpleObjectProperty
	val readOnlyMode = new SimpleBooleanProperty
	var Class testClass
	var ConfigurableApplicationContext tapirContext
	var TapirExecutor tapirExecutor

	/**
	 * This method is executed once everything else of the application is initialized.
	 */
	def void start(Parameters parameters) {
		try {
			val rawParameters = parameters.raw
			if (rawParameters.size < 1) {
				throw new IllegalArgumentException('The tapir extensions launcher requires the test class or test suite as first parameter')
			}
	
			val firstParameter = rawParameters.get(0)
			try {
				testClass = Class.forName(firstParameter)
			} catch (ClassNotFoundException ex) {
				throw new IllegalArgumentException('''The class '«firstParameter»' can not be found''')
			}
	
			performReinitializeExecutionPlan()
		} catch (Exception ex) {
			handleException(ex)
		}
	}

	/**
	 * This method is performed when the user wants to reinitialize the execution plan.
	 */
	private def void performReinitializeExecutionPlan() {
		// Set the given properties
		propertiesContent.value.filter[key !== null].forEach[System.setProperty(key, value)]

		// Restart the tapir context and show the execution plan
		restartTapirContext()

		val executionPlan = tapirExecutor.executionPlan
		val executionPlanItem = new ExecutionPlanTreeItem(executionPlan)
		executionPlanRoot.set(executionPlanItem)
		selectAllNodes(executionPlanItem)
		expandNodes(executionPlanItem)
	}

	private def restartTapirContext() {
		if (tapirContext !== null) {
			tapirContext.close
		}
		tapirContext = TapirBootstrapper.bootstrap(testClass)

		val tapirExecutorFactory = tapirContext.getBean(TapirExecutorFactory)
		tapirExecutor = tapirExecutorFactory.getExecutorForClass(testClass)
	}

	private def void expandNodes(TreeItem treeItem) {
		treeItem.expanded = true

		val value = treeItem.value
		if (value instanceof ExecutionPlan || value instanceof TestSuite) {
			treeItem.children.forEach[expandNodes]
		} else if (value instanceof TestClass) {
			treeItem.expanded = false
		}
	}

	/**
	 * This method is performed when the user wants to select all items.
	 */
	private def void performSelectAll() {
		selectAllNodes(executionPlanRoot.get)
	}

	private def void selectAllNodes(TreeItem treeItem) {
		(treeItem as CheckBoxTreeItem).selected = true
		treeItem.children.forEach[selectAllNodes]
	}

	/**
	 * This method is performed when the user wants to deselect all items.
	 */
	private def void performDeselectAll() {
		deselectAllNodes(executionPlanRoot.get)
	}

	private def void deselectAllNodes(TreeItem treeItem) {
		(treeItem as CheckBoxTreeItem).selected = false
		treeItem.children.forEach[deselectAllNodes]
	}

	/**
	 * This method is performed when the user wants to start the tests.
	 */
	private def void performStartTests() {
		new Thread [
			try {
				readOnlyMode.set(true)

				// We reset the execution step of the whole execution plan so that the rows are not colored
				resetExecutionState(executionPlanRoot.get)

				// We have to get the selected steps before we reinitialize the execution plan
				val selectedSteps = getSelectedSteps(executionPlanRoot.get)
				Platform.runLater[refreshTableObservable.value = new Object]

				// Configure our own invocation handler, which skips the tests if necessary
				val stepExecutionInvocationHandler = tapirContext.getBean(GUIStepExecutionInvocationHandler)
				stepExecutionInvocationHandler.selectedTestSteps = selectedSteps

				// Configure our own listener, which informs our view model about changes
				val executionListener = tapirContext.getBean(GUIExecutionListener)
				executionListener.executionPlanRoot = executionPlanRoot.get
				executionListener.refreshTableObservable = refreshTableObservable

				// Now start the actual execution
				tapirExecutor.execute
			} catch (Exception ex) {
				handleException(ex)
			} finally {
				readOnlyMode.set(false)
			}
		].start
	}

	private def void resetExecutionState(TreeItem treeItem) {
		(treeItem as AbstractCheckBoxTreeItem).executionStatus = ExecutionStatus.NONE
		treeItem.children.forEach[resetExecutionState(it)]
	}

	private def List getSelectedSteps(TreeItem treeItem) {
		if (treeItem instanceof TestStepTreeItem) {
			if ((treeItem as CheckBoxTreeItem).selected) {
				#[treeItem.value as TestStep]
			} else {
				#[]
			}
		} else {
			// All other tree items are no leafs, which means that we have to search them as well
			treeItem.children.map[selectedSteps] //
			.flatten //
			.toList
		}
	}

	/**
	 * This method is performed when the user wants to add a property entry.
	 */
	private def performAddProperty() {
		propertiesContent.add(new Property())
	}

	/**
	 * This method is performed when the user wants to delete a property entry.
	 */
	private def performDeleteProperty() {
		val selectedProperty = selectedProperty.get
		if (selectedProperty !== null) {
			propertiesContent.remove(selectedProperty)
		}
	}

	private def createCommand(Runnable aAction) {
		new DelegateCommand [
			new Action() {

				override protected action() throws Exception {
					try {
						aAction.run
					} catch (Exception ex) {
						handleException(ex)
					}
				}

			}
		]
	}

	private def handleException(Exception exception) {
		val Runnable runnable = [
			logger.error('An exception occurred', exception)

			val alert = new Alert(AlertType.ERROR)
			alert.title = 'Error'
			alert.headerText = exception.localizedMessage
			alert.showAndWait
		]

		// This method may be called from outside the JavaFX thread. In this case we have to make sure that it is executed in the JavaFX thread.
		Platform.runLater(runnable)
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy