|
23 | 23 | import static org.mockito.Mockito.verify; |
24 | 24 | import static org.mockito.Mockito.when; |
25 | 25 |
|
| 26 | +import com.github.udpa.udpa.type.v1.TypedStruct; |
26 | 27 | import com.github.xds.type.matcher.v3.Matcher; |
27 | 28 | import com.github.xds.type.matcher.v3.StringMatcher; |
28 | 29 | import com.google.protobuf.Any; |
|
49 | 50 | import java.net.SocketAddress; |
50 | 51 | import java.util.Collections; |
51 | 52 | import java.util.concurrent.ScheduledExecutorService; |
| 53 | +import javax.net.ssl.ExtendedSSLSession; |
| 54 | +import javax.net.ssl.SNIHostName; |
52 | 55 | import org.junit.After; |
53 | 56 | import org.junit.Before; |
54 | 57 | import org.junit.Test; |
@@ -762,6 +765,107 @@ public void parseFilterConfigWithEmptyConfig() { |
762 | 765 | assertThat(result.config.matcher).isNull(); |
763 | 766 | } |
764 | 767 |
|
| 768 | + @Test |
| 769 | + public void parseFilterConfigWithUdpaTypedStruct() throws Exception { |
| 770 | + com.google.protobuf.Struct struct = com.google.protobuf.Struct.newBuilder() |
| 771 | + .putFields("foo", com.google.protobuf.Value.newBuilder().setStringValue("bar").build()) |
| 772 | + .build(); |
| 773 | + |
| 774 | + TypedStruct udpaTypedStruct = TypedStruct.newBuilder() |
| 775 | + .setTypeUrl(FAKE_TYPE_URL) |
| 776 | + .setValue(struct) |
| 777 | + .build(); |
| 778 | + |
| 779 | + ExecuteFilterAction action = ExecuteFilterAction.newBuilder() |
| 780 | + .setTypedConfig(TypedExtensionConfig.newBuilder() |
| 781 | + .setName("child") |
| 782 | + .setTypedConfig(Any.pack(udpaTypedStruct)) |
| 783 | + .build()) |
| 784 | + .build(); |
| 785 | + |
| 786 | + Matcher.OnMatch matchAction = Matcher.OnMatch.newBuilder() |
| 787 | + .setAction(com.github.xds.core.v3.TypedExtensionConfig.newBuilder() |
| 788 | + .setName("action") |
| 789 | + .setTypedConfig(Any.pack(action)) |
| 790 | + .build()) |
| 791 | + .build(); |
| 792 | + |
| 793 | + Matcher matcher = Matcher.newBuilder() |
| 794 | + .setMatcherList(Matcher.MatcherList.newBuilder() |
| 795 | + .addMatchers(Matcher.MatcherList.FieldMatcher.newBuilder() |
| 796 | + .setOnMatch(matchAction) |
| 797 | + .build()) |
| 798 | + .build()) |
| 799 | + .build(); |
| 800 | + |
| 801 | + ExtensionWithMatcher proto = ExtensionWithMatcher.newBuilder() |
| 802 | + .setExtensionConfig(TypedExtensionConfig.newBuilder().setName("composite").build()) |
| 803 | + .setXdsMatcher(matcher) |
| 804 | + .build(); |
| 805 | + |
| 806 | + ConfigOrError<? extends FilterConfig> configRes = |
| 807 | + ConfigOrError.fromConfig(mock(Filter.FilterConfig.class)); |
| 808 | + when(fakeProvider.parseFilterConfig(any(com.google.protobuf.Message.class), any())) |
| 809 | + .thenReturn((ConfigOrError) configRes); |
| 810 | + |
| 811 | + ConfigOrError<CompositeFilter.CompositeFilterConfig> result = provider |
| 812 | + .parseFilterConfig(Any.pack(proto), getFilterContext()); |
| 813 | + |
| 814 | + assertThat(result.errorDetail).isNull(); |
| 815 | + verify(fakeProvider).parseFilterConfig(eq(struct), any()); |
| 816 | + } |
| 817 | + |
| 818 | + @Test |
| 819 | + public void parseFilterConfigWithXdsTypedStruct() throws Exception { |
| 820 | + com.google.protobuf.Struct struct = com.google.protobuf.Struct.newBuilder() |
| 821 | + .putFields("foo", com.google.protobuf.Value.newBuilder().setStringValue("bar").build()) |
| 822 | + .build(); |
| 823 | + |
| 824 | + com.github.xds.type.v3.TypedStruct xdsTypedStruct = |
| 825 | + com.github.xds.type.v3.TypedStruct.newBuilder() |
| 826 | + .setTypeUrl(FAKE_TYPE_URL) |
| 827 | + .setValue(struct) |
| 828 | + .build(); |
| 829 | + |
| 830 | + ExecuteFilterAction action = ExecuteFilterAction.newBuilder() |
| 831 | + .setTypedConfig(TypedExtensionConfig.newBuilder() |
| 832 | + .setName("child") |
| 833 | + .setTypedConfig(Any.pack(xdsTypedStruct)) |
| 834 | + .build()) |
| 835 | + .build(); |
| 836 | + |
| 837 | + Matcher.OnMatch matchAction = Matcher.OnMatch.newBuilder() |
| 838 | + .setAction(com.github.xds.core.v3.TypedExtensionConfig.newBuilder() |
| 839 | + .setName("action") |
| 840 | + .setTypedConfig(Any.pack(action)) |
| 841 | + .build()) |
| 842 | + .build(); |
| 843 | + |
| 844 | + Matcher matcher = Matcher.newBuilder() |
| 845 | + .setMatcherList(Matcher.MatcherList.newBuilder() |
| 846 | + .addMatchers(Matcher.MatcherList.FieldMatcher.newBuilder() |
| 847 | + .setOnMatch(matchAction) |
| 848 | + .build()) |
| 849 | + .build()) |
| 850 | + .build(); |
| 851 | + |
| 852 | + ExtensionWithMatcher proto = ExtensionWithMatcher.newBuilder() |
| 853 | + .setExtensionConfig(TypedExtensionConfig.newBuilder().setName("composite").build()) |
| 854 | + .setXdsMatcher(matcher) |
| 855 | + .build(); |
| 856 | + |
| 857 | + ConfigOrError<? extends FilterConfig> configRes = |
| 858 | + ConfigOrError.fromConfig(mock(Filter.FilterConfig.class)); |
| 859 | + when(fakeProvider.parseFilterConfig(any(com.google.protobuf.Message.class), any())) |
| 860 | + .thenReturn((ConfigOrError) configRes); |
| 861 | + |
| 862 | + ConfigOrError<CompositeFilter.CompositeFilterConfig> result = provider |
| 863 | + .parseFilterConfig(Any.pack(proto), getFilterContext()); |
| 864 | + |
| 865 | + assertThat(result.errorDetail).isNull(); |
| 866 | + verify(fakeProvider).parseFilterConfig(eq(struct), any()); |
| 867 | + } |
| 868 | + |
765 | 869 | @Test |
766 | 870 | public void clientInterceptorUsesOverrideMatcher() { |
767 | 871 | // Base matcher that matches "foo=bar" |
@@ -1150,6 +1254,46 @@ public void samplePercentDeterministic() { |
1150 | 1254 | assertThat(delegate.shouldExecute()).isFalse(); |
1151 | 1255 | } |
1152 | 1256 |
|
| 1257 | + @Test |
| 1258 | + public void samplePercentTenThousand() { |
| 1259 | + FractionalPercent percent = FractionalPercent.newBuilder() |
| 1260 | + .setNumerator(5000) |
| 1261 | + .setDenominator(FractionalPercent.DenominatorType.TEN_THOUSAND) |
| 1262 | + .build(); |
| 1263 | + |
| 1264 | + ThreadSafeRandom mockRandom = mock(ThreadSafeRandom.class); |
| 1265 | + |
| 1266 | + CompositeFilter.FilterDelegate delegate = new CompositeFilter.FilterDelegate( |
| 1267 | + Collections.emptyList(), percent, mockRandom); |
| 1268 | + |
| 1269 | + // Threshold is 5000/10000 = 0.5 |
| 1270 | + when(mockRandom.nextDouble()).thenReturn(0.4); |
| 1271 | + assertThat(delegate.shouldExecute()).isTrue(); |
| 1272 | + |
| 1273 | + when(mockRandom.nextDouble()).thenReturn(0.6); |
| 1274 | + assertThat(delegate.shouldExecute()).isFalse(); |
| 1275 | + } |
| 1276 | + |
| 1277 | + @Test |
| 1278 | + public void samplePercentMillion() { |
| 1279 | + FractionalPercent percent = FractionalPercent.newBuilder() |
| 1280 | + .setNumerator(500000) |
| 1281 | + .setDenominator(FractionalPercent.DenominatorType.MILLION) |
| 1282 | + .build(); |
| 1283 | + |
| 1284 | + ThreadSafeRandom mockRandom = mock(ThreadSafeRandom.class); |
| 1285 | + |
| 1286 | + CompositeFilter.FilterDelegate delegate = new CompositeFilter.FilterDelegate( |
| 1287 | + Collections.emptyList(), percent, mockRandom); |
| 1288 | + |
| 1289 | + // Threshold is 500000/1000000 = 0.5 |
| 1290 | + when(mockRandom.nextDouble()).thenReturn(0.4); |
| 1291 | + assertThat(delegate.shouldExecute()).isTrue(); |
| 1292 | + |
| 1293 | + when(mockRandom.nextDouble()).thenReturn(0.6); |
| 1294 | + assertThat(delegate.shouldExecute()).isFalse(); |
| 1295 | + } |
| 1296 | + |
1153 | 1297 | @Test |
1154 | 1298 | public void matchingDataInputSourceIp() { |
1155 | 1299 | Metadata headers = new Metadata(); |
@@ -1238,6 +1382,32 @@ public void matchingDataInputSourceIpNonInet() { |
1238 | 1382 | assertThat(data.getRelayedInput(inputConfig)).isNull(); |
1239 | 1383 | } |
1240 | 1384 |
|
| 1385 | + @Test |
| 1386 | + public void matchingDataInputServerNameSni() throws Exception { |
| 1387 | + Metadata headers = new Metadata(); |
| 1388 | + |
| 1389 | + ExtendedSSLSession mockSession = mock(ExtendedSSLSession.class); |
| 1390 | + SNIHostName sniHostName = new SNIHostName("bar.com"); |
| 1391 | + when(mockSession.getRequestedServerNames()).thenReturn(Collections.singletonList(sniHostName)); |
| 1392 | + |
| 1393 | + io.grpc.Attributes attributes = io.grpc.Attributes.newBuilder() |
| 1394 | + .set(io.grpc.Grpc.TRANSPORT_ATTR_SSL_SESSION, mockSession) |
| 1395 | + .build(); |
| 1396 | + |
| 1397 | + CompositeFilter.MatchingDataImpl data = |
| 1398 | + new CompositeFilter.MatchingDataImpl(headers, null, attributes); |
| 1399 | + |
| 1400 | + com.github.xds.core.v3.TypedExtensionConfig inputConfig = |
| 1401 | + com.github.xds.core.v3.TypedExtensionConfig.newBuilder() |
| 1402 | + .setTypedConfig(Any.newBuilder() |
| 1403 | + .setTypeUrl("type.googleapis.com/envoy.extensions.matching.common_inputs.network" |
| 1404 | + + ".v3.ServerNameInput") |
| 1405 | + .build()) |
| 1406 | + .build(); |
| 1407 | + |
| 1408 | + assertThat(data.getRelayedInput(inputConfig)).isEqualTo("bar.com"); |
| 1409 | + } |
| 1410 | + |
1241 | 1411 | @Test |
1242 | 1412 | public void providerMethodsCovered() { |
1243 | 1413 | assertThat(provider.typeUrls()).asList().containsExactly( |
|
0 commit comments