Search in sources :

Example 1 with OpSendMsg

use of org.apache.pulsar.client.impl.ProducerImpl.OpSendMsg in project incubator-pulsar by apache.

the class MessageIdTest method testCorruptMessageRemove.

/**
 * Verifies: if message is corrupted before sending to broker and if broker gives checksum error: then 1.
 * Client-Producer recomputes checksum with modified data 2. Retry message-send again 3. Broker verifies checksum 4.
 * client receives send-ack success
 *
 * @throws Exception
 */
@Test
public void testCorruptMessageRemove() throws Exception {
    final String topicName = "persistent://prop/use/ns-abc/retry-topic";
    // 1. producer connect
    ProducerImpl<byte[]> prod = (ProducerImpl<byte[]>) pulsarClient.newProducer().topic(topicName).sendTimeout(10, TimeUnit.MINUTES).create();
    ProducerImpl<byte[]> producer = spy(prod);
    Field producerIdField = ProducerImpl.class.getDeclaredField("producerId");
    producerIdField.setAccessible(true);
    long producerId = (long) producerIdField.get(producer);
    // registered spy ProducerImpl
    producer.cnx().registerProducer(producerId, producer);
    Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName("my-sub").subscribe();
    // 2. Stop the broker, and publishes messages. Messages are accumulated in the producer queue and they're
    // checksums
    // would have already been computed. If we change the message content at that point, it should result in a
    // checksum validation error
    // enable checksum at producer
    stopBroker();
    Message<byte[]> msg = MessageBuilder.create().setContent("message-1".getBytes()).build();
    CompletableFuture<MessageId> future = producer.sendAsync(msg);
    // 3. corrupt the message
    // new content would be 'message-3'
    msg.getData()[msg.getData().length - 1] = '2';
    // 4. Restart the broker to have the messages published
    startBroker();
    try {
        future.get();
        fail("send message should have failed with checksum excetion");
    } catch (Exception e) {
        if (e.getCause() instanceof PulsarClientException.ChecksumException) {
        // ok (callback should get checksum exception as message was modified and corrupt)
        } else {
            fail("Callback should have only failed with ChecksumException", e);
        }
    }
    // 5. Verify
    /**
     * verify: ProducerImpl.verifyLocalBufferIsNotCorrupted() => validates if message is corrupt
     */
    MessageImpl<byte[]> msg2 = (MessageImpl<byte[]>) MessageBuilder.create().setContent("message-1".getBytes()).build();
    ByteBuf payload = msg2.getDataBuffer();
    Builder metadataBuilder = ((MessageImpl<byte[]>) msg).getMessageBuilder();
    MessageMetadata msgMetadata = metadataBuilder.setProducerName("test").setSequenceId(1).setPublishTime(10L).build();
    ByteBufPair cmd = Commands.newSend(producerId, 1, 1, ChecksumType.Crc32c, msgMetadata, payload);
    // (a) create OpSendMsg with message-data : "message-1"
    OpSendMsg op = OpSendMsg.create(((MessageImpl<byte[]>) msg), cmd, 1, null);
    // a.verify: as message is not corrupt: no need to update checksum
    assertTrue(producer.verifyLocalBufferIsNotCorrupted(op));
    // (b) corrupt message
    // new content would be 'message-2'
    msg2.getData()[msg2.getData().length - 1] = '2';
    // b. verify: as message is corrupt: update checksum
    assertFalse(producer.verifyLocalBufferIsNotCorrupted(op));
    assertEquals(producer.getPendingQueueSize(), 0);
    // [2] test-recoverChecksumError functionality
    stopBroker();
    MessageImpl<byte[]> msg1 = (MessageImpl<byte[]>) MessageBuilder.create().setContent("message-1".getBytes()).build();
    future = producer.sendAsync(msg1);
    ClientCnx cnx = spy(new ClientCnx(new ClientConfigurationData(), ((PulsarClientImpl) pulsarClient).eventLoopGroup()));
    String exc = "broker is already stopped";
    // when client-try to recover checksum by resending to broker: throw exception as broker is stopped
    doThrow(new IllegalStateException(exc)).when(cnx).ctx();
    try {
        producer.recoverChecksumError(cnx, 1);
        fail("it should call : resendMessages() => which should throw above mocked exception");
    } catch (IllegalStateException e) {
        assertEquals(exc, e.getMessage());
    }
    producer.close();
    consumer.close();
    // clean reference of mocked producer
    producer = null;
}
Also used : ClientConfigurationData(org.apache.pulsar.client.impl.conf.ClientConfigurationData) OpSendMsg(org.apache.pulsar.client.impl.ProducerImpl.OpSendMsg) Builder(org.apache.pulsar.common.api.proto.PulsarApi.MessageMetadata.Builder) MessageBuilder(org.apache.pulsar.client.api.MessageBuilder) ByteBuf(io.netty.buffer.ByteBuf) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) PulsarAdminException(org.apache.pulsar.client.admin.PulsarAdminException) ByteBufPair(org.apache.pulsar.common.api.ByteBufPair) Field(java.lang.reflect.Field) MessageMetadata(org.apache.pulsar.common.api.proto.PulsarApi.MessageMetadata) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) MessageId(org.apache.pulsar.client.api.MessageId) Test(org.testng.annotations.Test)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)1 Field (java.lang.reflect.Field)1 PulsarAdminException (org.apache.pulsar.client.admin.PulsarAdminException)1 MessageBuilder (org.apache.pulsar.client.api.MessageBuilder)1 MessageId (org.apache.pulsar.client.api.MessageId)1 PulsarClientException (org.apache.pulsar.client.api.PulsarClientException)1 OpSendMsg (org.apache.pulsar.client.impl.ProducerImpl.OpSendMsg)1 ClientConfigurationData (org.apache.pulsar.client.impl.conf.ClientConfigurationData)1 ByteBufPair (org.apache.pulsar.common.api.ByteBufPair)1 MessageMetadata (org.apache.pulsar.common.api.proto.PulsarApi.MessageMetadata)1 Builder (org.apache.pulsar.common.api.proto.PulsarApi.MessageMetadata.Builder)1 Test (org.testng.annotations.Test)1