Skip to content

Commit 78895db

Browse files
committed
add some more unit tests
1 parent e28c8f5 commit 78895db

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed

xds/src/test/java/io/grpc/xds/internal/matcher/UnifiedMatcherTest.java

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,4 +1424,162 @@ public void matcherList_example3_nestedMatcher() {
14241424
assertThat(result.actions).hasSize(1);
14251425
assertThat(result.actions.get(0).getName()).isEqualTo("inner_matcher_2");
14261426
}
1427+
1428+
@Test
1429+
public void resolveInput_malformedProto_throws() {
1430+
// Create a config with correct typeUrl but corrupted/invalid bytes
1431+
TypedExtensionConfig config = TypedExtensionConfig.newBuilder()
1432+
.setTypedConfig(com.google.protobuf.Any.newBuilder()
1433+
.setTypeUrl("type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput")
1434+
.setValue(com.google.protobuf.ByteString.copyFromUtf8("invalid-proto-data"))
1435+
.build())
1436+
.build();
1437+
try {
1438+
UnifiedMatcher.resolveInput(config);
1439+
org.junit.Assert.fail("Should have thrown IllegalArgumentException");
1440+
} catch (IllegalArgumentException e) {
1441+
assertThat(e).hasMessageThat().contains("Invalid input config");
1442+
}
1443+
}
1444+
1445+
@Test
1446+
public void matchInput_headerName_invalidCharacters_throws() {
1447+
// A lowercase header name that is still invalid for gRPC Metadata keys
1448+
io.envoyproxy.envoy.type.matcher.v3.HttpRequestHeaderMatchInput proto =
1449+
io.envoyproxy.envoy.type.matcher.v3.HttpRequestHeaderMatchInput.newBuilder()
1450+
.setHeaderName("invalid$header")
1451+
.build();
1452+
TypedExtensionConfig config = TypedExtensionConfig.newBuilder()
1453+
.setTypedConfig(Any.pack(proto))
1454+
.build();
1455+
try {
1456+
UnifiedMatcher.resolveInput(config);
1457+
org.junit.Assert.fail("Should have thrown IllegalArgumentException");
1458+
} catch (IllegalArgumentException e) {
1459+
assertThat(e).hasMessageThat().contains("Invalid header name");
1460+
}
1461+
}
1462+
1463+
@Test
1464+
public void matchInput_headerName_binary_missing() {
1465+
MatchContext context = mock(MatchContext.class);
1466+
when(context.getMetadata()).thenReturn(new Metadata());
1467+
1468+
io.envoyproxy.envoy.type.matcher.v3.HttpRequestHeaderMatchInput proto =
1469+
io.envoyproxy.envoy.type.matcher.v3.HttpRequestHeaderMatchInput.newBuilder()
1470+
.setHeaderName("test-bin") // Binary suffix
1471+
.build();
1472+
MatchInput<MatchContext> input = UnifiedMatcher.resolveInput(
1473+
TypedExtensionConfig.newBuilder()
1474+
.setTypedConfig(com.google.protobuf.Any.pack(proto)).build());
1475+
1476+
assertThat(input.apply(context)).isNull();
1477+
}
1478+
1479+
@Test
1480+
public void noOpMatcher_noOnNoMatch_returnsNoMatch() {
1481+
// An empty Matcher proto defaults to a NoOpMatcher with no onNoMatch action
1482+
Matcher proto = Matcher.getDefaultInstance();
1483+
UnifiedMatcher matcher = UnifiedMatcher.fromProto(proto);
1484+
1485+
MatchResult result = matcher.match(mock(MatchContext.class), 0);
1486+
assertThat(result.matched).isFalse();
1487+
}
1488+
1489+
@Test
1490+
public void noOpMatcher_runtimeRecursionLimit_returnsNoMatch() {
1491+
Matcher proto = Matcher.getDefaultInstance();
1492+
UnifiedMatcher matcher = UnifiedMatcher.fromProto(proto);
1493+
1494+
// Manually trigger the runtime recursion check in NoOpMatcher
1495+
MatchResult result = matcher.match(mock(MatchContext.class), 17);
1496+
assertThat(result.matched).isFalse();
1497+
}
1498+
1499+
@Test
1500+
public void singlePredicate_celInputWithStringMatcher_throws() {
1501+
// Tests the explicit check that blocks CEL input for StringMatchers
1502+
Matcher.MatcherList.Predicate.SinglePredicate predicate =
1503+
Matcher.MatcherList.Predicate.SinglePredicate.newBuilder()
1504+
.setInput(TypedExtensionConfig.newBuilder()
1505+
.setTypedConfig(com.google.protobuf.Any.pack(
1506+
com.github.xds.type.matcher.v3.HttpAttributesCelMatchInput.getDefaultInstance())))
1507+
.setValueMatch(com.github.xds.type.matcher.v3.StringMatcher.newBuilder().setExact("foo"))
1508+
.build();
1509+
1510+
try {
1511+
PredicateEvaluator.fromProto(
1512+
Matcher.MatcherList.Predicate.newBuilder().setSinglePredicate(predicate).build());
1513+
org.junit.Assert.fail("Should have thrown IllegalArgumentException");
1514+
} catch (IllegalArgumentException e) {
1515+
assertThat(e).hasMessageThat().contains(
1516+
"HttpAttributesCelMatchInput cannot be used with StringMatcher");
1517+
}
1518+
}
1519+
1520+
@Test
1521+
public void singlePredicate_headerInputWithCelMatcher_throws() {
1522+
// Tests the inverse check: CelMatcher must use HttpAttributesCelMatchInput
1523+
com.github.xds.type.matcher.v3.CelMatcher celMatcher = createCelMatcher("true");
1524+
Matcher.MatcherList.Predicate.SinglePredicate predicate =
1525+
Matcher.MatcherList.Predicate.SinglePredicate.newBuilder()
1526+
.setInput(TypedExtensionConfig.newBuilder()
1527+
.setTypedConfig(com.google.protobuf.Any.pack(
1528+
io.envoyproxy.envoy.type.matcher.v3.HttpRequestHeaderMatchInput.newBuilder()
1529+
.setHeaderName("host").build())))
1530+
.setCustomMatch(TypedExtensionConfig.newBuilder()
1531+
.setTypedConfig(com.google.protobuf.Any.pack(celMatcher)))
1532+
.build();
1533+
1534+
try {
1535+
PredicateEvaluator.fromProto(
1536+
Matcher.MatcherList.Predicate.newBuilder().setSinglePredicate(predicate).build());
1537+
org.junit.Assert.fail("Should have thrown IllegalArgumentException");
1538+
} catch (IllegalArgumentException e) {
1539+
assertThat(e).hasMessageThat().contains(
1540+
"CelMatcher can only be used with HttpAttributesCelMatchInput");
1541+
}
1542+
}
1543+
1544+
@Test
1545+
public void singlePredicate_noMatcher_throws() {
1546+
// Triggers: "SinglePredicate must have either value_match or custom_match"
1547+
Matcher.MatcherList.Predicate.SinglePredicate predicate =
1548+
Matcher.MatcherList.Predicate.SinglePredicate.newBuilder()
1549+
.setInput(TypedExtensionConfig.newBuilder().setTypedConfig(com.google.protobuf.Any.pack(
1550+
com.github.xds.type.matcher.v3.HttpAttributesCelMatchInput.getDefaultInstance())))
1551+
.build();
1552+
1553+
try {
1554+
PredicateEvaluator.fromProto(
1555+
Matcher.MatcherList.Predicate.newBuilder().setSinglePredicate(predicate).build());
1556+
org.junit.Assert.fail("Should have thrown");
1557+
} catch (IllegalArgumentException e) {
1558+
assertThat(e).hasMessageThat().contains("must have either value_match or custom_match");
1559+
}
1560+
}
1561+
1562+
@Test
1563+
public void compoundMatchers_tooFewPredicates_throws() {
1564+
// Coverage for OrMatcher and AndMatcher minimum predicate requirements
1565+
Matcher.MatcherList.Predicate p = createHeaderMatchPredicate("h", "v");
1566+
Matcher.MatcherList.Predicate.PredicateList list =
1567+
Matcher.MatcherList.Predicate.PredicateList.newBuilder().addPredicate(p).build();
1568+
1569+
try {
1570+
PredicateEvaluator.fromProto(
1571+
Matcher.MatcherList.Predicate.newBuilder().setOrMatcher(list).build());
1572+
org.junit.Assert.fail();
1573+
} catch (IllegalArgumentException e) {
1574+
assertThat(e).hasMessageThat().contains("OrMatcher must have at least 2 predicates");
1575+
}
1576+
1577+
try {
1578+
PredicateEvaluator.fromProto(
1579+
Matcher.MatcherList.Predicate.newBuilder().setAndMatcher(list).build());
1580+
org.junit.Assert.fail();
1581+
} catch (IllegalArgumentException e) {
1582+
assertThat(e).hasMessageThat().contains("AndMatcher must have at least 2 predicates");
1583+
}
1584+
}
14271585
}

0 commit comments

Comments
 (0)