Skip to content

Commit a6e8b35

Browse files
committed
Release 0.7.2
- serializeNulls() for all toJSON - Make Body nullable in CompositeResponse Signed-off-by: Gopal S Akshintala <[email protected]>
1 parent dfb2275 commit a6e8b35

File tree

10 files changed

+127
-32
lines changed

10 files changed

+127
-32
lines changed

README.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ endif::[]
1818
:pmtemplates: src/integrationTest/resources/pm-templates
1919
:imagesdir: docs/images
2020
:prewrap!:
21-
:revoman-version: 0.7.1
21+
:revoman-version: 0.7.2
2222

2323
'''
2424

@@ -456,7 +456,7 @@ to qualify a step whose Request JSON payload needs to be unmarshalled/deserializ
456456
* Use bundled static factory methods like `ResponseConfig.unmarshallSuccessResponse()` and `ResponseConfig.unmarshallErrorResponse()` for expressiveness.
457457
* You can pass a `PostTxnStepPick` which is a `Predicate` used
458458
to qualify a step whose Response JSON payload needs to be unmarshalled/deserialized.
459-
* If you have set up `responseConfig()` once, wherever you wish to read or assert the response in your <<#_pre_step_and_post_step_hooks,Post-Step Hooks>>, you can call `stepReport.responseInfo.get().<TypeT>getTypedTxnObj()` which returns your response JSON as a Strong type to conveniently assert.
459+
* If you have set up `responseConfig()` once, wherever you wish to read or assert the response in your <<#_pre_step_and_post_step_hooks,Post-Step Hooks>>, you can call `stepReport.responseInfo.get().<TypeT>getTypedTxnObj()` which returns your response JSON as a Strong type.
460460

461461
[TIP]
462462
====

buildSrc/src/main/kotlin/Config.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
* ************************************************************************************************
77
*/
88
const val GROUP_ID = "com.salesforce.revoman"
9-
const val VERSION = "0.7.1"
9+
const val VERSION = "0.7.2"
1010
const val ARTIFACT_ID = "revoman"
1111
const val STAGING_PROFILE_ID = "1ea0a23e61ba7d"

src/integrationTest/java/com/salesforce/revoman/integration/core/CoreUtils.java

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,127 @@
1010
import static com.salesforce.revoman.input.config.HookConfig.post;
1111
import static com.salesforce.revoman.input.config.ResponseConfig.unmarshallResponse;
1212
import static com.salesforce.revoman.input.config.StepPick.PostTxnStepPick.afterStepContainingURIPathOfAny;
13+
import static com.salesforce.revoman.input.config.StepPick.PostTxnStepPick.afterStepEndingWithURIPathOfAny;
14+
import static com.salesforce.revoman.output.report.StepReport.containsHeader;
1315
import static org.junit.jupiter.api.Assertions.assertTrue;
1416

1517
import com.salesforce.revoman.input.config.HookConfig;
1618
import com.salesforce.revoman.input.config.ResponseConfig;
1719
import com.salesforce.revoman.input.json.adapters.salesforce.CompositeGraphResponse;
1820
import com.salesforce.revoman.input.json.adapters.salesforce.CompositeGraphResponse.Graph.ErrorGraph;
21+
import com.salesforce.revoman.input.json.adapters.salesforce.CompositeResponse;
1922
import com.salesforce.revoman.output.report.StepReport;
2023
import java.util.List;
21-
import kotlin.collections.CollectionsKt;
2224

2325
public class CoreUtils {
2426
private CoreUtils() {}
2527

2628
public static final String COMPOSITE_GRAPH_URI_PATH = "composite/graph";
2729

28-
public static final HookConfig ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS =
29-
post(
30-
afterStepContainingURIPathOfAny(COMPOSITE_GRAPH_URI_PATH),
31-
(stepReport, ignore) -> assertCompositeGraphResponseSuccess(stepReport));
32-
30+
/** Reusable Response config for CompositeGraphResponse to enhance debugging experience */
3331
public static ResponseConfig unmarshallCompositeGraphResponse() {
3432
return unmarshallResponse(
3533
afterStepContainingURIPathOfAny(COMPOSITE_GRAPH_URI_PATH),
3634
CompositeGraphResponse.class,
3735
CompositeGraphResponse.ADAPTER);
3836
}
3937

38+
/**
39+
* Reusable ReVoman Post-Step hooks that can be added to your configuration to assert
40+
* CompositeGraphResponse(success/error). For expected failure response, this expects you to add
41+
* `expectToFail=true` header to your request in Postman If you have to use a different header,
42+
* compose your own hook using {@link #assertCompositeGraphResponseSuccess(StepReport, String)}
43+
*/
44+
public static final HookConfig ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS =
45+
post(
46+
afterStepContainingURIPathOfAny(COMPOSITE_GRAPH_URI_PATH),
47+
(stepReport, ignore) -> assertCompositeGraphResponseSuccess(stepReport));
48+
49+
public static final String EXPECT_TO_FAIL_HEADER = "expectToFail";
50+
51+
private static final String UNSUCCESSFUL_COMPOSITE_GRAPH_RESPONSE_ERROR_MSG =
52+
"""
53+
Unsuccessful Composite Graph response for graphId: %s
54+
{
55+
first errorCode: %s
56+
first errorMessage: %s
57+
}
58+
StepReport:
59+
%s""";
60+
4061
public static void assertCompositeGraphResponseSuccess(StepReport stepReport) {
62+
assertCompositeGraphResponseSuccess(stepReport, EXPECT_TO_FAIL_HEADER);
63+
}
64+
65+
static void assertCompositeGraphResponseSuccess(
66+
StepReport stepReport, String expectToFailHeader) {
4167
final var responseTxnInfo = stepReport.responseInfo.get();
42-
final var graphResp =
68+
final var graphsResp =
4369
responseTxnInfo
4470
.<CompositeGraphResponse>getTypedTxnObj(
4571
CompositeGraphResponse.class, List.of(CompositeGraphResponse.ADAPTER))
46-
.getGraphs()
47-
.getFirst();
72+
.getGraphs();
73+
for (var graphResp : graphsResp) {
74+
assertTrue(
75+
graphResp.isSuccessful() || containsHeader(stepReport.requestInfo, expectToFailHeader),
76+
() -> {
77+
final var firstErrorResponseBody = ((ErrorGraph) graphResp).firstErrorResponseBody();
78+
return String.format(
79+
UNSUCCESSFUL_COMPOSITE_GRAPH_RESPONSE_ERROR_MSG,
80+
graphResp.getGraphId(),
81+
firstErrorResponseBody.getErrorCode(),
82+
firstErrorResponseBody.getMessage(),
83+
stepReport);
84+
});
85+
}
86+
}
87+
88+
public static final String COMPOSITE_URI_PATH = "composite";
89+
90+
/** Reusable Response config for CompositeGraphResponse to enhance debugging experience */
91+
public static ResponseConfig unmarshallCompositeResponse() {
92+
return unmarshallResponse(
93+
afterStepEndingWithURIPathOfAny(COMPOSITE_URI_PATH),
94+
CompositeResponse.class,
95+
CompositeResponse.ADAPTER);
96+
}
97+
98+
/**
99+
* Reusable ReVoman Post-Step hooks that can be added to your configuration to assert
100+
* CompositeResponse(success/error). For expected failure response, this expects you to add
101+
* `expectToFail=true` header to your request in Postman If you have to use a different header,
102+
* compose your own hook using {@link #assertCompositeResponseSuccess(StepReport, String)}
103+
*/
104+
public static final HookConfig ASSERT_COMPOSITE_RESPONSE_SUCCESS =
105+
post(
106+
afterStepEndingWithURIPathOfAny(COMPOSITE_URI_PATH),
107+
(stepReport, ignore) -> assertCompositeResponseSuccess(stepReport));
108+
109+
private static final String UNSUCCESSFUL_COMPOSITE_RESPONSE_ERROR_MSG =
110+
"""
111+
Unsuccessful Composite response:
112+
{
113+
first errorCode: %s
114+
first errorMessage: %s
115+
}
116+
StepReport:
117+
%s""";
118+
119+
static void assertCompositeResponseSuccess(StepReport stepReport) {
120+
assertCompositeResponseSuccess(stepReport, EXPECT_TO_FAIL_HEADER);
121+
}
122+
123+
static void assertCompositeResponseSuccess(StepReport stepReport, String expectToFailHeader) {
124+
final var responseTxnInfo = stepReport.responseInfo.get();
125+
final var compositeResp =
126+
responseTxnInfo.<CompositeResponse>getTypedTxnObj(
127+
CompositeResponse.class, List.of(CompositeResponse.ADAPTER));
48128
assertTrue(
49-
graphResp.isSuccessful(),
129+
compositeResp.isSuccessful() || containsHeader(stepReport.requestInfo, expectToFailHeader),
50130
() -> {
51-
final var firstErrorResponse =
52-
CollectionsKt.first(((ErrorGraph) graphResp).errorResponses());
53-
final var firstErrorResponseBody = ((ErrorGraph) graphResp).firstErrorResponseBody();
131+
final var firstErrorResponseBody = compositeResp.firstErrorResponseBody();
54132
return String.format(
55-
"Unsuccessful Composite Graph response%n{%n first error ReferenceId: %s%n first errorCode: %s%n first errorMessage: %s%n}%n%s",
56-
firstErrorResponse.getReferenceId(),
133+
UNSUCCESSFUL_COMPOSITE_RESPONSE_ERROR_MSG,
57134
firstErrorResponseBody.getErrorCode(),
58135
firstErrorResponseBody.getMessage(),
59136
stepReport);

src/integrationTest/java/com/salesforce/revoman/integration/core/bt2bs/ReVomanConfigForBT2BS.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import static com.salesforce.revoman.input.config.StepPick.PostTxnStepPick.afterStepContainingHeader;
1111
import static com.salesforce.revoman.input.config.StepPick.PostTxnStepPick.afterStepContainingURIPathOfAny;
1212
import static com.salesforce.revoman.integration.core.CoreUtils.ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS;
13+
import static com.salesforce.revoman.integration.core.CoreUtils.ASSERT_COMPOSITE_RESPONSE_SUCCESS;
1314
import static com.salesforce.revoman.integration.core.CoreUtils.unmarshallCompositeGraphResponse;
15+
import static com.salesforce.revoman.integration.core.CoreUtils.unmarshallCompositeResponse;
1416
import static com.salesforce.revoman.output.ExeType.HTTP_STATUS;
1517

1618
import com.salesforce.revoman.input.config.HookConfig;
@@ -33,8 +35,8 @@ private ReVomanConfigForBT2BS() {}
3335
Kick.configure()
3436
.templatePath(USER_CREATION_AND_SETUP_COLLECTION_PATH)
3537
.environmentPath(ENV_PATH)
36-
.responseConfig(unmarshallCompositeGraphResponse())
37-
.hook(ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS)
38+
.responseConfig(unmarshallCompositeGraphResponse(), unmarshallCompositeResponse())
39+
.hooks(ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS, ASSERT_COMPOSITE_RESPONSE_SUCCESS)
3840
.nodeModulesRelativePath(NODE_MODULE_RELATIVE_PATH)
3941
.haltOnFailureOfTypeExcept(
4042
HTTP_STATUS, afterStepContainingHeader(IGNORE_HTTP_STATUS_UNSUCCESSFUL))
@@ -62,8 +64,8 @@ HTTP_STATUS, afterStepContainingHeader(IGNORE_HTTP_STATUS_UNSUCCESSFUL))
6264
.templatePath(MB_SETUP_POSTMAN_COLLECTION_PATH)
6365
.haltOnFailureOfTypeExcept(
6466
HTTP_STATUS, afterStepContainingHeader(IGNORE_HTTP_STATUS_UNSUCCESSFUL))
65-
.responseConfig(unmarshallCompositeGraphResponse())
66-
.hook(ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS)
67+
.responseConfig(unmarshallCompositeGraphResponse(), unmarshallCompositeResponse())
68+
.hooks(ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS, ASSERT_COMPOSITE_RESPONSE_SUCCESS)
6769
.haltOnFailureOfTypeExcept(
6870
HTTP_STATUS, afterStepContainingHeader(IGNORE_HTTP_STATUS_UNSUCCESSFUL))
6971
.globalCustomTypeAdapter(IDAdapter.INSTANCE)
@@ -76,8 +78,11 @@ HTTP_STATUS, afterStepContainingHeader(IGNORE_HTTP_STATUS_UNSUCCESSFUL))
7678
static final Kick MILESTONE_CONFIG =
7779
Kick.configure()
7880
.templatePath(MB_POSTMAN_COLLECTION_PATH)
79-
.responseConfig(unmarshallCompositeGraphResponse())
80-
.hooks(MEMQ_AWAIT, ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS)
81+
.responseConfig(unmarshallCompositeGraphResponse(), unmarshallCompositeResponse())
82+
.hooks(
83+
MEMQ_AWAIT,
84+
ASSERT_COMPOSITE_GRAPH_RESPONSE_SUCCESS,
85+
ASSERT_COMPOSITE_RESPONSE_SUCCESS)
8186
.haltOnFailureOfTypeExcept(
8287
HTTP_STATUS, afterStepContainingHeader(IGNORE_HTTP_STATUS_UNSUCCESSFUL))
8388
.globalCustomTypeAdapter(IDAdapter.INSTANCE)

src/integrationTest/java/com/salesforce/revoman/integration/core/pq/PQE2EWithSMTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
* ----------------------------------------~~~~~ NOTE ~~~~~-----------------------------------------
4141
* This is only a sample to demo a full-blown test. You may not be able to execute this, as it needs
4242
* a specific server setup. If you are a Salesforce core developer, it takes less than 5 minutes to
43-
* setup an SM org,
43+
* set up an SM org.
4444
*
4545
* <p>- Follow these instructions: <a href="http://sfdc.co/sm-org-setup">SM Org setup</a>. - Replace
4646
* baseUrl of your server, username and password of the org admin here: <a

src/main/kotlin/com/salesforce/revoman/input/json/adapters/salesforce/CompositeResponse.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.salesforce.revoman.input.json.adapters.salesforce.CompositeResponse.R
88
import com.salesforce.revoman.input.json.factories.DiMorphicAdapter
99
import com.salesforce.revoman.input.json.mapW
1010
import com.salesforce.revoman.input.json.objW
11+
import com.salesforce.revoman.internal.json.AlwaysSerializeNulls
1112
import com.squareup.moshi.Json
1213
import com.squareup.moshi.JsonAdapter
1314
import com.squareup.moshi.JsonClass
@@ -29,8 +30,9 @@ data class CompositeResponse(val compositeResponse: List<Response>) {
2930
val httpHeaders: HttpHeaders
3031

3132
@JsonClass(generateAdapter = true)
33+
@AlwaysSerializeNulls
3234
data class SuccessResponse(
33-
val body: Body,
35+
val body: Body?,
3436
override val httpHeaders: HttpHeaders,
3537
override val httpStatusCode: Int,
3638
override val referenceId: String,

src/main/kotlin/com/salesforce/revoman/internal/json/MoshiReVoman.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ open class MoshiReVoman(builder: Moshi.Builder) {
111111
typesToIgnore: Set<Type> = emptySet(),
112112
): Moshi.Builder {
113113
// * NOTE 08 May 2024 gopala.akshintala: This cannot be static singleton as adapters added
114-
// mutates
115-
// the singleton
114+
// mutates the singleton.
116115
val moshiBuilder =
117116
Moshi.Builder()
118117
.add(JsonString.Factory())

src/main/kotlin/com/salesforce/revoman/output/report/TxnInfo.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ constructor(
9292
fun TxnInfo<Request>.uriPathEndsWith(path: String): Boolean {
9393
val sourcePath = httpMsg.uri.path.trim('/').split("/")
9494
val targetPath = path.trim('/').split("/")
95-
return indexOfSubList(sourcePath, targetPath) != -1 &&
96-
indexOfSubList(sourcePath, targetPath) + targetPath.lastIndex == sourcePath.lastIndex
95+
val indexOfSubList = indexOfSubList(sourcePath, targetPath)
96+
return indexOfSubList != -1 && indexOfSubList + targetPath.lastIndex == sourcePath.lastIndex
9797
}
9898
}
9999
}

src/test/java/com/salesforce/revoman/input/json/JsonPojoUtilsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ void compositeGraphResponseDiMorphicMarshallUnmarshall() throws JSONException {
7878
}
7979

8080
@Test
81-
@DisplayName("DiMorphic CompositeQuery Success/Error QueryResponse --> POJO --> JSON")
82-
void compositeQueryResponseDiMorphicMarshallUnmarshall() throws JSONException {
81+
@DisplayName("DiMorphic Composite Success/Error Response --> POJO --> JSON")
82+
void compositeResponseDiMorphicMarshallUnmarshall() throws JSONException {
8383
// JSON --> POJO
8484
final var jsonFileConfig =
8585
JsonFile.<CompositeResponse>unmarshall()

src/test/resources/composite/query/resp/query-response-all-success.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@
150150
"httpHeaders": {},
151151
"httpStatusCode": 200,
152152
"referenceId": "qlrs"
153+
},
154+
{
155+
"body": null,
156+
"httpHeaders": {},
157+
"httpStatusCode": 204,
158+
"referenceId": "taxAdminNewPassword"
159+
},
160+
{
161+
"body": null,
162+
"httpHeaders": {},
163+
"httpStatusCode": 204,
164+
"referenceId": "productAndPricingAdminNewPassword"
153165
}
154166
]
155167
}

0 commit comments

Comments
 (0)