21
21
import static java .util .Collections .unmodifiableMap ;
22
22
import static java .util .Optional .ofNullable ;
23
23
24
+ import com .chutneytesting .ExecutionConfiguration ;
24
25
import com .chutneytesting .action .spi .ActionExecutionResult ;
25
26
import com .chutneytesting .action .spi .injectable .Target ;
26
27
import com .chutneytesting .engine .domain .environment .TargetImpl ;
39
40
import com .chutneytesting .engine .domain .execution .report .StepExecutionReport ;
40
41
import com .chutneytesting .engine .domain .execution .strategies .StepStrategyDefinition ;
41
42
import com .chutneytesting .tools .Try ;
43
+ import com .fasterxml .jackson .core .JsonProcessingException ;
44
+ import com .fasterxml .jackson .databind .ObjectMapper ;
42
45
import com .google .common .collect .Lists ;
43
46
import com .google .common .collect .Maps ;
44
47
import java .time .Duration ;
@@ -67,7 +70,7 @@ public class Step {
67
70
private Target target ;
68
71
private final StepExecutor executor ;
69
72
private final StepDataEvaluator dataEvaluator ;
70
-
73
+ private static final ObjectMapper objectMapper = ExecutionConfiguration . reportObjectMapper ();
71
74
private StepContext stepContext ;
72
75
73
76
public Step (StepDataEvaluator dataEvaluator , StepDefinition definition , StepExecutor executor , List <Step > steps ) {
@@ -77,7 +80,7 @@ public Step(StepDataEvaluator dataEvaluator, StepDefinition definition, StepExec
77
80
this .executor = executor ;
78
81
this .steps = steps ;
79
82
this .state = new StepState (definition .name );
80
- this .stepContext = new StepContext ();
83
+ this .stepContext = new StepContext (objectMapper );
81
84
}
82
85
83
86
public static Step nonExecutable (StepDefinition definition ) {
@@ -111,7 +114,7 @@ public Status execute(ScenarioExecution scenarioExecution, ScenarioContext scena
111
114
target = dataEvaluator .evaluateTarget (target , evaluationContext );
112
115
resolveName (evaluationContext );
113
116
Try
114
- .exec (() -> this .stepContext = new StepContext (scenarioContext , localContext , evaluatedInputs ))
117
+ .exec (() -> this .stepContext = new StepContext (scenarioContext , localContext , evaluatedInputs , objectMapper ))
115
118
.ifSuccess (stepContextExecuted -> {
116
119
executor .execute (scenarioExecution , target , this );
117
120
if (Status .SUCCESS .equals (this .state .status ())) {
@@ -154,6 +157,10 @@ public String name() {
154
157
return this .state .name ();
155
158
}
156
159
160
+ public ObjectMapper getObjectMapper () {
161
+ return objectMapper ;
162
+ }
163
+
157
164
public void resolveName (Map <String , Object > context ) {
158
165
this .state .setName (dataEvaluator .silentEvaluateString (state .name (), context ));
159
166
}
@@ -329,10 +336,6 @@ public void addStepExecution(Step step) {
329
336
this .steps .add (step );
330
337
}
331
338
332
- public void addStepExecution (List <Step > steps ) {
333
- steps .forEach (this ::addStepExecution );
334
- }
335
-
336
339
public Map <String , Object > getEvaluatedInputs () {
337
340
return unmodifiableMap (this .stepContext .getEvaluatedInputs ());
338
341
}
@@ -345,6 +348,14 @@ public Map<String, Object> getStepOutputs() {
345
348
return unmodifiableMap (this .stepContext .getStepOutputs ());
346
349
}
347
350
351
+ public Map <String , Object > getStepContextInputSnapshot () {
352
+ return this .stepContext .stepContextSnapshot .getInputsSnapshot ();
353
+ }
354
+
355
+ public Map <String , Object > getStepContextOutputSnapshot () {
356
+ return this .stepContext .stepContextSnapshot .getOutputsSnapshot ();
357
+ }
358
+
348
359
public void removeStepExecution () {
349
360
this .steps .clear ();
350
361
}
@@ -356,20 +367,27 @@ private static class StepContext {
356
367
private final Map <String , Object > localContext ;
357
368
private final Map <String , Object > evaluatedInputs ;
358
369
private final Map <String , Object > stepOutputs ;
370
+ private StepContextSnapshot stepContextSnapshot ;
359
371
360
- private StepContext () {
361
- this (new ScenarioContextImpl (), new LinkedHashMap <>(), new LinkedHashMap <>());
372
+ private StepContext (ObjectMapper objectMapper ) {
373
+ this (new ScenarioContextImpl (), new LinkedHashMap <>(), new LinkedHashMap <>(), objectMapper );
362
374
}
363
375
364
- private StepContext (ScenarioContext scenarioContext , Map <String , Object > localContext , Map <String , Object > evaluatedInputs ) throws EvaluationException {
365
- this (scenarioContext , localContext , evaluatedInputs , new LinkedHashMap <>());
376
+ private StepContext (ScenarioContext scenarioContext , Map <String , Object > localContext , Map <String , Object > evaluatedInputs , ObjectMapper objectMapper ) throws EvaluationException {
377
+ this (scenarioContext , localContext , evaluatedInputs , new LinkedHashMap <>(), objectMapper );
366
378
}
367
379
368
- private StepContext (ScenarioContext scenarioContext , Map <String , Object > localContext , Map <String , Object > evaluatedInputs , Map <String , Object > stepOutputs ) {
380
+ private StepContext (ScenarioContext scenarioContext , Map <String , Object > localContext , Map <String , Object > evaluatedInputs , Map <String , Object > stepOutputs , ObjectMapper objectMapper ) {
369
381
this .scenarioContext = scenarioContext ;
370
382
this .localContext = localContext ;
371
383
this .evaluatedInputs = evaluatedInputs ;
372
384
this .stepOutputs = stepOutputs ;
385
+ this .stepContextSnapshot = new StepContextSnapshot (objectMapper );
386
+ }
387
+
388
+ private StepContext copySnapshotsInputOutput () {
389
+ this .stepContextSnapshot = new StepContextSnapshot (evaluatedInputs , stepOutputs , objectMapper );
390
+ return this ;
373
391
}
374
392
375
393
private Map <String , Object > evaluationContext () {
@@ -387,17 +405,6 @@ private Map<String, Object> getEvaluatedInputs() {
387
405
return ofNullable (evaluatedInputs ).orElse (emptyMap ());
388
406
}
389
407
390
- @ SafeVarargs
391
- private void addLocalContext (Map .Entry <String , Object >... entries ) {
392
- this .addLocalContext (Map .ofEntries (entries ));
393
- }
394
-
395
- private void addLocalContext (Map <String , Object > localContext ) {
396
- if (localContext != null ) {
397
- this .localContext .putAll (localContext );
398
- }
399
- }
400
-
401
408
private void addStepOutputs (Map <String , Object > stepOutputs ) {
402
409
if (stepOutputs != null ) {
403
410
this .stepOutputs .putAll (stepOutputs );
@@ -415,7 +422,47 @@ private Map<String, Object> getStepOutputs() {
415
422
}
416
423
417
424
private StepContext copy () {
418
- return new StepContext (scenarioContext .unmodifiable (), unmodifiableMap (localContext ), unmodifiableMap (evaluatedInputs ), unmodifiableMap (stepOutputs ));
425
+ return new StepContext (scenarioContext .unmodifiable (), unmodifiableMap (localContext ), unmodifiableMap (evaluatedInputs ), unmodifiableMap (stepOutputs ), objectMapper ).copySnapshotsInputOutput ();
426
+ }
427
+ }
428
+
429
+ public static class StepContextSnapshot {
430
+ private final Map <String , Object > inputsSnapshot ;
431
+ private final Map <String , Object > outputsSnapshot ;
432
+ private final ObjectMapper objectMapper ;
433
+
434
+ public StepContextSnapshot (ObjectMapper objectMapper ) {
435
+ this .objectMapper = objectMapper ;
436
+ this .inputsSnapshot = emptyMap ();
437
+ this .outputsSnapshot = emptyMap ();
438
+ }
439
+
440
+ public StepContextSnapshot (Map <String , Object > inputsSnapshot , Map <String , Object > outputsSnapshot , ObjectMapper objectMapper ) {
441
+ this .objectMapper = objectMapper ;
442
+ this .inputsSnapshot = mapStringObjectToString (inputsSnapshot );
443
+ this .outputsSnapshot = mapStringObjectToString (outputsSnapshot );
444
+ }
445
+
446
+ public Map <String , Object > getInputsSnapshot () {
447
+ return unmodifiableMap (inputsSnapshot );
448
+ }
449
+
450
+ public Map <String , Object > getOutputsSnapshot () {
451
+ return unmodifiableMap (outputsSnapshot );
452
+ }
453
+
454
+ private Map <String , Object > mapStringObjectToString (Map <String , Object > originalMap ) {
455
+ Map <String , Object > stringMap = new HashMap <>();
456
+ originalMap .forEach ((key , value ) -> {
457
+ try {
458
+ String stringObject = objectMapper .writeValueAsString (value );
459
+ Object jsonObject = objectMapper .readTree (stringObject );
460
+ stringMap .put (key , jsonObject );
461
+ } catch (JsonProcessingException e ) {
462
+ throw new RuntimeException (e );
463
+ }
464
+ });
465
+ return stringMap ;
419
466
}
420
467
}
421
468
}
0 commit comments