@@ -133,6 +133,42 @@ public void celMatcher_throwsIfReturnsString() {
133133 }
134134 }
135135
136+ @ Test
137+ public void celMatcher_evaluationError_returnsFalse () {
138+ CelMatcher celMatcher = createCelMatcher ("int(request.path) == 0" );
139+ Matcher .MatcherList .Predicate .SinglePredicate predicate =
140+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
141+ .setInput (TypedExtensionConfig .newBuilder ()
142+ .setTypedConfig (Any .pack (
143+ com .github .xds .type .matcher .v3 .HttpAttributesCelMatchInput
144+ .getDefaultInstance ())))
145+ .setCustomMatch (TypedExtensionConfig .newBuilder ()
146+ .setTypedConfig (Any .pack (celMatcher )))
147+ .build ();
148+ Matcher proto = Matcher .newBuilder ()
149+ .setMatcherList (Matcher .MatcherList .newBuilder ()
150+ .addMatchers (Matcher .MatcherList .FieldMatcher .newBuilder ()
151+ .setPredicate (Matcher .MatcherList .Predicate .newBuilder ()
152+ .setSinglePredicate (predicate ))
153+ .setOnMatch (Matcher .OnMatch .newBuilder ()
154+ .setAction (TypedExtensionConfig .newBuilder ().setName ("matched" )))))
155+ .setOnNoMatch (Matcher .OnMatch .newBuilder ()
156+ .setAction (TypedExtensionConfig .newBuilder ().setName ("no-match" )))
157+ .build ();
158+
159+ UnifiedMatcher matcher = UnifiedMatcher .fromProto (proto );
160+ MatchContext context = mock (MatchContext .class );
161+ when (context .getPath ()).thenReturn ("not-an-int" );
162+ // Ensure metadata access (if any by environment) checks out
163+ when (context .getMetadata ()).thenReturn (new Metadata ());
164+ when (context .getId ()).thenReturn ("1" );
165+
166+ MatchResult result = matcher .match (context , 0 );
167+ // Should return false for match, so it falls through to no-match
168+ assertThat (result .matched ).isTrue ();
169+ assertThat (result .actions .get (0 ).getName ()).isEqualTo ("no-match" );
170+ }
171+
136172 @ Test
137173 public void celStringExtractor_throwsIfReturnsBool () {
138174 try {
@@ -852,6 +888,123 @@ public void matcherRunner_checkMatch_returnsNullOnNoMatch() {
852888 assertThat (results ).isNull ();
853889 }
854890
891+ @ Test
892+ public void predicate_missingType_throws () {
893+ Matcher .MatcherList .Predicate proto = Matcher .MatcherList .Predicate .getDefaultInstance ();
894+ try {
895+ PredicateEvaluator .fromProto (proto );
896+ org .junit .Assert .fail ("Should have thrown IllegalArgumentException" );
897+ } catch (IllegalArgumentException e ) {
898+ assertThat (e ).hasMessageThat ().contains ("Predicate must have one of" );
899+ }
900+ }
901+
902+ @ Test
903+ public void celMatcher_missingExprMatch_throws () {
904+ com .github .xds .type .matcher .v3 .CelMatcher celProto =
905+ com .github .xds .type .matcher .v3 .CelMatcher .getDefaultInstance ();
906+ Matcher .MatcherList .Predicate proto = Matcher .MatcherList .Predicate .newBuilder ()
907+ .setSinglePredicate (Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
908+ .setInput (TypedExtensionConfig .newBuilder ().setTypedConfig (Any .pack (
909+ com .github .xds .type .matcher .v3 .HttpAttributesCelMatchInput .getDefaultInstance ())))
910+ .setCustomMatch (TypedExtensionConfig .newBuilder ().setTypedConfig (Any .pack (celProto ))))
911+ .build ();
912+ try {
913+ PredicateEvaluator .fromProto (proto );
914+ org .junit .Assert .fail ("Should have thrown" );
915+ } catch (IllegalArgumentException e ) {
916+ assertThat (e ).hasMessageThat ().contains ("CelMatcher must have expr_match" );
917+ }
918+ }
919+
920+ @ Test
921+ public void singlePredicate_unsupportedCustomMatcher_throws () {
922+ Matcher .MatcherList .Predicate proto = Matcher .MatcherList .Predicate .newBuilder ()
923+ .setSinglePredicate (Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
924+ .setInput (TypedExtensionConfig .newBuilder ().setTypedConfig (Any .pack (
925+ com .github .xds .type .matcher .v3 .HttpAttributesCelMatchInput .getDefaultInstance ())))
926+ .setCustomMatch (TypedExtensionConfig .newBuilder ().setTypedConfig (
927+ Any .pack (com .google .protobuf .Empty .getDefaultInstance ()))))
928+ .build ();
929+ try {
930+ PredicateEvaluator .fromProto (proto );
931+ org .junit .Assert .fail ("Should have thrown" );
932+ } catch (IllegalArgumentException e ) {
933+ assertThat (e ).hasMessageThat ().contains ("Unsupported custom_match matcher" );
934+ }
935+ }
936+
937+ @ Test
938+ public void singlePredicate_missingInput_throws () {
939+ Matcher .MatcherList .Predicate proto = Matcher .MatcherList .Predicate .newBuilder ()
940+ .setSinglePredicate (Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
941+ .setValueMatch (
942+ com .github .xds .type .matcher .v3 .StringMatcher .newBuilder ().setExact ("foo" )))
943+ .build ();
944+ try {
945+ PredicateEvaluator .fromProto (proto );
946+ org .junit .Assert .fail ("Should have thrown" );
947+ } catch (IllegalArgumentException e ) {
948+ assertThat (e ).hasMessageThat ().contains ("SinglePredicate must have input" );
949+ }
950+ }
951+
952+ @ Test
953+ public void singlePredicate_missingMatcher_throws () {
954+ Matcher .MatcherList .Predicate proto = Matcher .MatcherList .Predicate .newBuilder ()
955+ .setSinglePredicate (Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
956+ .setInput (TypedExtensionConfig .newBuilder ().setTypedConfig (Any .pack (
957+ com .github .xds .type .matcher .v3 .HttpAttributesCelMatchInput .getDefaultInstance ()))))
958+ .build ();
959+ try {
960+ PredicateEvaluator .fromProto (proto );
961+ org .junit .Assert .fail ("Should have thrown" );
962+ } catch (IllegalArgumentException e ) {
963+ assertThat (e ).hasMessageThat ().contains (
964+ "SinglePredicate must have either value_match or custom_match" );
965+ }
966+ }
967+
968+ @ Test
969+ public void orMatcher_tooFewPredicates_throws () {
970+ Matcher .MatcherList .Predicate .PredicateList protoList =
971+ Matcher .MatcherList .Predicate .PredicateList .newBuilder ()
972+ .addPredicate (Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (
973+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
974+ .setInput (TypedExtensionConfig .newBuilder ().setName ("i" ))
975+ .setValueMatch (
976+ com .github .xds .type .matcher .v3 .StringMatcher .newBuilder ().setExact ("v" ))))
977+ .build ();
978+ Matcher .MatcherList .Predicate proto = Matcher .MatcherList .Predicate .newBuilder ()
979+ .setOrMatcher (protoList )
980+ .build ();
981+ try {
982+ PredicateEvaluator .fromProto (proto );
983+ org .junit .Assert .fail ("Should have thrown" );
984+ } catch (IllegalArgumentException e ) {
985+ assertThat (e ).hasMessageThat ().contains ("OrMatcher must have at least 2 predicates" );
986+ }
987+ }
988+
989+ @ Test
990+ public void andMatcher_tooFewPredicates_throws () {
991+ Matcher .MatcherList .Predicate .PredicateList proto =
992+ Matcher .MatcherList .Predicate .PredicateList .newBuilder ()
993+ .addPredicate (Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (
994+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
995+ .setInput (TypedExtensionConfig .newBuilder ().setName ("i" ))
996+ .setValueMatch (
997+ com .github .xds .type .matcher .v3 .StringMatcher .newBuilder ().setExact ("v" ))))
998+ .build ();
999+ try {
1000+ PredicateEvaluator .fromProto (
1001+ Matcher .MatcherList .Predicate .newBuilder ().setAndMatcher (proto ).build ());
1002+ org .junit .Assert .fail ("Should have thrown" );
1003+ } catch (IllegalArgumentException e ) {
1004+ assertThat (e ).hasMessageThat ().contains ("AndMatcher must have at least 2 predicates" );
1005+ }
1006+ }
1007+
8551008 @ Test
8561009 public void matcherList_firstMatchWins_evenIfNestedNoMatch () {
8571010 Matcher .MatcherList .Predicate predicate = createHeaderMatchPredicate ("path" , "/common" );
0 commit comments