Skip to content

Commit 29e3fb5

Browse files
committed
Validate stepId exists (when applicable)
1 parent f9822a1 commit 29e3fb5

File tree

2 files changed

+109
-22
lines changed

2 files changed

+109
-22
lines changed

src/main/java/com/apiflows/parser/OpenAPIWorkflowValidator.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
public class OpenAPIWorkflowValidator {
1111

1212
private OpenAPIWorkflow openAPIWorkflow = null;
13-
private Set<String> workflowIds = new HashSet<>();
14-
private Map<String, Set<String>> stepIds = new HashMap<>();
15-
private Set<Schema> components = new HashSet<>();
13+
Set<String> workflowIds = new HashSet<>();
14+
Map<String, Set<String>> stepIds = new HashMap<>();
15+
Set<Schema> components = new HashSet<>();
1616

1717
OpenAPIWorkflowValidator() {
1818
}
@@ -181,7 +181,7 @@ List<String> validateStep(Step step, String workflowId ) {
181181
}
182182

183183
if(step.getDependsOn() != null) {
184-
if(this.stepIds.get(workflowId) == null || !this.stepIds.get(workflowId).contains(step.getDependsOn())) {
184+
if(!stepExists(workflowId, step.getDependsOn())) {
185185
errors.add("'Step " + stepId + " 'dependsOn' is invalid (no such a step exists)");
186186
}
187187

@@ -195,11 +195,11 @@ List<String> validateStep(Step step, String workflowId ) {
195195
}
196196

197197
for(SuccessAction successAction: step.getOnSuccess()) {
198-
errors.addAll(validateSuccessAction(successAction, stepId));
198+
errors.addAll(validateSuccessAction(workflowId, stepId, successAction));
199199
}
200200

201201
for(FailureAction failureAction : step.getOnFailure()) {
202-
errors.addAll(validateFailureAction(failureAction, stepId));
202+
errors.addAll(validateFailureAction(workflowId, stepId, failureAction));
203203

204204
}
205205

@@ -241,7 +241,7 @@ List<String> validateParameter(Parameter parameter, String workflowId ) {
241241
return errors;
242242
}
243243

244-
List<String> validateSuccessAction(SuccessAction successAction, String stepId) {
244+
List<String> validateSuccessAction(String workflowId, String stepId, SuccessAction successAction) {
245245
List<String> SUPPORTED_VALUES = Arrays.asList("end", "goto");
246246

247247
List<String> errors = new ArrayList<>();
@@ -264,10 +264,17 @@ List<String> validateSuccessAction(SuccessAction successAction, String stepId) {
264264
errors.add("Step " + stepId + " SuccessAction cannot define both workflowId and stepId");
265265
}
266266

267+
if(successAction.getStepId() != null && successAction.getType() != null && successAction.getType().equals("goto")) {
268+
// when type `goto` stepId must exist (if provided)
269+
if (!stepExists(workflowId, successAction.getStepId())) {
270+
errors.add("Step " + stepId + " SuccessAction stepId is invalid (no such a step exists)");
271+
}
272+
}
273+
267274
return errors;
268275
}
269276

270-
List<String> validateFailureAction(FailureAction failureAction, String stepId) {
277+
List<String> validateFailureAction(String workflowId, String stepId, FailureAction failureAction) {
271278
List<String> SUPPORTED_VALUES = Arrays.asList("end", "retry", "goto");
272279

273280
List<String> errors = new ArrayList<>();
@@ -300,6 +307,15 @@ List<String> validateFailureAction(FailureAction failureAction, String stepId) {
300307

301308
}
302309

310+
if(failureAction.getStepId() != null && failureAction.getType() != null
311+
&& (failureAction.getType().equals("goto") || failureAction.getType().equals("retry"))) {
312+
// when type `goto` or `retry` stepId must exist (if provided)
313+
if (!stepExists(workflowId, failureAction.getStepId())) {
314+
errors.add("Step " + stepId + " FailureAction stepId is invalid (no such a step exists)");
315+
}
316+
}
317+
318+
303319
return errors;
304320
}
305321

@@ -424,6 +440,10 @@ List<String> loadStepIds(List<Workflow> workflows) {
424440
return errors;
425441
}
426442

443+
boolean stepExists(String workflowId, String stepId) {
444+
return this.stepIds.get(workflowId) != null && this.stepIds.get(workflowId).contains(stepId);
445+
}
446+
427447
public boolean isValidJsonPointer(String jsonPointerString) {
428448

429449
boolean ret;

src/test/java/com/apiflows/parser/OpenAPIWorkflowValidatorTest.java

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import com.apiflows.model.*;
44
import org.junit.jupiter.api.Test;
55

6-
import java.util.ArrayList;
7-
import java.util.List;
6+
import java.util.*;
87

98
import static org.junit.jupiter.api.Assertions.*;
109

@@ -235,7 +234,9 @@ void validateParameterWithoutValue() {
235234

236235
@Test
237236
void validateSuccessAction() {
237+
String workflowId = "w1";
238238
String stepId = "step-one";
239+
239240
SuccessAction successAction = new SuccessAction()
240241
.type("end")
241242
.stepId("step-one");
@@ -244,12 +245,14 @@ void validateSuccessAction() {
244245
new Criterion()
245246
.context("$statusCode == 200"));
246247

247-
assertEquals(0, validator.validateSuccessAction(successAction, stepId).size());
248+
assertEquals(0, validator.validateSuccessAction(workflowId, stepId, successAction).size());
248249
}
249250

250251
@Test
251252
void validateSuccessActionInvalidType() {
253+
String workflowId = "w1";
252254
String stepId = "step-one";
255+
253256
SuccessAction successAction = new SuccessAction()
254257
.type("invalid-type")
255258
.stepId("step-one");
@@ -258,12 +261,14 @@ void validateSuccessActionInvalidType() {
258261
new Criterion()
259262
.context("$statusCode == 200"));
260263

261-
assertEquals(1, validator.validateSuccessAction(successAction, stepId).size());
264+
assertEquals(1, validator.validateSuccessAction(workflowId, stepId, successAction).size());
262265
}
263266

264267
@Test
265268
void validateSuccessActionMissingEntity() {
269+
String workflowId = "w1";
266270
String stepId = "step-one";
271+
267272
SuccessAction successAction = new SuccessAction()
268273
.type("end")
269274
.stepId(null)
@@ -273,12 +278,14 @@ void validateSuccessActionMissingEntity() {
273278
new Criterion()
274279
.context("$statusCode == 200"));
275280

276-
assertEquals(1, validator.validateSuccessAction(successAction, stepId).size());
281+
assertEquals(1, validator.validateSuccessAction(workflowId, stepId, successAction).size());
277282
}
278283

279284
@Test
280285
void validateSuccessActionInvalidEntity() {
286+
String workflowId = "w1";
281287
String stepId = "step-one";
288+
282289
SuccessAction successAction = new SuccessAction()
283290
.type("end")
284291
.stepId("step-one")
@@ -288,9 +295,33 @@ void validateSuccessActionInvalidEntity() {
288295
new Criterion()
289296
.condition("$statusCode == 200"));
290297

291-
assertEquals(1, validator.validateSuccessAction(successAction, stepId).size());
298+
assertEquals(1, validator.validateSuccessAction(workflowId, stepId, successAction).size());
299+
}
300+
301+
@Test
302+
void validateSuccessActionInvalidStepId() {
303+
String workflowId = "w1";
304+
305+
OpenAPIWorkflowValidator validator = new OpenAPIWorkflowValidator();
306+
307+
Map<String, Set<String>> stepIds = new HashMap<>();
308+
stepIds.put("w1", Set.of("step-one", "step-two", "step-three"));
309+
310+
validator.stepIds = stepIds;
311+
312+
String stepId = "step-one";
313+
SuccessAction successAction = new SuccessAction()
314+
.type("goto")
315+
.stepId("step-dummy");
316+
317+
successAction.addCriteria(
318+
new Criterion()
319+
.context("$statusCode == 200"));
320+
321+
assertEquals(1, validator.validateSuccessAction(workflowId, stepId, successAction).size());
292322
}
293323

324+
294325
@Test
295326
void validateCriterion() {
296327
String stepId = "step-one";
@@ -338,9 +369,11 @@ void validateCriterionMissingContext() {
338369

339370
@Test
340371
void validateFailureAction() {
372+
String workflowId = "w1";
341373
String stepId = "step-one";
374+
342375
FailureAction failureAction = new FailureAction()
343-
.type("retry")
376+
.type("end")
344377
.stepId("step-one")
345378
.retryAfter(1000L)
346379
.retryLimit(3);
@@ -349,12 +382,14 @@ void validateFailureAction() {
349382
new Criterion()
350383
.context("$statusCode == 200"));
351384

352-
assertEquals(0, validator.validateFailureAction(failureAction, stepId).size());
385+
assertEquals(0, validator.validateFailureAction(workflowId, stepId, failureAction).size());
353386
}
354387

355388
@Test
356389
void validateFailureActionInvalidType() {
390+
String workflowId = "w1";
357391
String stepId = "step-one";
392+
358393
FailureAction failureAction = new FailureAction()
359394
.type("dummy")
360395
.stepId("step-one")
@@ -365,14 +400,16 @@ void validateFailureActionInvalidType() {
365400
new Criterion()
366401
.context("$statusCode == 200"));
367402

368-
assertEquals(1, validator.validateFailureAction(failureAction, stepId).size());
403+
assertEquals(1, validator.validateFailureAction(workflowId, stepId, failureAction).size());
369404
}
370405

371406
@Test
372407
void validateFailureActionInvalidRetrySettings() {
408+
String workflowId = "w1";
373409
String stepId = "step-one";
410+
374411
FailureAction failureAction = new FailureAction()
375-
.type("retry")
412+
.type("end")
376413
.stepId("step-one")
377414
.retryAfter(-1000L)
378415
.retryLimit(-3);
@@ -381,12 +418,14 @@ void validateFailureActionInvalidRetrySettings() {
381418
new Criterion()
382419
.context("$statusCode == 200"));
383420

384-
assertEquals(2, validator.validateFailureAction(failureAction, stepId).size());
421+
assertEquals(2, validator.validateFailureAction(workflowId, stepId, failureAction).size());
385422
}
386423

387424
@Test
388425
void validateFailureActionMissingEntity() {
426+
String workflowId = "w1";
389427
String stepId = "step-one";
428+
390429
FailureAction failureAction = new FailureAction()
391430
.type("retry")
392431
.stepId(null)
@@ -398,14 +437,16 @@ void validateFailureActionMissingEntity() {
398437
new Criterion()
399438
.context("$statusCode == 200"));
400439

401-
assertEquals(1, validator.validateFailureAction(failureAction, stepId).size());
440+
assertEquals(1, validator.validateFailureAction(workflowId, stepId, failureAction).size());
402441
}
403442

404443
@Test
405444
void validateFailureActionInvalidEntity() {
445+
String workflowId = "w1";
406446
String stepId = "step-one";
447+
407448
FailureAction failureAction = new FailureAction()
408-
.type("retry")
449+
.type("end")
409450
.stepId("step-one")
410451
.workflowId("workflow-test")
411452
.retryAfter(1000L)
@@ -415,9 +456,35 @@ void validateFailureActionInvalidEntity() {
415456
new Criterion()
416457
.context("$statusCode == 200"));
417458

418-
assertEquals(1, validator.validateFailureAction(failureAction, stepId).size());
459+
assertEquals(1, validator.validateFailureAction(workflowId, stepId, failureAction).size());
460+
}
461+
462+
@Test
463+
void validateFailureActionInvalidStepId() {
464+
String workflowId = "w1";
465+
String stepId = "step-one";
466+
467+
OpenAPIWorkflowValidator validator = new OpenAPIWorkflowValidator();
468+
469+
Map<String, Set<String>> stepIds = new HashMap<>();
470+
stepIds.put("w1", Set.of("step-one", "step-two", "step-three"));
471+
472+
validator.stepIds = stepIds;
473+
474+
FailureAction failureAction = new FailureAction()
475+
.type("retry")
476+
.stepId("step-dummy")
477+
.retryAfter(1000L)
478+
.retryLimit(3);
479+
480+
failureAction.addCriteria(
481+
new Criterion()
482+
.context("$statusCode == 200"));
483+
484+
assertEquals(1, validator.validateFailureAction(workflowId, stepId, failureAction).size());
419485
}
420486

487+
421488
@Test
422489
void loadWorkflowIWithDuplicateIds() {
423490
List<Workflow> list = List.of(

0 commit comments

Comments
 (0)