Groovy slurper.parser variable of a variable - groovy

Here is the snippet of my groovy script:
jsonFileData = slurper.parse(jsonFile)
Here is my JSON file
{
"MEMXYZ": {
"LINKOPT": {
"RMODE": "31",
"AMODE": "ANY"
},
"PROCESSOR": "PROCESSOR XYZ",
"DB2": {
"OWNER": "USER1",
"QUALIFER": "DB2ADMIN",
"SSID": "DBC1"
},
"COBOL": {
"VERSION": "V6",
"CICS": "V5R6M0",
"OPTIONS": "LIST,MAP,RENT",
"DB2": "YES"
}
}
}
println "Print1 ***** Parsing PROCESSOR = ${jsonFileData.MEMXYZ.PROCESSOR}"
println "Print2 ***** Parsing PROCESSOR = ${jsonFileData}.${Member}.PROCESSOR"
The Print1 is working fine with with explicit Member name "MEMXYZ", but I have problem with Print2, which I need to have the dyanmic ${Member} variable substitution. Please help!
${Member} is MEMXYZ
Please help to solve the Print2 statement

".. ${abc} ..." just injects the value of abc variable into string.
To access values of map (result of slurper.parse(...) in your case) you could use one of approaches:
jsonFileData[Member].PROCESSOR
jsonFileData[Member]['PROCESSOR']
So, your print line could look like:
println "PROCESSOR = ${jsonFileData[Member].PROCESSOR}"

Related

Groovy and Spring Cloud Contract - Variable in the bodyAsValue

I would like to know how am I supposed to create in Groovy the Json payload with a random value.
For example
Contract.make {
name"MyFirstContract"
description "A description"
request {
method "POST"
url "/api/team/createTeam"
headers {
contentType applicationJson()
accept applicationJson()
header"Authorization", execute('bearerOfAccessToken()')
}
body """ {
"authenticatedUserCode":"papas",
"input": {
"name":"${execute('generateTeamUniqueName()')}",
"teamDefinitionName": "JUNIT TEST NAME",
"context":"context AHO",
"description":"team Description",
"members":
[
{"role":"Junit Reviewer",
"memberType":"USER",
"reference":"papas"
},
{"role":"Junit Observer",
"memberType":"USER",
"reference":"papas"
},
{"role":"Junit Collaborator",
"memberType":"USER",
"reference":"papas"
},
{"role":"Junit Reviewer",
"memberType":"USER",
"reference":"papas"
}
]
} } """
}
The important part from the previous code is the following that fails during compilation.
"name":"${execute('generateTeamUniqueName()')}",
with the following error message:
Execution default-generateTests of goal org.springframework.cloud:spring-cloud-contract-maven-plugin:3.0.2:gener
ateTests failed: expecting '}' or ',' but got current char 'E' with an int value of 69
Is it possible to call a method inside the body or I have to return the ALL the contents of the body through the same method???
Thank you!
You have to call it for the whole body, it won't work for part of it

Failed to create AWSConfig rule: InvalidParameterValueException: Blank spaces are not acceptable for input parameter: threshold

I am trying to create an aws config rule for checking that cloudtrail alarms are enabled. I get the following error Error: Error creating AWSConfig rule: Failed to create AWSConfig rule: InvalidParameterValueException: Blank spaces are not acceptable for input parameter: threshold. when I run terraform apply. I'm not sure what the formatting issue is in the input parameters argument (see input_parameters). The apply works if I remove everything except for metricName i.e
input_parameters = "{\"metricName\":\"CloudTrailConfigChanges\"}"
Any help would be greatly appreciated.
resource aws_config_config_rule ensure-log-alarm-exists-for-cloudtrail {
name = "ensure-log-alarm-exists-for-cloudtrail"
description = "Checks whether cloudwatch alarm is on for cloudtrail configuration changes"
source {
owner = "AWS"
source_identifier = "CLOUDWATCH_ALARM_SETTINGS_CHECK"
}
input_parameters = "{\"metricName\":\"CloudTrailConfigChanges\",\"threshold\":1,\"evaluationPeriod\":1,\"period\":300,\"comparisionOperator\":\"GreaterThanOrEqualToThreshold\",\"statistic\":\"Sum\"}"
}
It seems like there is an issue parsing type ints from json strings: https://github.com/hashicorp/terraform-provider-aws/issues/773#issuecomment-385454229
I get the same error even with
input_parameters =<<EOF
{
"metricName":"CloudTrailConfigChanges",
"threshold":1
}
EOF
or
input_parameters = jsonencode({"metricName":"CloudTrailConfigChanges","threshold"=1})
Converting wrapping the int value in quotes does not work either.
resource "aws_config_config_rule" "ensure-log-alarm-exists-for-cloudtrail" {
name = "ensure-log-alarm-exists-for-cloudtrail"
description = "Checks whether cloudwatch alarm is on for cloudtrail configuration changes"
source {
owner = "AWS"
source_identifier = "CLOUDWATCH_ALARM_SETTINGS_CHECK"
}
input_parameters = jsonencode({
metricName = "CloudTrailConfigChanges"
threshold = "1"
})
}
The code above produces the following error:
Unknown parameters provided in the inputParameters:
With your examples you're still specifying the threshold as an integer. Try making it a string.
resource "aws_config_config_rule" "ensure-log-alarm-exists-for-cloudtrail" {
name = "ensure-log-alarm-exists-for-cloudtrail"
description = "Checks whether cloudwatch alarm is on for cloudtrail configuration changes"
source {
owner = "AWS"
source_identifier = "CLOUDWATCH_ALARM_SETTINGS_CHECK"
}
input_parameters = jsonencode({
metricName = "CloudTrailConfigChanges"
threshold = "1"
})
}
I ran into an error like this, and what resolved it for me was to add a condition. I don't fully understand why this worked and why it caused this error without the condition, but I saw the condition used in an AWS example.
For example, I first tried using something straightforward like this to reference a parameter:
"InputParameters": {
"appNames": {
"Ref": "ApplicationNames"
}
}
When my resource referenced the ApplicationNames parameter directly like this, it was giving that error. But using Conditions and referencing the parameter this way caused it to work, as in this full template example:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Just a stripped-down example",
"Parameters": {
"ApplicationNames": {
"Type": "String",
"Default": "This Has Spaces",
"MinLength": "1",
"ConstraintDescription": "This parameter is required."
}
},
"Conditions": {
"ApplicationNamesDefined": {
"Fn::Not": [
{
"Fn::Equals": [
"",
{
"Ref": "ApplicationNames"
}
]
}
]
}
},
"Resources": {
"SampleRule": {
"Type": "AWS::Config::ConfigRule",
"DependsOn": "SecurityHubCustomUpdaterFunction",
"Properties": {
"ConfigRuleName": "TheName",
"Description": "It was here that I was getting 'Blank spaces are not acceptable for input parameter: applicationNames' before I added the Conditions and Fn::If to reference it",
"InputParameters": {
"appNames": {
"Fn::If": [
"ApplicationNamesDefined",
{
"Ref": "ApplicationNames"
},
{
"Ref": "AWS::NoValue"
}
]
}
},
"Scope": {
"ComplianceResourceTypes": [
"AWS::SSM::ManagedInstanceInventory"
]
},
"Source": {
"Owner": "AWS",
"SourceIdentifier": "EC2_MANAGEDINSTANCE_APPLICATIONS_REQUIRED"
}
}
}
}
}
So you may want to try with Conditions usage.

Inject matchesJsonPath from Groovy into Spring Cloud Contract

When writing a Spring Cloud Contract in Groovy,
I want to specify an explicit JSON path expression.
The expression:
"$.['variants'][*][?(#.['name'] == 'product_0004' && #.['selected'] == true)]"
shall appear in the generated json, like so:
{
"request" : {
"bodyPatterns": [ {
"matchesJsonPath": "$.['variants'][*][?(#.['name'] == 'product_0004' && #.['selected'] == true)]"
} ]
}
}
in order to match e.g.:
{ "variants": [
{ "name": "product_0003", "selected": false },
{ "name": "product_0004", "selected": true },
{ "name": "product_0005", "selected": false } ]
}
and to not match e.g.:
{ "variants": [
{ "name": "product_0003", "selected": false },
{ "name": "product_0004", "selected": false },
{ "name": "product_0005", "selected": true } ]
}
Is this possible using consumers, bodyMatchers, or some other facility of the Groovy DSL?
There are some possibilities with matching on json path, but you wouldn't necessarily use it for matching on explicit values, but rather to make a flexible stub for the consumer by using regex. There are some possibilities though.
So the body section is your static request body with hardcoded values, while the bodyMatchers section provides you the ability to make the stub matching from the consumer side more flexible.
Contract.make {
request {
method 'POST'
url '/some-url'
body ([
id: id
items: [
foo: foo
bar: bar
],
[
foo: foo
bar: foo
]
])
bodyMatchers {
jsonPath('$.id', byEquality()) //1
jsonPath('$.items[*].foo', byRegex('(?:^|\\W)foo(?:$|\\W)')) //2
jsonPath('$.items[*].bar', byRegex(nonBlank())) //3
}
headers {
contentType(applicationJson())
}
}
response {
status 200
}
}
I referenced some lines
1: "byEquality()" in the bodyMatchers section means: the input from the consumer must be equal to the value provided in the body for this contract/stub to match, in other words must be "id".
2: I'm not sure how nicely the //1 solution will work when the property is in a list, and you want the stub to be flexible with the amount of items provided. Therefor I also included this byRegex which basically means, for any item in the list, the property foo must have exactly value "foo". However, I dont really know why you would want to do this.
3: This is where bodyMatchers are actually most useful. This line means: match to this contract if every property bar in the list of items is a non blank string. This allows you to have a dynamic stub with a flexible size of lists/arrays.
All the conditions in bodyMatchers need to be met for the stub to match.

How to search in anonymous and nested array using find or findAll in groovy's closures using REST-Assured library?

I have following JSON response anonymous body and I need to parse nested arrays dynamically to retrieve a key's value based on a condition by using find or findAll in the groovy's closures
[
{
"children": [
{
"attr": {
"reportId": "1",
"reportShortName": "ABC",
"description": "test,
}
},
{
"attr": {
"reportId": "2",
"reportShortName": "XYZ",
"description": "test",
}
}
}
]
I've tried the following ways and had no luck to retrieve the reportId key's value from the JSON response
package com.src.test.api;
import static io.restassured.RestAssured.given;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
public class GetReportId {
public void getReportId(String reportName) throws Exception {
String searchReports = "http://localhost:8080/reports";
Response resp=given().request().when().get(searchReports).then().extract().response();
JsonPath jsonPath = new JsonPath(resp.asString());
String reportId1 =jsonPath.get("$.find{it.children.contains(restAssuredJsonRootObject.$.children.find{it.attr.reportShortName == 'ABC'})}.attr.reportId");
String reportId2 = jsonPath.get("$.find{it.children.attr.reportShortName.contains(restAssuredJsonRootObject.$.children.find{it.attr.reportShortName.equals('XYZ')}.attr.reportShortName)}.attr.reportId");
System.out.println("ReportId: " + reportId1);
}
}
There could be multiple JSON objects in the parent anonymous array and need to make use of find or findAll within the groovy closures to get the reportId
Need to get the reportId, but seems that something is wrong. Any help would be appreciated.
Assuming you want all the reportIds
List<String> reportIds = jsonPath.get("children.flatten().attr.reportId");
will give you what you want, even it the parent anonymous array has multiple entries.
I tested with the following JSON
[
{
"children": [
{
"attr": {
"reportId": "1",
"reportShortName": "ABC",
"description": "test"
}
},
{
"attr": {
"reportId": "2",
"reportShortName": "XYZ",
"description": "test"
}
}
]
},
{
"children": [
{
"attr": {
"reportId": "3",
"reportShortName": "DEF",
"description": "test"
}
},
{
"attr": {
"reportId": "4",
"reportShortName": "IJK",
"description": "test"
}
}
]
}
]
and it gives me ["1", "2", "3", "4"] i.e. reportIds from all the children
If you know the index of the reportId you're looking for then you can use it like so:
String reportId = jsonPath.get("children.flatten().attr.reportId[0]");
If you're looking for the reportId of a particular report you can do that too:
String reportId = jsonPath.get("children.flatten().attr.find{it.reportShortName == 'ABC'}.reportId")
will give you "1".
Note: The type of the variable you assign the results to are important for type inference and casting. For example, you CANNOT do:
String [] reportIds = jsonPath.get("children.flatten().attr.reportId");
or
int reportId = jsonPath.get("children.flatten().attr.reportId[0]");
Both those things will throw a ClassCastException.

Jmeter Groovy replacing JSON file

In Jmeter JSR223Preprocessor with Groovy I load a generic JSON file xyz looking like this:
{
"name": "dummy",
"block1": {
"var1": 1,
"var2": {
"value": 1,
"unit": "Miles",
},
"var3": {
"value": 3,
"unit": "Seconds",
},
"myList": [{"Id": 0}]
}
I like to come up with an elegant way to replace the var2 "Value" with a configurable value sayconfVal. This works:
String path = vars.get("basePath")+"xyz.json" ;
xyz = new File(path).getText("UTF-8");
xyz = xyz.replaceAll ('"value": 1', '"value": ${confVal}');
However I am not comfortable with this because it is vulnerable with spaces, and moreover I have another Value on var3 and someone could accidentally change 1 to 3. So I like to index to that child var2.Value then get Value.
Thank you
Add JSR223 PreProcessor as a child of the HTTP Request which body you need to amend
Put the following code into "Script" area:
def xyz = new File(vars.get("basePath")+"xyz.json")
def request = new groovy.json.JsonSlurper().parse(xyz)
request.block1.var2.value=vars.get('confVal') as int
xyz.newWriter().withWriter { writer ->
writer << new groovy.json.JsonBuilder(request).toPrettyString()
}
That's it, the value in the file should be replaced with what you have in the ${confVal} variable in the runtime.
More information:
Groovy: Parsing and producing JSON
Apache Groovy - Why and How You Should Use It

Resources