How can I unit test an HTTP service in Ballerina? - testing

Suppose I have an echo HTTP service written in Ballerina as follows:
import ballerina/http;
service / on new http:Listener(9090) {
resource function post echo(#http:Payload json payload) returns json {
return payload;
}
}
How can I write unit test the behavior of the echo resource method?

You can write unit tests for an HTTP service using the Ballerina HTTP client.
Place the tests inside the tests directory inside your Ballerina project.
Following is an example test:
import ballerina/http;
import ballerina/test;
#test:Config {}
function testService() returns error? {
http:Client httpClient = check new("http://localhost:9090");
json requestPayload = {message: "hello"};
http:Request request = new;
request.setPayload(requestPayload);
json responsePayload = check httpClient->post("/echo", request);
test:assertEquals(responsePayload, requestPayload);
}
Here, we send a payload and get it back using an HTTP client, and then check whether the echo service sends back the same payload.
When running the tests, the service will be started automatically. You don't have to run them manually.

Related

How to handle a GET request for REST API request which is having a body with QAF Webservice

I am using QAF Webservice support for API automation. I have a case where a GET request has a body present. If I pass the request as either using properties file or xml file, on executing I am getting 404 not found response. If the GET request does not have a body present, it works fine in that scenario without any issues. But not with GET request having a body. Upon debugging, found that jersey client API at the end changes the request from GET to POST if a GET request has a body. Please let me know on how to handle this scenario using QAF WebService.
Thanks,
You can use apache HttpClient that will allow to have body with get request. In order to use apache HttpClient, you need to provide implementation of RestClientFactory and register using property rest.client.impl.
Here is the sample code from the qaf users group.
package qaf.example.tests;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import com.qmetry.qaf.automation.ws.rest.RestClientFactory;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandler;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.client.apache.ApacheHttpClient;
import com.sun.jersey.client.apache.ApacheHttpClientHandler;
import com.sun.jersey.client.apache.config.DefaultApacheHttpClientConfig;
/**
* #author chirag
*
*/
public class ApacheClientProvider extends RestClientFactory {
#Override
protected Client createClient() {
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
connectionManager.getParams().setConnectionTimeout(5000);
connectionManager.getParams().setSoTimeout(1000);
connectionManager.getParams().setDefaultMaxConnectionsPerHost(10);
HttpClient httpClient = new HttpClient(connectionManager);
ApacheHttpClientHandler clientHandler = new ApacheHttpClientHandler(httpClient);
ClientHandler root = new ApacheHttpClient(clientHandler );
ClientConfig config = new DefaultApacheHttpClientConfig();
Client client = new Client(root, config);
return client;
}
}
In order to use it, register your class using rest.client.impl property, in above case:
rest.client.impl=qaf.example.tests.ApacheClientProvider

Failed to load Resource : the server ressponded with the status 404(Not Found) in console in Angular 5

This is quiz.service.ts
import { Injectable, } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class QuizService
{
readonly rootUrl = 'http://localhost:4200';
constructor(private http : HttpClient)
{
}
insertParticipant(name: string, email: string)
{
var body = {
Name : name,
Email: email
}
return this.http.post(this.rootUrl + '/api/InsertParticipant',body);
}
}
I get this error:
Failed to load Resource : the server responded with the status 404(Not Found) in console in Angular 5
I think its the url issue is there.
My angular version details
Angular CLI : 1.7.4
Node : 12.13.0
OS : win32 * 64
Angular : 5.2.11
I think the url is having the navigation problem.
How to solve the error?
What is the proper way to route the url in angular 5.2?
as I can see you don't have backend and try to send a requests into your .ts file (mayby I'm wrong).
But if it's true, you need a server with backend api to make http requests (it can be a server on your local machine or it can be remote server) and you need a method that will process your request.
Request will be look like this your_server_url/api/insert_participant.
Also you can you use https://www.npmjs.com/package/angular-in-memory-web-api to emulate CRUD operations without servers api. It intercepts Angular Http and HttpClient requests that would otherwise go to the remote server and redirects them to an in-memory data store that you control.

Passing String value from Angular $http post to Spring #RestController

I have a REST api endpoint like this -
#RequestMapping(value = "/createform/custom/name", method = RequestMethod.POST)
public String nameSubmit(#RequestBody String name) {
return "you have submitted this name ***** "+name;
}
From angular service I tried to make a REST call like this -
var data = 'name='+inputName;
$http.post(uploadUrl, data, {
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(
function(success){
alert(success.data);
},
function(error){
alert(error.status);
}
);
Now I always get a -1 HTTP status and control goes to error block. I also tried #RequestParam instead of #RequestBody but no luck. But if I try to access the service through curl or chrome postman , everything works fine. Only when I try through angular application I get stuck with -1 response.
It was a CORS issue. I tried the Spring proposed solutions first. But the "gs-rest-service-cors" jar was not found in Maven repository. Hence ended up writing a filter as shown here and things worked fine.

Communication between AngularJS and a Jersey Webservice which are on a different domain. Can't access correct session

Lately I've been playing around with AngularJS and Java EE 6. I've build an webservice with Jersey and deployed the project on Glassfish. Because I needed some kind of authentication and an OAuth implementation or an JDBCRealm seemed overkill I decided to just create a session if the user successfully logged in.
#POST
#Path("/login")
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
public Response login(LoginDAO loginData, #Context HttpServletRequest req) {
req.getSession().invalidate();
loginData.setPassword(PasswordGenerator.hash(loginData.getPassword()));
User foundUser = database.login(loginData);
if(foundUser == null) {
return Response.status(Status.CONFLICT).build();
}
req.getSession(true).setAttribute("username", foundUser.getUsername());
return Response.ok().build();
}
#GET
#Path("/ping")
public Response ping(#Context HttpServletRequest req) {
if(req.getSession().getAttribute("username") == null) {
return Response.ok("no session with an username attribute has been set").build();
}
return Response.ok(req.getSession(true).getAttribute("username")).build();
}
This seems to work alright, if I post to /login from Postman or from a basic jQuery webpage deployed on glassfish I do get the correct username back and a session has been placed. If I then send a GET request to /ping I do get the username back from which I logged in.
I've an AngularJS application deployed on a node.js webserver which needed to login. Because this server is on another port its on another domain and I had to go through the pain of enabling cors. I did this by building a container response filter which sets the response headers.
public class CrossOriginResourceSharingFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest creq, ContainerResponse cresp) {
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Origin", "http://localhost:8000");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Credentials", "true");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
return cresp;
}
}
This did made it possible for me to send different types of HTTP requests from AngularJS to Java EE 6 application deployed on glassfish.
The problem is that when I send a POST request from AngularJS to the /login method, a session is created and I do get my username back. But when I send a GET request to the /ping method I get the "no session with an username attribute has been set" notice.
I believe this has to do with cross domain prevention and that I've to set the withCredentials tag when I send a xhr request. I've been trying to do this in AngularJS but haven't found out how to do this.
function LoginCtrl($scope, $http) {
$scope.login = function() {
$http.post("glassfish:otherport/api/login", $scope.credentials).
success(function(data) {
console.log(data);
}).
error(function(data, error) {
console.log(error);
});
};
};
And in another controller:
$scope.getUsername = function() {
$http.get("glassfish:otherport/api/ping", {}).
success(function(data) {
$scope.username = data;
}).
error(function() {
$scope.username = "error";
})
}
I've tried to set withCredentials is true
$http.defaults.withCredentials = true;
This however didn't solve my problem. I also tried to send it with every request in the config parameter but this didn't solve my problem either.
Depending on the version of AngularJS you are using you might have to set it on each $http.
Since 1.2 you can do:
$http.get(url,{ withCredentials: true, ...})
From 1.1.1 you can globally configure it:
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]).
If you're using an older version of Angular, try passing a config object to $http that specifies withCredentials. That should work in versions before 1.1:
$http({withCredentials: true, ...}).get(...)
See also mruelans answer and:
https://github.com/angular/angular.js/pull/1209
http://docs.angularjs.org/api/ng.$http
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#section_5
just an update to #iwein anwser, that we can now set in config itself
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]).
https://github.com/angular/angular.js/pull/1209
(available only after unstable version: 1.1.1)
In 1.2 version, this doesn't work for me:
$http({withCredentials: true, ...}).get(...)
if I read the doc, the shortcut method should take the config object
$http.get(url,{ withCredentials: true, ...})
$http is a singleton, That's the only way to mix in a same application requests with and without credentials.

Grails how to post out to someone else's API

I am writing a Grails app, and I want the controller to hit some other API with a POST and then use the response to generate the page my user sees. I am not able to Google the right terms to find anything about posting to another page and receiving the response with Grails. Links to tutorials or answers like "Thats called..." would me much appreciated.
Seems like you are integrating with some sort of RESTful web service. There is REST client plugin, linked here.
Alternatively, its quite easy to do this without a plugin, linked here.
I highly recommend letting your controller just be a controller. Abstract your interface with this outside service into some class like OtherApiService or some sort of utility. Keep all the code that communicates with this outside service in one place; that way you can mock your integration component and make testing everywhere else easy. If you do this as a service, you have room to expand, say in the case you want to start storing some data from the API in your own app.
Anyway, cutting and posting from the linked documentation (the second link), the following shows how to send a GET to an API and how to set up handlers for success and failures, as well as dealing with request headers and query params -- this should have everything you need.
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.5.0-RC2' )
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
def http = new HTTPBuilder( 'http://ajax.googleapis.com' )
// perform a GET request, expecting JSON response data
http.request( GET, JSON ) {
uri.path = '/ajax/services/search/web'
uri.query = [ v:'1.0', q: 'Calvin and Hobbes' ]
headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
// response handler for a success response code:
response.success = { resp, json ->
println resp.statusLine
// parse the JSON response object:
json.responseData.results.each {
println " ${it.titleNoFormatting} : ${it.visibleUrl}"
}
}
// handler for any failure status code:
response.failure = { resp ->
println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
}
}
You might also want to check out this, for some nifty tricks. Is has an example with a POST method.