List of usage examples for io.netty.buffer ByteBuf skipBytes
public abstract ByteBuf skipBytes(int length);
From source file:org.apache.drill.exec.rpc.ProtobufLengthDecoder.java
License:Apache License
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (!ctx.channel().isOpen()) { if (in.readableBytes() > 0) { logger.info("Channel is closed, discarding remaining {} byte(s) in buffer.", in.readableBytes()); }/*from w w w.ja va 2s . c o m*/ in.skipBytes(in.readableBytes()); return; } in.markReaderIndex(); final byte[] buf = new byte[5]; for (int i = 0; i < buf.length; i++) { if (!in.isReadable()) { in.resetReaderIndex(); return; } buf[i] = in.readByte(); if (buf[i] >= 0) { int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); if (length < 0) { throw new CorruptedFrameException("negative length: " + length); } if (length == 0) { throw new CorruptedFrameException("Received a message of length 0."); } if (in.readableBytes() < length) { in.resetReaderIndex(); return; } else { // need to make buffer copy, otherwise netty will try to refill this buffer if we move the readerIndex forward... // TODO: Can we avoid this copy? ByteBuf outBuf; try { outBuf = allocator.buffer(length); } catch (OutOfMemoryException e) { logger.warn( "Failure allocating buffer on incoming stream due to memory limits. Current Allocation: {}.", allocator.getAllocatedMemory()); in.resetReaderIndex(); outOfMemoryHandler.handle(); return; } outBuf.writeBytes(in, in.readerIndex(), length); in.skipBytes(length); if (RpcConstants.EXTRA_DEBUGGING) { logger.debug(String.format( "ReaderIndex is %d after length header of %d bytes and frame body of length %d bytes.", in.readerIndex(), i + 1, length)); } out.add(outBuf); return; } } } // Couldn't find the byte whose MSB is off. throw new CorruptedFrameException("length wider than 32-bit"); }
From source file:org.apache.drill.exec.rpc.RpcDecoder.java
License:Apache License
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { if (!ctx.channel().isOpen()) { return;//from w w w . j ava2 s. c o m } if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("Inbound rpc message received."); } // now, we know the entire message is in the buffer and the buffer is constrained to this message. Additionally, // this process should avoid reading beyond the end of this buffer so we inform the ByteBufInputStream to throw an // exception if be go beyond readable bytes (as opposed to blocking). final ByteBufInputStream is = new ByteBufInputStream(buffer, buffer.readableBytes()); // read the rpc header, saved in delimited format. checkTag(is, RpcEncoder.HEADER_TAG); final RpcHeader header = RpcHeader.parseDelimitedFrom(is); if (RpcConstants.EXTRA_DEBUGGING) { logger.debug(" post header read index {}", buffer.readerIndex()); } // read the protobuf body into a buffer. checkTag(is, RpcEncoder.PROTOBUF_BODY_TAG); final int pBodyLength = readRawVarint32(is); final ByteBuf pBody = buffer.slice(buffer.readerIndex(), pBodyLength); buffer.skipBytes(pBodyLength); pBody.retain(1); if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("Read protobuf body of length {} into buffer {}.", pBodyLength, pBody); } if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("post protobufbody read index {}", buffer.readerIndex()); } ByteBuf dBody = null; int dBodyLength = 0; // read the data body. if (buffer.readableBytes() > 0) { if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("Reading raw body, buffer has {} bytes available, is available {}.", buffer.readableBytes(), is.available()); } checkTag(is, RpcEncoder.RAW_BODY_TAG); dBodyLength = readRawVarint32(is); if (buffer.readableBytes() != dBodyLength) { throw new CorruptedFrameException(String.format( "Expected to receive a raw body of %d bytes but received a buffer with %d bytes.", dBodyLength, buffer.readableBytes())); } dBody = buffer.slice(); dBody.retain(1); if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("Read raw body of {}", dBody); } } else { if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("No need to read raw body, no readable bytes left."); } } // return the rpc message. InboundRpcMessage m = new InboundRpcMessage(header.getMode(), header.getRpcType(), header.getCoordinationId(), pBody, dBody); // move the reader index forward so the next rpc call won't try to work with it. buffer.skipBytes(dBodyLength); messageCounter.incrementAndGet(); if (RpcConstants.SOME_DEBUGGING) { logger.debug("Inbound Rpc Message Decoded {}.", m); } out.add(m); }
From source file:org.apache.drill.exec.rpc.SaslDecryptionHandler.java
License:Apache License
public void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws IOException { if (!ctx.channel().isOpen()) { logger.trace("Channel closed before decoding the message of {} bytes", msg.readableBytes()); msg.skipBytes(msg.readableBytes()); return;//from w w w .ja v a 2 s.c o m } try { if (logger.isTraceEnabled()) { logger.trace("Trying to decrypt the encrypted message of size: {} with maxWrappedSize", msg.readableBytes()); } // All the encrypted blocks are prefixed with it's length in network byte order (or BigEndian format). Netty's // default Byte order of ByteBuf is Little Endian, so we cannot just do msg.getInt() as that will read the 4 // octets in little endian format. // // We will read the length of one complete encrypted chunk and decode that. msg.getBytes(msg.readerIndex(), lengthOctets.array(), 0, RpcConstants.LENGTH_FIELD_LENGTH); final int wrappedMsgLength = lengthOctets.getInt(0); msg.skipBytes(RpcConstants.LENGTH_FIELD_LENGTH); // Since lengthBasedFrameDecoder will ensure we have enough bytes it's good to have this check here. assert (msg.readableBytes() == wrappedMsgLength); // Uncomment the below code if msg can contain both of Direct and Heap ByteBuf. Currently Drill only supports // DirectByteBuf so the below condition will always be false. If the msg are always HeapByteBuf then in // addition also remove the allocation of encodedMsg from constructor. /*if (msg.hasArray()) { wrappedMsg = msg.array(); } else { if (RpcConstants.EXTRA_DEBUGGING) { logger.debug("The input bytebuf is not backed by a byte array so allocating a new one"); }*/ // Check if the wrappedMsgLength doesn't exceed agreed upon maxWrappedSize. As per SASL RFC 2222/4422 we // should close the connection since it represents a security attack. if (wrappedMsgLength > maxWrappedSize) { throw new RpcException(String.format( "Received encoded buffer size: %d is larger than negotiated " + "maxWrappedSize: %d. Closing the connection as this is unexpected.", wrappedMsgLength, maxWrappedSize)); } final byte[] wrappedMsg = encodedMsg; // Copy the wrappedMsgLength of bytes into the byte array msg.getBytes(msg.readerIndex(), wrappedMsg, 0, wrappedMsgLength); //} // SASL library always copies the origMsg internally to a new byte array // and return another new byte array after decrypting the message. The memory for this // will be Garbage collected by JVM since SASL Library releases it's reference after // returning the byte array. final byte[] decodedMsg = saslCodec.unwrap(wrappedMsg, 0, wrappedMsgLength); if (logger.isTraceEnabled()) { logger.trace("Successfully decrypted incoming message. Length after decryption: {}", decodedMsg.length); } // Update the msg reader index since we have decrypted this chunk msg.skipBytes(wrappedMsgLength); // Allocate a new Bytebuf to copy the decrypted chunk. final ByteBuf decodedMsgBuf = ctx.alloc().buffer(decodedMsg.length); decodedMsgBuf.writeBytes(decodedMsg); // Add the decrypted chunk to output buffer for next handler to take care of it. out.add(decodedMsgBuf); } catch (OutOfMemoryException e) { logger.warn("Failure allocating buffer on incoming stream due to memory limits."); msg.resetReaderIndex(); outOfMemoryHandler.handle(); } catch (IOException e) { logger.error("Something went wrong while unwrapping the message: {} with MaxEncodeSize: {} and " + "error: {}", msg, maxWrappedSize, e.getMessage()); throw e; } }
From source file:org.apache.drill.exec.rpc.SaslEncryptionHandler.java
License:Apache License
public void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws IOException { if (!ctx.channel().isOpen()) { logger.debug("In " + RpcConstants.SASL_ENCRYPTION_HANDLER + " and channel is not open. " + "So releasing msg memory before encryption."); msg.release();/* w w w.ja v a 2 s . c om*/ return; } try { // If encryption is enabled then this handler will always get ByteBuf of type Composite ByteBuf assert (msg instanceof CompositeByteBuf); final CompositeByteBuf cbb = (CompositeByteBuf) msg; final int numComponents = cbb.numComponents(); // Get all the components inside the Composite ByteBuf for encryption for (int currentIndex = 0; currentIndex < numComponents; ++currentIndex) { final ByteBuf component = cbb.component(currentIndex); // Each component ByteBuf size should not be greater than wrapSizeLimit since ChunkCreationHandler // will break the RPC message into chunks of wrapSizeLimit. if (component.readableBytes() > wrapSizeLimit) { throw new RpcException( String.format("Component Chunk size: %d is greater than the wrapSizeLimit: %d", component.readableBytes(), wrapSizeLimit)); } // Uncomment the below code if msg can contain both of Direct and Heap ByteBuf. Currently Drill only supports // DirectByteBuf so the below condition will always be false. If the msg are always HeapByteBuf then in // addition also remove the allocation of origMsgBuffer from constructor. /*if (component.hasArray()) { origMsg = component.array(); } else { if (RpcConstants.EXTRA_DEBUGGING) { logger.trace("The input bytebuf is not backed by a byte array so allocating a new one"); }*/ final byte[] origMsg = origMsgBuffer; component.getBytes(component.readerIndex(), origMsg, 0, component.readableBytes()); //} if (logger.isTraceEnabled()) { logger.trace("Trying to encrypt chunk of size:{} with wrapSizeLimit:{} and chunkMode: {}", component.readableBytes(), wrapSizeLimit); } // Length to encrypt will be component length not origMsg length since that can be greater. final byte[] wrappedMsg = saslCodec.wrap(origMsg, 0, component.readableBytes()); if (logger.isTraceEnabled()) { logger.trace("Successfully encrypted message, original size: {} Final Size: {}", component.readableBytes(), wrappedMsg.length); } // Allocate the buffer (directByteBuff) for copying the encrypted byte array and 4 octets for length of the // encrypted message. This is preferred since later on if the passed buffer is not in direct memory then it // will be copied by the channel into a temporary direct memory which will be cached to the thread. The size // of that temporary direct memory will be size of largest message send. final ByteBuf encryptedBuf = ctx.alloc() .buffer(wrappedMsg.length + RpcConstants.LENGTH_FIELD_LENGTH); // Based on SASL RFC 2222/4422 we should have starting 4 octet as the length of the encrypted buffer in network // byte order. SASL framework provided by JDK doesn't do that by default and leaves it upto application. Whereas // Cyrus SASL implementation of sasl_encode does take care of this. lengthOctets.putInt(wrappedMsg.length); encryptedBuf.writeBytes(lengthOctets.array()); // reset the position for re-use in next round lengthOctets.rewind(); // Write the encrypted bytes inside the buffer encryptedBuf.writeBytes(wrappedMsg); // Update the msg and component reader index msg.skipBytes(component.readableBytes()); component.skipBytes(component.readableBytes()); // Add the encrypted buffer into the output to send it on wire. out.add(encryptedBuf); } } catch (OutOfMemoryException e) { logger.warn("Failure allocating buffer on incoming stream due to memory limits."); msg.resetReaderIndex(); outOfMemoryHandler.handle(); } catch (IOException e) { logger.error( "Something went wrong while wrapping the message: {} with MaxRawWrapSize: {}, ChunkMode: {} " + "and error: {}", msg, wrapSizeLimit, e.getMessage()); throw e; } }
From source file:org.apache.drill.exec.rpc.ZeroCopyProtobufLengthDecoder.java
License:Apache License
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (!ctx.channel().isOpen()) { if (in.readableBytes() > 0) logger.info("Channel is closed, discarding remaining {} byte(s) in buffer.", in.readableBytes()); in.skipBytes(in.readableBytes()); return;/* ww w. j a v a 2s.c o m*/ } in.markReaderIndex(); final byte[] buf = new byte[5]; for (int i = 0; i < buf.length; i++) { if (!in.isReadable()) { in.resetReaderIndex(); return; } buf[i] = in.readByte(); if (buf[i] >= 0) { int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); if (length < 0) { throw new CorruptedFrameException("negative length: " + length); } if (length == 0) { throw new CorruptedFrameException("Received a message of length 0."); } if (in.readableBytes() < length) { in.resetReaderIndex(); return; } else { // need to make buffer copy, otherwise netty will try to refill this buffer if we move the readerIndex forward... // TODO: Can we avoid this copy? ByteBuf outBuf = in.copy(in.readerIndex(), length); in.skipBytes(length); if (RpcConstants.EXTRA_DEBUGGING) logger.debug(String.format( "ReaderIndex is %d after length header of %d bytes and frame body of length %d bytes.", in.readerIndex(), i + 1, length)); out.add(outBuf); return; } } } // Couldn't find the byte whose MSB is off. throw new CorruptedFrameException("length wider than 32-bit"); }
From source file:org.apache.flink.runtime.query.netty.KvStateClientHandlerTest.java
License:Apache License
/** * Tests that on reads the expected callback methods are called and read * buffers are recycled./* ww w. j av a2s . c om*/ */ @Test public void testReadCallbacksAndBufferRecycling() throws Exception { KvStateClientHandlerCallback callback = mock(KvStateClientHandlerCallback.class); EmbeddedChannel channel = new EmbeddedChannel(new KvStateClientHandler(callback)); // // Request success // ByteBuf buf = KvStateRequestSerializer.serializeKvStateRequestResult(channel.alloc(), 1222112277, new byte[0]); buf.skipBytes(4); // skip frame length // Verify callback channel.writeInbound(buf); verify(callback, times(1)).onRequestResult(eq(1222112277L), any(byte[].class)); assertEquals("Buffer not recycled", 0, buf.refCnt()); // // Request failure // buf = KvStateRequestSerializer.serializeKvStateRequestFailure(channel.alloc(), 1222112278, new RuntimeException("Expected test Exception")); buf.skipBytes(4); // skip frame length // Verify callback channel.writeInbound(buf); verify(callback, times(1)).onRequestFailure(eq(1222112278L), any(RuntimeException.class)); assertEquals("Buffer not recycled", 0, buf.refCnt()); // // Server failure // buf = KvStateRequestSerializer.serializeServerFailure(channel.alloc(), new RuntimeException("Expected test Exception")); buf.skipBytes(4); // skip frame length // Verify callback channel.writeInbound(buf); verify(callback, times(1)).onFailure(any(RuntimeException.class)); // // Unexpected messages // buf = channel.alloc().buffer(4).writeInt(1223823); // Verify callback channel.writeInbound(buf); verify(callback, times(2)).onFailure(any(IllegalStateException.class)); assertEquals("Buffer not recycled", 0, buf.refCnt()); // // Exception caught // channel.pipeline().fireExceptionCaught(new RuntimeException("Expected test Exception")); verify(callback, times(3)).onFailure(any(RuntimeException.class)); // // Channel inactive // channel.pipeline().fireChannelInactive(); verify(callback, times(4)).onFailure(any(ClosedChannelException.class)); }
From source file:org.apache.flink.runtime.query.netty.KvStateServerHandlerTest.java
License:Apache License
/** * Tests a simple successful query via an EmbeddedChannel. *//*from w w w . ja va 2 s . c o m*/ @Test public void testSimpleQuery() throws Exception { KvStateRegistry registry = new KvStateRegistry(); AtomicKvStateRequestStats stats = new AtomicKvStateRequestStats(); KvStateServerHandler handler = new KvStateServerHandler(registry, TEST_THREAD_POOL, stats); EmbeddedChannel channel = new EmbeddedChannel(getFrameDecoder(), handler); // Register state ValueStateDescriptor<Integer> desc = new ValueStateDescriptor<>("any", IntSerializer.INSTANCE); desc.setQueryable("vanilla"); int numKeyGroups = 1; AbstractStateBackend abstractBackend = new MemoryStateBackend(); DummyEnvironment dummyEnv = new DummyEnvironment("test", 1, 0); dummyEnv.setKvStateRegistry(registry); AbstractKeyedStateBackend<Integer> backend = abstractBackend.createKeyedStateBackend(dummyEnv, new JobID(), "test_op", IntSerializer.INSTANCE, numKeyGroups, new KeyGroupRange(0, 0), registry.createTaskRegistry(dummyEnv.getJobID(), dummyEnv.getJobVertexId())); final TestRegistryListener registryListener = new TestRegistryListener(); registry.registerListener(registryListener); // Update the KvState and request it int expectedValue = 712828289; int key = 99812822; backend.setCurrentKey(key); ValueState<Integer> state = backend.getPartitionedState(VoidNamespace.INSTANCE, VoidNamespaceSerializer.INSTANCE, desc); state.update(expectedValue); byte[] serializedKeyAndNamespace = KvStateRequestSerializer.serializeKeyAndNamespace(key, IntSerializer.INSTANCE, VoidNamespace.INSTANCE, VoidNamespaceSerializer.INSTANCE); long requestId = Integer.MAX_VALUE + 182828L; assertTrue(registryListener.registrationName.equals("vanilla")); ByteBuf request = KvStateRequestSerializer.serializeKvStateRequest(channel.alloc(), requestId, registryListener.kvStateId, serializedKeyAndNamespace); // Write the request and wait for the response channel.writeInbound(request); ByteBuf buf = (ByteBuf) readInboundBlocking(channel); buf.skipBytes(4); // skip frame length // Verify the response assertEquals(KvStateRequestType.REQUEST_RESULT, KvStateRequestSerializer.deserializeHeader(buf)); KvStateRequestResult response = KvStateRequestSerializer.deserializeKvStateRequestResult(buf); assertEquals(requestId, response.getRequestId()); int actualValue = KvStateRequestSerializer.deserializeValue(response.getSerializedResult(), IntSerializer.INSTANCE); assertEquals(expectedValue, actualValue); assertEquals(stats.toString(), 1, stats.getNumRequests()); // Wait for async successful request report long deadline = System.nanoTime() + TimeUnit.NANOSECONDS.convert(30, TimeUnit.SECONDS); while (stats.getNumSuccessful() != 1 && System.nanoTime() <= deadline) { Thread.sleep(10); } assertEquals(stats.toString(), 1, stats.getNumSuccessful()); }
From source file:org.apache.flink.runtime.query.netty.KvStateServerHandlerTest.java
License:Apache License
/** * Tests the failure response with {@link UnknownKvStateID} as cause on * queries for unregistered KvStateIDs./* ww w. j a va 2 s . co m*/ */ @Test public void testQueryUnknownKvStateID() throws Exception { KvStateRegistry registry = new KvStateRegistry(); AtomicKvStateRequestStats stats = new AtomicKvStateRequestStats(); KvStateServerHandler handler = new KvStateServerHandler(registry, TEST_THREAD_POOL, stats); EmbeddedChannel channel = new EmbeddedChannel(getFrameDecoder(), handler); long requestId = Integer.MAX_VALUE + 182828L; ByteBuf request = KvStateRequestSerializer.serializeKvStateRequest(channel.alloc(), requestId, new KvStateID(), new byte[0]); // Write the request and wait for the response channel.writeInbound(request); ByteBuf buf = (ByteBuf) readInboundBlocking(channel); buf.skipBytes(4); // skip frame length // Verify the response assertEquals(KvStateRequestType.REQUEST_FAILURE, KvStateRequestSerializer.deserializeHeader(buf)); KvStateRequestFailure response = KvStateRequestSerializer.deserializeKvStateRequestFailure(buf); assertEquals(requestId, response.getRequestId()); assertTrue("Did not respond with expected failure cause", response.getCause() instanceof UnknownKvStateID); assertEquals(1, stats.getNumRequests()); assertEquals(1, stats.getNumFailed()); }
From source file:org.apache.flink.runtime.query.netty.KvStateServerHandlerTest.java
License:Apache License
/** * Tests the failure response with {@link UnknownKeyOrNamespace} as cause * on queries for non-existing keys./*w ww . ja v a 2s . com*/ */ @Test public void testQueryUnknownKey() throws Exception { KvStateRegistry registry = new KvStateRegistry(); AtomicKvStateRequestStats stats = new AtomicKvStateRequestStats(); KvStateServerHandler handler = new KvStateServerHandler(registry, TEST_THREAD_POOL, stats); EmbeddedChannel channel = new EmbeddedChannel(getFrameDecoder(), handler); int numKeyGroups = 1; AbstractStateBackend abstractBackend = new MemoryStateBackend(); DummyEnvironment dummyEnv = new DummyEnvironment("test", 1, 0); dummyEnv.setKvStateRegistry(registry); KeyedStateBackend<Integer> backend = abstractBackend.createKeyedStateBackend(dummyEnv, new JobID(), "test_op", IntSerializer.INSTANCE, numKeyGroups, new KeyGroupRange(0, 0), registry.createTaskRegistry(dummyEnv.getJobID(), dummyEnv.getJobVertexId())); final TestRegistryListener registryListener = new TestRegistryListener(); registry.registerListener(registryListener); // Register state ValueStateDescriptor<Integer> desc = new ValueStateDescriptor<>("any", IntSerializer.INSTANCE); desc.setQueryable("vanilla"); backend.getPartitionedState(VoidNamespace.INSTANCE, VoidNamespaceSerializer.INSTANCE, desc); byte[] serializedKeyAndNamespace = KvStateRequestSerializer.serializeKeyAndNamespace(1238283, IntSerializer.INSTANCE, VoidNamespace.INSTANCE, VoidNamespaceSerializer.INSTANCE); long requestId = Integer.MAX_VALUE + 22982L; assertTrue(registryListener.registrationName.equals("vanilla")); ByteBuf request = KvStateRequestSerializer.serializeKvStateRequest(channel.alloc(), requestId, registryListener.kvStateId, serializedKeyAndNamespace); // Write the request and wait for the response channel.writeInbound(request); ByteBuf buf = (ByteBuf) readInboundBlocking(channel); buf.skipBytes(4); // skip frame length // Verify the response assertEquals(KvStateRequestType.REQUEST_FAILURE, KvStateRequestSerializer.deserializeHeader(buf)); KvStateRequestFailure response = KvStateRequestSerializer.deserializeKvStateRequestFailure(buf); assertEquals(requestId, response.getRequestId()); assertTrue("Did not respond with expected failure cause", response.getCause() instanceof UnknownKeyOrNamespace); assertEquals(1, stats.getNumRequests()); assertEquals(1, stats.getNumFailed()); }
From source file:org.apache.flink.runtime.query.netty.KvStateServerHandlerTest.java
License:Apache License
/** * Tests the failure response on a failure on the {@link InternalKvState#getSerializedValue(byte[])} * call.//from ww w . j av a 2 s. c om */ @Test public void testFailureOnGetSerializedValue() throws Exception { KvStateRegistry registry = new KvStateRegistry(); AtomicKvStateRequestStats stats = new AtomicKvStateRequestStats(); KvStateServerHandler handler = new KvStateServerHandler(registry, TEST_THREAD_POOL, stats); EmbeddedChannel channel = new EmbeddedChannel(getFrameDecoder(), handler); // Failing KvState InternalKvState<?> kvState = mock(InternalKvState.class); when(kvState.getSerializedValue(any(byte[].class))) .thenThrow(new RuntimeException("Expected test Exception")); KvStateID kvStateId = registry.registerKvState(new JobID(), new JobVertexID(), new KeyGroupRange(0, 0), "vanilla", kvState); ByteBuf request = KvStateRequestSerializer.serializeKvStateRequest(channel.alloc(), 282872, kvStateId, new byte[0]); // Write the request and wait for the response channel.writeInbound(request); ByteBuf buf = (ByteBuf) readInboundBlocking(channel); buf.skipBytes(4); // skip frame length // Verify the response assertEquals(KvStateRequestType.REQUEST_FAILURE, KvStateRequestSerializer.deserializeHeader(buf)); KvStateRequestFailure response = KvStateRequestSerializer.deserializeKvStateRequestFailure(buf); assertTrue(response.getCause().getMessage().contains("Expected test Exception")); assertEquals(1, stats.getNumRequests()); assertEquals(1, stats.getNumFailed()); }