OK, so I was able to make this work, to some degree. The while loop keeps Groovy 'active' still and the listener I used to adjust a variable to simply say that it was pressed and then if the variable changes it runs the script I want.
Sorry to keep posting in my own thread but figured since UISupport seems to have very little documentation someone else might find this information useful.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFileChooser;
import javax.swing.*;
import com.eviware.soapui.support.types.StringToStringsMap
import com.eviware.soapui.support.UISupport
import com.eviware.soapui.model.testsuite.Assertable
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import java.awt.Component;
import javax.swing.Box;
import java.awt.Dimension;
def UISupport = com.eviware.soapui.support.UISupport;
SoapUITest.LaunchLog()
public class SoapUITest extends JFrame {
public static JPanel contentPane;
public static JTextArea xmlInput;
private JScrollPane scrollPane_1;
public static JTextArea LoggerResults;
private Box horizontalBox;
private Box verticalBox;
private Box horizontalBox_1;
private JButton btnSubmit;
private JButton btnCancel;
private Component rigidArea;
private Component rigidArea_1;
private Component verticalStrut;
private Component verticalStrut_1;
private Component horizontalStrut;
public static int testThis = 0;
public static JFrame frame;
public static void LaunchLog() {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
try {
frame = new SoapUITest();
frame.setName("Output");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
}
}
});
}
public SoapUITest() {
setTitle("SoapUI Output");
setBounds(100, 100, 1000, 750);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS));
verticalBox = Box.createVerticalBox();
contentPane.add(verticalBox);
horizontalBox = Box.createHorizontalBox();
verticalBox.add(horizontalBox);
JScrollPane scrollPane = new JScrollPane();
horizontalBox.add(scrollPane);
xmlInput = new JTextArea();
xmlInput.setLineWrap(true);
scrollPane.setViewportView(xmlInput);
horizontalStrut = Box.createHorizontalStrut(20);
horizontalBox.add(horizontalStrut);
scrollPane_1 = new JScrollPane();
horizontalBox.add(scrollPane_1);
LoggerResults = new JTextArea();
LoggerResults.setLineWrap(true);
scrollPane_1.setViewportView(LoggerResults);
horizontalBox_1 = Box.createHorizontalBox();
verticalBox.add(horizontalBox_1);
verticalStrut = Box.createVerticalStrut(20);
horizontalBox_1.add(verticalStrut);
btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
horizontalBox_1.add(btnCancel);
rigidArea = Box.createRigidArea(new Dimension(20, 20));
horizontalBox_1.add(rigidArea);
btnSubmit = new JButton("Submit");
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
testThis++;
}
});
horizontalBox_1.add(btnSubmit);
rigidArea_1 = Box.createRigidArea(new Dimension(480, 20));
horizontalBox_1.add(rigidArea_1);
verticalStrut_1 = Box.createVerticalStrut(20);
horizontalBox_1.add(verticalStrut_1);
}
}
def activeFrame;
def allFrames = SoapUITest.frame.getFrames();
for(listFrames in allFrames ) {
if (listFrames.getName().equals("Output") && listFrames.isShowing()) {
activeFrame = listFrames
}
}
int buttonpushNum = 0;
while (activeFrame.isShowing()) {
if (SoapUITest.testThis != buttonpushNum) {
log.info SoapUITest.xmlInput.getText();
log.info SoapUITest.testThis + " " + buttonpushNum
buttonpushNum++
}
}
If anyone is interested in this code, feel free to use it. I will give a brief explanation of what I am using it for and if anyone has a suggestion for improvements please let me know.
Step 1)
The groovy script asks the user to input the property file(s)
public File[] propFilesSelect() {
def propPath = context.expand('${#Project#propPath}');
File[] propfiles = null;
JFileChooser chooser;
String currentDir = new File("").getAbsolutePath();
if (propPath.length() > 1 ) {
chooser = new JFileChooser(propPath);
} else {
chooser = new JFileChooser(currentDir);
}
if( com.eviware.soapui.SoapUI.isCommandLine() ) {
chooser.setSelectedFile(new File(context.expand('${#Project#propFiles}')));
}
chooser.setMultiSelectionEnabled(true);
int returnValue = chooser.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
propfiles = chooser.getSelectedFiles();
}
//If the path wasn't the same as what was stored, ask if they want to change their default path. Genius!
if( !com.eviware.soapui.SoapUI.isCommandLine() ) {
if ( propfiles[0].getParent() != context.expand('${#Project#propPath}') ) {
int reply = JOptionPane.showConfirmDialog(null, "Would you like to store this Directory?", "Default Directory", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) {
testRunner.testCase.testSuite.project.setPropertyValue( "propPath", propfiles[0].getParent() )
}
}
}
return propfiles;
}
Note the command line ability, it still asks for property file if ran from my external source in case the user wants to run multiple (it preselects the one being sent to it for ease though).
Step 2)
The groovy script finds all of the test steps for the test case, storing these into a map
propFiles = propFilesSelect();
int buttonpushNum = 0;
for (file in propFiles ) {
//SoapUITest.LaunchLog();
propReader = new FileReader(file);
def propArray = []
//Just reading the file here
propReader.eachLine({propArray.add(it)});
def temp = []
for (prop in propArray ) {
if (prop.length() > 1 ) {
if (prop.substring(0,1) != '#' ) {
properties = prop.split('=')
if (properties.size() > 1) {
//Split the file, trim it down, put it to lower case and store it in the map
props.put("["+properties[0].trim().toLowerCase()+"]",properties[1].trim());
}
}
}
}
Note: The code does not close here. It stays open so that it will continue to process each property file individually. If you wanted to here, you could possibly multi-thread to do it simultaneously (Does SoapUI support multi-threading, haven't tried yet)
Step 3)
Parse your properties as needed and then launch your UI to control the flow of the system. After the UI launch, insert a loop for each different test case from your TC list. This will be used to parse your XML for running. These test steps are essentially just place holders for the XML and tags for the properties.
SoapUITest.LaunchLog();
for ( tests in testRunner.testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class) ) {
testName = tests.getName();
//this section disables the test step if there is a flag in the property saying testName = false or enables if testName = true.
if ( props.containsKey("["+testName.toLowerCase()+"]")) {
if ( props.get("["+testName.toLowerCase()+"]").toBoolean() && tests.disabled) {
log.info "Enabling " + testName
tests.disabled = false;
} else if (!props.get("["+testName.toLowerCase()+"]").toBoolean() && !tests.disabled){
tests.disabled = true;
}
}
//this section checks to see if it failed previously, is the testName is "Runner" (My step for running) or if the step is disabled
if (testName != "Runner" && fail != true && !tests.disabled) {
//Put the testName into the Results output screen so the user knows which test step is being ran
SoapUITest.LoggerResults.append("\n"+testName + "\n\n");
//Regexp to parse through the XML and check for the tags. I use [property$default~casesens]. I was lazy with casesens
def holder = groovyUtils.getXmlHolder(testName+"#Request");
def xml = holder.getPrettyXml()
def regexp = ("<([^<>]+)>(.*?)</\\1>");
def matcher = xml =~ regexp;
matcher.each {
/*
* Getting default properties and whether it is case sensitive
*/
def propKey;
def String[] defaultProp = it[2].tokenize("\$");
if (defaultProp.size() > 1) {
propKey = defaultProp[0] + "]";
} else {
propKey = it[2];
}
def String[] caseSens = it[2].tokenize("~");
if ( props.containsKey(propKey.toLowerCase())) {
def replaced = props.get(propKey.toLowerCase());
if ( caseSens.size() > 1 && caseSens[1].equalsIgnoreCase("lower]") ) {
replaced = replaced.toLowerCase();
} else if ( caseSens.size() > 1 && caseSens[1].equalsIgnoreCase("upper]") ) {
replaced = replaced.toUpperCase();
}
xml = xml.replace(it[2],replaced);
} else if (defaultProp.size() > 1){
if (caseSens.size() > 1 ) {
xml = xml.replace(it[2],defaultProp[1].substring(0,defaultProp[1].size()-7));
} else {
xml = xml.replace(it[2],defaultProp[1].substring(0,defaultProp[1].size() - 1 ));
}
} else {
xml = xml.replace(it[0],"")
}
}
//Putting the current Test step as the title of the UI, the XML in both of the text areas so that we can edit and view the XML
SoapUITest.frame.setTitle(testName);
SoapUITest.xmlInput.setText(xml + "\n");
SoapUITest.LoggerResults.append("\nRequest:\n");
SoapUITest.LoggerResults.append(xml + "\n");
SoapUITest.LoggerResults.setCaretPosition(SoapUITest.LoggerResults.getDocument().getLength());
/*
* This section puts the formatted xml from the previous step into a
* property. It then starts setting up information for the test case
* like headers, username and password.
*/
testRunner.testCase.setPropertyValue("Runner",xml);
//Headers
if (props.containsKey("[xxxx]")) {
String[] curHeader = context.testCase.getTestStepByName("Runner").getTestRequest().getRequestHeaders().get("xxxx");
for (remove in curHeader ) {
headers.remove('PARTNER_NAME',remove)
context.testCase.getTestStepByName("Runner").getTestRequest().setRequestHeaders(headers)
}
headers.put('PARTNER_NAME',props.get("[partner_name]"))
context.testCase.getTestStepByName("Runner").getTestRequest().setRequestHeaders(headers)
} else {
String[] curHeader = context.testCase.getTestStepByName("Runner").getTestRequest().getRequestHeaders().get("xxxx");
for (remove in curHeader ) {
headers.remove('xxxx',remove)
context.testCase.getTestStepByName("Runner").getTestRequest().setRequestHeaders(headers)
}
}
//Username and Password
context.testCase.getTestStepByName("Runner").getTestRequest().setPassword(props.get("[password]"));
context.testCase.getTestStepByName("Runner").getTestRequest().setUsername(props.get("[username]"));
/*
* Stealing the assertions from the respective test steps and putting it into the Runner
* test step
*/
def testRan = testRunner.testCase.getTestStepByName(testName);
def Assertions = testRan.getAssertions();
def removeAssertions = testRunner.testCase.getTestStepByName("Runner").getAssertions();
for (key in removeAssertions.keySet()) {
testRunner.testCase.getTestStepByName("Runner").removeAssertion(removeAssertions.get(key));
}
for (assertion in Assertions.keySet()) {
testRunner.testCase.getTestStepByName("Runner").cloneAssertion(Assertions.get(assertion),assertion);
}
/*
* So all the parsing and set up has been performed, it is time to go ahead and run it.
* The below function runs the Runner TestStep once and stores the XML in 2 different
* ways currently. This should make it easier for different verification steps.
*/
testRunResultsXML = testRunner.runTestStepByName("Runner").getResponse();
testRunResults = groovyUtils.getXmlHolder("Runner#Response");
testPrint = testRunResults.getPrettyXml();
/*
* TODO:
*
* Verification Steps
* Conversation ID storing
* Any other information that we need/want stored
* Default information
* Other awesomeness
*/
def resultsMatcher = testPrint =~ regexp;
resultsMatcher.each {
//it[1] is your XML tag, it[2] is your xml value. If you need to store info from your XML for later use (Passer step, essentially), do it here
}
//Let's put the Response from the step back to the output
SoapUITest.LoggerResults.append("\nResponse:\n");
SoapUITest.LoggerResults.append(testPrint + "\n");
SoapUITest.LoggerResults.setCaretPosition(SoapUITest.LoggerResults.getDocument().getLength());
//I have mine set up to be automated unless it fails, if you want to verify the XML at every step just bypass this if statement and that should take care of it
if ( testRunner.testCase.getTestStepByName("Runner").getAssertionStatus().toString().equals("FAILED") && fail != true) {
fixed = false;
//Alert the user that it failed. Bad day.
SoapUITest.LoggerResults.append("\n\n\n Test Step Failed.\n Edit XML and fix!");
SoapUITest.LoggerResults.setCaretPosition(SoapUITest.LoggerResults.getDocument().getLength());
//Get a list of the frames
def activeFrame;
def allFrames = SoapUITest.frame.getFrames();
for(listFrames in allFrames ) {
if (listFrames.getName().equals("Output") && listFrames.isShowing()) {
//Set the frame you want to activeFrame variable.
activeFrame = listFrames
}
}
//While the frame exists, it is open and nothing has been fixed, wait for the User input
while (activeFrame != null && activeFrame.isShowing() && fixed == false) {
//This if statement checks if the user pushed the button.
if (SoapUITest.testThis != buttonpushNum) {
//If it did, just repeat the above steps with the XML from the xmlInput Text Area this time.
testRunner.testCase.setPropertyValue("Runner",SoapUITest.xmlInput.getText());
testRunResultsXML = testRunner.runTestStepByName("Runner").getResponse();
testRunResults = groovyUtils.getXmlHolder("Runner#Response");
testPrint = testRunResults.getPrettyXml();
resultsMatcher = testPrint =~ regexp;
resultsMatcher.each {
//Insert your regex here, a lot of these sections will be better off as functions I know but I am simply testing at the point
}
//and print the respone.
SoapUITest.LoggerResults.append("\nResponse:\n");
SoapUITest.LoggerResults.append(testPrint + "\n");
//Increase buttonpushNum to equal the testThis number
buttonpushNum++
}
//If the assertion isn't failed this time, than set fixed to true to break the while loop
if ( !testRunner.testCase.getTestStepByName("Runner").getAssertionStatus().toString().equals("FAILED") ) {
fixed = true;
}
}
//If all of that didn't fix it, give the user the option to just quit trying.
if ( fixed != true ) {
int assertAlert = JOptionPane.showConfirmDialog(null," Assertion failed at Test Step " +testName+". Would you like to continue?", "Assertion Failed. Bad Day", JOptionPane.YES_NO_OPTION);
if (assertAlert == JOptionPane.NO_OPTION) {
fail = true;
}
}
}
}
}
}
If anyone has any suggestions, questions or comments please, please feel free to ask. If you want the command line controls, just let me know.