@@ -1582,4 +1582,133 @@ public void compoundMatchers_tooFewPredicates_throws() {
15821582 assertThat (e ).hasMessageThat ().contains ("AndMatcher must have at least 2 predicates" );
15831583 }
15841584 }
1585+
1586+ @ Test
1587+ public void singlePredicate_invalidCelMatcherProto_throws () {
1588+ // Triggers "Invalid CelMatcher config"
1589+ // Create a CEL matcher config with invalid bytes to trigger InvalidProtocolBufferException
1590+ TypedExtensionConfig config = TypedExtensionConfig .newBuilder ()
1591+ .setTypedConfig (com .google .protobuf .Any .newBuilder ()
1592+ .setTypeUrl ("type.googleapis.com/xds.type.matcher.v3.CelMatcher" )
1593+ .setValue (com .google .protobuf .ByteString .copyFromUtf8 ("invalid" ))
1594+ .build ())
1595+ .build ();
1596+
1597+ Matcher .MatcherList .Predicate .SinglePredicate predicate =
1598+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
1599+ .setInput (TypedExtensionConfig .newBuilder ()
1600+ .setTypedConfig (Any .pack (
1601+ com .github .xds .type .matcher .v3 .HttpAttributesCelMatchInput .getDefaultInstance ())))
1602+ .setCustomMatch (config )
1603+ .build ();
1604+
1605+ try {
1606+ PredicateEvaluator .fromProto (
1607+ Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (predicate ).build ());
1608+ org .junit .Assert .fail ("Should have thrown IllegalArgumentException" );
1609+ } catch (IllegalArgumentException e ) {
1610+ assertThat (e ).hasMessageThat ().contains ("Invalid CelMatcher config" );
1611+ }
1612+ }
1613+
1614+ @ Test
1615+ public void singlePredicate_celEvalError_returnsFalse () {
1616+ // Triggers "return false" in "catch (CelEvaluationException e)"
1617+ // Expression: [][0] -> Index out of bounds, runtime error
1618+ // Type check passes (list access).
1619+ // We need a CheckedExpr.
1620+
1621+ // We rely on a runtime failure (division by zero) to trigger CelEvaluationException.
1622+
1623+ Matcher .MatcherList .Predicate .SinglePredicate predicate =
1624+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
1625+ .setInput (TypedExtensionConfig .newBuilder ()
1626+ .setTypedConfig (Any .pack (
1627+ com .github .xds .type .matcher .v3 .HttpAttributesCelMatchInput .getDefaultInstance ())))
1628+ .setCustomMatch (TypedExtensionConfig .newBuilder ()
1629+ .setTypedConfig (Any .pack (createCelMatcher ("1/0 == 0" ))))
1630+ .build ();
1631+
1632+ PredicateEvaluator evaluator = PredicateEvaluator .fromProto (
1633+ Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (predicate ).build ());
1634+
1635+ // Eval should return false (caught exception)
1636+ assertThat (evaluator .evaluate (mock (MatchContext .class ))).isFalse ();
1637+ }
1638+
1639+ @ Test
1640+ public void stringMatcher_emptySuffix_throws () {
1641+ // Triggers "StringMatcher suffix ... must be non-empty"
1642+ Matcher .MatcherList .Predicate .SinglePredicate predicate =
1643+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
1644+ .setInput (TypedExtensionConfig .newBuilder ()
1645+ .setTypedConfig (Any .pack (
1646+ io .envoyproxy .envoy .type .matcher .v3 .HttpRequestHeaderMatchInput .newBuilder ()
1647+ .setHeaderName ("host" ).build ())))
1648+ .setValueMatch (com .github .xds .type .matcher .v3 .StringMatcher .newBuilder ().setSuffix ("" ))
1649+ .build ();
1650+
1651+ try {
1652+ PredicateEvaluator .fromProto (
1653+ Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (predicate ).build ());
1654+ org .junit .Assert .fail ("Should have thrown IllegalArgumentException" );
1655+ } catch (IllegalArgumentException e ) {
1656+ assertThat (e ).hasMessageThat ().contains (
1657+ "StringMatcher suffix (match_pattern) must be non-empty" );
1658+ }
1659+ }
1660+
1661+ @ Test
1662+ public void stringMatcher_unknownPattern_throws () {
1663+ // Triggers "Unknown StringMatcher match pattern"
1664+ Matcher .MatcherList .Predicate .SinglePredicate predicate =
1665+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
1666+ .setInput (TypedExtensionConfig .newBuilder ()
1667+ .setTypedConfig (Any .pack (
1668+ io .envoyproxy .envoy .type .matcher .v3 .HttpRequestHeaderMatchInput .newBuilder ()
1669+ .setHeaderName ("host" ).build ())))
1670+ .setValueMatch (com .github .xds .type .matcher .v3 .StringMatcher .getDefaultInstance ())
1671+ .build ();
1672+
1673+ try {
1674+ PredicateEvaluator .fromProto (
1675+ Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (predicate ).build ());
1676+ org .junit .Assert .fail ("Should have thrown IllegalArgumentException" );
1677+ } catch (IllegalArgumentException e ) {
1678+ assertThat (e ).hasMessageThat ().contains ("Unknown StringMatcher match pattern" );
1679+ }
1680+ }
1681+
1682+
1683+ @ Test
1684+ public void singlePredicate_stringMatcher_safeRegex_matches () {
1685+ // Verifies valid safe_regex config
1686+ com .github .xds .type .matcher .v3 .RegexMatcher regexMatcher =
1687+ com .github .xds .type .matcher .v3 .RegexMatcher .newBuilder ()
1688+ .setRegex ("f.*o" )
1689+ .build ();
1690+
1691+ Matcher .MatcherList .Predicate .SinglePredicate predicate =
1692+ Matcher .MatcherList .Predicate .SinglePredicate .newBuilder ()
1693+ .setInput (TypedExtensionConfig .newBuilder ()
1694+ .setTypedConfig (Any .pack (
1695+ io .envoyproxy .envoy .type .matcher .v3 .HttpRequestHeaderMatchInput .newBuilder ()
1696+ .setHeaderName ("host" ).build ())))
1697+ .setValueMatch (com .github .xds .type .matcher .v3 .StringMatcher .newBuilder ()
1698+ .setSafeRegex (regexMatcher ))
1699+ .build ();
1700+
1701+ PredicateEvaluator evaluator = PredicateEvaluator .fromProto (
1702+ Matcher .MatcherList .Predicate .newBuilder ().setSinglePredicate (predicate ).build ());
1703+
1704+ MatchContext context = mock (MatchContext .class );
1705+ when (context .getMetadata ()).thenReturn (new Metadata ());
1706+ // host header not present -> null -> false
1707+ assertThat (evaluator .evaluate (context )).isFalse ();
1708+
1709+ Metadata headers = new Metadata ();
1710+ headers .put (Metadata .Key .of ("host" , Metadata .ASCII_STRING_MARSHALLER ), "foo" );
1711+ when (context .getMetadata ()).thenReturn (headers );
1712+ assertThat (evaluator .evaluate (context )).isTrue ();
1713+ }
15851714}
0 commit comments