Skip to content

Commit

Permalink
Fix update limitation for response body template
Browse files Browse the repository at this point in the history
Implements #116
  • Loading branch information
testillano authored and Eduardo Ramos Testillano (eramedu) committed Mar 15, 2024
1 parent d4bbed1 commit cee7290
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 10 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2346,8 +2346,12 @@ The **source** of information is classified after parsing the following possible
- response.body: response body as template. Should be interpreted depending on the response content type. The use of provisioned response as template reference is rare but could ease the build of structures for further transformations, In case of `json` it will be the document from *root*.
As the transformation steps modify this data container, its value as a source is likewise updated.
- response.body.`/<node1>/../<nodeN>`: response body node `json` path. This source path **admits variables substitution**. The use of provisioned response as template reference is rare but could ease the build of `json` structures for further transformations.
As the transformation steps modify this data container, its value as a source is likewise updated.
- request.header.`<hname>`: request header component (i.e. *content-type*). Take into account that header fields values are received [lower cased](https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2).
- eraser: this is used to indicate that the *target* specified (next section) must be removed or reset. Some of those targets are:
Expand Down Expand Up @@ -4257,8 +4261,8 @@ Usage: server_data_configuration [-h|--help]; Manages agent server data configur
[--disable-purge] ; Skips events post-removal when a provision on 'purge' state is reached.
[--enable-purge] ; Processes events post-removal when a provision on 'purge' state is reached.
Usage: server_matching [-h|--help]; Gets/updates current server matching configuration
(http://localhost:8074/admin/v1/server-matching).
Usage: server_matching [-h|--help] [file]; Gets/updates current server matching configuration
(http://localhost:8074/admin/v1/server-matching).
Usage: server_provision [-h|--help] [--clean] [file]; Cleans/gets/updates current server provision configuration
(http://localhost:8074/admin/v1/server-provision).
Usage: server_provision_unused [-h|--help]; Get current server provision configuration still not used
Expand Down
7 changes: 4 additions & 3 deletions src/model/AdminServerProvision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ bool AdminServerProvision::processSources(std::shared_ptr<Transformation> transf
const DataPart &requestBodyDataPart,
const nghttp2::asio_http2::header_map &requestHeaders,
bool &eraser,
std::uint64_t generalUniqueServerSequence) const {
std::uint64_t generalUniqueServerSequence,
bool usesResponseBodyAsTransformationJsonTarget, const nlohmann::json &responseBodyJson) const {

switch (transformation->getSourceType()) {
case Transformation::SourceType::RequestUri:
Expand Down Expand Up @@ -129,7 +130,7 @@ bool AdminServerProvision::processSources(std::shared_ptr<Transformation> transf
{
std::string path = transformation->getSource(); // document path (empty or not to be whole or node)
replaceVariables(path, transformation->getSourcePatterns(), variables, global_variable_->get());
if (!sourceVault.setObject(getResponseBody(), path)) {
if (!sourceVault.setObject(usesResponseBodyAsTransformationJsonTarget ? responseBodyJson:getResponseBody(), path)) {
LOGDEBUG(
std::string msg = ert::tracing::Logger::asString("Unable to extract path '%s' from response body (it is null) in transformation item", transformation->getSource().c_str());
ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
Expand Down Expand Up @@ -1138,7 +1139,7 @@ void AdminServerProvision::transform( const std::string &requestUri,
LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Processing transformation item: %s", transformation->asString().c_str()), ERT_FILE_LOCATION));

// SOURCES: RequestUri, RequestUriPath, RequestUriParam, RequestBody, ResponseBody, RequestHeader, Eraser, Math, Random, Timestamp, Strftime, Recvseq, SVar, SGvar, Value, ServerEvent, InState
if (!processSources(transformation, sourceVault, variables, requestUri, requestUriPath, requestQueryParametersMap, requestBodyDataPart, requestHeaders, eraser, generalUniqueServerSequence)) {
if (!processSources(transformation, sourceVault, variables, requestUri, requestUriPath, requestQueryParametersMap, requestBodyDataPart, requestHeaders, eraser, generalUniqueServerSequence, usesResponseBodyAsTransformationJsonTarget, responseBodyJson)) {
LOGDEBUG(ert::tracing::Logger::debug("Transformation item skipped on source", ERT_FILE_LOCATION));
continue;
}
Expand Down
6 changes: 5 additions & 1 deletion src/model/AdminServerProvision.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,11 @@ class AdminServerProvision
const DataPart &requestBodyDataPart,
const nghttp2::asio_http2::header_map &requestHeaders,
bool &eraser,
std::uint64_t generalUniqueServerSequence) const;
std::uint64_t generalUniqueServerSequence,
bool usesResponseBodyAsTransformationJsonTarget, const nlohmann::json &responseBodyJson) const; // these two last parameters are used to
// know if original response body provision
// or the one dynamically modified, must be
// used as source

bool processFilters(std::shared_ptr<Transformation> transformation,
TypeConverter& sourceVault,
Expand Down
6 changes: 3 additions & 3 deletions src/model/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,20 +280,20 @@ bool jsonConstraint(const nlohmann::json &received, const nlohmann::json &expect

for (auto& [key, value] : expected.items()) {

// Verificar si la clave existe en el documento a validar
// Check if key exists in document:
if (!received.contains(key)) {
failReport = ert::tracing::Logger::asString("JsonConstraint FAILED: expected key '%s' is missing in validated source", key.c_str());
LOGDEBUG(ert::tracing::Logger::debug(failReport, ERT_FILE_LOCATION));
return false;
}

// Verificar si el valor es un objeto JSON y llamar a la función de forma recursiva si es así
// Check if value is JSON object to make recursive call:
if (value.is_object()) {
if (!h2agent::model::jsonConstraint(received[key], value, failReport)) {
return false;
}
} else {
// Verificar si el valor coincide
// Check same value:
if (received[key] != value) {
failReport = ert::tracing::Logger::asString("JsonConstraint FAILED: expected value for key '%s' differs regarding validated source", key.c_str());
LOGDEBUG(ert::tracing::Logger::debug(failReport, ERT_FILE_LOCATION));
Expand Down
2 changes: 1 addition & 1 deletion tools/helpers.src
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ client_data_configuration() {
}

server_matching() {
[ "$1" = "-h" -o "$1" = "--help" ] && echo "Usage: server_matching [-h|--help]; Gets/updates current server matching configuration (${ADMIN_URL}/server-matching)." && return 0
[ "$1" = "-h" -o "$1" = "--help" ] && echo "Usage: server_matching [-h|--help] [file]; Gets/updates current server matching configuration (${ADMIN_URL}/server-matching)." && return 0
[ -z "$1" ] && do_curl ${ADMIN_URL}/server-matching && return 0
do_curl -XPOST -d@${1} -H 'content-type:application/json' ${ADMIN_URL}/server-matching
}
Expand Down
25 changes: 25 additions & 0 deletions tools/play-h2agent/examples/JsonConstraint/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
When we request a GET to the server with uri '/validate',
we will obtain a status code 200 if response is validated
against this body (417 if not):

{
"id": "test_2",
"randoms": [
"2", "2"
]
}

Traffic classification (matching configuration) will be simple, FullMatching,
as the example is done for an static/constant and hence, predictable URI.

Traffic behavior (provision configuration) will configure a response which
depends on random number <R> between 1 and 5:

{
"id": "test_<R>",
"foo": "bar",
"randoms": [
"<R>", "2"
],
"completed": true
}
4 changes: 4 additions & 0 deletions tools/play-h2agent/examples/JsonConstraint/request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"method": "GET",
"uri": "/validate"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"algorithm":"FullMatching"
}
43 changes: 43 additions & 0 deletions tools/play-h2agent/examples/JsonConstraint/server-provision.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"requestMethod": "GET",
"requestUri": "/validate",
"responseCode": 200,
"responseBody": {
"foo": "bar",
"completed": true
},
"transform": [
{
"source": "random.1.5",
"target": "var.R"
},
{
"source": "value.test_@{R}",
"target": "response.body.json.string./id"
},
{
"source": "value.[\"@{R}\", \"2\"]",
"target": "response.body.json.jsonstring./randoms"
},
{
"source": "response.body",
"target": "var.expectedBody",
"filter": {
"JsonConstraint": {
"id": "test_2",
"randoms": [
"2",
"2"
]
}
}
},
{
"source": "value.417",
"target": "response.statusCode",
"filter": {
"ConditionVar": "!expectedBody"
}
}
]
}

0 comments on commit cee7290

Please sign in to comment.