下面列出了io.grpc.Metadata.Key#of ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Test
public void dupBinHeadersWithComma() {
Key<byte[]> key = Key.of("bytes-bin", BINARY_BYTE_MARSHALLER);
Http2Headers http2Headers = new GrpcHttp2RequestHeaders(2);
http2Headers.add(AsciiString.of("bytes-bin"), AsciiString.of("BaS,e6,,4+,padding=="));
http2Headers.add(AsciiString.of("bytes-bin"), AsciiString.of("more"));
http2Headers.add(AsciiString.of("bytes-bin"), AsciiString.of(""));
Metadata recoveredHeaders = Utils.convertHeaders(http2Headers);
byte[][] values = Iterables.toArray(recoveredHeaders.getAll(key), byte[].class);
assertTrue(Arrays.deepEquals(
new byte[][] {
BaseEncoding.base64().decode("BaS"),
BaseEncoding.base64().decode("e6"),
BaseEncoding.base64().decode(""),
BaseEncoding.base64().decode("4+"),
BaseEncoding.base64().decode("padding"),
BaseEncoding.base64().decode("more"),
BaseEncoding.base64().decode("")},
values));
}
@Test
public void dupBinHeadersWithComma() {
Key<byte[]> key = Key.of("bytes-bin", BINARY_BYTE_MARSHALLER);
Http2Headers http2Headers = new GrpcHttp2RequestHeaders(2);
http2Headers.add(AsciiString.of("bytes-bin"), AsciiString.of("BaS,e6,,4+,padding=="));
http2Headers.add(AsciiString.of("bytes-bin"), AsciiString.of("more"));
http2Headers.add(AsciiString.of("bytes-bin"), AsciiString.of(""));
Metadata recoveredHeaders = Utils.convertHeaders(http2Headers);
byte[][] values = Iterables.toArray(recoveredHeaders.getAll(key), byte[].class);
assertTrue(Arrays.deepEquals(
new byte[][] {
BaseEncoding.base64().decode("BaS"),
BaseEncoding.base64().decode("e6"),
BaseEncoding.base64().decode(""),
BaseEncoding.base64().decode("4+"),
BaseEncoding.base64().decode("padding"),
BaseEncoding.base64().decode("more"),
BaseEncoding.base64().decode("")},
values));
}
@Test
public void keyEqualsHashNameWorks() {
Key<?> k1 = Key.of("case", Metadata.ASCII_STRING_MARSHALLER);
Key<?> k2 = Key.of("CASE", Metadata.ASCII_STRING_MARSHALLER);
assertEquals(k1, k1);
assertNotEquals(k1, null);
assertNotEquals(k1, new Object(){});
assertEquals(k1, k2);
assertEquals(k1.hashCode(), k2.hashCode());
// Check that the casing is preserved.
assertEquals("CASE", k2.originalName());
assertEquals("case", k2.name());
}
@Test
public void invalidKeyName() {
try {
Key.of("io.grpc/key1", Metadata.ASCII_STRING_MARSHALLER);
fail("Should have thrown");
} catch (IllegalArgumentException e) {
assertEquals("Invalid character '/' in key name 'io.grpc/key1'", e.getMessage());
}
}
@Test
public void noStickinessEnabled_withStickyHeader() {
loadBalancer.handleResolvedAddressGroups(servers, Attributes.EMPTY);
for (Subchannel subchannel : subchannels.values()) {
loadBalancer.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
}
verify(mockHelper, times(4))
.updateBalancingState(any(ConnectivityState.class), pickerCaptor.capture());
SubchannelPicker picker = pickerCaptor.getValue();
Key<String> stickinessKey = Key.of("my-sticky-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata headerWithStickinessValue = new Metadata();
headerWithStickinessValue.put(stickinessKey, "my-sticky-value");
doReturn(headerWithStickinessValue).when(mockArgs).getHeaders();
List<Subchannel> allSubchannels = getList(picker);
Subchannel sc1 = picker.pickSubchannel(mockArgs).getSubchannel();
Subchannel sc2 = picker.pickSubchannel(mockArgs).getSubchannel();
Subchannel sc3 = picker.pickSubchannel(mockArgs).getSubchannel();
Subchannel sc4 = picker.pickSubchannel(mockArgs).getSubchannel();
assertEquals(nextSubchannel(sc1, allSubchannels), sc2);
assertEquals(nextSubchannel(sc2, allSubchannels), sc3);
assertEquals(nextSubchannel(sc3, allSubchannels), sc1);
assertEquals(sc4, sc1);
assertNull(loadBalancer.getStickinessMapForTest());
}
@Test
public void stickinessEnabled_withStickyHeader() {
Map<String, Object> serviceConfig = new HashMap<String, Object>();
serviceConfig.put("stickinessMetadataKey", "my-sticky-key");
Attributes attributes = Attributes.newBuilder()
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build();
loadBalancer.handleResolvedAddressGroups(servers, attributes);
for (Subchannel subchannel : subchannels.values()) {
loadBalancer.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
}
verify(mockHelper, times(4))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
SubchannelPicker picker = pickerCaptor.getValue();
Key<String> stickinessKey = Key.of("my-sticky-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata headerWithStickinessValue = new Metadata();
headerWithStickinessValue.put(stickinessKey, "my-sticky-value");
doReturn(headerWithStickinessValue).when(mockArgs).getHeaders();
Subchannel sc1 = picker.pickSubchannel(mockArgs).getSubchannel();
assertEquals(sc1, picker.pickSubchannel(mockArgs).getSubchannel());
assertEquals(sc1, picker.pickSubchannel(mockArgs).getSubchannel());
assertEquals(sc1, picker.pickSubchannel(mockArgs).getSubchannel());
assertEquals(sc1, picker.pickSubchannel(mockArgs).getSubchannel());
verify(mockArgs, atLeast(4)).getHeaders();
assertNotNull(loadBalancer.getStickinessMapForTest());
assertThat(loadBalancer.getStickinessMapForTest()).hasSize(1);
}
@Override
public void onHeaders(Metadata metadata) {
super.onHeaders(metadata);
ImmutableMap.Builder<String, String> headerBuilder = ImmutableMap.builder();
for (String key : metadata.keys()) {
// Ignore binary headers
if (!key.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {
Key<String> stringKey = Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
if (metadata.containsKey(stringKey)) {
headerBuilder.put(key, metadata.get(stringKey));
}
}
}
headerMap = headerBuilder.build();
}
public static Key<String> getKey(String key) {
Key<String> headKey = keyMap.get(key);
if (headKey == null) {
headKey = Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
Key<String> old = keyMap.putIfAbsent(key, headKey);
if (old != null) {
headKey = old;
}
}
return headKey;
}
@Test
public void keyEqualsHashNameWorks() {
Key<?> k1 = Key.of("case", Metadata.ASCII_STRING_MARSHALLER);
Key<?> k2 = Key.of("CASE", Metadata.ASCII_STRING_MARSHALLER);
assertEquals(k1, k1);
assertNotEquals(k1, null);
assertNotEquals(k1, new Object(){});
assertEquals(k1, k2);
assertEquals(k1.hashCode(), k2.hashCode());
// Check that the casing is preserved.
assertEquals("CASE", k2.originalName());
assertEquals("case", k2.name());
}
@Test
public void invalidKeyName() {
try {
Key.of("io.grpc/key1", Metadata.ASCII_STRING_MARSHALLER);
fail("Should have thrown");
} catch (IllegalArgumentException e) {
assertEquals("Invalid character '/' in key name 'io.grpc/key1'", e.getMessage());
}
}
StickinessState(@Nonnull String stickinessKey) {
this.key = Key.of(stickinessKey, Metadata.ASCII_STRING_MARSHALLER);
}
@Test(expected = IllegalArgumentException.class)
public void binaryHeaderWithoutSuffix() {
Key.of("plainstring", UTF8_STRING_MARSHALLER);
}
@Test
public void stickinessEnabled_withDifferentStickyHeaders() {
Map<String, Object> serviceConfig = new HashMap<String, Object>();
serviceConfig.put("stickinessMetadataKey", "my-sticky-key");
Attributes attributes = Attributes.newBuilder()
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build();
loadBalancer.handleResolvedAddressGroups(servers, attributes);
for (Subchannel subchannel : subchannels.values()) {
loadBalancer.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
}
verify(mockHelper, times(4))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
SubchannelPicker picker = pickerCaptor.getValue();
Key<String> stickinessKey = Key.of("my-sticky-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata headerWithStickinessValue1 = new Metadata();
headerWithStickinessValue1.put(stickinessKey, "my-sticky-value");
Metadata headerWithStickinessValue2 = new Metadata();
headerWithStickinessValue2.put(stickinessKey, "my-sticky-value2");
List<Subchannel> allSubchannels = getList(picker);
doReturn(headerWithStickinessValue1).when(mockArgs).getHeaders();
Subchannel sc1a = picker.pickSubchannel(mockArgs).getSubchannel();
doReturn(headerWithStickinessValue2).when(mockArgs).getHeaders();
Subchannel sc2a = picker.pickSubchannel(mockArgs).getSubchannel();
doReturn(headerWithStickinessValue1).when(mockArgs).getHeaders();
Subchannel sc1b = picker.pickSubchannel(mockArgs).getSubchannel();
doReturn(headerWithStickinessValue2).when(mockArgs).getHeaders();
Subchannel sc2b = picker.pickSubchannel(mockArgs).getSubchannel();
assertEquals(sc1a, sc1b);
assertEquals(sc2a, sc2b);
assertEquals(nextSubchannel(sc1a, allSubchannels), sc2a);
assertEquals(nextSubchannel(sc1b, allSubchannels), sc2b);
verify(mockArgs, atLeast(4)).getHeaders();
assertNotNull(loadBalancer.getStickinessMapForTest());
assertThat(loadBalancer.getStickinessMapForTest()).hasSize(2);
}
@Test
public void stickiness_goToTransientFailure_pick_backToReady() {
Map<String, Object> serviceConfig = new HashMap<String, Object>();
serviceConfig.put("stickinessMetadataKey", "my-sticky-key");
Attributes attributes = Attributes.newBuilder()
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build();
loadBalancer.handleResolvedAddressGroups(servers, attributes);
for (Subchannel subchannel : subchannels.values()) {
loadBalancer.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
}
verify(mockHelper, times(4))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
SubchannelPicker picker = pickerCaptor.getValue();
Key<String> stickinessKey = Key.of("my-sticky-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata headerWithStickinessValue = new Metadata();
headerWithStickinessValue.put(stickinessKey, "my-sticky-value");
doReturn(headerWithStickinessValue).when(mockArgs).getHeaders();
// first pick
Subchannel sc1 = picker.pickSubchannel(mockArgs).getSubchannel();
// go to transient failure
loadBalancer
.handleSubchannelState(sc1, ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE));
verify(mockHelper, times(5))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
picker = pickerCaptor.getValue();
// second pick
Subchannel sc2 = picker.pickSubchannel(mockArgs).getSubchannel();
// go back to ready
loadBalancer.handleSubchannelState(sc1, ConnectivityStateInfo.forNonError(READY));
verify(mockHelper, times(6))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
picker = pickerCaptor.getValue();
// third pick
Subchannel sc3 = picker.pickSubchannel(mockArgs).getSubchannel();
assertEquals(sc2, sc3);
verify(mockArgs, atLeast(3)).getHeaders();
assertNotNull(loadBalancer.getStickinessMapForTest());
assertThat(loadBalancer.getStickinessMapForTest()).hasSize(1);
}
@Test
public void stickiness_goToTransientFailure_backToReady_pick() {
Map<String, Object> serviceConfig = new HashMap<String, Object>();
serviceConfig.put("stickinessMetadataKey", "my-sticky-key");
Attributes attributes = Attributes.newBuilder()
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build();
loadBalancer.handleResolvedAddressGroups(servers, attributes);
for (Subchannel subchannel : subchannels.values()) {
loadBalancer.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
}
verify(mockHelper, times(4))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
SubchannelPicker picker = pickerCaptor.getValue();
Key<String> stickinessKey = Key.of("my-sticky-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata headerWithStickinessValue1 = new Metadata();
headerWithStickinessValue1.put(stickinessKey, "my-sticky-value");
doReturn(headerWithStickinessValue1).when(mockArgs).getHeaders();
// first pick
Subchannel sc1 = picker.pickSubchannel(mockArgs).getSubchannel();
// go to transient failure
loadBalancer
.handleSubchannelState(sc1, ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE));
Metadata headerWithStickinessValue2 = new Metadata();
headerWithStickinessValue2.put(stickinessKey, "my-sticky-value2");
doReturn(headerWithStickinessValue2).when(mockArgs).getHeaders();
verify(mockHelper, times(5))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
picker = pickerCaptor.getValue();
// second pick with a different stickiness value
@SuppressWarnings("unused")
Subchannel sc2 = picker.pickSubchannel(mockArgs).getSubchannel();
// go back to ready
loadBalancer.handleSubchannelState(sc1, ConnectivityStateInfo.forNonError(READY));
doReturn(headerWithStickinessValue1).when(mockArgs).getHeaders();
verify(mockHelper, times(6))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
picker = pickerCaptor.getValue();
// third pick with my-sticky-value1
Subchannel sc3 = picker.pickSubchannel(mockArgs).getSubchannel();
assertEquals(sc1, sc3);
verify(mockArgs, atLeast(3)).getHeaders();
assertNotNull(loadBalancer.getStickinessMapForTest());
assertThat(loadBalancer.getStickinessMapForTest()).hasSize(2);
}
@Test
public void stickiness_oneSubchannelShutdown() {
Map<String, Object> serviceConfig = new HashMap<String, Object>();
serviceConfig.put("stickinessMetadataKey", "my-sticky-key");
Attributes attributes = Attributes.newBuilder()
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build();
loadBalancer.handleResolvedAddressGroups(servers, attributes);
for (Subchannel subchannel : subchannels.values()) {
loadBalancer.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
}
verify(mockHelper, times(4))
.updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
SubchannelPicker picker = pickerCaptor.getValue();
Key<String> stickinessKey = Key.of("my-sticky-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata headerWithStickinessValue = new Metadata();
headerWithStickinessValue.put(stickinessKey, "my-sticky-value");
doReturn(headerWithStickinessValue).when(mockArgs).getHeaders();
List<Subchannel> allSubchannels = Lists.newArrayList(getList(picker));
Subchannel sc1 = picker.pickSubchannel(mockArgs).getSubchannel();
// shutdown channel directly
loadBalancer
.handleSubchannelState(sc1, ConnectivityStateInfo.forNonError(ConnectivityState.SHUTDOWN));
assertNull(loadBalancer.getStickinessMapForTest().get("my-sticky-value").value);
assertEquals(nextSubchannel(sc1, allSubchannels),
picker.pickSubchannel(mockArgs).getSubchannel());
assertThat(loadBalancer.getStickinessMapForTest()).hasSize(1);
verify(mockArgs, atLeast(2)).getHeaders();
Subchannel sc2 = picker.pickSubchannel(mockArgs).getSubchannel();
assertEquals(sc2, loadBalancer.getStickinessMapForTest().get("my-sticky-value").value);
// shutdown channel via name resolver change
List<EquivalentAddressGroup> newServers = new ArrayList<>(servers);
newServers.remove(sc2.getAddresses());
loadBalancer.handleResolvedAddressGroups(newServers, attributes);
verify(sc2, times(1)).shutdown();
loadBalancer.handleSubchannelState(sc2, ConnectivityStateInfo.forNonError(SHUTDOWN));
assertNull(loadBalancer.getStickinessMapForTest().get("my-sticky-value").value);
assertEquals(nextSubchannel(sc2, allSubchannels),
picker.pickSubchannel(mockArgs).getSubchannel());
assertThat(loadBalancer.getStickinessMapForTest()).hasSize(1);
verify(mockArgs, atLeast(2)).getHeaders();
}
private static <T> Key<T> copyKey(Key<T> key, Metadata.BinaryStreamMarshaller<T> marshaller) {
return Key.of(key.originalName(), marshaller);
}
@Test(expected = IllegalArgumentException.class)
public void binaryHeaderWithoutSuffix() {
Key.of("plainstring", UTF8_STRING_MARSHALLER);
}