Validate request Body using github.com/jarcoal/httpmock - unit-testing

The function I am trying to test accepts data structs, forms a query_dsl and then makes a /_search call to elastic search with the formed query.
Hence I want to assert on the query_dsl and url which gets formed.
I am using github.com/jarcoal/httpmock to mock net/http requests in my unit tests. As per the doc it exposes func GetCallCountInfo() map[string]int to validate how many times a particular endpoint was hit.
But I am also interested in knowing what was the request body when this call was made.
http.Client is not exposed, hence can not override/mock that for testing.
If it is not possible using this package then is there any other library which can mock the network request and also gives hold of request body?

Following #georgeok Suggestion,
We can create a mock http server and capture the request body when request is made.
Following is the code snippet to create a server and store the request body.
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
actualRequestBody, err = ioutil.ReadAll(req.Body)
check(err)
// Send mock response to be tested
_, err := rw.Write(bytes)
check(err)
}))
defer server.Close()
Now our request body is stored on actualRequestBody variable, and we can assert on this for correctness.
The only thing necessary to make sure this works is to make the call at host server.URL. As it spins up a server on the address mentioned at server.URL. So if the call from your code is being made to different server this will not catch it.

Related

In Postman how to mock a post API call to return reponses based on the request body?

I'm trying to leverage Postman's mock server feature to mock an API that my application calls.
This is a Post request. I have gone through the documentation and as advised I have saved the responses as examples.
When I try hit the mock URL I get the postman error response
Here is my setup -
My Collection with saved examples
MY mock server
After going through your query, I can see that you're trying to match an example based on the body passed with the request.
To match an example based on the request body, you can leverage the body matching feature of mock servers by:
Enabling the body matching feature from the mock edit page (Reference: https://learning.postman.com/docs/designing-and-developing-your-api/mocking-data/setting-up-mock/#matching-request-body-and-headers).
OR
Passing an additional x-mock-match-request-body header with value as true along with your mock request to get the desired results.
You can find more information on how to use body matching feature with mock servers here: https://learning.postman.com/docs/designing-and-developing-your-api/mocking-data/matching-algorithm/#6-check-for-header-and-body-matching.
Do let me know if this doesn't solve your issue. In that case, it would be helpful if you can share the mock request that you're sending to get the response.

How to execute Go functions by order in Unit Test? [duplicate]

This question already has answers here:
How to run golang tests sequentially?
(5 answers)
Closed 12 months ago.
I am new to Go and want to write a unit test for this small API:
login request.
logout request.
I expect them to be executed by order and both requests are successful.
However, when I execute the TestAPI, the last assert is always wrong and tells me the current user (abc#abc) is not logged in. I know they run in parallel (thus when handling logout request, the backend cookie hasn't stored this username yet) but I don't know how to rewrite so that the login request always happens before the logout request.
I don't want to waste your time, but I did google it for quite a while but found no solution for my case.
Many thanks for your help!
func PostJson(uri string, param map[string]string, router *gin.Engine) *httptest.ResponseRecorder {
jsonByte, _ := json.Marshal(param)
req := httptest.NewRequest("POST", uri, bytes.NewReader(jsonByte))
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
return w
}
func TestAPI(t *testing.T) {
server := setUpServer()
var w *httptest.ResponseRecorder
param := make(map[string]string)
param["email"] = "abc#abc"
param["password"] = "123"
param2 := make(map[string]string)
param2["email"] = "abc#abc"
urlLogin := "/login"
w = PostJson(urlLogin, param, server)
assert.Equal(t, 200, w.Code)
assert.Equal(t, w.Body.String(), "{\"msg\":\"login success\",\"status\":\"success\"}")
urlLogout := "/logout"
w = PostJson(urlLogout, param2, server)
assert.Equal(t, 200, w.Code)
assert.Equal(t, w.Body.String(), "{\"msg\":\"logout success\",\"status\":\"success\"}")
Statements within a single test run sequentially
I know they run in parallel
The statements within a single test run sequentially. Those statements are all in the same top level TestAPI test function, so they run sequentially.
On Cookies
I know they run in parallel (thus when handling logout request, the backend cookie hasn't stored this username yet)
Cookies are held by the frontend, and their content can't be trusted
There is no such thing as a "backend" cookie. A cookie is a response header from the backend that the client includes in the request headers of subsequent requests.
The implication of this is that clients have full control over the content of their cookies. Generally cookies contain an unguessable random value to identify the user, which is associated with user data in backend session storage.
If you really are putting the username in the cookie, and then trusting that username, your application's security is trivial to bypass (I just set the name of whatever user I'd like to be in my cookie before making a request).
Gin should supply a secure session management system, maybe backed by something like redis. Make sure you're using it, and not really putting user names in cookies.
You the client must store the cookie and include it in subsequent requests
Your http client bears the responsibility of including cookies from prior responses in subsequent requests. You're doing nothing to include the response cookie from the login, within the request cookie from the logout. Thus the logout request is "not logged in".
What you need is a "cookie jar," a common term for a mechanism to store and include cookies for subsequent requests. One is provided by https://pkg.go.dev/net/http/cookiejar and can be added to an http.Client, but you're not actually using an http.Client - you're calling your server handler on the request directly.
Simple option: let http.Client handle request cookies for you:
Refactor your test to run a "real" http server with testhttp and then make
"real" requests against the server.
Use https://pkg.go.dev/net/http/httptest#Server to start a test http server on localhost, with the handler you provide from you router.
Create an http.Client with a jar (https://pkg.go.dev/net/http#Client.Jar)
Then simply reuse the http client to make the requests, cookies included.
https://pkg.go.dev/net/http/cookiejar#example-New has a good example of how this could be done.
More Work: store cookies in your case, with ResponseRecorder and a direct c all to the http response handler
If you want to do what http.Client could do for you, create a cookie jar at the test level.
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
if err != nil {
t.Fail(err)
}
Include the cookies from the jar in every request and return add the cookies from the response to the jar. The obvious place to do this is your PostJson code, to which the jar could be passed as an additional argument.
Before you make the request, get the jar's cookies for the url with https://pkg.go.dev/net/http#CookieJar.Cookies. Then add those cookies to the request by iterating over the list of cookies and calling req's https://pkg.go.dev/net/http#Request.AddCookie for each.
Then "make" the request as you do now.
After the response is returned, you must add the cookies to the cookie jar.
You can access response cookies via https://pkg.go.dev/net/http/httptest#ResponseRecorder.Result on your response recorder, which will return an * http.Response. You can then call https://pkg.go.dev/net/http#Response.Cookies on that response.
Add those cookies to the jar with https://pkg.go.dev/net/http#CookieJar.SetCookies.
The code might look something like:
func PostJson(uri string, param map[string]string, router *gin.Engine, jar http.CookieJar) *httptest.ResponseRecorder {
jsonByte, _ := json.Marshal(param)
req := httptest.NewRequest("POST", uri, bytes.NewReader(jsonByte))
for _, cookie := range jar.Cookies(uri) {
req.AddCookie(cookie)
}
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
jar.SetCookies(uri, w.Result().Cookies())
return w
}
A final note on the value of reproducible code in questions.
If you would have made your code something I could run without significant modification, I would have spent time implementing and testing my suggested changes, and then I could give you a working example. So next time you have a good stack over flow question, take the time to invest in complete code that we can run, maybe in a Go Playground share. In addition to making it a lot easier to provide a high qualityu answer, it's also excellent practice for you!

Receive Callback request inside Postman automated test

I am trying to write automated tests with Postman. I am new to postman automation world so sorry if the question will seem dumb.
In the api that I need to test when I send a request I immediately receive a response with a transactionID, no matter transaction succeeded or not. Along with my request I send a CallbackURL to the server where I expect the actual transaction result to be called back. The server will do a PUT request back to the CallbackURL that I have provided with the transactionID and the actual response or error.
So the question is, can I have such kind of scenarios in my postman tests?
I guess I should run a web server and expose an endpoint which will expect a PUT request and I should get the body of this PUT request in my tests to check it, and respond back to it with success.
In other words, within my script I need to perform the following actions:
Do a request to the server passing a callback URL
check the immediate response from the server and keep the returned transactionID
Have a webserver run with an endpoint that I passed as a callback URL
Expect a request to that endpoint with transactionID and actual response
Check that the response is what I actually expected
Respond to the request with success
I was thinking about Postman Mock server, but seems it is not designed for such usage.
I also think may be I can run some JS Webserver (may be nodeJS) inside the postman Sandbox...
Actually I am very new to postman testing and I am really confused about this kind of issue. Is it even possible to do this with postman or I need something else?
There are some features provided by POSTMAN which can help you to resolve your problem
When you do request to server passing callback URL it gives you transactionID in response. Save that transactionID in environment variable or global variable. Same you can do it for callbackURL.
Eg. pm.environment.set("transactionID", transactionID);
Then you can do the second request where you passed callback URL and transactionID which you have already.
In short in POSTMAN there are features like
Set global and environment variable which helps to pass some values fetched from response to another request.
call other request on success of first request
eg. postman.setnextRequest({{requestname}});
If you can mentioned your problem statement little bit in details it will be easy to answer in better way.
Hope This Will Help You

Postman Mock Server matching algorithm logic for request body param

I have two scenarios for the following API URL.
POST http://{{ip_port}}/oauth/token
When I put the user name and password correctly, it should return
200 and mock json response.
When I put user name and password incorrectly, it should return 401 and mocked json(error).
In Postman Mock server, I noticed that there is no matching algorithm logic for request param.
I want to filter by request param and return related mock responses. I don't want to add two URLs(/token and /failedtoken) for above scenarios.
Currently Postman only support three logic for matching algorithm logic.
Properly formatted responses
HTTP method
Filter by URL
Is there any way to add only one URL for many scenarios in Postman Mock Server?
Postman Mock Server now supports matching by request body. You can use it by specifying a custom header (x-mock-match-request-body to true).
You can also check out an example that demonstrates how this feature works by going to New->Templates and searching for Request Body Matching.

Simplest way to make HTTP request in Spring

In my Spring web application I need to make an HTTP request to a non-RESTful API, and parse the response body back as a String (it's a single-dimension CSV list).
I've used RestTemplate before, but this isn't RESTful and doesn't map nicely on to classes. Whenever I implement something like this 'by hand' (eg using HttpClient) I invariably find out later that Spring has a utility class that makes things much simpler.
Is there anything in Spring that will do this job 'out of the box'?
If you look at the source of RestTemplate you will find that internally it uses
java.net.URL
and
url.openConnection()
that is the standard way in Java to make HTTP calls, so you are safe to use that. If there would be a "HTTP client" utility in spring then the RestTemplate would use that too.
I use the Spring Boot with Spring 4.3 Core inside and found a very simple way to make Http request and read responses by using OkHttpClient. Here is the code
Request request = new Request.Builder().method("PUT", "some your request body")
.url(YOUR_URL)
.build();
OkHttpClient httpClient = new OkHttpClient();
try
{
Response response = httpClient.newBuilder()
.readTimeout(1, TimeUnit.SECONDS)
.build()
.newCall(request)
.execute();
if(response.isSuccessful())
{
// notification about succesful request
}
else
{
// notification about failure request
}
}
catch (IOException e1)
{
// notification about other problems
}