How do you send XML post request using rest-assured? - rest-assured

I have to send a post request with xml data and then validate the response like example checking the status code and response body.

You can either pass a pojo (remember to set the content-type to application/xml) and rest assured will automatically transform it into XML. For example:
#XmlRootElement
public class Greeting {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
and then you can use it like this:
Greeting greeting = new Greeting();
greeting.setFirstName("John");
greeting.setLastName("Doe");
given().contentType(ContentType.XML).and().body(object).when().post("/somewhere"). ..
it'll send the following XML:
<greeting>
<firstName>John</firstName>
<lastName>Doe</lastName>
</greeting>
Let's say that the server is responding with the same XML as the one you see above then you can validate the response status code and body like this:
given().
contentType(ContentType.XML).
body(object).
when().
post("/somewhere").
then().
statusCode(200).
body("greeting.firstName", equalTo("John")).
body("greeting.lastName", equalTo("Doe"));
REST Assured will automatically understand the the response body is XML if the server returns an XML content-type. Note that equalTo is statically imported from org.hamcrest.Matchers#equalTo.

Related

RestAssured: How to validate response body with JSON schema if response body has extra values?

I am validating json schema using matchesJsonSchemaInClasspath. It is working fine if response body have the same values that are defined in schema.json file.
If response body have EXTRA variable / value which is not define in json schema then it does not fail. How to fail this test case?
FOR EXAMPLE:
Below is response body which has predefined JSON schema.
{
"employee": {
"name": "sonoo",
"salary": 56000,
"married": true
}
}
If response body gives extra values such as email / phone then it is still passing. I need to make it fail.This is my test case to fail if response body return extra value. How to validate this test case?
{
"employee": {
"name": "Mike",
"salary": 56000,
"Phone": "+XXX",
"email": "test#gmail.com",
"married": true
}
}
Create a POJO class representing the json
public class Employee {
private String name;
private float salary;
private boolean married;
// Getter Methods
public String getName() {
return name;
}
public float getSalary() {
return salary;
}
public boolean getMarried() {
return married;
}
// Setter Methods
public void setName(String name) {
this.name = name;
}
public void setSalary(float salary) {
this.salary = salary;
}
public void setMarried(boolean married) {
this.married = married;
}
}
Use the following rest assured command to deserialize the response
Employee emp = response.getBody().as(Employee.class);
The above command will automatically fail and throw an error when additional field such as email or phone number is added to response body.

Spring Cloud Dataflow UI Not Rendering Whitelisted Properties

I have Spring Cloud DataFlow v1.3.1.RELEASE running locally, and I've created a small sample 'processor' app to illustrate what I see happening.
The Boot application has two #ConfigurationProperties classes:
DemoApplicationProperties:
#ConfigurationProperties
#Validated
public class DemoApplicationProperties {
/**
* The first name of the person.
*/
private String firstName;
/**
* The last name of the person.
*/
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
and DemoApplicationPropertiesTwo:
#ConfigurationProperties
#Validated
public class DemoApplicationPropertiesTwo {
/**
* The person's middle name.
*/
private String middleName;
/**
* The date of birth.
*/
private String birthdate;
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getBirthdate() {
return birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
}
I also include a unit test to make sure the BootApplicationConfigurationMetadataResolver is resolving all the whitelisted classes appropriately.
public class WhiteListTests {
private BootApplicationConfigurationMetadataResolver metadataResolver;
#Test
public void testMetadataResolver() {
metadataResolver = new BootApplicationConfigurationMetadataResolver(this.getClass().getClassLoader());
Resource app = new FileSystemResource(".\\target\\classes\\");
List<ConfigurationMetadataProperty> list = metadataResolver.listProperties(app);
for(ConfigurationMetadataProperty listItem : list) {
StringBuilder sb = new StringBuilder();
sb.append(listItem.getId() + ": " + listItem.getName() + " :: " + listItem.getType());
System.out.println(sb.toString());
}
}
}
The output of the unit test is as expected:
birthdate: birthdate :: java.lang.String
middle-name: middle-name :: java.lang.String
first-name: first-name :: java.lang.String
last-name: last-name :: java.lang.String
However, when I register the Boot application as a 'processor' in Spring Cloud Dataflow, and inspect the registered application, the UI only partially renders the discovered whitelisted properties:
I have a ZIP file of the project source code, but for whatever reason, cannot figure out how to attach it here.
Inside the file spring-configuration-metadata-whitelist.properties did you add the two classes in the property ?
Example
configuration.classes = org.springframework.cloud.stream.app.file.sink.FileSinkProperties
and
com.anotherpackage.MainConfig.java
Both the properties class must be declared in the spring-configuration-metadata-whitelist.properties file. Shell, Dashboard, and REST endpoints should then be able to produce the results consistently.
Here's the same example in action.

Wrapping IHttpActionResult - Generic solution

I'd like to wrap IHttpActionResult because I need some extra data to be consumed by the client app.
My first approach was to create and return simple DTO, wrapping result object if succeeded:
Response DTO:
public class Response<T>
{
public string ErrorMessage { get; set; }
public bool Success { get; set; }
public string CodeStatus { get; set; }
public T Result { get; set; }
public Response(bool isSuccess, [Optional] T result, [Optional] string codeStatus, [Optional] string errorMessage)
{
Success = isSuccess;
Result = result;
CodeStatus = codeStatus;
ErrorMessage = errorMessage;
}
}
Controller:
public IHttpActionResult Get(int id)
{
return BadRequest(new Response<MyObjectClass>(false, null,"Invalid Id",400));
...
return Ok(new Response<MyObjectClass>(true, result);
}
I've found it very ineffective way to deal with wrapping. I dont find it very elegant way. I've tried to figured out some generic solution and ended up with the following:
Example Controller Action:
public IHttpActionResult GetById(int id)
{
var result = _someService.Get(id);
if (result == null)
return NotFound().WithError("Invalid Id");
return Ok().WithSuccess(result);
}
This still returns Response DTO.
I've wrapped IHttpActionResult to deal with creating Response DTO:
public class HttpActionResult : IHttpActionResult
{
private readonly string _errorMessage;
private readonly IHttpActionResult _innerResult;
private readonly object _result;
private readonly bool _isSuccess;
public HttpActionResult(IHttpActionResult inner, bool isSuccess, object result,string errorMessage)
{
_errorMessage = errorMessage;
_innerResult = inner;
_result = result;
_isSuccess = isSuccess;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = await _innerResult.ExecuteAsync(cancellationToken);
response.Content = new ObjectContent(typeof(Response), new Response(_isSuccess, _result, ((int)response.StatusCode).ToString(), _errorMessage), new JsonMediaTypeFormatter());
return response;
}
}
Finally I've added extension methods to IHttpActionResult to easier use in controller:
public static class IHttpActionResultExtensions
{
public static IHttpActionResult WithSuccess(this IHttpActionResult inner, object result = null, string message = null)
{
return new HttpActionResult(inner, true, result, message);
}
public static IHttpActionResult WithError(this IHttpActionResult inner, string message = null)
{
return new HttpActionResult(inner, false,null, message);
}
}
What are the alternatives to deal with wrapping http messages in API Controller?
What weak points do you see in my solution?
BTW, I see some weak points on your approach:
WebAPI is meant to be used to create RESTful Web services. Why are you trying to provide another layer of status and other details? HTTP is rich enough to cover these requirements. For example, you can use standard status codes and a subcode as follows: 500.1, 500.2.
Success or failure is easier to express with HTTP status codes. 2XX range for successful operations, and for an unsuccessful one you can use, for example, 400 (Bad Request). 401 for an unauthorized access... 500 for a server failure...
WebAPI already provides ModelState to let the framework build a response object. Use it and try to don't re-invent the wheel.
Again, keep it simple. Response entity goes on the response body. Success or failure is expressed by status codes. Details about a bad request are added to the ModelState dictionary. An error message should be set to the response's ReasonPhrase.
IHttpActionResult implementations are meant to transform your domain result into an HTTP response. That is, you're in the right track excepting when you try to return your response object as is. My advise is you should use your IHttpActionResult to set every detail on your own response object to standard HTTP semantics, and notify errors using ModelState out-of-the-box approach which works well.
Avoid IHttpActionResult and use HttpResponseException with Business Entity as result type. As in your solution, you cannot write statically typed test cases.
For example,
protected void ThrowHttpError(HttpStatusCode statusCode, string message)
{
throw new HttpResponseException(
new HttpResponseMessage(statusCode) {
ReasonPhrase = message,
// HTTP 2.0 ignores ReasonPhrase
// so we send ReasonPhrase again in the Content
Content = new StringContent(message)
});
}
// some generic option...
protected void ThrowHttpError<T>(HttpStatusCode statusCode, T content)
where T:class
{
throw new HttpResponseException(
new HttpResponseMessage(statusCode) {
ReasonPhrase = "Error",
Content = JsonConvert.Serialize(content)
});
}
Your methods,
public async Task<Product> Get(long id){
var product = await context.Products
.FirstOrDefaultAsync( x=> x.ProductID == id);
if(product==null){
ThrowHttpError(HttpStatusCode.NotFound,
$"Product not found for {id}");
}
if(product.RequiresValidation){
// generic version....
ThrowHttpError(HttpStatusCode.Conflict,
new Product{
ProductID = product.ProductID,
ValidationRequestCode = product.ValidationRequestCode
});
}
return product;
}
For further more, you can customise method ThrowHttpError to suite your needs. Best part is, it is still testable.

struts2 taglib Object access in jsp

HI i have created one action, that contain one Document Object. I want to display those properties in jsp. i used to struts tag i am not able to get it , i am able to get string property of action , but not Object can you please help me... se my code below. i went all suport. i am not able to fix it. i am using tomcat7 .
public class SearchResultAction extends ActionSupport{
private static Logger log = Logger.getLogger(SearchResultAction.class);
private String name;
private DocumentData documentData;
public String execute() throws Exception {
documentData=new DocumentData();
documentData.setdocName("docName");
documentData.setdDocTitle("docTitle");
if (documentData!=null)
{
return SUCCESS;
}else{
return ERROR;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DocumentData getDocumentData() {
return documentData;
}
public void setDocumentData(DocumentData documentData) {
this.documentData = documentData;
}
}
My jsp code is:
<s:property value="documentData.docName" default="object is null"/>
My pojo class is:
public class DocumentData {
String docName;
String dDocTitle;
String dDocDate;
String dDocAuther;
// setters and getters for all property
}
Your docName setter doesn't follow JavaBean conventions; does your getter?
E.g., setdocName should be setDocName, the getter getDocName.
OGNL is going to call getDocName(), if the method doesn't exist, you won't get data.

Access ApplicationResource.properties file from Action Class in Struts 2

can i access ApplicationResource.properties file keys from Action Class in Struts 2
and update the values of the key ?
I don't think you can update the values of those keys directly, that would kind of defeat the purpose of it being (static) resources.
You can however use placeholders.
ApplicationResources.properties
property.key=Hi {0}, there's a problem with {1}
MyAction.java
public ActionForward execute(ActionMapping mapping,
ActionForm form,
javax.servlet.ServletRequest request,
javax.servlet.ServletResponse response)
throws java.lang.Exception {
MessageResources msgResource = getResources(request);
String msg = msgResource.getMessage("property.key", "Sankar", "updating values in the resources.");
}
Yes its possible.
Lets say if you have a property error.login in applicationResources.properties file.
eg : error.login= Invalid Username/Password. Please try again.
then in the Action class you can access it like this : getText("error.login")
Complete example:
applicationResources.properties
error.login= Invalid Username/Password
LoginAction.java
package net.sumitknath.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String username;
private String password;
public String execute() {
if (this.username.equals("admin") && this.password.equals("admin123")) {
return "success";
} else {
addActionError(getText("error.login"));
return "error";
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

Resources