Scenario Outline Examples reference to the defined variable is lost when moving from version 1.2.0 of karate to version 1.3.0 - karate

Reference to the defined variable is lost when moving from version 1.2.0 of karate to version 1.3.0.
Please give a solution to fix this.
#e-invoice
Feature: With Space user, send e-invoice standing order agreement to bank as an ADD action (constraint checks)
Background:
* url baseUrl
* configure ssl = true
* callonce read('classpath:e_invoice_adapter/space/e-invoice-space-liveness.feature')
* call read('classpath:utils/common.feature')
* def testData = read('classpath:e_invoice_adapter/space/soa/test_data/space_send_e_invoice_soa_validation.csv')
* def getDbConnection = callonce read('classpath:utils/connectDB.feature#getDbConnectionInfo')
* def db = getDbConnection.db
Scenario Outline: Space user sends an e-invoice soa, <scenarioName>
* def arrayIndex = function(x, index){ return index == __num}
* copy eInvoiceTestData = karate.filter(testData, arrayIndex)
* print eInvoiceTestData
* def sendEInvoiceSoaSpace = call read('classpath:e_invoice_adapter/space/soa/core/send-e-invoice-soa-validation-process.feature') eInvoiceTestData
* print eInvoiceTestData
Examples:
|testData|
#ignore
Scenario: Debugging 1 scenario - user sends an e-invoice soa
* def arrayIndex = function(x, index){ return index == 36}
* copy eInvoiceTestData = karate.filter(testData, arrayIndex)
* print eInvoiceTestData
* def sendEInvoiceSoaSpace = call read('classpath:e_invoice_adapter/space/soa/core/send-e-invoice-soa-validation-process.feature') eInvoiceTestData
* print eInvoiceTestData
#ignore
Feature:Send e-invoice standing order agreement with Space user process
Background:
Scenario Outline:
* def eInvoiceTestData = __arg
* def soaRequest = {"input": {"agreement": {}}}
Given eval if ('<removeParameter>' != 'x') karate.remove('soaRequest', '<removeParameter>')
Given eval if (<systemId> != 'x') karate.set('soaRequest', 'input.agreement.systemId', <systemId>)
Given eval if ('<sellerRegistrationNumber>' != 'x') karate.set('soaRequest', 'input.agreement.sellerRegistrationNumber', '<sellerRegistrationNumber>')
Given eval if (<serviceId> != 'x') karate.set('soaRequest', 'input.agreement.serviceId', <serviceId>)
Given eval if ('<payerIban>' != 'x') karate.set('soaRequest', 'input.agreement.payerIban', '<payerIban>')
Given eval if ('<payerCode>' != 'x') karate.set('soaRequest', 'input.agreement.payerCode', '<payerCode>')
Given eval if ('<payerName>' != 'x') karate.set('soaRequest', 'input.agreement.payerName', '<payerName>')
Given eval if ('<paymentLimit>' != 'x') karate.set('soaRequest', 'input.agreement.paymentLimit', <paymentLimit>)
Given eval if ('<monthlyLimit>' != 'x') karate.set('soaRequest', 'input.agreement.monthlyLimit', <monthlyLimit>)
Given eval if ('<startDate>' != 'x') karate.set('soaRequest', 'input.agreement.startDate', <startDate>)
Given eval if ('<endDate>' != 'x') karate.set('soaRequest', 'input.agreement.endDate', <endDate>)
Given eval if ('<signingDate>' != 'x') karate.set('soaRequest', 'input.agreement.signingDate', <signingDate>)
* print soaRequest
* set eInvoiceTestData.postSOA.request = soaRequest
* def sendEInvoiceSoa = call read('classpath:e_invoice_adapter/space/soa/reuse-soa.feature#spaceSoaSend') eInvoiceTestData
* set eInvoiceTestData.postSOA.requestUri = sendEInvoiceSoa.requestUri
* set eInvoiceTestData.postSOA.response = sendEInvoiceSoa.response
* print sendEInvoiceSoa.response
* def expectedResponse = read('classpath:e_invoice_adapter/space/soa/response/validation/<expectedResponse>')
* match sendEInvoiceSoa.response == expectedResponse
Examples:
|eInvoiceTestData|
report with karate 1.3.0 for one scenario
report with karate 1.3.0 for scenario outline
Karate version 1.2.0 and earlier worked perfectly for me.
I hope version 1.3 performs no worse than 1.2. How to do it?
report with karate 1.2.0 for one scenario
report with karate 1.2.0 for scenario outline
Structure I used to test the REST API.

Related

I would like to check whether a string is within a predefined list in my Karate Scenario

The scenarios work if I create individual ones for each permutation however I would like to avoid having to read the file multiple times considering it can become quite a large file.
Scenario Outline: Mass_A is correct for STD and PCE
* def row =
"""
{
Artikeltyp: '<Artikeltyp>',
MinBestellmengeEinheit: '<MinBestellmengeEinheit>',
Mass_A: '<Mass_A>'
}
"""
* def tempArtikeltyp = '<Artikeltyp>'
* def tempMinBestellmengeEinheit = '<MinBestellmengeEinheit>'
* def tempMass_A = '<Mass_A>'
* def listMinBestTypes = ['PCE','PR','DZN']
* def expected = (tempArtikeltyp == 'STD' && (karate.match(listMinBestTypes,tempMinBestellmengeEinheit).pass) && (tempMass_A.length <= 0)) ? 'Mass_A is NOT populated for STD and PCE' : 'Mass_A is correct for STD and PCE'
* match expected == karate.info.scenarioName
Examples:
| read('input.csv')|
Any guidance would be much appreciated.
Here is a suggestion. Please re-think your entire approach. Start with the CSV file, convert it to JSON and then run all the permutations or combinations you want. Example below:
Scenario:
* def isValid = function(x){ return true }
* def data = read('input.csv')
* match each data == '#? isValid(_)'

Ruby - Implement an SQL server?

I have an application which has a Ruby API. I would like to link to this application from a SQL server system.
Is there a way for me to implement a Ruby SQL server which receives SQL statements and returns the requested data from the applications. Is it then possible to hook into this from an SQL server applications?
E.G.
# request as string like "SELECT * FROM MAIN_TABLE WHERE SOME_COLUMN = <SOME DATA>"
SQLEngine.OnRequest do |request|
Application.RunSQL(request)
end
P.S. I don't have any experience with SQL server, so have no idea how one would go about this...
Note: I'm not asking how I can query an SQL server database, I'm asking how I can implement an SQL server connection.
After some searching I found a few other stack overflow questions about how to make Database Drivers in other languages:
creating a custom odbc driver for application
Implementing a ODBC driver
Creating a custom ODBC driver
Alternatives to writing an ODBC driver
Potentially these will be useful for others going down this road, the most hopeful suggestion is implementing the wire protocol, of which one has been made in python which should be relatively easy to port
import SocketServer
import struct
def char_to_hex(char):
retval = hex(ord(char))
if len(retval) == 4:
return retval[-2:]
else:
assert len(retval) == 3
return "0" + retval[-1]
def str_to_hex(inputstr):
return " ".join(char_to_hex(char) for char in inputstr)
class Handler(SocketServer.BaseRequestHandler):
def handle(self):
print "handle()"
self.read_SSLRequest()
self.send_to_socket("N")
self.read_StartupMessage()
self.send_AuthenticationClearText()
self.read_PasswordMessage()
self.send_AuthenticationOK()
self.send_ReadyForQuery()
self.read_Query()
self.send_queryresult()
def send_queryresult(self):
fieldnames = ['abc', 'def']
HEADERFORMAT = "!cih"
fields = ''.join(self.fieldname_msg(name) for name in fieldnames)
rdheader = struct.pack(HEADERFORMAT, 'T', struct.calcsize(HEADERFORMAT) - 1 + len(fields), len(fieldnames))
self.send_to_socket(rdheader + fields)
rows = [[1, 2], [3, 4]]
DRHEADER = "!cih"
for row in rows:
dr_data = struct.pack("!ii", -1, -1)
dr_header = struct.pack(DRHEADER, 'D', struct.calcsize(DRHEADER) - 1 + len(dr_data), 2)
self.send_to_socket(dr_header + dr_data)
self.send_CommandComplete()
self.send_ReadyForQuery()
def send_CommandComplete(self):
HFMT = "!ci"
msg = "SELECT 2\x00"
self.send_to_socket(struct.pack(HFMT, "C", struct.calcsize(HFMT) - 1 + len(msg)) + msg)
def fieldname_msg(self, name):
tableid = 0
columnid = 0
datatypeid = 23
datatypesize = 4
typemodifier = -1
format_code = 0 # 0=text 1=binary
return name + "\x00" + struct.pack("!ihihih", tableid, columnid, datatypeid, datatypesize, typemodifier, format_code)
def read_socket(self):
print "Trying recv..."
data = self.request.recv(1024)
print "Received {} bytes: {}".format(len(data), repr(data))
print "Hex: {}".format(str_to_hex(data))
return data
def send_to_socket(self, data):
print "Sending {} bytes: {}".format(len(data), repr(data))
print "Hex: {}".format(str_to_hex(data))
return self.request.sendall(data)
def read_Query(self):
data = self.read_socket()
msgident, msglen = struct.unpack("!ci", data[0:5])
assert msgident == "Q"
print data[5:]
def send_ReadyForQuery(self):
self.send_to_socket(struct.pack("!cic", 'Z', 5, 'I'))
def read_PasswordMessage(self):
data = self.read_socket()
b, msglen = struct.unpack("!ci", data[0:5])
assert b == "p"
print "Password: {}".format(data[5:])
def read_SSLRequest(self):
data = self.read_socket()
msglen, sslcode = struct.unpack("!ii", data)
assert msglen == 8
assert sslcode == 80877103
def read_StartupMessage(self):
data = self.read_socket()
msglen, protoversion = struct.unpack("!ii", data[0:8])
print "msglen: {}, protoversion: {}".format(msglen, protoversion)
assert msglen == len(data)
parameters_string = data[8:]
print parameters_string.split('\x00')
def send_AuthenticationOK(self):
self.send_to_socket(struct.pack("!cii", 'R', 8, 0))
def send_AuthenticationClearText(self):
self.send_to_socket(struct.pack("!cii", 'R', 8, 3))
if __name__ == "__main__":
server = SocketServer.TCPServer(("localhost", 9876), Handler)
try:
server.serve_forever()
except:
server.shutdown()
Every programming language – including Ruby – supplies packages which implement interfaces to various SQL servers.
Start here: Ruby database access.

Karate: Remove a dynamic element from from JSON

* def res1 = {"member":{"muid":"MBR1"},"part":[{"PID":"M123"},{"supportedMembers":[{"muid":"MBR3","status":{"code":"A"}},{"muid":"MBR2","status":{"code":"I"}}]}]}
* def res2 = {"members":[{"member":{"muid":"MBR2","test":[{"EID":"E123"}]}},{"member":{"muid":"MBR3","test":[{"EID":"E123"}]}}]}
Karate: Match array elements of two different JSON
I have another requirement which is related to my earlier post.
* def id = res1.member.muid
I want to remove id from res2 response, which can be any where in res2.members.member, and do the matching with res1 to see the presence of muids
I tried something like below, but its not working:
* karate.remove('$res2.members[*]..muid','$.muid[id]')
Sample Code:
Feature: Validation
Scenario:
* def res1 = {"member":{"muid":"MBR1"},"part":[{"PID":"M123"},{"supportedMembers":[{"muid":"MBR3","status":{"code":"A"}},{"muid":"MBR2","status":{"code":"I"}}]}]}
* def res2 = {"members":[{"member":{"muid":"MBR2","test":[{"EID":"E123"}]}},{"member":{"muid":"MBR3","test":[{"EID":"E123"}]}}]}
* def id = res1.member.muid
* def res2ids = $res2.members[*]..muid
* def data2 = karate.mapWithKey(res2ids, 'muid')
* print data2
* def res2ids = karate.jsonPath(data2, "$[?(#.muid != '" + id+ "')]")
* def res2ids = $res2ids[*]..muid
* print res2ids
* match res1.part[1].supportedMembers[*].muid contains only res2ids

Karate - how to run multiple scenarios in a single feature file parallely?

I Have 4 scenarios in my feature file, and I want all my four scenarios to run in parallel, here is my feature file,
Feature:
Background:
* def Json = Java.type('Json')
* def dq = new Json()
* def result = dq.makeJson('0')
* def result1 = dq.makeJson('110')
* def result2 = dq.makeJson('220')
* def result3 = dq.makeJson('330')
Scenario Outline: id : <id>
* def ds_hotel_id = '<id>'
* print ds_hotel_id
Examples:
|result|
Scenario Outline: id : <id>
* def ds_hotel_id = '<id>'
* print ds_hotel_id
Examples:
|result1|
Scenario Outline: id : <id>
* def ds_hotel_id = '<id>'
* print ds_hotel_id
Examples:
|result2|
Scenario Outline: id : <id>
* def ds_hotel_id = '<id>'
* print ds_hotel_id
Examples:
|result3|
I am running it by this command line,
mvn clean test -Dcucumber.options="--plugin html:target/cucumber-html " -Dtest=dsRunner.java
What should I do, so that it can make it run all the scenarios simultaneously so that I can decrease the compilation time for my project? :)
Starting with version 0.9.0, scenarios are launched in parallel, unless specified otherwise with #parallel=false
If your features are running in parallel, then your scenarios will.
You should switch to 0.9.1 if that is not already the case.

How to add custom statistics in Grinder

In Grinder we'd like to add customized statistics
grinder.statistics.registerSummaryExpression("connTimeout", "userLong0")
grinder.statistics.forCurrentTest.addLong("userLong0", 1)
And it seems to be successful as we can get the customized field in Grinder out file
The problem is that the value of that statistics is always 0
Here is the complete script implemented by Jython
# -*- coding: utf-8 -*-
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from com.netease.cloud.ndir.performance import Query
from com.netease.cloud.ndir.performance import QueryReturnCode
def writeToFile(text):
filename = "response.log"
file = open(filename, "a")
file.write(str(text) + "\n")
file.close()
ndir_client = grinder.getProperties().getProperty("ndirClient")
query_file = grinder.getProperties().getProperty("queryFile")
request = Query("grinder.properties", query_file)
grinder.statistics.registerSummaryExpression("connTimeout", "userLong0")
grinder.statistics.registerSummaryExpression("readTimeout", "userLong1")
grinder.statistics.registerSummaryExpression("code!=200", "userLong2")
grinder.statistics.registerSummaryExpression("docs=[]", "userLong3")
grinder.statistics.registerSummaryExpression("unknown", "userLong4")
class TestRunner:
def __init__(self):
grinder.statistics.delayReports=True
def initialSleep(self):
sleepTime = grinder.threadNumber * 20 # per thread
grinder.sleep(sleepTime, 0)
def query(self):
if ndir_client == "true":
query = request.randomQueryByNdirClient
else:
query = request.randomQueryByHttpGet
try:
result = query()
except:
writeToFile("exception")
grinder.statistics.forCurrentTest.addLong("userLong4", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
if result == 0:
grinder.getStatistics().getForCurrentTest().setSuccess(True)
return
elif result == 1:
grinder.statistics.forCurrentTest.addLong("userLong0", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
elif result == 2:
grinder.statistics.forCurrentTest.addLong("userLong1", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
elif result == 3:
grinder.statistics.forCurrentTest.addLong("userLong2", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
elif result == 4:
grinder.statistics.forCurrentTest.addLong("userLong3", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(True)
return
else:
grinder.statistics.forCurrentTest.addLong("userLong4", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
request = Test(120, 'query').wrap(query)
def __call__(self):
if grinder.runNumber == 0:
self.initialSleep()
self.request(self)
I suspect the problem is that you are marking tests as failed, but expecting the statistics to appear in the summary. Only successful tests are accumulated into the summary statistics.
Try registering data log expressions as well
grinder.statistics.registerDataLogExpression("connTimeout", "userLong0")
grinder.statistics.registerDataLogExpression("readTimeout", "userLong1")
grinder.statistics.registerDataLogExpression("code!=200", "userLong2")
grinder.statistics.registerDataLogExpression("docs=[]", "userLong3")
grinder.statistics.registerDataLogExpression("unknown", "userLong4")
Then you'll at least see the values in the data log file of the worker process.