use of io.cdap.cdap.messaging.data.RawMessage in project cdap by caskdata.
the class MessagingHttpServiceTest method testBasicPubSub.
@Test
public void testBasicPubSub() throws Exception {
TopicId topicId = new NamespaceId("ns1").topic("testBasicPubSub");
// Publish to a non-existing topic should get not found exception
try {
client.publish(StoreRequestBuilder.of(topicId).addPayload("a").build());
Assert.fail("Expected TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
// Consume from a non-existing topic should get not found exception
try {
client.prepareFetch(topicId).fetch();
Assert.fail("Expected TopicNotFoundException");
} catch (TopicNotFoundException e) {
// Expected
}
client.createTopic(new TopicMetadata(topicId));
// Publish a non-transactional message with empty payload should result in failure
try {
client.publish(StoreRequestBuilder.of(topicId).build());
Assert.fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected
}
// Publish a non-tx message, no RollbackDetail is returned
Assert.assertNull(client.publish(StoreRequestBuilder.of(topicId).addPayload("m0").addPayload("m1").build()));
// Publish a transactional message, a RollbackDetail should be returned
RollbackDetail rollbackDetail = client.publish(StoreRequestBuilder.of(topicId).addPayload("m2").setTransaction(1L).build());
Assert.assertNotNull(rollbackDetail);
// Rollback the published message
client.rollback(topicId, rollbackDetail);
// Fetch messages non-transactionally (should be able to read all the messages since rolled back messages
// are still visible until ttl kicks in)
List<RawMessage> messages = new ArrayList<>();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).fetch()) {
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(3, messages.size());
for (int i = 0; i < 3; i++) {
Assert.assertEquals("m" + i, Bytes.toString(messages.get(i).getPayload()));
}
// Consume transactionally. It should get only m0 and m1 since m2 has been rolled back
List<RawMessage> txMessages = new ArrayList<>();
Transaction transaction = new Transaction(3L, 3L, new long[0], new long[] { 2L }, 2L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartTime(0).setTransaction(transaction).fetch()) {
Iterators.addAll(txMessages, iterator);
}
Assert.assertEquals(2, txMessages.size());
for (int i = 0; i < 2; i++) {
Assert.assertEquals("m" + i, Bytes.toString(messages.get(i).getPayload()));
}
// Fetch again from a given message offset exclusively.
// Expects one message to be fetched
byte[] startMessageId = messages.get(1).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).fetch()) {
// It should have only one message (m2)
Assert.assertTrue(iterator.hasNext());
RawMessage msg = iterator.next();
Assert.assertEquals("m2", Bytes.toString(msg.getPayload()));
}
// Fetch again from the last message offset exclusively
// Expects no message to be fetched
startMessageId = messages.get(2).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).fetch()) {
Assert.assertFalse(iterator.hasNext());
}
// Fetch with start time. It should get both m0 and m1 since they are published in the same request, hence
// having the same publish time
startMessageId = messages.get(1).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartTime(new MessageId(startMessageId).getPublishTimestamp()).setLimit(2).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(2, messages.size());
for (int i = 0; i < 2; i++) {
Assert.assertEquals("m" + i, Bytes.toString(messages.get(i).getPayload()));
}
// Publish 2 messages, one transactionally, one without transaction
client.publish(StoreRequestBuilder.of(topicId).addPayload("m3").setTransaction(2L).build());
client.publish(StoreRequestBuilder.of(topicId).addPayload("m4").build());
// Consume without transactional, it should see m2, m3 and m4
startMessageId = messages.get(1).getId();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(3, messages.size());
for (int i = 0; i < 3; i++) {
Assert.assertEquals("m" + (i + 2), Bytes.toString(messages.get(i).getPayload()));
}
// Consume using a transaction that doesn't have tx = 2L visible. It should get no message as it should block on m3
transaction = new Transaction(3L, 3L, new long[0], new long[] { 2L }, 2L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).setTransaction(transaction).fetch()) {
Assert.assertFalse(iterator.hasNext());
}
// Consume using a transaction that has tx = 2L in the invalid list. It should skip m3 and got m4
transaction = new Transaction(3L, 3L, new long[] { 2L }, new long[0], 0L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).setTransaction(transaction).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(1, messages.size());
Assert.assertEquals("m4", Bytes.toString(messages.get(0).getPayload()));
// Consume using a transaction that has tx = 2L committed. It should get m3 and m4
transaction = new Transaction(3L, 3L, new long[0], new long[0], 0L);
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setStartMessage(startMessageId, false).setTransaction(transaction).fetch()) {
messages.clear();
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(2, messages.size());
for (int i = 0; i < 2; i++) {
Assert.assertEquals("m" + (i + 3), Bytes.toString(messages.get(i).getPayload()));
}
client.deleteTopic(topicId);
}
use of io.cdap.cdap.messaging.data.RawMessage in project cdap by caskdata.
the class MessagingHttpServiceTest method testReuseRequest.
@Test
public void testReuseRequest() throws IOException, TopicAlreadyExistsException, TopicNotFoundException, UnauthorizedException {
// This test a StoreRequest object can be reused.
// This test is to verify storing transaction messages to the payload table
TopicId topicId = new NamespaceId("ns1").topic("testReuseRequest");
client.createTopic(new TopicMetadata(topicId));
StoreRequest request = StoreRequestBuilder.of(topicId).addPayload("m1").addPayload("m2").build();
// Publish the request twice
client.publish(request);
client.publish(request);
// Expects four messages
List<RawMessage> messages = new ArrayList<>();
try (CloseableIterator<RawMessage> iterator = client.prepareFetch(topicId).setLimit(10).fetch()) {
Iterators.addAll(messages, iterator);
}
Assert.assertEquals(4, messages.size());
List<String> expected = Arrays.asList("m1", "m2", "m1", "m2");
Assert.assertEquals(expected, messages.stream().map(RawMessage::getPayload).map(Bytes::toString).collect(Collectors.toList()));
}
use of io.cdap.cdap.messaging.data.RawMessage in project cdap by cdapio.
the class AuditPublishTest method fetchAuditMessages.
private List<AuditMessage> fetchAuditMessages() throws TopicNotFoundException, IOException {
List<AuditMessage> result = new ArrayList<>();
try (CloseableIterator<RawMessage> iterator = messagingService.prepareFetch(auditTopic).fetch()) {
while (iterator.hasNext()) {
RawMessage message = iterator.next();
result.add(GSON.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), AuditMessage.class));
}
}
return result;
}
use of io.cdap.cdap.messaging.data.RawMessage in project cdap by cdapio.
the class LeaderElectionMessagingServiceTest method testTransition.
@Test
public void testTransition() throws Throwable {
final TopicId topicId = NamespaceId.SYSTEM.topic("topic");
Injector injector1 = createInjector(0);
Injector injector2 = createInjector(1);
// Start a messaging service, which would becomes leader
ZKClientService zkClient1 = injector1.getInstance(ZKClientService.class);
zkClient1.startAndWait();
final MessagingService firstService = injector1.getInstance(MessagingService.class);
if (firstService instanceof Service) {
((Service) firstService).startAndWait();
}
// Publish a message with the leader
firstService.publish(StoreRequestBuilder.of(topicId).addPayload("Testing1").build());
// Start another messaging service, this one would be follower
ZKClientService zkClient2 = injector2.getInstance(ZKClientService.class);
zkClient2.startAndWait();
final MessagingService secondService = injector2.getInstance(MessagingService.class);
if (secondService instanceof Service) {
((Service) secondService).startAndWait();
}
// Try to call the follower, should get service unavailable.
try {
secondService.listTopics(NamespaceId.SYSTEM);
Assert.fail("Expected service unavailable");
} catch (ServiceUnavailableException e) {
// Expected
}
// Make the ZK session timeout for the leader service. The second one should pickup.
KillZKSession.kill(zkClient1.getZooKeeperSupplier().get(), zkClient1.getConnectString(), 10000);
// Publish one more message and then fetch from the current leader
List<String> messages = Retries.callWithRetries(new Retries.Callable<List<String>, Throwable>() {
@Override
public List<String> call() throws Throwable {
secondService.publish(StoreRequestBuilder.of(topicId).addPayload("Testing2").build());
List<String> messages = new ArrayList<>();
try (CloseableIterator<RawMessage> iterator = secondService.prepareFetch(topicId).fetch()) {
while (iterator.hasNext()) {
messages.add(new String(iterator.next().getPayload(), "UTF-8"));
}
}
return messages;
}
}, RetryStrategies.timeLimit(10, TimeUnit.SECONDS, RetryStrategies.fixDelay(1, TimeUnit.SECONDS)));
Assert.assertEquals(Arrays.asList("Testing1", "Testing2"), messages);
// Shutdown the current leader. The session timeout one should becomes leader again.
if (secondService instanceof Service) {
((Service) secondService).stopAndWait();
}
// Try to fetch message from the current leader again.
// Should see two messages (because the cache is cleared and fetch is from the backing store).
messages = Retries.callWithRetries(new Retries.Callable<List<String>, Throwable>() {
@Override
public List<String> call() throws Throwable {
List<String> messages = new ArrayList<>();
try (CloseableIterator<RawMessage> iterator = firstService.prepareFetch(topicId).fetch()) {
while (iterator.hasNext()) {
messages.add(new String(iterator.next().getPayload(), "UTF-8"));
}
}
return messages;
}
}, RetryStrategies.timeLimit(10, TimeUnit.SECONDS, RetryStrategies.fixDelay(1, TimeUnit.SECONDS)));
Assert.assertEquals(Arrays.asList("Testing1", "Testing2"), messages);
zkClient1.stopAndWait();
zkClient2.stopAndWait();
}
use of io.cdap.cdap.messaging.data.RawMessage in project cdap by cdapio.
the class FetchHandler method poll.
@POST
@Path("poll")
public void poll(FullHttpRequest request, HttpResponder responder, @PathParam("namespace") String namespace, @PathParam("topic") String topic) throws Exception {
TopicId topicId = new NamespaceId(namespace).topic(topic);
// Currently only support avro
if (!"avro/binary".equals(request.headers().get(HttpHeaderNames.CONTENT_TYPE))) {
throw new BadRequestException("Only avro/binary content type is supported.");
}
// Decode the poll request
Decoder decoder = DecoderFactory.get().directBinaryDecoder(new ByteBufInputStream(request.content()), null);
DatumReader<GenericRecord> datumReader = new GenericDatumReader<>(Schemas.V1.ConsumeRequest.SCHEMA);
// Fetch the messages
CloseableIterator<RawMessage> iterator = fetchMessages(datumReader.read(null, decoder), topicId);
try {
responder.sendContent(HttpResponseStatus.OK, new MessagesBodyProducer(iterator, messageChunkSize), new DefaultHttpHeaders().set(HttpHeaderNames.CONTENT_TYPE, "avro/binary"));
} catch (Throwable t) {
iterator.close();
throw t;
}
}
Aggregations