Passing value from Groovy script to DataSync in SoapUI - groovy

I have a script that loops through a dataset X and for each record in that dataset X loops in another dataset Y and retrieves some results. How can I pass those results to a DataSink?
A number of suggestions around have been to use properties however in my groovy script I have a loop within which i receive the results and if i populate a property with every result i guess i will only be able to see the last result in the property, and my DataSink will only find the last result.
My code below:
def goodWeather = context.expand( '${#TestCase#goodWeather}' ) as String
if (goodWeather.equals("false"))
{
def response = context.expand( '${CityWeatherRequest#Response#declare namespace ns1=\'http://tempuri.org/\'; //ns1:GetCityWeatherResponse[1]/ns1:GetCityWeatherResult[1]/ns1:Weather[1]}' )
def cityinfo_City = context.expand( '${GetCitiesDS#cityinfo_City}' )
def cityinfo_Country = context.expand( '${GetCitiesDS#cityinfo_Country}' )
//Keep count to restrict number of returns. CountSuggestedCities is a property.
def count = context.expand( '${#TestCase#countSuggestedCities}' ) as Integer
assert count instanceof Integer
//Suggest some cities if skies are clear
if (response.contains("clear sky"))
{
if (count == 0) log.info("Making suggestions")
count ++
testRunner.testCase.setPropertyValue("countSuggestedCities", count.toString());
log.info(cityinfo_City + " located in: " + cityinfo_Country);
}
//Check property maxSuggestedCities to see if maximum suggestes required as been reached.
if (count == (context.expand( '${#TestCase#maxSuggestedCities}' ) as Integer))
{
testRunner.testCase.setPropertyValue("countSuggestedCities", "0");
testRunner.testCase.setPropertyValue("goodWeather", "true");
testRunner.gotoStepByName("SeperatorScript");
}
}
else
{
testRunner.gotoStepByName("SeperatorScript");
}
What I want is to replace log.info(cityinfo_City + " located in: " + cityinfo_Country); with saving that information to a database using a DataSink.

I don't think the soapui doc provides examples about DataSink with groovy and database. But you can always use Groovy sql to do the insertion. Here is the example code:
def driverName = "com.mysql.jdbc.Driver"
com.eviware.soapui.support.GroovyUtils.registerJdbcDriver(driverName)
def user = "root" // change this , password, and jdbc url
def password = ""
def con = groovy.sql.Sql.newInstance("jdbc:mysql://localhost:3306/test_for_so",
user, password, driverName)
def cityinfo_City = 'London'
def cityinfo_Country = 'England'
con.execute("INSERT INTO cityinfo (cityinfo_City, cityinfo_Country) VALUES (?, ?)",
[cityinfo_City, cityinfo_Country])
con.close()

Related

SoapUI to read request parameters from a file ( free version)

I have a file with following contents
987656
987534
I have a Groovy script as following as a test step before my test :
def myTestCase = context.testCase
new File("filepath/data1.txt").eachLine { line ->
myTestCase.setPropertyValue("inputValue", line)
inputValue = context.expand( '${#TestCase#inputValue}' )
log.info inputValue
}
The log output for the script gives me both the values from the file :
987656
987534
I have a Testcase custom property set up as "inputValue" and in my test I call the parameter as
<enr:Id>${#TestCase#inputValue}</enr:Id>
During execution the test always runs for the last value "987534" and not for both the inputs.
What should I be doing to execute the test for all the values present in the text file?
Thanks
The way to loop through values like that is to, in the eachLine loop, call the SOAP step, like this:
def myTestCase = context.testCase
new File("filepath/data1.txt").eachLine { line ->
myTestCase.setPropertyValue("inputValue", line)
inputValue = context.expand( "${#TestCase#inputValue}" )
log.info inputValue
//define the step
def soapTestStep = testRunner.testCase.getTestStepByName("YourSOAPRequestName").name
//call the step
testRunner.runTestStepByName(soapTestStep)
//if you want to do something with the response XML
def responseSOAP = context.expand("${YourSOAPRequestName#Response}")
//if you want to check a value in the response XML
def responseSection = responseSOAP =~ /someNode>(.*)<\/someNode/
def responseValue = responseSection[0][1]
log.info "response: ${responseValue}"
}

Combining Optional Passed query filters in Peewee

I am trying to Link a flask server to a Peewee database. I have a Rest GET request that passes data of the form
{'a':1,'b':2, 'filter':{'name':'Foo', 'count':3}}
I want to write a method that converts my filters into a database query and execute it to return their resource:
import datetime
import peewee as pw
import uuid
DATABASE = "Resources.db"
database = pw.SqliteDatabase(DATABASE)
class BaseModel(pw.Model):
class Meta:
database = database
class Resource(BaseModel):
name = pw.CharField(unique=True)
current_count = pw.IntegerField(default=1)
total_count = pw.IntegerField(default=1)
flavor = pw.CharField(default="undefined")
users = pw.TextField()
metadata = pw.TextField(default="")
is_avalible = pw.BooleanField(default=True)
uuid = pw.UUIDField(primary_key=True, default=uuid.uuid4)
max_reservation_time = pw.IntegerField(default=10)
def __str__(self):
return f"My name is {self.name} {vars(self)}"
This is kinda what my resource looks like. Here is what I am trying to do... (not a working full example)
def filter(filters):
for i,j in filters.items():
dq = Resource.select().where(getattr(Resource, i) == j)
for resource in dq:
print(resource)
if __name__ == "__main__":
try:
database.connect()
except pw.OperationalError:
print("Open Connection")
try:
create_tables()
except pw.OperationalError:
print("Resource table already exists!")
with database.atomic():
reso = Resource.create(name="Burns", current_count=4, total_count=5, users="Bar", blah=2)
filter({'name':"Burns","total_count":5})
Here I would expect to get back: My name is Burns {'__data__': {'uuid': UUID('80808e3a-4b10-47a5-9d4f-ff9ff9ca6f5c'), 'name': 'Burns', 'current_count': 4, 'total_count': 5, 'flavor': 'undefined', 'users': 'Grant', 'metadata': '', 'is_avalible': True, 'max_reservation_time': 10}, '_dirty': set(), '__rel__': {}}I believe I might be able to create individual peewee.expressions and join them some how, I just am not sure how.
Since peewee expressions can be arbitrarily combined using the builtin & and | operators, we'll use the reduce() function to combine the list using the given operand:
def filter(filters):
expression_list = [getattr(Resource, field) == value
for field, value in filters.items()]
# To combine all expressions with "AND":
anded_expr = reduce(operator.and_, expression_list)
# To combine all expressions with "OR":
ored_expr = reduce(operator.or_, expression_list)
# Then:
return Resource.select().where(anded_expr) # or, ored_expr
Thanks to #coleifer for the reminder. Here was my solution:
OP_MAP = {
"==": pw.OP.EQ,
"!=": pw.OP.NE,
">": pw.OP.GT,
"<": pw.OP.LT,
">=": pw.OP.GTE,
"<=": pw.OP.LTE,
}
def _generate_expressions(model, query_filter):
expressions = []
for expression in query_filter:
expressions.append(
pw.Expression(
getattr(model, expression["attr"]), OP_MAP[expression["op"]], expression["value"]
)
)
return expressions
def generate_query(model, query_data):
if query_data.get("filters") is None:
database_query = model.select()
else:
database_query = model.select().where(
*(_generate_expressions(model, query_data["filters"]))
)
return database_query
I pass the type of object I want to create an expression for and operator in the filter data. Iterating over the filters I can build the expressions and combine them.

Checking a value across multiple arrays

I have a context property named 'flights'. I want to check if there is no value for this property, then go to the 'Iteration' test step, else set the first value of the property as a test case property.
Now what I want to do is perform a compare using this test case property value with a couple of arrays. Below is the scenario;
Check if value is in the villas array, if so +1 to VillasCount, else check in hotels array, if in there then +1 to beachCount else +1 to noCount.
Code is below:
// define properties required for the script to run.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def dataFolder = groovyUtils.projectPath
//Define an empty array list to load data from datasheet
def dataTable_properties = [];
int villasCount = context.getProperty("villasCount")
def lines = new File(dataFolder + "/Test.csv").readLines()
def villas = []
lines.eachWithIndex { line, index ->
if (index) {
def data = line.split(',')*.trim()
if (data[0]) villas << data[0]
}
}
log.info "Villas : ${villas}"
context.setProperty("villasCount", villasCount)
Maybe something like:
for(f in flights){
if(villas.contains(f)){
villasCount = villasCount + 1
}
}
Not 100% sure what you needed to compare, but you could easily expand this to check whatever you wanted.
If this is way off please provide more information on what you were trying to compare.

using variables in groovy context.expand expression

I tried to automate a test case using groovy script and soapUI.
Sending a soap request, I got a response contains a company list.
What I'ld like to do is verifying names of listed companies.
Size of the response array is not fixed.
So I tried the script below just for the beginning but I got stuck..
def count = context.expand( '${Properties#count}' )
count = count.toInteger()
def i = 0
while (i<count)
(
def response = context.expand( '${getCompanyList#Response#//multiRef['+i+']/#id}' )
log.info(response)
i=İ+1
)
I get
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Script12.groovy: 6: unexpected token: def # line 6, column 1. def response = context.expand( '${getCompanyList#Response#//multiRef['+i+']/#id}' ) ^ org.codehaus.groovy.syntax.SyntaxException: unexpected token: def # line 6, column 1. at
I should somehow put "i" in the "response" definition..
You are using the wrong characters to in your while statement, it should be braces ({}), not parentheses (()).
This is why the error is regarding the def on line 6, and has nothing to do with the i variable.
You also have İ in your example, which is not a valid variable name in Groovy.
I think you wanted this:
def count = context.expand( '${Properties#count}' )
count = count.toInteger()
def i = 0
while (i<count) {
def response = context.expand( '${getCompanyList#Response#//multiRef['+i+']/#id}' )
log.info(response)
i=i+1
}
However, this being Groovy, you can do this much cleaner using:
def count = context.expand( '${Properties#count}' )
count.toInteger().times { i ->
def response = context.expand( '${getCompanyList#Response#//multiRef['+i+']/#id}' )
log.info(response)
}
(And if you replace i inside the closure with it, you can remove the i -> as well.)

Sorting arrays in Groovy

I'm trying to compare two arrays in groovy. My attempts so far have yielded a mixed response and therefore I'm turning to the collective for advice.
In the following code I'm taking 2 REST responses, parsing them and placing everything under the Invoice node into an array. I then further qualify my array so I have a list of InvoiceIDs and then try to compare the results of the two responses to ensure they are the same.
When I compare the array of InvoiceIDs (Guids) they match - this is not what I expect as the invoice order is currently different between my my 2 response sources.
When I sort the arrays of Invoices IDs the results differ.
I'm suspecting my code is faulty, but have spent an hour rattling through it, to no avail.
Any advice on sorting arrays in groovy or on the code below would be most appreciated:
gu = new com.eviware.soapui.support.GroovyUtils( context )
def xmlSlurper = new groovy.util.XmlSlurper()
// Setting up the response parameters
def responseSTAGE = xmlSlurper.parseText(context.expand('${GET Invoices - STAGE#Response}'));
def responseSTAGE2 = xmlSlurper.parseText(context.expand('${GET Invoices - STAGE2#Response}'));
responseInvoicesSTAGE = responseSTAGE.Invoices
responseInvoicesSTAGE2 = responseSTAGE2.Invoices
def arrayOfInvoicesSTAGE = []
def arrayOfInvoicesSTAGE2 = []
def counter = 0
for (invoice in responseInvoicesSTAGE.Invoice) {
arrayOfInvoicesSTAGE[counter] = responseInvoicesSTAGE.Invoice[counter].InvoiceID
//log.info counter+" STAGE"+arrayOfInvoicesSTAGE[counter]
arrayOfInvoicesSTAGE2[counter] = responseInvoicesSTAGE2.Invoice[counter].InvoiceID
//log.info counter+" STAGE2"+arrayOfInvoicesSTAGE2[counter]
counter++
}
log.info arrayOfInvoicesSTAGE
log.info arrayOfInvoicesSTAGE2
def sortedSTAGE = arrayOfInvoicesSTAGE.sort()
def sortedSTAGE2 = arrayOfInvoicesSTAGE2.sort()
log.info sortedSTAGE
As an aside, can't you replace:
def arrayOfInvoicesSTAGE = []
def arrayOfInvoicesSTAGE2 = []
def counter = 0
for (invoice in responseInvoicesSTAGE.Invoice) {
arrayOfInvoicesSTAGE[counter] = responseInvoicesSTAGE.Invoice[counter].InvoiceID
//log.info counter+" STAGE"+arrayOfInvoicesSTAGE[counter]
arrayOfInvoicesSTAGE2[counter] = responseInvoicesSTAGE2.Invoice[counter].InvoiceID
//log.info counter+" STAGE2"+arrayOfInvoicesSTAGE2[counter]
counter++
}
with
def arrayOfInvoicesSTAGE = responseInvoicesSTAGE.Invoice*.InvoiceID
def arrayOfInvoicesSTAGE2 = responseInvoicesSTAGE2.Invoice*.InvoiceID
Two arrays are considered equal in Groovy if they have they have the same number of elements and each element in the same position are equal. You can verify this by running the following code in the Groovy console
Integer[] foo = [1,2,3,4]
Integer[] bar = [4,3,2,1]
assert foo != bar
bar.sort()
assert foo == bar

Resources