From 6488faf580fca82d36e12a06a7d3e08164e3e069 Mon Sep 17 00:00:00 2001 From: Osanda Deshan Date: Mon, 18 Jan 2021 12:15:58 +0530 Subject: [PATCH 1/3] Refactored code --- ...g And Reading Values From Data Stores.spec | 2 +- .../intelliapi/{common => }/BodyType.java | 2 +- .../intelliapi/{common => }/Constants.java | 2 +- .../ExecutionContextHook.java | 2 +- .../intelliapi/{common => }/HttpMethod.java | 2 +- .../maxsoft/intelliapi/api/ApiInvoker.java | 16 +++---- ...d.java => ApiRequestPayloadProcessor.java} | 4 +- ...esponse.java => ApiResponseProcessor.java} | 4 +- ...sor.java => FormDataRequestProcessor.java} | 8 ++-- ...ocessor.java => JsonRequestProcessor.java} | 6 +-- .../intelliapi/database/MongoOperator.java | 2 +- .../intelliapi/database/MySqlOperator.java | 2 +- .../api/ApiRequestPayloadConfigStepImpl.java | 4 +- .../api/ApiResponseDataProcessorStepImpl.java | 2 +- .../api/ApiResponseValidatorStepImpl.java | 48 +++++++++---------- .../stepimpl/api/OtherStepImpl.java | 6 +-- .../stepimpl/database/MongoStepImpl.java | 2 +- .../intelliapi/util/DataStoreProcessor.java | 2 +- .../intelliapi/util/FrameworkUtil.java | 4 +- .../intelliapi/util/fileoperator/CsvFile.java | 2 +- .../util/fileoperator/TextFile.java | 4 +- .../util/reader/ApiDocumentReader.java | 2 +- .../reader/EnvironmentPropertyReader.java | 2 +- src/test/resources/csv/timestamp.csv | 34 ++++++------- src/test/resources/csv/userIds.csv | 16 ++----- 25 files changed, 86 insertions(+), 94 deletions(-) rename src/main/java/com/maxsoft/intelliapi/{common => }/BodyType.java (86%) rename src/main/java/com/maxsoft/intelliapi/{common => }/Constants.java (99%) rename src/main/java/com/maxsoft/intelliapi/{executionhooks => }/ExecutionContextHook.java (96%) rename src/main/java/com/maxsoft/intelliapi/{common => }/HttpMethod.java (86%) rename src/main/java/com/maxsoft/intelliapi/api/{ApiRequestPayload.java => ApiRequestPayloadProcessor.java} (97%) rename src/main/java/com/maxsoft/intelliapi/api/{ApiResponse.java => ApiResponseProcessor.java} (99%) rename src/main/java/com/maxsoft/intelliapi/api/{FormDataHttpMethodsProcessor.java => FormDataRequestProcessor.java} (99%) rename src/main/java/com/maxsoft/intelliapi/api/{JsonHttpMethodsProcessor.java => JsonRequestProcessor.java} (96%) diff --git a/specs/data_stores/Saving And Reading Values From Data Stores.spec b/specs/data_stores/Saving And Reading Values From Data Stores.spec index ed6da1f..fe58fe0 100644 --- a/specs/data_stores/Saving And Reading Values From Data Stores.spec +++ b/specs/data_stores/Saving And Reading Values From Data Stores.spec @@ -12,7 +12,7 @@ tags: data_store, regression ## Get configurations of the testing environment -* Configurations of the testing environment +* Print configuration details of the testing environment ## Saving values to Data Store diff --git a/src/main/java/com/maxsoft/intelliapi/common/BodyType.java b/src/main/java/com/maxsoft/intelliapi/BodyType.java similarity index 86% rename from src/main/java/com/maxsoft/intelliapi/common/BodyType.java rename to src/main/java/com/maxsoft/intelliapi/BodyType.java index 3023c7e..27f071d 100644 --- a/src/main/java/com/maxsoft/intelliapi/common/BodyType.java +++ b/src/main/java/com/maxsoft/intelliapi/BodyType.java @@ -1,4 +1,4 @@ -package com.maxsoft.intelliapi.common; +package com.maxsoft.intelliapi; /** * Project Name : MaxSoft-IntelliAPI diff --git a/src/main/java/com/maxsoft/intelliapi/common/Constants.java b/src/main/java/com/maxsoft/intelliapi/Constants.java similarity index 99% rename from src/main/java/com/maxsoft/intelliapi/common/Constants.java rename to src/main/java/com/maxsoft/intelliapi/Constants.java index 18d8c37..f0a4eec 100644 --- a/src/main/java/com/maxsoft/intelliapi/common/Constants.java +++ b/src/main/java/com/maxsoft/intelliapi/Constants.java @@ -1,4 +1,4 @@ -package com.maxsoft.intelliapi.common; +package com.maxsoft.intelliapi; import java.io.File; diff --git a/src/main/java/com/maxsoft/intelliapi/executionhooks/ExecutionContextHook.java b/src/main/java/com/maxsoft/intelliapi/ExecutionContextHook.java similarity index 96% rename from src/main/java/com/maxsoft/intelliapi/executionhooks/ExecutionContextHook.java rename to src/main/java/com/maxsoft/intelliapi/ExecutionContextHook.java index 8a39aad..778577a 100644 --- a/src/main/java/com/maxsoft/intelliapi/executionhooks/ExecutionContextHook.java +++ b/src/main/java/com/maxsoft/intelliapi/ExecutionContextHook.java @@ -1,4 +1,4 @@ -package com.maxsoft.intelliapi.executionhooks; +package com.maxsoft.intelliapi; import com.maxsoft.intelliapi.util.LogUtil; import com.thoughtworks.gauge.*; diff --git a/src/main/java/com/maxsoft/intelliapi/common/HttpMethod.java b/src/main/java/com/maxsoft/intelliapi/HttpMethod.java similarity index 86% rename from src/main/java/com/maxsoft/intelliapi/common/HttpMethod.java rename to src/main/java/com/maxsoft/intelliapi/HttpMethod.java index 817765c..fbc5fb4 100644 --- a/src/main/java/com/maxsoft/intelliapi/common/HttpMethod.java +++ b/src/main/java/com/maxsoft/intelliapi/HttpMethod.java @@ -1,4 +1,4 @@ -package com.maxsoft.intelliapi.common; +package com.maxsoft.intelliapi; /** * Project Name : MaxSoft-IntelliAPI diff --git a/src/main/java/com/maxsoft/intelliapi/api/ApiInvoker.java b/src/main/java/com/maxsoft/intelliapi/api/ApiInvoker.java index ca600c1..2c7e399 100644 --- a/src/main/java/com/maxsoft/intelliapi/api/ApiInvoker.java +++ b/src/main/java/com/maxsoft/intelliapi/api/ApiInvoker.java @@ -1,18 +1,18 @@ package com.maxsoft.intelliapi.api; import com.maxsoft.intelliapi.util.FrameworkUtil; -import com.maxsoft.intelliapi.common.BodyType; -import com.maxsoft.intelliapi.common.HttpMethod; +import com.maxsoft.intelliapi.BodyType; +import com.maxsoft.intelliapi.HttpMethod; import io.restassured.http.Headers; import java.security.InvalidParameterException; -import static com.maxsoft.intelliapi.api.ApiRequestPayload.getApiEndpointToBeInvoked; -import static com.maxsoft.intelliapi.api.FormDataHttpMethodsProcessor.postFormDataApiWithAuthMultipleHeaders; -import static com.maxsoft.intelliapi.api.FormDataHttpMethodsProcessor.putFormDataApiWithAuthMultipleHeaders; -import static com.maxsoft.intelliapi.api.JsonHttpMethodsProcessor.*; -import static com.maxsoft.intelliapi.common.BodyType.JSON; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.getApiEndpointToBeInvoked; +import static com.maxsoft.intelliapi.api.FormDataRequestProcessor.postFormDataApiWithAuthMultipleHeaders; +import static com.maxsoft.intelliapi.api.FormDataRequestProcessor.putFormDataApiWithAuthMultipleHeaders; +import static com.maxsoft.intelliapi.api.JsonRequestProcessor.*; +import static com.maxsoft.intelliapi.BodyType.JSON; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; /** diff --git a/src/main/java/com/maxsoft/intelliapi/api/ApiRequestPayload.java b/src/main/java/com/maxsoft/intelliapi/api/ApiRequestPayloadProcessor.java similarity index 97% rename from src/main/java/com/maxsoft/intelliapi/api/ApiRequestPayload.java rename to src/main/java/com/maxsoft/intelliapi/api/ApiRequestPayloadProcessor.java index 3735311..8756583 100644 --- a/src/main/java/com/maxsoft/intelliapi/api/ApiRequestPayload.java +++ b/src/main/java/com/maxsoft/intelliapi/api/ApiRequestPayloadProcessor.java @@ -6,7 +6,7 @@ import java.util.*; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; import static com.maxsoft.intelliapi.util.reader.ApiDocumentReader.*; @@ -20,7 +20,7 @@ * Description : **/ -public class ApiRequestPayload { +public class ApiRequestPayloadProcessor { public static void initializeApiToBeInvoked(String apiEndpointName) { setApiEndpoint(apiEndpointName); diff --git a/src/main/java/com/maxsoft/intelliapi/api/ApiResponse.java b/src/main/java/com/maxsoft/intelliapi/api/ApiResponseProcessor.java similarity index 99% rename from src/main/java/com/maxsoft/intelliapi/api/ApiResponse.java rename to src/main/java/com/maxsoft/intelliapi/api/ApiResponseProcessor.java index a6e7d99..e4a192d 100644 --- a/src/main/java/com/maxsoft/intelliapi/api/ApiResponse.java +++ b/src/main/java/com/maxsoft/intelliapi/api/ApiResponseProcessor.java @@ -16,7 +16,7 @@ import java.io.IOException; import java.util.concurrent.TimeUnit; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.*; import static com.maxsoft.intelliapi.util.LogUtil.printError; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; @@ -30,7 +30,7 @@ * Description : **/ -public class ApiResponse { +public class ApiResponseProcessor { public static void saveStatusCode(Response response) { saveValueForScenario(VAR_API_RESPONSE_STATUS_CODE, String.valueOf(response.statusCode())); diff --git a/src/main/java/com/maxsoft/intelliapi/api/FormDataHttpMethodsProcessor.java b/src/main/java/com/maxsoft/intelliapi/api/FormDataRequestProcessor.java similarity index 99% rename from src/main/java/com/maxsoft/intelliapi/api/FormDataHttpMethodsProcessor.java rename to src/main/java/com/maxsoft/intelliapi/api/FormDataRequestProcessor.java index 354208b..2ea6567 100644 --- a/src/main/java/com/maxsoft/intelliapi/api/FormDataHttpMethodsProcessor.java +++ b/src/main/java/com/maxsoft/intelliapi/api/FormDataRequestProcessor.java @@ -9,9 +9,9 @@ import java.util.Collections; import java.util.Map; -import static com.maxsoft.intelliapi.api.ApiRequestPayload.getFormData; -import static com.maxsoft.intelliapi.api.ApiResponse.*; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.getFormData; +import static com.maxsoft.intelliapi.api.ApiResponseProcessor.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; import static io.restassured.RestAssured.given; import static io.restassured.config.EncoderConfig.encoderConfig; @@ -25,7 +25,7 @@ * Description : **/ -public class FormDataHttpMethodsProcessor { +public class FormDataRequestProcessor { public static void postFormDataApiWithAuthMultipleHeaders(String invokingEndpoint, String accessToken, Headers headers) { Response response; diff --git a/src/main/java/com/maxsoft/intelliapi/api/JsonHttpMethodsProcessor.java b/src/main/java/com/maxsoft/intelliapi/api/JsonRequestProcessor.java similarity index 96% rename from src/main/java/com/maxsoft/intelliapi/api/JsonHttpMethodsProcessor.java rename to src/main/java/com/maxsoft/intelliapi/api/JsonRequestProcessor.java index a2ada28..9bdab69 100644 --- a/src/main/java/com/maxsoft/intelliapi/api/JsonHttpMethodsProcessor.java +++ b/src/main/java/com/maxsoft/intelliapi/api/JsonRequestProcessor.java @@ -4,8 +4,8 @@ import io.restassured.http.Headers; import io.restassured.response.Response; -import static com.maxsoft.intelliapi.api.ApiResponse.*; -import static com.maxsoft.intelliapi.common.Constants.AUTHORIZATION_HEADER_NAME; +import static com.maxsoft.intelliapi.api.ApiResponseProcessor.*; +import static com.maxsoft.intelliapi.Constants.AUTHORIZATION_HEADER_NAME; import static io.restassured.RestAssured.given; /** @@ -17,7 +17,7 @@ * Description : **/ -public class JsonHttpMethodsProcessor { +public class JsonRequestProcessor { public static void getApiWithAuthMultipleHeaders(String invokingEndpoint, String accessToken, Headers headers) { Response response; diff --git a/src/main/java/com/maxsoft/intelliapi/database/MongoOperator.java b/src/main/java/com/maxsoft/intelliapi/database/MongoOperator.java index f1a72c7..2d6cef9 100644 --- a/src/main/java/com/maxsoft/intelliapi/database/MongoOperator.java +++ b/src/main/java/com/maxsoft/intelliapi/database/MongoOperator.java @@ -11,7 +11,7 @@ import java.util.Collections; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.saveValueForScenario; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; import static com.mongodb.client.model.Filters.eq; diff --git a/src/main/java/com/maxsoft/intelliapi/database/MySqlOperator.java b/src/main/java/com/maxsoft/intelliapi/database/MySqlOperator.java index 1c7583b..7da987b 100644 --- a/src/main/java/com/maxsoft/intelliapi/database/MySqlOperator.java +++ b/src/main/java/com/maxsoft/intelliapi/database/MySqlOperator.java @@ -13,7 +13,7 @@ import java.util.Collections; import java.util.List; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; import static com.maxsoft.intelliapi.util.DataStoreProcessor.saveValueForScenario; import static com.maxsoft.intelliapi.util.LogUtil.printError; diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java index b80f573..6fb267b 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java @@ -8,9 +8,9 @@ import java.util.List; -import static com.maxsoft.intelliapi.api.ApiRequestPayload.*; +import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.*; import static com.maxsoft.intelliapi.util.FrameworkUtil.*; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; import static com.maxsoft.intelliapi.util.DataStoreProcessor.*; diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseDataProcessorStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseDataProcessorStepImpl.java index 5e2c6de..17347bb 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseDataProcessorStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseDataProcessorStepImpl.java @@ -6,7 +6,7 @@ import java.util.List; -import static com.maxsoft.intelliapi.api.ApiResponse.*; +import static com.maxsoft.intelliapi.api.ApiResponseProcessor.*; /** * Project Name : MaxSoft-IntelliAPI diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseValidatorStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseValidatorStepImpl.java index 3964224..f763ee7 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseValidatorStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiResponseValidatorStepImpl.java @@ -1,6 +1,6 @@ package com.maxsoft.intelliapi.stepimpl.api; -import com.maxsoft.intelliapi.api.ApiResponse; +import com.maxsoft.intelliapi.api.ApiResponseProcessor; import com.maxsoft.intelliapi.util.fileoperator.TextFile; import com.thoughtworks.gauge.Step; import com.thoughtworks.gauge.Table; @@ -10,7 +10,7 @@ import java.util.List; import static com.maxsoft.intelliapi.util.FrameworkUtil.*; -import static com.maxsoft.intelliapi.common.Constants.VAR_API_RESPONSE_STATUS_CODE; +import static com.maxsoft.intelliapi.Constants.VAR_API_RESPONSE_STATUS_CODE; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; import static com.maxsoft.intelliapi.util.DataStoreProcessor.readFromDataStore; @@ -43,10 +43,10 @@ public void checkJsonPathValueContainsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(1)); if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathValueContainsText(jsonPath, + ApiResponseProcessor.checkJsonPathValueContainsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathValueContainsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathValueContainsText(jsonPath, jsonPathValue); } } } @@ -65,14 +65,14 @@ public void checkJsonPathValueFromDataStoreContainsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(4)); if(isTrue(isRetrievedFromDataStore)) { - ApiResponse.checkJsonPathValueContainsText(jsonPath, + ApiResponseProcessor.checkJsonPathValueContainsText(jsonPath, readFromDataStore(dataStoreType, dataStoreVariableName)); } else { if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathValueContainsText(jsonPath, + ApiResponseProcessor.checkJsonPathValueContainsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathValueContainsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathValueContainsText(jsonPath, jsonPathValue); } } } @@ -89,10 +89,10 @@ public void checkJsonPathValueNotContainsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(1)); if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathValueNotContainsText(jsonPath, + ApiResponseProcessor.checkJsonPathValueNotContainsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathValueNotContainsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathValueNotContainsText(jsonPath, jsonPathValue); } } } @@ -111,14 +111,14 @@ public void checkJsonPathValueFromDataStoreNotContainsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(4)); if(isTrue(isRetrievedFromDataStore)) { - ApiResponse.checkJsonPathValueNotContainsText(jsonPath, + ApiResponseProcessor.checkJsonPathValueNotContainsText(jsonPath, readFromDataStore(dataStoreType, dataStoreVariableName)); } else { if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathValueNotContainsText(jsonPath, + ApiResponseProcessor.checkJsonPathValueNotContainsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathValueNotContainsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathValueNotContainsText(jsonPath, jsonPathValue); } } } @@ -135,10 +135,10 @@ public void checkJsonPathAssertionEqualsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(1)); if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathAssertionEqualsText(jsonPath, + ApiResponseProcessor.checkJsonPathAssertionEqualsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathAssertionEqualsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathAssertionEqualsText(jsonPath, jsonPathValue); } } } @@ -157,14 +157,14 @@ public void checkJsonPathAssertionFromDataStoreEqualsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(4)); if(isTrue(isRetrievedFromDataStore)) { - ApiResponse.checkJsonPathAssertionEqualsText(jsonPath, + ApiResponseProcessor.checkJsonPathAssertionEqualsText(jsonPath, readFromDataStore(dataStoreType, dataStoreVariableName)); } else { if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathAssertionEqualsText(jsonPath, + ApiResponseProcessor.checkJsonPathAssertionEqualsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathAssertionEqualsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathAssertionEqualsText(jsonPath, jsonPathValue); } } } @@ -181,10 +181,10 @@ public void checkJsonPathAssertionNotEqualsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(1)); if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathAssertionNotEqualsText(jsonPath, + ApiResponseProcessor.checkJsonPathAssertionNotEqualsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathAssertionNotEqualsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathAssertionNotEqualsText(jsonPath, jsonPathValue); } } } @@ -203,14 +203,14 @@ public void checkJsonPathAssertionFromDataStoreNotEqualsText(Table table){ String jsonPathValue = row.getCell(columnNames.get(4)); if(isTrue(isRetrievedFromDataStore)) { - ApiResponse.checkJsonPathAssertionNotEqualsText(jsonPath, + ApiResponseProcessor.checkJsonPathAssertionNotEqualsText(jsonPath, readFromDataStore(dataStoreType, dataStoreVariableName)); } else { if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathAssertionNotEqualsText(jsonPath, + ApiResponseProcessor.checkJsonPathAssertionNotEqualsText(jsonPath, TextFile.read(getFilePathFromFileSyntax(jsonPathValue))); } else { - ApiResponse.checkJsonPathAssertionNotEqualsText(jsonPath, jsonPathValue); + ApiResponseProcessor.checkJsonPathAssertionNotEqualsText(jsonPath, jsonPathValue); } } } @@ -227,10 +227,10 @@ public void checkJsonPathExistence(Table table){ String jsonPathValue = row.getCell(columnNames.get(1)); if (hasContainedFileSyntax(jsonPathValue)) { - ApiResponse.checkJsonPathExistence(jsonPath, + ApiResponseProcessor.checkJsonPathExistence(jsonPath, Boolean.valueOf(TextFile.read(getFilePathFromFileSyntax(jsonPathValue)))); } else { - ApiResponse.checkJsonPathExistence(jsonPath, Boolean.valueOf(jsonPathValue)); + ApiResponseProcessor.checkJsonPathExistence(jsonPath, Boolean.valueOf(jsonPathValue)); } } } diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java index 04e142f..6997baf 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java @@ -5,8 +5,8 @@ import com.thoughtworks.gauge.Step; import io.restassured.http.Headers; -import static com.maxsoft.intelliapi.api.ApiRequestPayload.getHeaders; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.getHeaders; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; /** @@ -21,7 +21,7 @@ public class OtherStepImpl { // Use this method to print the testing environment name in the HTML report - @Step("Configurations of the testing environment") + @Step("Print configuration details of the testing environment") public void printTestingEnvDetails() { FrameworkUtil.printTestingEnvDetails(); } diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/database/MongoStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/database/MongoStepImpl.java index 6dc6650..8688843 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/database/MongoStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/database/MongoStepImpl.java @@ -9,7 +9,7 @@ import java.util.List; import static com.maxsoft.intelliapi.util.FrameworkUtil.*; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.*; /** diff --git a/src/main/java/com/maxsoft/intelliapi/util/DataStoreProcessor.java b/src/main/java/com/maxsoft/intelliapi/util/DataStoreProcessor.java index 9ac691c..15fd7d7 100644 --- a/src/main/java/com/maxsoft/intelliapi/util/DataStoreProcessor.java +++ b/src/main/java/com/maxsoft/intelliapi/util/DataStoreProcessor.java @@ -5,7 +5,7 @@ import java.security.InvalidParameterException; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.LogUtil.printError; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; diff --git a/src/main/java/com/maxsoft/intelliapi/util/FrameworkUtil.java b/src/main/java/com/maxsoft/intelliapi/util/FrameworkUtil.java index 5d29a35..a86136d 100644 --- a/src/main/java/com/maxsoft/intelliapi/util/FrameworkUtil.java +++ b/src/main/java/com/maxsoft/intelliapi/util/FrameworkUtil.java @@ -10,7 +10,7 @@ import java.util.Date; import java.util.Random; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; import static java.time.temporal.ChronoUnit.SECONDS; @@ -47,7 +47,7 @@ public static void replaceAllColumnValuesToCurrentTimestamp(String filePath, Str } public static void printTestingEnvDetails() { - printInfo("Configurations of Test Execution Environment\n\n"); + printInfo("Configurations of test execution environment\n\n"); printInfo("Operating System: " + OS); printInfo("Environment: " + ENVIRONMENT.toUpperCase()); printInfo("Base URL: " + EnvironmentPropertyReader.getBaseUrl()); diff --git a/src/main/java/com/maxsoft/intelliapi/util/fileoperator/CsvFile.java b/src/main/java/com/maxsoft/intelliapi/util/fileoperator/CsvFile.java index a932855..a6203ff 100644 --- a/src/main/java/com/maxsoft/intelliapi/util/fileoperator/CsvFile.java +++ b/src/main/java/com/maxsoft/intelliapi/util/fileoperator/CsvFile.java @@ -6,7 +6,7 @@ import java.io.*; import java.util.List; -import static com.maxsoft.intelliapi.common.Constants.CURRENT_DIRECTORY; +import static com.maxsoft.intelliapi.Constants.CURRENT_DIRECTORY; /** * Project Name : MaxSoft-IntelliAPI diff --git a/src/main/java/com/maxsoft/intelliapi/util/fileoperator/TextFile.java b/src/main/java/com/maxsoft/intelliapi/util/fileoperator/TextFile.java index 86c0099..f06de29 100644 --- a/src/main/java/com/maxsoft/intelliapi/util/fileoperator/TextFile.java +++ b/src/main/java/com/maxsoft/intelliapi/util/fileoperator/TextFile.java @@ -7,8 +7,8 @@ import java.util.Scanner; import static com.maxsoft.intelliapi.util.FrameworkUtil.isTrue; -import static com.maxsoft.intelliapi.common.Constants.IS_AUTHENTICATION_REQUIRED; -import static com.maxsoft.intelliapi.common.Constants.RETRIEVE_TOKEN_FROM_TEXT_FILE; +import static com.maxsoft.intelliapi.Constants.IS_AUTHENTICATION_REQUIRED; +import static com.maxsoft.intelliapi.Constants.RETRIEVE_TOKEN_FROM_TEXT_FILE; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; import static com.maxsoft.intelliapi.util.LogUtil.printError; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; diff --git a/src/main/java/com/maxsoft/intelliapi/util/reader/ApiDocumentReader.java b/src/main/java/com/maxsoft/intelliapi/util/reader/ApiDocumentReader.java index e5de810..8ceaee0 100644 --- a/src/main/java/com/maxsoft/intelliapi/util/reader/ApiDocumentReader.java +++ b/src/main/java/com/maxsoft/intelliapi/util/reader/ApiDocumentReader.java @@ -9,7 +9,7 @@ import java.io.IOException; import java.security.InvalidParameterException; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.DataStoreProcessor.saveValueForScenario; /** diff --git a/src/main/java/com/maxsoft/intelliapi/util/reader/EnvironmentPropertyReader.java b/src/main/java/com/maxsoft/intelliapi/util/reader/EnvironmentPropertyReader.java index e0d989e..c9d483d 100644 --- a/src/main/java/com/maxsoft/intelliapi/util/reader/EnvironmentPropertyReader.java +++ b/src/main/java/com/maxsoft/intelliapi/util/reader/EnvironmentPropertyReader.java @@ -2,7 +2,7 @@ import java.security.InvalidParameterException; -import static com.maxsoft.intelliapi.common.Constants.*; +import static com.maxsoft.intelliapi.Constants.*; /** * Project Name : MaxSoft-IntelliAPI diff --git a/src/test/resources/csv/timestamp.csv b/src/test/resources/csv/timestamp.csv index 7480781..5e354be 100644 --- a/src/test/resources/csv/timestamp.csv +++ b/src/test/resources/csv/timestamp.csv @@ -1,18 +1,18 @@ "userId","timestamp" -"17","2021-01-04T14:28:24.931Z" -"18","2021-01-04T14:28:24.938Z" -"19","2021-01-04T14:28:24.940Z" -"20","2021-01-04T14:28:24.942Z" -"21","2021-01-04T14:28:24.944Z" -"23","2021-01-04T14:28:24.947Z" -"26","2021-01-04T14:28:24.949Z" -"27","2021-01-04T14:28:24.952Z" -"29","2021-01-04T14:28:24.954Z" -"30","2021-01-04T14:28:24.956Z" -"32","2021-01-04T14:28:24.958Z" -"33","2021-01-04T14:28:24.960Z" -"34","2021-01-04T14:28:24.962Z" -"35","2021-01-04T14:28:24.964Z" -"36","2021-01-04T14:28:24.966Z" -"39","2021-01-04T14:28:24.968Z" -"40","2021-01-04T14:28:24.970Z" +"17","2021-01-18T12:02:32.218Z" +"18","2021-01-18T12:02:32.223Z" +"19","2021-01-18T12:02:32.224Z" +"20","2021-01-18T12:02:32.225Z" +"21","2021-01-18T12:02:32.226Z" +"23","2021-01-18T12:02:32.227Z" +"26","2021-01-18T12:02:32.228Z" +"27","2021-01-18T12:02:32.229Z" +"29","2021-01-18T12:02:32.230Z" +"30","2021-01-18T12:02:32.231Z" +"32","2021-01-18T12:02:32.232Z" +"33","2021-01-18T12:02:32.233Z" +"34","2021-01-18T12:02:32.234Z" +"35","2021-01-18T12:02:32.235Z" +"36","2021-01-18T12:02:32.238Z" +"39","2021-01-18T12:02:32.240Z" +"40","2021-01-18T12:02:32.241Z" diff --git a/src/test/resources/csv/userIds.csv b/src/test/resources/csv/userIds.csv index fe8805c..99754f2 100644 --- a/src/test/resources/csv/userIds.csv +++ b/src/test/resources/csv/userIds.csv @@ -1,13 +1,5 @@ "userId" -"37" -"38" -"39" -"40" -"41" -"42" -"43" -"44" -"45" -"46" -"47" -"48" +"23" +"24" +"25" +"26" From 0fad3f01b35c074569a63d643414a257ba4848cc Mon Sep 17 00:00:00 2001 From: Osanda Deshan Date: Wed, 20 Jan 2021 17:11:38 +0530 Subject: [PATCH 2/3] Implemented steps to invoke GET API from data store values --- specs/other/GET API From Data Store 1.spec | 55 ++++++++++++++++++ specs/other/GET API From Data Store 2.spec | 44 ++++++++++++++ .../stepimpl/api/OtherStepImpl.java | 54 +++++++++++++++++ .../resources/api_document/dev_api_doc.xlsx | Bin 15291 -> 15383 bytes .../resources/api_document/qa_api_doc.xlsx | Bin 15290 -> 15383 bytes .../resources/api_document/uat_api_doc.xlsx | Bin 15290 -> 15383 bytes 6 files changed, 153 insertions(+) create mode 100644 specs/other/GET API From Data Store 1.spec create mode 100644 specs/other/GET API From Data Store 2.spec diff --git a/specs/other/GET API From Data Store 1.spec b/specs/other/GET API From Data Store 1.spec new file mode 100644 index 0000000..f02bb6a --- /dev/null +++ b/specs/other/GET API From Data Store 1.spec @@ -0,0 +1,55 @@ +# Invoke GET API From Data Store With Authentication Specification + +Project Name : MaxSoft-IntelliAPI +Developer : Osanda Deshan +Version : 1.0.0 +Date : 1/20/2021 +Time : 1:58 PM +Description : This is an executable specification file + +tags: get_api, regression + + + |JSON Path|Expected Response Status Code| + |---------|-----------------------------| + |$[0].url |200 | + |$[1].url |200 | + |$[2].url |200 | + |$[3].url |200 | + + +## Invoke GET Request from a response's JSON Path value with authentication +* Given that a user needs to invoke "Get urls" +* And the user set the request authentication configurations as follows + |Configuration |Configuration Value| + |------------------------------------------------------------------|-------------------| + |Is authentication required? |Yes | + |Do you need to retrieve the access token from the text file? |Yes | + |Provide the access token if you need to authorize the API manually|N/A | +* And the user set the request headers using data stores as follows + |Header Name |Is Data Store Used?|Data Store Type|Data Store Variable Name|Header Value | + |-------------|-------------------|---------------|------------------------|-----------------------------------| + |App-Name |no | | |IntelliAPI | + |Organization |no | | |MaxSoft | +* When the user invokes the API +* Then the status code for the request is "200" +* And the JSON Path Assertions for the response should be equal to the values inside the data stores + |JSON Path |Is Data Store Used?|Data Store Type|Data Store Variable Name|Expected Value | + |--------------|-------------------|---------------|------------------------|------------------------------------------------| + |$[0].name |no | | |First photo | + |$[1].name |no | | |Second photo | + |$[3].name |no | | |Get all tasks with auth header | +* And the user saves an API request url in the JSON Path to a data store +* And the user set the request authentication configurations as follows + |Configuration |Configuration Value| + |------------------------------------------------------------------|-------------------| + |Is authentication required? |Yes | + |Do you need to retrieve the access token from the text file? |Yes | + |Provide the access token if you need to authorize the API manually|N/A | +* And the user set the request headers using data stores as follows + |Header Name |Is Data Store Used?|Data Store Type|Data Store Variable Name|Header Value | + |-------------|-------------------|---------------|------------------------|-----------------------------------| + |App-Name |no | | |IntelliAPI | + |Organization |no | | |MaxSoft | +* And invoke a GET request from the API request url saved in the data store +* Then the status code for the request is \ No newline at end of file diff --git a/specs/other/GET API From Data Store 2.spec b/specs/other/GET API From Data Store 2.spec new file mode 100644 index 0000000..0a752fd --- /dev/null +++ b/specs/other/GET API From Data Store 2.spec @@ -0,0 +1,44 @@ +# Invoke GET API From Data Store Without Authentication Specification + +Project Name : MaxSoft-IntelliAPI +Developer : Osanda Deshan +Version : 1.0.0 +Date : 1/20/2021 +Time : 1:58 PM +Description : This is an executable specification file + +tags: get_api, regression + + + |JSON Path|Expected Response Status Code| + |---------|-----------------------------| + |$[0].url |200 | + |$[1].url |200 | + |$[2].url |200 | + |$[3].url |400 | + + +## Invoke GET Request from a response's JSON Path value without authentication +* Given that a user needs to invoke "Get urls" +* And the user set the request authentication configurations as follows + |Configuration |Configuration Value| + |------------------------------------------------------------------|-------------------| + |Is authentication required? |Yes | + |Do you need to retrieve the access token from the text file? |Yes | + |Provide the access token if you need to authorize the API manually|N/A | +* And the user set the request headers using data stores as follows + |Header Name |Is Data Store Used?|Data Store Type|Data Store Variable Name|Header Value | + |-------------|-------------------|---------------|------------------------|-----------------------------------| + |App-Name |no | | |IntelliAPI | + |Organization |no | | |MaxSoft | +* When the user invokes the API +* Then the status code for the request is "200" +* And the JSON Path Assertions for the response should be equal to the values inside the data stores + |JSON Path |Is Data Store Used?|Data Store Type|Data Store Variable Name|Expected Value | + |--------------|-------------------|---------------|------------------------|------------------------------------------------| + |$[0].name |no | | |First photo | + |$[1].name |no | | |Second photo | + |$[3].name |no | | |Get all tasks with auth header | +* And the user saves an API request url in the JSON Path to a data store +* And invoke a GET request from the API request url saved in the data store +* Then the status code for the request is \ No newline at end of file diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java index 6997baf..e977b00 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java @@ -7,7 +7,12 @@ import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.getHeaders; import static com.maxsoft.intelliapi.Constants.*; +import static com.maxsoft.intelliapi.api.ApiResponseProcessor.saveResponseJsonPathValue; +import static com.maxsoft.intelliapi.api.JsonRequestProcessor.getApiWithAuthMultipleHeaders; import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; +import static com.maxsoft.intelliapi.util.FrameworkUtil.isTrue; +import static com.maxsoft.intelliapi.util.FrameworkUtil.readAccessToken; +import static com.maxsoft.intelliapi.util.LogUtil.printInfo; /** * Project Name : MaxSoft-IntelliAPI @@ -42,6 +47,55 @@ public void invokeApi() { } } + @Step("And the user saves an API request url in the JSON Path to a data store") + public void saveApiEndpointInResponseBody(String jsonPath) { + saveResponseJsonPathValue(SCENARIO, VAR_API_ENDPOINT, jsonPath); + } + + @Step("And invoke a GET request from the API request url saved in the data store") + public void doGetRequestFromDataStore() { + String invokingEndpoint = getSavedValueForScenario(VAR_API_ENDPOINT); + String headerNamesList = getSavedValueForScenario(VAR_API_HEADER_NAMES_LIST); + String headerValuesList = getSavedValueForScenario(VAR_API_HEADER_VALUES_LIST); + + String accessToken, isAuthenticationRequired, isAccessTokenRetrievedFromTextFile, accessTokenString; + String accessTokenInFile = readAccessToken(); + + try { + isAuthenticationRequired = getSavedValueForScenario(IS_AUTHENTICATION_REQUIRED).toLowerCase(); + isAccessTokenRetrievedFromTextFile = getSavedValueForScenario(RETRIEVE_TOKEN_FROM_TEXT_FILE).toLowerCase(); + accessTokenString = getSavedValueForScenario(MANUAL_TOKEN); + } catch (Exception ex) { + isAuthenticationRequired = ""; + isAccessTokenRetrievedFromTextFile = ""; + accessTokenString = ""; + } + + if (isTrue(isAuthenticationRequired)) { + if (isTrue(isAccessTokenRetrievedFromTextFile)) { + accessToken = accessTokenInFile; + } else { + accessToken = accessTokenString; + } + } else { + accessToken = ""; + } + + printInfo(""); + printInfo(""); + printInfo("Invoked API Endpoint:\n" + invokingEndpoint + "\n\n"); + printInfo("HTTP Method is: GET\n\n"); + + if (headerNamesList == null || headerNamesList.equals("") || + headerValuesList == null || headerValuesList.equals("")) { + getApiWithAuthMultipleHeaders(invokingEndpoint, accessToken, new Headers()); + } else { + getApiWithAuthMultipleHeaders(invokingEndpoint, accessToken, + new Headers(getHeaders(headerNamesList, headerValuesList))); + } + } + + // Use this method to replace the rows of a column in a given CSV with the timestamp @Step("And replace the row values in column of the CSV into the timestamp pattern") public void replaceAllColumnValuesToCurrentTimestamp(String columnName, String filePath, String timestampPattern) { FrameworkUtil.replaceAllColumnValuesToCurrentTimestamp(CURRENT_DIRECTORY + filePath, columnName, timestampPattern); diff --git a/src/test/resources/api_document/dev_api_doc.xlsx b/src/test/resources/api_document/dev_api_doc.xlsx index 83b127363cc0c269d1e4ad6bb2332cf40671baef..3fbcf9f37dd8b0a64268cdd544a2e4ae23bcfbc7 100644 GIT binary patch delta 5698 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 X%E|$?Fy((OJ?21`ivTY5590p;)0-|I diff --git a/src/test/resources/api_document/uat_api_doc.xlsx b/src/test/resources/api_document/uat_api_doc.xlsx index 3500b73287feaabd743d307cadf5380daaa7319f..1f04e2faab396ac895f49b5249c05d5632bf96ff 100644 GIT binary patch delta 5677 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 X%E|$?Fy((OJ?21`ivTY5590p;)0-|I From 55c177c3838d3f3e9578063c5f6eaa3f1346bc0f Mon Sep 17 00:00:00 2001 From: Osanda Deshan Date: Wed, 20 Jan 2021 18:50:48 +0530 Subject: [PATCH 3/3] Fixed some step names and moved some steps to new class --- specs/other/GET API From Data Store 1.spec | 5 +- specs/other/GET API From Data Store 2.spec | 5 +- .../api/ApiRequestInvokerStepImpl.java | 86 +++++++++++++++++++ .../api/ApiRequestPayloadConfigStepImpl.java | 11 ++- .../stepimpl/api/OtherStepImpl.java | 75 +--------------- 5 files changed, 102 insertions(+), 80 deletions(-) create mode 100644 src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestInvokerStepImpl.java diff --git a/specs/other/GET API From Data Store 1.spec b/specs/other/GET API From Data Store 1.spec index f02bb6a..6485e52 100644 --- a/specs/other/GET API From Data Store 1.spec +++ b/specs/other/GET API From Data Store 1.spec @@ -19,6 +19,7 @@ tags: get_api, regression ## Invoke GET Request from a response's JSON Path value with authentication + * Given that a user needs to invoke "Get urls" * And the user set the request authentication configurations as follows |Configuration |Configuration Value| @@ -39,7 +40,7 @@ tags: get_api, regression |$[0].name |no | | |First photo | |$[1].name |no | | |Second photo | |$[3].name |no | | |Get all tasks with auth header | -* And the user saves an API request url in the JSON Path to a data store +* Given that a user needs to invoke a GET API from the JSON Path value * And the user set the request authentication configurations as follows |Configuration |Configuration Value| |------------------------------------------------------------------|-------------------| @@ -51,5 +52,5 @@ tags: get_api, regression |-------------|-------------------|---------------|------------------------|-----------------------------------| |App-Name |no | | |IntelliAPI | |Organization |no | | |MaxSoft | -* And invoke a GET request from the API request url saved in the data store +* When the user invokes the GET API * Then the status code for the request is \ No newline at end of file diff --git a/specs/other/GET API From Data Store 2.spec b/specs/other/GET API From Data Store 2.spec index 0a752fd..1d02ff3 100644 --- a/specs/other/GET API From Data Store 2.spec +++ b/specs/other/GET API From Data Store 2.spec @@ -19,6 +19,7 @@ tags: get_api, regression ## Invoke GET Request from a response's JSON Path value without authentication + * Given that a user needs to invoke "Get urls" * And the user set the request authentication configurations as follows |Configuration |Configuration Value| @@ -39,6 +40,6 @@ tags: get_api, regression |$[0].name |no | | |First photo | |$[1].name |no | | |Second photo | |$[3].name |no | | |Get all tasks with auth header | -* And the user saves an API request url in the JSON Path to a data store -* And invoke a GET request from the API request url saved in the data store +* Given that a user needs to invoke a GET API from the JSON Path value +* When the user invokes the GET API * Then the status code for the request is \ No newline at end of file diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestInvokerStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestInvokerStepImpl.java new file mode 100644 index 0000000..0b52a5e --- /dev/null +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestInvokerStepImpl.java @@ -0,0 +1,86 @@ +package com.maxsoft.intelliapi.stepimpl.api; + +import com.maxsoft.intelliapi.api.ApiInvoker; +import com.thoughtworks.gauge.Step; +import io.restassured.http.Headers; + +import static com.maxsoft.intelliapi.Constants.*; +import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.getHeaders; +import static com.maxsoft.intelliapi.api.JsonRequestProcessor.getApiWithAuthMultipleHeaders; +import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; +import static com.maxsoft.intelliapi.util.FrameworkUtil.isTrue; +import static com.maxsoft.intelliapi.util.FrameworkUtil.readAccessToken; +import static com.maxsoft.intelliapi.util.LogUtil.printInfo; + +/** + * Project Name : MaxSoft-IntelliAPI + * Developer : Osanda Deshan + * Version : 1.0.0 + * Date : 1/20/2021 + * Time : 6:21 PM + * Description : + **/ + +public class ApiRequestInvokerStepImpl { + +/* Use this method when you need to pass the JSON request in previous step and the access token from the text file + into the GET/POST/PUT/DELETE API. The "saveRequestAuthConfigurations" must use before using this step */ + @Step("When the user invokes the API") + public void invokeApi() { + String jsonRequest = String.valueOf(getSavedValueForScenario(VAR_API_JSON_REQUEST_BODY)); + String headerNamesList = getSavedValueForScenario(VAR_API_HEADER_NAMES_LIST); + String headerValuesList = getSavedValueForScenario(VAR_API_HEADER_VALUES_LIST); + + if (headerNamesList == null || headerNamesList.equals("") || + headerValuesList == null || headerValuesList.equals("")) { + ApiInvoker.invoke(jsonRequest, new Headers()); + } else { + ApiInvoker.invoke(jsonRequest, new Headers(getHeaders(headerNamesList, headerValuesList))); + } + } + +/* Use this method to invoke a GET API from a request url in the response's JSON path. + The "saveApiEndpointInResponseBody" must use before using this step */ + @Step("When the user invokes the GET API") + public void doGetRequestFromDataStore() { + String invokingEndpoint = getSavedValueForScenario(VAR_API_ENDPOINT); + String headerNamesList = getSavedValueForScenario(VAR_API_HEADER_NAMES_LIST); + String headerValuesList = getSavedValueForScenario(VAR_API_HEADER_VALUES_LIST); + + String accessToken, isAuthenticationRequired, isAccessTokenRetrievedFromTextFile, accessTokenString; + String accessTokenInFile = readAccessToken(); + + try { + isAuthenticationRequired = getSavedValueForScenario(IS_AUTHENTICATION_REQUIRED).toLowerCase(); + isAccessTokenRetrievedFromTextFile = getSavedValueForScenario(RETRIEVE_TOKEN_FROM_TEXT_FILE).toLowerCase(); + accessTokenString = getSavedValueForScenario(MANUAL_TOKEN); + } catch (Exception ex) { + isAuthenticationRequired = ""; + isAccessTokenRetrievedFromTextFile = ""; + accessTokenString = ""; + } + + if (isTrue(isAuthenticationRequired)) { + if (isTrue(isAccessTokenRetrievedFromTextFile)) { + accessToken = accessTokenInFile; + } else { + accessToken = accessTokenString; + } + } else { + accessToken = ""; + } + + printInfo(""); + printInfo(""); + printInfo("Invoked API Endpoint:\n" + invokingEndpoint + "\n\n"); + printInfo("HTTP Method is: GET\n\n"); + + if (headerNamesList == null || headerNamesList.equals("") || + headerValuesList == null || headerValuesList.equals("")) { + getApiWithAuthMultipleHeaders(invokingEndpoint, accessToken, new Headers()); + } else { + getApiWithAuthMultipleHeaders(invokingEndpoint, accessToken, + new Headers(getHeaders(headerNamesList, headerValuesList))); + } + } +} diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java index 6fb267b..4a9ef0a 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/ApiRequestPayloadConfigStepImpl.java @@ -8,11 +8,12 @@ import java.util.List; +import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.*; +import static com.maxsoft.intelliapi.api.ApiResponseProcessor.saveResponseJsonPathValue; +import static com.maxsoft.intelliapi.util.DataStoreProcessor.*; import static com.maxsoft.intelliapi.util.FrameworkUtil.*; -import static com.maxsoft.intelliapi.Constants.*; import static com.maxsoft.intelliapi.util.LogUtil.printInfo; -import static com.maxsoft.intelliapi.util.DataStoreProcessor.*; /** * Project Name : MaxSoft-IntelliAPI @@ -31,6 +32,12 @@ public void apiToBeInvoked(String apiEndpointName) { initializeApiToBeInvoked(apiEndpointName); } + // Use this method before invoking a GET API from a request url in the response's JSON path + @Step("Given that a user needs to invoke a GET API from the JSON Path value ") + public void saveApiEndpointInResponseBody(String jsonPath) { + saveResponseJsonPathValue(SCENARIO, VAR_API_ENDPOINT, jsonPath); + } + // Use this method to replace the placeholders inside the API Endpoint in Excel @Step("And the user set values to the API endpoint placeholders as follows ") public void setApiEndpointReplacements(Table table) { diff --git a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java index e977b00..c417462 100644 --- a/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java +++ b/src/main/java/com/maxsoft/intelliapi/stepimpl/api/OtherStepImpl.java @@ -1,18 +1,9 @@ package com.maxsoft.intelliapi.stepimpl.api; -import com.maxsoft.intelliapi.api.ApiInvoker; import com.maxsoft.intelliapi.util.FrameworkUtil; import com.thoughtworks.gauge.Step; -import io.restassured.http.Headers; -import static com.maxsoft.intelliapi.api.ApiRequestPayloadProcessor.getHeaders; -import static com.maxsoft.intelliapi.Constants.*; -import static com.maxsoft.intelliapi.api.ApiResponseProcessor.saveResponseJsonPathValue; -import static com.maxsoft.intelliapi.api.JsonRequestProcessor.getApiWithAuthMultipleHeaders; -import static com.maxsoft.intelliapi.util.DataStoreProcessor.getSavedValueForScenario; -import static com.maxsoft.intelliapi.util.FrameworkUtil.isTrue; -import static com.maxsoft.intelliapi.util.FrameworkUtil.readAccessToken; -import static com.maxsoft.intelliapi.util.LogUtil.printInfo; +import static com.maxsoft.intelliapi.Constants.CURRENT_DIRECTORY; /** * Project Name : MaxSoft-IntelliAPI @@ -31,70 +22,6 @@ public void printTestingEnvDetails() { FrameworkUtil.printTestingEnvDetails(); } - /* Use this method when you need to pass the JSON request in previous step and the access token from the text file into the GET/POST/PUT/DELETE API. - The "saveRequestAuthConfigurations" must use before using this step */ - @Step("When the user invokes the API") - public void invokeApi() { - String jsonRequest = String.valueOf(getSavedValueForScenario(VAR_API_JSON_REQUEST_BODY)); - String headerNamesList = getSavedValueForScenario(VAR_API_HEADER_NAMES_LIST); - String headerValuesList = getSavedValueForScenario(VAR_API_HEADER_VALUES_LIST); - - if (headerNamesList == null || headerNamesList.equals("") || - headerValuesList == null || headerValuesList.equals("")) { - ApiInvoker.invoke(jsonRequest, new Headers()); - } else { - ApiInvoker.invoke(jsonRequest, new Headers(getHeaders(headerNamesList, headerValuesList))); - } - } - - @Step("And the user saves an API request url in the JSON Path to a data store") - public void saveApiEndpointInResponseBody(String jsonPath) { - saveResponseJsonPathValue(SCENARIO, VAR_API_ENDPOINT, jsonPath); - } - - @Step("And invoke a GET request from the API request url saved in the data store") - public void doGetRequestFromDataStore() { - String invokingEndpoint = getSavedValueForScenario(VAR_API_ENDPOINT); - String headerNamesList = getSavedValueForScenario(VAR_API_HEADER_NAMES_LIST); - String headerValuesList = getSavedValueForScenario(VAR_API_HEADER_VALUES_LIST); - - String accessToken, isAuthenticationRequired, isAccessTokenRetrievedFromTextFile, accessTokenString; - String accessTokenInFile = readAccessToken(); - - try { - isAuthenticationRequired = getSavedValueForScenario(IS_AUTHENTICATION_REQUIRED).toLowerCase(); - isAccessTokenRetrievedFromTextFile = getSavedValueForScenario(RETRIEVE_TOKEN_FROM_TEXT_FILE).toLowerCase(); - accessTokenString = getSavedValueForScenario(MANUAL_TOKEN); - } catch (Exception ex) { - isAuthenticationRequired = ""; - isAccessTokenRetrievedFromTextFile = ""; - accessTokenString = ""; - } - - if (isTrue(isAuthenticationRequired)) { - if (isTrue(isAccessTokenRetrievedFromTextFile)) { - accessToken = accessTokenInFile; - } else { - accessToken = accessTokenString; - } - } else { - accessToken = ""; - } - - printInfo(""); - printInfo(""); - printInfo("Invoked API Endpoint:\n" + invokingEndpoint + "\n\n"); - printInfo("HTTP Method is: GET\n\n"); - - if (headerNamesList == null || headerNamesList.equals("") || - headerValuesList == null || headerValuesList.equals("")) { - getApiWithAuthMultipleHeaders(invokingEndpoint, accessToken, new Headers()); - } else { - getApiWithAuthMultipleHeaders(invokingEndpoint, accessToken, - new Headers(getHeaders(headerNamesList, headerValuesList))); - } - } - // Use this method to replace the rows of a column in a given CSV with the timestamp @Step("And replace the row values in column of the CSV into the timestamp pattern") public void replaceAllColumnValuesToCurrentTimestamp(String columnName, String filePath, String timestampPattern) {