Search in sources :

Example 1 with OpSendMsg

use of com.yahoo.pulsar.client.impl.ProducerImpl.OpSendMsg in project pulsar by yahoo.

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";
    ProducerConfiguration config = new ProducerConfiguration();
    config.setSendTimeout(10, TimeUnit.MINUTES);
    // 1. producer connect
    Producer prod = pulsarClient.createProducer(topicName, config);
    ProducerImpl producer = spy((ProducerImpl) 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 consumer = pulsarClient.subscribe(topicName, "my-sub");
    // 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 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
    // (5.1) Verify: producer's recoverChecksumError and updateChecksum invoked
    verify(producer, times(1)).recoverChecksumError(any(), anyLong());
    verify(producer, times(1)).verifyLocalBufferIsNotCorrupted(any());
    /**
         * (5.3) verify: ProducerImpl.verifyLocalBufferIsNotCorrupted() => validates if message
         * is corrupt
         */
    MessageImpl msg2 = (MessageImpl) MessageBuilder.create().setContent("message-1".getBytes()).build();
    ByteBuf payload = msg2.getDataBuffer();
    Builder metadataBuilder = ((MessageImpl) msg).getMessageBuilder();
    MessageMetadata msgMetadata = metadataBuilder.setProducerName("test").setSequenceId(1).setPublishTime(10L).build();
    ByteBuf cmd = Commands.newSend(producerId, 1, 1, ChecksumType.Crc32c, msgMetadata, payload);
    // (a) create OpSendMsg with message-data : "message-1"
    OpSendMsg op = OpSendMsg.create(((MessageImpl) 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 msg1 = (MessageImpl) MessageBuilder.create().setContent("message-1".getBytes()).build();
    future = producer.sendAsync(msg1);
    ClientCnx cnx = spy(new ClientCnx((PulsarClientImpl) pulsarClient) {
    });
    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 : Message(com.yahoo.pulsar.client.api.Message) OpSendMsg(com.yahoo.pulsar.client.impl.ProducerImpl.OpSendMsg) MessageBuilder(com.yahoo.pulsar.client.api.MessageBuilder) Builder(com.yahoo.pulsar.common.api.proto.PulsarApi.MessageMetadata.Builder) ProducerConfiguration(com.yahoo.pulsar.client.api.ProducerConfiguration) DoubleByteBuf(com.yahoo.pulsar.common.api.DoubleByteBuf) ByteBuf(io.netty.buffer.ByteBuf) PulsarAdminException(com.yahoo.pulsar.client.admin.PulsarAdminException) PulsarClientException(com.yahoo.pulsar.client.api.PulsarClientException) Field(java.lang.reflect.Field) MessageMetadata(com.yahoo.pulsar.common.api.proto.PulsarApi.MessageMetadata) Producer(com.yahoo.pulsar.client.api.Producer) Consumer(com.yahoo.pulsar.client.api.Consumer) PulsarClientException(com.yahoo.pulsar.client.api.PulsarClientException) MessageId(com.yahoo.pulsar.client.api.MessageId) Test(org.testng.annotations.Test)

Aggregations

PulsarAdminException (com.yahoo.pulsar.client.admin.PulsarAdminException)1 Consumer (com.yahoo.pulsar.client.api.Consumer)1 Message (com.yahoo.pulsar.client.api.Message)1 MessageBuilder (com.yahoo.pulsar.client.api.MessageBuilder)1 MessageId (com.yahoo.pulsar.client.api.MessageId)1 Producer (com.yahoo.pulsar.client.api.Producer)1 ProducerConfiguration (com.yahoo.pulsar.client.api.ProducerConfiguration)1 PulsarClientException (com.yahoo.pulsar.client.api.PulsarClientException)1 OpSendMsg (com.yahoo.pulsar.client.impl.ProducerImpl.OpSendMsg)1 DoubleByteBuf (com.yahoo.pulsar.common.api.DoubleByteBuf)1 MessageMetadata (com.yahoo.pulsar.common.api.proto.PulsarApi.MessageMetadata)1 Builder (com.yahoo.pulsar.common.api.proto.PulsarApi.MessageMetadata.Builder)1 ByteBuf (io.netty.buffer.ByteBuf)1 Field (java.lang.reflect.Field)1 Test (org.testng.annotations.Test)1