How to print atribute value from Response in teardown script - soap

I want to print attribute value from response if my assertion fails. Sample error Response:
<soapenv:Body>
<ns0:Fault xmlns:ns1="http://www.w3.org/2003/05/soap-envelope" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>OSB-382500</faultcode>
<faultstring>Mandatory Parameter Customer Type cannot be empty (uuid: 1f8b9637-11b1-47ea-9ebd-3abf2fda950e)</faultstring>
<detail>
<ns0:Fault xmlns:ns0="http://group.vodafone.com/contract/vfo/fault/v1" xmlns:ns2="http://group.vodafone.com/contract/vho/header/v1" xmlns:ns3="http://group.vodafone.com/schema/common/v1" xmlns:ns6="http://docs.oasis-open.org/wsrf/bf-2" xmlns:ns7="http://www.w3.org/2005/08/addressing">
<ns6:Timestamp>2017-08-16T20:44:27.15+05:30</ns6:Timestamp>
<ns6:ErrorCode>500</ns6:ErrorCode>
<ns0:Name/>
<ns0:Severity>Critical</ns0:Severity>
<ns0:Category>Technical</ns0:Category>
<ns0:ReasonCode>ReasonCode</ns0:ReasonCode>
<ns0:Message>Service Callout Failure</ns0:Message>
</ns0:Fault>
</detail>
</ns0:Fault>
</soapenv:Body>
I want to print value "Service Callout Failure" if my assertion fails.
Currently my script is printing assertion status and testcase name. I want to print the particular attribute value from response. My Teardown Script:
import com.eviware.soapui.model.testsuite.Assertable.AssertionStatus
import jxl.*;
import jxl.write.*;
def TestCase = testRunner.getTestCase()
def StepList = TestCase.getTestStepList()
def status
def i = 0
WritableWorkbook workbook1 = Workbook.createWorkbook(new File("C:\\report1.xls"));
WritableSheet sheet1 = workbook1.createSheet("Report Worksheet", 0);
StepList.each{
if(it.metaClass.hasProperty(it,'assertionStatus')){
if(it.assertionStatus == AssertionStatus.FAILED){
log.info "${it.name} FAIL..."
status = "FAIL";
}else if(it.assertionStatus == AssertionStatus.VALID){
log.info "${it.name} OK!"
status = "Passed";
}else if(it.assertionStatus == AssertionStatus.UNKNOWN){
log.info "${it.name} UNKNOWN (PROBABLY NOT EXECUTED)"
status = "UNKNOWN";
}
}
Label label1 = new Label(i, sheet1.rows, it.name);
Label label2 = new Label(i+1, sheet1.rows, status);
sheet1.addCell(label1);
sheet1.addCell(label2);
}
workbook1.write();
workbook1.close();

I am using context.expand to get data from response to groovy,
for example
def hotel = context.expand( '${SearchHotels#Response#declare namespace ns1=\'someNamespace\'; declare namespace ns2=\'someNamespace2\'; //ns2:SearchHotelsResponse[1]/ns2:SearchHotelsResult[1]/ns1:TWS_HotelList[1]/ns1:Hotel[1]}' )
Namespace aside, at SearchHotels#Response... SearchHotels is name of test step, you can get response message using correct path to ns0:Message and then print it instead of constant data...

I used the below statement:
def req = it.name; message[k] = context.expand('${'+req+'#Response#declare namespace ns0=\'http://group.vodafone.com/contract/vfo/fault/v1\'; //ns0:Message}')
and it worked.

Related

FastAPI Pytest why does client returns 422

I'm trying to implement testing my post route. It works in my project. I have problems only with pytest.
main.py:
#app.post('/create_service', status_code=status.HTTP_201_CREATED)
async def post_service(
response: Response, service: CreateService, db: Session = Depends(get_db)
):
service_model = models.Service()
service_name = service.name
service_instance = db.query(models.Service).filter(
models.Service.name == service_name
).first()
if service_instance is None:
service_model.name = service_name
db.add(service_model)
db.commit()
serviceversion_model = models.ServiceVersion()
service_instance = db.query(models.Service).filter(
models.Service.name == service_name
).first()
serviceversion_instance = db.query(models.ServiceVersion).filter(
models.ServiceVersion.service_id == service_instance.id
).filter(models.ServiceVersion.version == service.version).first()
if serviceversion_instance:
raise HTTPException(
status_code=400, detail='Version of service already exists'
)
serviceversion_model.version = service.version
serviceversion_model.is_used = service.is_used
serviceversion_model.service_id = service_instance.id
db.add(serviceversion_model)
db.commit()
db.refresh(serviceversion_model)
service_dict = service.dict()
for key in list(service_dict):
if isinstance(service_dict[key], list):
sub_dicts = service_dict[key]
if not sub_dicts:
response.status_code = status.HTTP_400_BAD_REQUEST
return HTTPException(status_code=400, detail='No keys in config')
servicekey_models = []
for i in range(len(sub_dicts)):
servicekey_model = models.ServiceKey()
servicekey_models.append(servicekey_model)
servicekey_models[i].service_id = service_instance.id
servicekey_models[i].version_id = serviceversion_model.id
servicekey_models[i].service_key = sub_dicts[i].get('service_key')
servicekey_models[i].service_value = sub_dicts[i].get('service_value')
db.add(servicekey_models[i])
db.commit()
return 'created'
test_main.py:
def test_create_service(client, db: Session = Depends(get_db)):
key = Key(service_key='testkey1', service_value='testvalue1')
service = CreateService(
name="testname1",
version="testversion1",
is_used=True,
keys=[key, ]
)
response = client.post("/create_service", params={"service": service.dict()})
assert response.status_code == 200
I tried to post service as json, as CreateService instance and finally as params dictionary. I have no errors at response line only with the last one . But I got 422 response status code. What is wrong?
If it can help:
schemas.py
class Key(BaseModel):
service_key: str
service_value: str
class CreateService(BaseModel):
name: str
version: str
is_used: bool
keys: list[Key]
class Config:
orm_mode = True
Don't use params. Use json:
response = client.post("/create_service", json=service.dict())

How do I make a HTTP PUT call from XLRelease to update data in Adobe Workfront?

I am attempting to make an HTTP PUT request from XLRelease to update data in Adobe Workfront. I have been able to successfully login using the API client and GET data. I have also been able to successfully update data using Postman as well as using a native Python script. I am using the HttpRequest library within XLR. I am receiving the same response back in XLR as I am when successfully updating when using Postman, however, the data is not updated when using XLR.
My code is as follows:
import json
WORKFRONT_API_HOST = releaseVariables['url']
WORKFRONT_API_VERSION = releaseVariables['wfApiVersion']
WORKFRONT_API_KEY = releaseVariables['apiKey']
WORKFRONT_USERNAME = releaseVariables['wfUsername']
FI_ID = releaseVariables['target_customer_id']
newPortfolioId = releaseVariables['target_portfolio_id']
WORKFRONT_API_URL = WORKFRONT_API_HOST + WORKFRONT_API_VERSION
def wfLogin():
sessionID = ""
login_endpoint = "/login"
login_request = HttpRequest({'url': WORKFRONT_API_URL})
login_response = login_request.get(login_endpoint + "?apiKey=" + str(WORKFRONT_API_KEY).replace("u'","'") + "&username=" + WORKFRONT_USERNAME, contentType='application/json')
if login_response.getStatus() != 200:
print('# Error logging into WF\n')
print(login_response.getStatus())
print(login_response.errorDump())
sys.exit(1)
else:
json_response = json.loads(login_response.getResponse())
print ("Logged in to WF")
sessionID = json_response['data']['sessionID']
return sessionID
def wfLogout(sessionID):
logout_endpoint = "/logout"
logout_request = HttpRequest({'url': WORKFRONT_API_URL})
logout_response = logout_request.get(logout_endpoint + "?sessionID=" + sessionID, contentType='application/json')
if logout_response.getStatus() != 200:
print('# Error logging out of WF\n')
print(logout_response.getStatus())
print(logout_response.errorDump())
sys.exit(1)
else:
json_response = json.loads(logout_response.getResponse())
print ("Logged out of WF")
result = []
session_id = wfLogin()
if session_id != "":
customer_request = HttpRequest({'url': WORKFRONT_API_URL})
endpoint = '/prgm/%s?sessionID=%s&portfolioID=%s&customerID=%s' % (FI_ID, session_id, newPortfolioId, FI_ID)
jsonObj = "{}"
payload = {}
customer_response = customer_request.put(endpoint, jsonObj, contentType='application/json')
if customer_response.getStatus() != 200:
print('# Error connecting to WF\n')
print(customer_response)
print(customer_response.getStatus())
print(customer_response.errorDump())
sys.exit(1)
else:
response_json = json.loads(customer_response.getResponse())
print ("response_json: ", response_json)
#log out of current session
wfLogout(session_id)
else:
print ("No sessionID is available")
sys.exit(1)

py.test capture unhandled exception

We are using py.test 2.8.7 and I have the below method which creates a separate log file for every test-case. However this does not handle unhandled Exceptions. So if a code snippet throws an Exception instead of failing with an assert, the stack-trace of the Exception is not logged into the separate file. Can someone please help me in how I could capture these Exceptions?
def remove_special_chars(input):
"""
Replaces all special characters which ideally shout not be included in the name of a file
Such characters will be replaced with a dot so we know there was something useful there
"""
for special_ch in ["/", "\\", "<", ">", "|", "&", ":", "*", "?", "\"", "'"]:
input = input.replace(special_ch, ".")
return input
def assemble_test_fqn(node):
"""
Assembles a fully-qualified name for our test-case which will be used as its test log file name
"""
current_node = node
result = ""
while current_node is not None:
if current_node.name == "()":
current_node = current_node.parent
continue
if result != "":
result = "." + result
result = current_node.name + result
current_node = current_node.parent
return remove_special_chars(result)
# This fixture creates a logger per test-case
#pytest.yield_fixture(scope="function", autouse=True)
def set_log_file_per_method(request):
"""
Creates a separate file logging handler for each test method
"""
# Assembling the location of the log folder
test_log_dir = "%s/all_test_logs" % (request.config.getoption("--output-dir"))
# Creating the log folder if it does not exist
if not os.path.exists(test_log_dir):
os.makedirs(test_log_dir)
# Adding a file handler
test_log_file = "%s/%s.log" % (test_log_dir, assemble_test_fqn(request.node))
file_handler = logging.FileHandler(filename=test_log_file, mode="w")
file_handler.setLevel("INFO")
log_format = request.config.getoption("--log-format")
log_formatter = logging.Formatter(log_format)
file_handler.setFormatter(log_formatter)
logging.getLogger('').addHandler(file_handler)
yield
# After the test finished, we remove the file handler
file_handler.close()
logging.getLogger('').removeHandler(file_handler)
I have ended-up with a custom plugin:
import io
import os
import pytest
def remove_special_chars(text):
"""
Replaces all special characters which ideally shout not be included in the name of a file
Such characters will be replaced with a dot so we know there was something useful there
"""
for special_ch in ["/", "\\", "<", ">", "|", "&", ":", "*", "?", "\"", "'"]:
text = text.replace(special_ch, ".")
return text
def assemble_test_fqn(node):
"""
Assembles a fully-qualified name for our test-case which will be used as its test log file name
The result will also include the potential path of the log file as the parents are appended to the fqn with a /
"""
current_node = node
result = ""
while current_node is not None:
if current_node.name == "()":
current_node = current_node.parent
continue
if result != "":
result = "/" + result
result = remove_special_chars(current_node.name) + result
current_node = current_node.parent
return result
def as_unicode(text):
"""
Encodes a text into unicode
If it's already unicode, we do not touch it
"""
if isinstance(text, unicode):
return text
else:
return unicode(str(text))
class TestReport:
"""
Holds a test-report
"""
def __init__(self, fqn):
self._fqn = fqn
self._errors = []
self._sections = []
def add_error(self, error):
"""
Adds an error (either an Exception or an assertion error) to the list of errors
"""
self._errors.append(error)
def add_sections(self, sections):
"""
Adds captured sections to our internal list of sections
Since tests can have multiple phases (setup, call, teardown) this will be invoked for all phases
If for a newer phase we already captured a section, we override it in our already existing internal list
"""
interim = []
for current_section in self._sections:
section_to_add = current_section
# If the current section we already have is also present in the input parameter,
# we override our existing section with the one from the input as that's newer
for index, input_section in enumerate(sections):
if current_section[0] == input_section[0]:
section_to_add = input_section
sections.pop(index)
break
interim.append(section_to_add)
# Adding the new sections from the input parameter to our internal list
for input_section in sections:
interim.append(input_section)
# And finally overriding our internal list of sections
self._sections = interim
def save_to_file(self, log_folder):
"""
Saves the current report to a log file
"""
# Adding a file handler
test_log_file = "%s/%s.log" % (log_folder, self._fqn)
# Creating the log folder if it does not exist
if not os.path.exists(os.path.dirname(test_log_file)):
os.makedirs(os.path.dirname(test_log_file))
# Saving the report to the given log file
with io.open(test_log_file, 'w', encoding='UTF-8') as f:
for error in self._errors:
f.write(as_unicode(error))
f.write(u"\n\n")
for index, section in enumerate(self._sections):
f.write(as_unicode(section[0]))
f.write(u":\n")
f.write((u"=" * (len(section[0]) + 1)) + u"\n")
f.write(as_unicode(section[1]))
if index < len(self._sections) - 1:
f.write(u"\n")
class ReportGenerator:
"""
A py.test plugin which collects the test-reports and saves them to a separate file per test
"""
def __init__(self, output_dir):
self._reports = {}
self._output_dir = output_dir
#pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(self, item, call):
outcome = yield
# Generating the fully-qualified name of the underlying test
fqn = assemble_test_fqn(item)
# Getting the already existing report for the given test from our internal dict or creating a new one if it's not already present
# We need to do this as this method will be invoked for each phase (setup, call, teardown)
if fqn not in self._reports:
report = TestReport(fqn)
self._reports.update({fqn: report})
else:
report = self._reports[fqn]
result = outcome.result
# Appending the sections for the current phase to the test-report
report.add_sections(result.sections)
# If we have an error, we add that as well to the test-report
if hasattr(result, "longrepr") and result.longrepr is not None:
error = result.longrepr
error_text = ""
if isinstance(error, str) or isinstance(error, unicode):
error_text = as_unicode(error)
elif isinstance(error, tuple):
error_text = u"\n".join([as_unicode(e) for e in error])
elif hasattr(error, "reprcrash") and hasattr(error, "reprtraceback"):
if error.reprcrash is not None:
error_text += str(error.reprcrash)
if error.reprtraceback is not None:
if error_text != "":
error_text += "\n\n"
error_text += str(error.reprtraceback)
else:
error_text = as_unicode(error)
report.add_error(error_text)
# Finally saving the report
# We need to do this for all phases as we don't know if and when a test would fail
# This will essentially override the previous log file for a test if we are in a newer phase
report.save_to_file("%s/all_test_logs" % self._output_dir)
def pytest_configure(config):
config._report_generator = ReportGenerator("result")
config.pluginmanager.register(config._report_generator)

Save attachments from response in SoapUI

I get 2 files in response of a SOAP request. I try to save these files with followig Groovy script. I use script as a script assertion for test step. First file is saved successfully in execution, but couldn't find second one.
def fileName = "C:\\<mydirectory>"+'/test.pdf'
def fileName1 = "C:\\<mydirectory>"+'/test1.pdf'
def response = messageExchange.response
assert null != response, "response is null"
def outFile = new FileOutputStream(new File(fileName))
def outFile1 = new FileOutputStream(new File(fileName1))
def ins = messageExchange.responseAttachments[0]?.inputStream
def ins1 = messageExchange.responseAttachments[0]?.inputStream
if (ins) {
com.eviware.soapui.support.Tools.writeAll(outFile, ins)
}
ins.close()
outFile.close()
if (ins1) {
com.eviware.soapui.support.Tools.writeAll(outFile1, ins)
}
ins1.close()
outFile1.close()

Attaching file in SoapUI with groovy

I'm creating some tests in SoapUI. SOAP request, that i want to test has attachment. When I'm setting it manualy, everything is ok:
But in my case, i need to set attachment dynamically. I'm trying to made it by properties to hold file path, and groovy script to set attachment. but it's not work at all:
// get request
def request = testRunner.testCase.getTestStepByName( "UploadRoutingCodes" ).testRequest
// clear existing attachments
for( a in request.attachments ) {
request.removeAttachment( a )
}
// get file to attach
//def fileName = context.expand( '${Source of data#PathToXRC File data name }' )
def fileName = context.expand( '${#TestCase#XRC_file_name}' )
def filePath = context.expand( '${#Project#XRC_files_path}' )
log.info "file: " + filePath + fileName
def file = new File(filePath + fileName )
if ( file == null) {
log.error "bad filename"
}
else
{
// attach and set properties
def attachment = request.attachFile( file, true )
attachment.contentType = "application/octet-stream"
def list = fileName.tokenize("\\");
attachment.setPart(list.last())
}
After run this script, request look like this:
Documentation to SoapUI is not helpful at all.
So, my question is: what i'm doing wrong?
I found the answer:
def holder2 = groovyUtils.getXmlHolder( "UploadRoutingCodes#Request" ) // Get Request body
def startDate2 = holder2.setNodeValue( "//blac:FileByteStream","cid:"+list.last()); //Set "link" to attachment in request body
holder2.updateProperty() //and update
attachment.setPart(list.last()); //set attachment
Thaven, thank you for your answer. It helped. I will attach my full groovy script as I spent some time to fully assembled your parts, but anyhow all tributes goes to you.
Please note that:
//FileNamePath
def fileNamePath = testCase.getTestStepAt(testRunner.testCase.getTestStepIndexByName("FileNameProperties")).getProperty("FileNamePath")
//FileName
def fileName = testCase.getTestStepAt(testRunner.testCase.getTestStepIndexByName("FileNameProperties")).getProperty("FileName")
are the test step properties defined inside the test case. Filename: my_sample_filename.xml and FileNamePath: C:\samples\my_sample_filename.xml accordingly.
import groovy.xml.MarkupBuilder
import org.custommonkey.xmlunit.*
import java.util.Random
import java.security.MessageDigest
import java.nio.file.*
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def projectPath = groovyUtils.projectPath
log.info projectPath
def project = testRunner.testCase.testSuite.project
log.info "Project: " + project.name
def myTestSuite = testRunner.testCase.testSuite;
log.info "TestSuite: " + myTestSuite.name
def testCase = testRunner.testCase
log.info "TestCase: " + testCase.name
def testStepUploadDataAfterCheck = testCase.getTestStepByName("UploadDataAfterCheck")
def request= testStepUploadDataAfterCheck.testRequest
log.info "TestStep: " + testStepUploadDataAfterCheck.name
// clear existing attachments
for( a in request.attachments ) {
request.removeAttachment( a )
}
//FileNamePath
def fileNamePath = testCase.getTestStepAt(testRunner.testCase.getTestStepIndexByName("FileNameProperties")).getProperty("FileNamePath")
//FileName
def fileName = testCase.getTestStepAt(testRunner.testCase.getTestStepIndexByName("FileNameProperties")).getProperty("FileName")
// get file to attach
log.info "file to attach: " + fileNamePath.getValue()
def file = new File(fileNamePath.getValue() )
if ( file == null) {
log.error "bad filename"
}
else
{
// attach and set properties
def attachment = request.attachFile( file, true )
attachment.contentType = "application/octet-stream"
attachment.setPart(fileName.getValue())
def holder2 = groovyUtils.getXmlHolder( "UploadDataAfterCheck#Request" ) // Get Request body
holder2.setNodeValue( "//upl:UploadDataAfterCheckRequest/uploadedData","cid:"+fileName.getValue()); //Set "link" to attachment in request body
holder2.updateProperty() //and update
log.info "file attached succesfully"
}
And here is my soap request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:upl="http://www.acer.europa.eu/aris/upload">
<soapenv:Header/>
<soapenv:Body>
<upl:UploadDataAfterCheckRequest>
<uploadedData>cid:my_sample_filename.xml</uploadedData>
</upl:UploadDataAfterCheckRequest>
</soapenv:Body>
</soapenv:Envelope>