Grails 3.3.11 Integration Test (GrailsApplication) - grails

I am now in trouble with the configuration variable GrailsApplication in my Integration Tests. I don't know why, but, I am not managing to get its value when testing my api. I am using Grails 3.3.11. The value of the variable is being null and, due to it, I can't authenticate to perform the tests. I would appreciate your help. I am using Grails 3.3.11.
package br.com.xxx.id.test.integration
//Imports were moved out to simplify understanding
class IdControllerSpec extends Specification {
def grailsApplication
#Value('${local.server.port}')
Integer serverPort
String accessToken
String baseUrl
JSONObject documentPropertiesForTesting
JSONObject documentForTesting
String partTest
String userTest
String typeIdTest
String refreshToken
void setup(){
baseUrl = "http://localhost:${serverPort}/cmbid/api/v1"
partTest = "partTest"
}
void "Saving a new and valid document properties"() {
when:
refreshToken = grailsApplication.config.getProperty('refreshToken')
accessToken = "Bearer " + authenticateXxxAut()
documentPropertiesForTesting = createNewTestDocumentProperties()
typeIdTest = documentPropertiesForTesting.get("message").toString().substring(20,52)
then:
documentPropertiesForTesting.get("status") == "ok"
documentPropertiesForTesting.get("message").contains("properly saved!")
cleanup:
DocumentProperties.withNewSession {
def dp = DocumentProperties.findById(typeIdTest)
dp.delete(flush: true)
}
}
def authenticateXxxAut() {
CloseableHttpClient httpClient = HttpClients.createDefault();
String response = ""
try {
JSONObject responseBody
println('****************************')
println(grailsApplication.config.getProperty('aut.newTokenUrl'))
println(grailsApplication.config.getProperty('refreshToken)'))
println('****************************')
def httpPost = new HttpPost(grailsApplication.config.getProperty('aut.newTokenUrl') + grailsApplication.config.getProperty('refreshToken)'))
CloseableHttpResponse httpResponse = httpClient.execute(httpPost)
if (httpResponse.getStatusLine().getStatusCode() == 200) {
responseBody = new JSONObject(EntityUtils.toString(httpResponse.getEntity()))
response = responseBody.get("access_token")
} else {
response = httpResponse.getStatusLine().getStatusCode().toString()
}
} catch (Exception e){
print(e.getLocalizedMessage())
} finally {
httpClient.close()
return response
}
}

I've been upgrading a Grails 2.x app to version 3.3.11 and just referencing the (provided) variable serverPort worked for me. The IDE shows it as being uninitialized but running the tests, it gets the correct value assigned. I also have my test classes annotated with #Integration(applicationClass = Application.class).
Here's how I get the URL to point against:
def url = "http://localhost:${serverPort}${grailsApplication.config.getProperty('server.contextPath', String, '')}"

Related

Rest Assured Serenity getting Null point when move the environmental specific configuration to different class

I have set the URL in the serenity.config and runnig the API resquest based on the regions.All are working fine but when i want to reduce the repeated codes as i have lot of apis to automate.
I tried to create a seperate class for {EnvironmentSpecificConfiguration} and tried to call in the test steps class getting null point.help me how can i reduce the code and make repeated thing in a reusable class.I am using retassured with serenity ,gradle
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
LocalDate nextday = today.plusDays(2);
private EnvironmentVariables environmentVariables;
public Response response;
String basePath = "/booking/search";
#Step("user perform a GET search request current day")
public void SearchCurrentDay() {
String BASEURI = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("base.api.url");
response = SerenityRest.given().contentType("application/json")
.header("Content-Type", "application/json")
.when().queryParam("type", 2)
.queryParam("date_req", today.toString())
.queryParam("days", 1)
.queryParam("id", 1)
.get(BASEURI + basePath);
System.out.println("Search json response:::==>" + response.prettyPrint());
}
#Step("user perform a GET diary search request Tomorrow")
public void dairySearchTomorrow() {
String BASEURI = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("base.api.url");
response = SerenityRest.given().contentType("application/json")
.header("Content-Type", "application/json")
.when().queryParam("type", 2)
.queryParam("date_req", tomorrow.toString())
.get(BASEURI + basePath);
System.out.println("search json response:::==>" + response.prettyPrint());
}
#Step("user perform a GET diary search request next day")
public void dairySearchNextDay() {
String BASEURI = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("base.api.url");
response = SerenityRest.given().contentType("application/json")
.header("Content-Type", "application/json")
.when().queryParam("type", 2)
.queryParam("date_req", nextday.toString())
.get(BASEURI + basePath);
System.out.println("search json response:::==>" + response.prettyPrint());
}
}
Issue has been Resolved as I used the:
String BASEURI = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("base.api.url");
in #Before annotation to use it globally

How to use annotations to create OpenAPI (Swagger) documentation on Grails 4

We are creating API documentation for an existing Grails 4 App. We are having difficulties in understanding how to use Swagger annotations.
Let's assume the following Controller:
class IntegratorController {
def maintenanceService
def saveMaintenance() {
def message = 'success'
def status = '200'
try {
def maintenanceJson = request.JSON.maintenances
def ret=maintenanceService.processMaintenanceJSON(maintenanceJson)
} catch (Exception e) {
log.error("Error to process restricions", e)
message = 'error : ${e.getMessage()}'
status = '500'
}
def result = ['message':message]
render(status: status, contentType: "application/json", text: result as JSON)
}
}
This controller expects you to send a request JSON like this example:
{ "job":42,
"maintenances": [
{"idPort":42, "idMaintenance":42, "shipName":"myship01", "obs":"asap"},
{"idPort":43, "idMaintenance":43, "shipName":"myship02", "obs":"asap"}]}
A basic annotation will be this:
#Controller("/")
class IntegratorController {
def maintenanceService
#Post(uri="/saveMaintenance", produces = MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Operation(summary = "Create one or more ship maintenance")
#ApiResponse(responseCode = "500", description = "If internal service throws an Exception")
def saveMaintenance() {
def message = 'success'
def status = '200'
try {
def maintenanceJson = request.JSON.maintenances
def savedMaintenances=maintenanceService.processMaintenanceJSON(maintenanceJson)
} catch (Exception e) {
log.error("Error to process restricions", e)
message = 'error : ${e.getMessage()}'
status = '500'
}
def result = ['message':message]
render(status: status, contentType: "application/json", text: result as JSON)
}
}
Where and how to annotate the request JSON sent in the post operation?
Thank you!
The request object is "scoped" by Grails. So you need to use #RequestBody annotation to declare what it is outside the method declaration. You also need to create classes to describe what it is because the JSON deserialization is loosely typed.
This is an example:
#Post(uri="/saveMaintenance", produces = MediaType.APPLICATION_JSON)
#Operation(summary = "Summary here",
description = "Description here",
requestBody = #RequestBody(description = "Inside Operation"), tags = ["IntegratorWebController"])
#RequestBody(description = "Description here", required = true,
content = #Content(schema = #Schema(implementation = YourRequestDAO.class, anyOf = [YourRequestDAO.class, YourRequestDAODependency.class])))
#ApiResponses(value=[
#ApiResponse(responseCode="200", description = "Return status=OK in success", content = #Content(mediaType = "application/json", schema = #Schema(implementation = YourResponseDAO.class))),
#ApiResponse(responseCode="404", description = "Return status=BAD_REQUEST if you mess up", content = #Content(mediaType = "application/json", schema = #Schema(implementation = YourResponseDAO.class)))])
def saveOrUpdateActivity(){
(...)
Well Swagger and OpenAPI are 'schemas' that are preloaded at runtime to build the call structure; GraphQL also has a schema as well to load its call structure.
I did a video on it here to help you understand how this works: https://youtu.be/AJJVnwULbbc
The way Grails did this prior to 4.0 was with plugins like the 'swagger plugin' or with BeAPI plugin (which I maintain).
I don't see a supported plugin in 4.0 so I don't see how they are doing this now.

Tfs Microsoft Api is failing to get httpclient to create workitem

Could someone please help what does this error means
is it some connection issue?
operation performed on onpremise tfs server
here i am using TFS personal access token to do authorize operations.
Here is a code snippet creating a Bug work item in DevOps using HttpClient library, for your reference:
public class CreateBug
{
readonly string _uri;
readonly string _personalAccessToken;
readonly string _project;
public CreateBug()
{
_uri = "https://xxx.visualstudio.com";
_personalAccessToken = "xxx";
_project = "xxxxx";
}
public WorkItem CreateBugUsingClientLib()
{
Uri uri = new Uri(_uri);
string personalAccessToken = _personalAccessToken;
string project = _project;
VssBasicCredential credentials = new VssBasicCredential("", _personalAccessToken);
JsonPatchDocument patchDocument = new JsonPatchDocument();
//add fields and thier values to your patch document
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/fields/System.Title",
Value = "Authorization Errors"
}
);
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/fields/Microsoft.VSTS.Common.Priority",
Value = "1"
}
);
VssConnection connection = new VssConnection(uri, credentials);
WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
try
{
WorkItem result = workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "Bug").Result;
Console.WriteLine("Bug Successfully Created: Bug #{0}", result.Id);
return result;
}
catch (AggregateException ex)
{
Console.WriteLine("Error creating bug: {0}", ex.InnerException.Message);
return null;
}
}
}
Due to error message text was having encoding issue, was not able to figure out the issue, Did debug on server and found out TTFS url with collection was not forming properly hence it was giving "page not found" error message, after that we fixed it by updating the tfs api url.

Springfox global response header

In my spring boot rest API, I'm sending back a unique request id header "x-request-id" for every response (irrespective of the method) for every endpoint. I can add this using something like this:
#ApiResponses(value = {
#ApiResponse(
code = 200,
message = "Successful status response",
responseHeaders = {
#ResponseHeader(
name = "x-request-id",
description = "auto generated unique request id",
response = String.class)})
})
This works fine and I can see it in the Swagger UI. However, doing this for every endpoint is a tedious + maintenance problem. I'm looking to do this globally but the Springfox documentation only shows about global response message using .globalResponseMessage option - I can't find anything for global response headers.
Ended up creating an annotation to handle this:
package com.abc.xyz.api.docs.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ResponseHeader;
import com.abc.xyz.api.constants.ApiConstants;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
#ApiResponses(value = {
#ApiResponse(
code = 200,
message = "Successful status response",
responseHeaders = {
#ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
#ApiResponse(
code = 401,
message = "Successful status response",
responseHeaders = {
#ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
#ApiResponse(
code = 403,
message = "Successful status response",
responseHeaders = {
#ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
#ApiResponse(
code = 404,
message = "Successful status response",
responseHeaders = {
#ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
}
)
public #interface RequestIdMethod {};
With this, I can add this as a marker annotation in front of my methods:
#RequestMapping(value = "/heartbeat", method = RequestMethod.GET)
#RequestIdMethod
public Heartbeat checkHeartbeat() {
return new Heartbeat(status);
}
It is not great because I need to repeat the entire #ApiResponse annotation block for every http return code (obviously there could be other return codes but I only covered the default codes shown by Springfox). Would have been better if there was a way to parameterize the entire #ApiResponse block.
I know I'm late to the party here, but I did find a way to globally add a header to every response using reflection (might not be required but turned out to be the easiest way for me to get EVERY response. You can also check for all ApiResponses annotations but some were added implicitly and therefore left out with that approach).
#Component
#Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 10)
public class RequestIdResponseHeaderPlugin implements OperationBuilderPlugin {
#Override
public boolean supports(DocumentationType documentationType) {
return true;
}
#Override
public void apply(OperationContext operationContext) {
try {
// we use reflection here since the operationBuilder.build() method would lead to different operation ids
// and we only want to access the private field 'responseMessages' to add the request-id header to it
Field f = operationContext.operationBuilder().getClass().getDeclaredField("responseMessages");
f.setAccessible(true);
Set<ResponseMessage> responseMessages = (Set<ResponseMessage>) f.get(operationContext.operationBuilder());
responseMessages.forEach(message -> {
int code = message.getCode();
Map<String, Header> map = new HashMap<>();
map.put("my-header-name", new Header(null, null, new ModelRef("string")));
ResponseMessage responseMessage = new ResponseMessageBuilder().code(code).headersWithDescription(map).build();
operationContext.operationBuilder().responseMessages(Collections.singleton(responseMessage));
});
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
Found this way after looking into the method responseMessages() of the operation-builder. It internally merges response-headers based on the status-code and the logic itself will simply add headers to existing response-headers.
Hope it helps someone since it does not require you to annotate every single endpoint.
I updated my Docket configuration to include the Global header on every API. Hope this helps.
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.contact(new Contact("My Support", null, "My Email"))
.description("My Description")
.licenseUrl("My License")
.title("My Title")
.termsOfServiceUrl("My Terms and Conditions")
.version("My Version")
.build())
.globalOperationParameters(Collections.singletonList(new ParameterBuilder()
.name("x-request-id")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build()))
.select()
.paths(PathSelectors.regex("/user*))
.build()
.directModelSubstitute(LocalDate.class, String.class)
.directModelSubstitute(LocalDateTime.class, String.class);

rest assured File not Found error

When i use authorization in headers for rest assured by bassing token variable giving "File Not Found" error. And if hardcode the token in headers then it's working successfully. Can anyone help me out what can be the issue. Below is my code,
public static void getIndentId() throws IOException {
if(indentId == null){
Payloads pal = new Payloads();
RestAssured.baseURI = CommonFunctions.getSitApiGatewayEndPoint();
String sessionKey = GbPortalLogin.getSessionKey();
String token = "Token "+sessionKey;
System.out.println(token);
Response res = given().
header("Content-Type","application/json").
header("Authorization",token).
body(pal.createIndentPayload()).
when().post(Resources.createNbIndent).
then().extract().response();
String s = res.asString();
System.out.println(s);
/*System.out.println(res.getBody().toString());
JsonPath js = CommonFunctions.rawToJson(res);
indentId = js.get("id").toString();*/
}

Resources