Skip to content
This repository was archived by the owner on Jul 10, 2024. It is now read-only.

Commit c3d5506

Browse files
PROC-1564: Validate rules for CRUD without context defined
1 parent c35c9e0 commit c3d5506

File tree

5 files changed

+100
-14
lines changed

5 files changed

+100
-14
lines changed

proctor-common/src/main/java/com/indeed/proctor/common/ProctorUtils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ public static void verifyInternallyConsistentDefinition(
10771077
@Nonnull final ConsumableTestDefinition testDefinition)
10781078
throws IncompatibleTestMatrixException {
10791079
verifyInternallyConsistentDefinition(
1080-
testName, matrixSource, testDefinition, ProvidedContext.nonEvaluableContext());
1080+
testName, matrixSource, testDefinition, ProvidedContext.evaluableContext());
10811081
}
10821082

10831083
/**
@@ -1216,7 +1216,7 @@ private static void verifyInternallyConsistentDefinition(
12161216
try {
12171217
RuleVerifyUtils.verifyRule(
12181218
rule,
1219-
providedContext.shouldEvaluate(),
1219+
providedContext.getEvaluationMode(),
12201220
expressionFactory,
12211221
elContext,
12221222
providedContext.getUninstantiatedIdentifiers());

proctor-common/src/main/java/com/indeed/proctor/common/ProvidedContext.java

+33
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@
77

88
/** May provide a map of identifiers to use for rule evaluation */
99
public class ProvidedContext {
10+
enum ProvidedContextEvaluationMode {
11+
EVALUATE_WITH_CONTEXT,
12+
EVALUATE_WITHOUT_CONTEXT,
13+
SKIP_EVALUATION;
14+
}
1015
/** @deprecated Use factory method nonEvaluableContext() */
1116
@Deprecated
1217
public static final Map<String, ValueExpression> EMPTY_CONTEXT = Collections.emptyMap();
1318

1419
private static final ProvidedContext NON_EVALUABLE =
1520
new ProvidedContext(ProvidedContext.EMPTY_CONTEXT, false);
21+
private static final ProvidedContext EMPTY_EVALUABLE =
22+
new ProvidedContext(
23+
ProvidedContext.EMPTY_CONTEXT,
24+
ProvidedContextEvaluationMode.EVALUATE_WITHOUT_CONTEXT);
1625
private final Map<String, ValueExpression> context;
1726
private final Set<String> uninstantiatedIdentifiers;
1827
/** if false, indicates that for rule verification, this context is unusable (empty) */
1928
private final boolean shouldEvaluate;
2029

30+
private final ProvidedContextEvaluationMode mode;
31+
2132
/** @deprecated Use factory methods */
2233
@Deprecated
2334
public ProvidedContext(
@@ -27,6 +38,20 @@ public ProvidedContext(
2738
this.context = context;
2839
this.shouldEvaluate = shouldEvaluate;
2940
this.uninstantiatedIdentifiers = uninstantiatedIdentifiers;
41+
this.mode =
42+
shouldEvaluate
43+
? ProvidedContextEvaluationMode.EVALUATE_WITH_CONTEXT
44+
: ProvidedContextEvaluationMode.SKIP_EVALUATION;
45+
}
46+
47+
/** @deprecated Use factory methods */
48+
@Deprecated
49+
public ProvidedContext(
50+
final Map<String, ValueExpression> context, final ProvidedContextEvaluationMode mode) {
51+
this.context = context;
52+
this.shouldEvaluate = mode == ProvidedContextEvaluationMode.SKIP_EVALUATION;
53+
this.uninstantiatedIdentifiers = Collections.emptySet();
54+
this.mode = mode;
3055
}
3156

3257
/** @deprecated Use factory methods */
@@ -53,6 +78,10 @@ public static ProvidedContext nonEvaluableContext() {
5378
return NON_EVALUABLE;
5479
}
5580

81+
public static ProvidedContext evaluableContext() {
82+
return EMPTY_EVALUABLE;
83+
}
84+
5685
public Map<String, ValueExpression> getContext() {
5786
return context;
5887
}
@@ -61,6 +90,10 @@ public Set<String> getUninstantiatedIdentifiers() {
6190
return uninstantiatedIdentifiers;
6291
}
6392

93+
public ProvidedContextEvaluationMode getEvaluationMode() {
94+
return mode;
95+
}
96+
6497
public boolean shouldEvaluate() {
6598
return shouldEvaluate;
6699
}

proctor-common/src/main/java/com/indeed/proctor/common/RuleVerifyUtils.java

+33-12
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,31 @@ private RuleVerifyUtils() {}
2929
*
3030
* @param shouldEvaluate if false, only checks syntax is correct
3131
*/
32+
@Deprecated
3233
public static void verifyRule(
3334
final String testRule,
3435
final boolean shouldEvaluate,
3536
final ExpressionFactory expressionFactory,
3637
final ELContext elContext,
3738
final Set<String> absentIdentifiers)
3839
throws InvalidRuleException {
40+
verifyRule(
41+
testRule,
42+
shouldEvaluate
43+
? ProvidedContext.ProvidedContextEvaluationMode.EVALUATE_WITH_CONTEXT
44+
: ProvidedContext.ProvidedContextEvaluationMode.SKIP_EVALUATION,
45+
expressionFactory,
46+
elContext,
47+
absentIdentifiers);
48+
}
49+
50+
public static void verifyRule(
51+
final String testRule,
52+
final ProvidedContext.ProvidedContextEvaluationMode evaluationMode,
53+
final ExpressionFactory expressionFactory,
54+
final ELContext elContext,
55+
final Set<String> absentIdentifiers)
56+
throws InvalidRuleException {
3957
if (!isEmptyElExpression(testRule)) {
4058
final ValueExpression valueExpression;
4159
try {
@@ -51,7 +69,7 @@ public static void verifyRule(
5169
testRule));
5270
}
5371

54-
if (shouldEvaluate) {
72+
if (evaluationMode != ProvidedContext.ProvidedContextEvaluationMode.SKIP_EVALUATION) {
5573
/*
5674
* must have a context to test against, even if it's "Collections.emptyMap()", how to
5775
* tell if this method is used for ProctorBuilder or during load of the testMatrix.
@@ -73,17 +91,20 @@ public static void verifyRule(
7391
testRule));
7492
}
7593

76-
// Check identifiers in the AST and verify variable names
77-
final Node undefinedIdentifier =
78-
checkUndefinedIdentifier(root, elContext, absentIdentifiers);
79-
if (undefinedIdentifier != null) {
80-
throw new InvalidRuleException(
81-
String.format(
82-
"The variable %s is defined in rule %s, however it "
83-
+ "is not defined in the application's test specification. Add the variable to your application's "
84-
+ "providedContext.json or remove it from the rule, or if the application should not load your "
85-
+ "test report the issue to the Proctor team.",
86-
undefinedIdentifier.getImage(), testRule));
94+
if (evaluationMode
95+
== ProvidedContext.ProvidedContextEvaluationMode.EVALUATE_WITH_CONTEXT) {
96+
// Check identifiers in the AST and verify variable names
97+
final Node undefinedIdentifier =
98+
checkUndefinedIdentifier(root, elContext, absentIdentifiers);
99+
if (undefinedIdentifier != null) {
100+
throw new InvalidRuleException(
101+
String.format(
102+
"The variable %s is defined in rule %s, however it "
103+
+ "is not defined in the application's test specification. Add the variable to your application's "
104+
+ "providedContext.json or remove it from the rule, or if the application should not load your "
105+
+ "test report the issue to the Proctor team.",
106+
undefinedIdentifier.getImage(), testRule));
107+
}
87108
}
88109

89110
// Evaluate rule with given context

proctor-common/src/test/java/com/indeed/proctor/common/TestProctorUtils.java

+16
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,22 @@ public void testELValidity_inProctorBuilderAllocationRules()
473473
"-1:0.25,0:0.5,1:0.25"));
474474
verifyInternallyConsistentDefinition(
475475
"testELevalProctor", "test el recognition", testDefVal1);
476+
477+
// testing valid functions pass with proctor included functions (will throw exception if
478+
// can't find) and backwards compatibility
479+
final ConsumableTestDefinition testDefVal2 =
480+
constructDefinition(
481+
buckets,
482+
fromCompactAllocationFormat(
483+
"${proctor:version('213.0')=='2.0.0.0'}|-1:0.5,0:0.5,1:0.0",
484+
"-1:0.25,0:0.5,1:0.25"));
485+
assertThatThrownBy(
486+
() ->
487+
verifyInternallyConsistentDefinition(
488+
"testELevalProctor", "test el recognition", testDefVal2))
489+
.isInstanceOf(IncompatibleTestMatrixException.class)
490+
.hasMessage(
491+
"Invalid allocation rule in testELevalProctor: Failed to evaluate a rule ${proctor:version('213.0')=='2.0.0.0'}: Problems calling function [proctor:version]");
476492
}
477493

478494
@Test

proctor-common/src/test/java/com/indeed/proctor/common/TestRuleVerifyUtils.java

+16
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,22 @@ public void testVerifyRulesNestedMapBoolean() {
122122
new String[] {});
123123
}
124124

125+
@Test
126+
public void testVerifyRulesProctorVersion() {
127+
expectInvalidRule(
128+
"${version != proctor:version('213.0')}",
129+
new Object[][] {
130+
{"version", ""},
131+
},
132+
new String[] {});
133+
expectValidRule(
134+
"${version != proctor:version('213.0.0.0')}",
135+
new Object[][] {
136+
{"version", ""},
137+
},
138+
new String[] {});
139+
}
140+
125141
@Test
126142
public void testValidRulesWithMethodCall() {
127143
expectValidRule(

0 commit comments

Comments
 (0)