mirror of https://github.com/dapr/java-sdk.git
Migrate PubSub removing flaky test
Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
This commit is contained in:
parent
3a8fd611da
commit
b40a5b23c7
|
@ -0,0 +1,637 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.dapr.it.testcontainers.pubsub.http;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.dapr.client.DaprClient;
|
||||||
|
import io.dapr.client.DaprClientBuilder;
|
||||||
|
import io.dapr.client.DaprPreviewClient;
|
||||||
|
import io.dapr.client.domain.BulkPublishEntry;
|
||||||
|
import io.dapr.client.domain.BulkPublishRequest;
|
||||||
|
import io.dapr.client.domain.BulkPublishResponse;
|
||||||
|
import io.dapr.client.domain.CloudEvent;
|
||||||
|
import io.dapr.client.domain.HttpExtension;
|
||||||
|
import io.dapr.client.domain.Metadata;
|
||||||
|
import io.dapr.client.domain.PublishEventRequest;
|
||||||
|
import io.dapr.config.Properties;
|
||||||
|
import io.dapr.it.pubsub.http.PubSubIT;
|
||||||
|
import io.dapr.serializer.DaprObjectSerializer;
|
||||||
|
import io.dapr.spring.boot.autoconfigure.client.DaprClientAutoConfiguration;
|
||||||
|
import io.dapr.testcontainers.DaprContainer;
|
||||||
|
import io.dapr.testcontainers.DaprLogLevel;
|
||||||
|
import io.dapr.utils.TypeRef;
|
||||||
|
import org.assertj.core.api.SoftAssertions;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Tag;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||||
|
import org.springframework.test.context.DynamicPropertySource;
|
||||||
|
import org.testcontainers.containers.Network;
|
||||||
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static io.dapr.it.Retry.callWithRetry;
|
||||||
|
import static io.dapr.it.TestUtils.assertThrowsDaprException;
|
||||||
|
import static io.dapr.it.TestUtils.assertThrowsDaprExceptionWithReason;
|
||||||
|
import static io.dapr.it.testcontainers.ContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
@SpringBootTest(
|
||||||
|
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
|
||||||
|
classes = {
|
||||||
|
TestPubSubApplication.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@Testcontainers
|
||||||
|
@Tag("testcontainers")
|
||||||
|
public class DaprPubSubIT {
|
||||||
|
|
||||||
|
private static final Network DAPR_NETWORK = Network.newNetwork();
|
||||||
|
private static final Random RANDOM = new Random();
|
||||||
|
private static final int PORT = RANDOM.nextInt(1000) + 8000;
|
||||||
|
private static final String APP_FOUND_MESSAGE_PATTERN = ".*application discovered on port.*";
|
||||||
|
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
private static final String PUBSUB_APP_ID = "pubsub-dapr-app";
|
||||||
|
private static final String PUBSUB_NAME = "pubsub";
|
||||||
|
|
||||||
|
// topics
|
||||||
|
private static final String TOPIC_BULK = "testingbulktopic";
|
||||||
|
private static final String TOPIC_NAME = "testingtopic";
|
||||||
|
private static final String ANOTHER_TOPIC_NAME = "anothertopic";
|
||||||
|
private static final String TYPED_TOPIC_NAME = "typedtestingtopic";
|
||||||
|
private static final String BINARY_TOPIC_NAME = "binarytopic";
|
||||||
|
private static final String TTL_TOPIC_NAME = "ttltopic";
|
||||||
|
private static final String LONG_TOPIC_NAME = "testinglongvalues";
|
||||||
|
|
||||||
|
|
||||||
|
private static final int NUM_MESSAGES = 10;
|
||||||
|
|
||||||
|
// typeRefs
|
||||||
|
private static final TypeRef<List<CloudEvent>> CLOUD_EVENT_LIST_TYPE_REF = new TypeRef<>() {
|
||||||
|
};
|
||||||
|
private static final TypeRef<List<CloudEvent<PubSubIT.ConvertToLong>>> CLOUD_EVENT_LONG_LIST_TYPE_REF =
|
||||||
|
new TypeRef<>() {
|
||||||
|
};
|
||||||
|
private static final TypeRef<List<CloudEvent<PubSubIT.MyObject>>> CLOUD_EVENT_MYOBJECT_LIST_TYPE_REF =
|
||||||
|
new TypeRef<>() {
|
||||||
|
};
|
||||||
|
|
||||||
|
@Container
|
||||||
|
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||||
|
.withAppName(PUBSUB_APP_ID)
|
||||||
|
.withNetwork(DAPR_NETWORK)
|
||||||
|
.withDaprLogLevel(DaprLogLevel.DEBUG)
|
||||||
|
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
|
||||||
|
.withAppChannelAddress("host.testcontainers.internal")
|
||||||
|
.withAppPort(PORT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose the Dapr ports to the host.
|
||||||
|
*
|
||||||
|
* @param registry the dynamic property registry
|
||||||
|
*/
|
||||||
|
@DynamicPropertySource
|
||||||
|
static void daprProperties(DynamicPropertyRegistry registry) {
|
||||||
|
registry.add("dapr.http.endpoint", DAPR_CONTAINER::getHttpEndpoint);
|
||||||
|
registry.add("dapr.grpc.endpoint", DAPR_CONTAINER::getGrpcEndpoint);
|
||||||
|
registry.add("server.port", () -> PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
org.testcontainers.Testcontainers.exposeHostPorts(PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should receive INVALID_ARGUMENT when the specified Pub/Sub name does not exist")
|
||||||
|
public void shouldReceiveInvalidArgument() throws Exception {
|
||||||
|
Wait.forLogMessage(APP_FOUND_MESSAGE_PATTERN, 1).waitUntilReady(DAPR_CONTAINER);
|
||||||
|
|
||||||
|
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||||
|
assertThrowsDaprExceptionWithReason(
|
||||||
|
"INVALID_ARGUMENT",
|
||||||
|
"INVALID_ARGUMENT: pubsub unknown pubsub is not found",
|
||||||
|
"DAPR_PUBSUB_NOT_FOUND",
|
||||||
|
() -> client.publishEvent("unknown pubsub", "mytopic", "payload").block());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should receive INVALID_ARGUMENT using bulk publish when the specified Pub/Sub name does not exist")
|
||||||
|
public void shouldReceiveInvalidArgumentWithBulkPublish() throws Exception {
|
||||||
|
try (DaprPreviewClient client = createDaprClientBuilder().buildPreviewClient()) {
|
||||||
|
assertThrowsDaprException(
|
||||||
|
"INVALID_ARGUMENT",
|
||||||
|
"INVALID_ARGUMENT: pubsub unknown pubsub is not found",
|
||||||
|
() -> client.publishEvents("unknown pubsub", "mytopic", "text/plain", "message").block());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should publish some payload types successfully")
|
||||||
|
public void shouldPublishSomePayloadTypesWithNoError() throws Exception {
|
||||||
|
|
||||||
|
DaprObjectSerializer serializer = createJacksonObjectSerializer();
|
||||||
|
|
||||||
|
try (
|
||||||
|
DaprClient client = createDaprClientBuilder().withObjectSerializer(serializer).build();
|
||||||
|
DaprPreviewClient previewClient = createDaprClientBuilder().withObjectSerializer(serializer)
|
||||||
|
.buildPreviewClient()
|
||||||
|
) {
|
||||||
|
|
||||||
|
publishBulkStringsAsserting(previewClient);
|
||||||
|
|
||||||
|
publishMyObjectAsserting(previewClient);
|
||||||
|
|
||||||
|
publishByteAsserting(previewClient);
|
||||||
|
|
||||||
|
publishCloudEventAsserting(previewClient);
|
||||||
|
|
||||||
|
Thread.sleep(10000);
|
||||||
|
|
||||||
|
callWithRetry(() -> validatePublishedMessages(client), 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should publish various payload types to different topics")
|
||||||
|
public void testPubSub() throws Exception {
|
||||||
|
|
||||||
|
DaprObjectSerializer serializer = createJacksonObjectSerializer();
|
||||||
|
|
||||||
|
// Send a batch of messages on one topic
|
||||||
|
try (DaprClient client = createDaprClientBuilder().withObjectSerializer(serializer).build()) {
|
||||||
|
|
||||||
|
sendBulkMessagesAsText(client, TOPIC_NAME);
|
||||||
|
|
||||||
|
sendBulkMessagesAsText(client, ANOTHER_TOPIC_NAME);
|
||||||
|
|
||||||
|
//Publishing an object.
|
||||||
|
PubSubIT.MyObject object = new PubSubIT.MyObject();
|
||||||
|
object.setId("123");
|
||||||
|
client.publishEvent(PUBSUB_NAME, TOPIC_NAME, object).block();
|
||||||
|
System.out.println("Published one object.");
|
||||||
|
|
||||||
|
client.publishEvent(PUBSUB_NAME, TYPED_TOPIC_NAME, object).block();
|
||||||
|
System.out.println("Published another object.");
|
||||||
|
|
||||||
|
//Publishing a single byte: Example of non-string based content published
|
||||||
|
publishOneByteSync(client, TOPIC_NAME);
|
||||||
|
|
||||||
|
CloudEvent<String> cloudEvent = new CloudEvent<>();
|
||||||
|
cloudEvent.setId("1234");
|
||||||
|
cloudEvent.setData("message from cloudevent");
|
||||||
|
cloudEvent.setSource("test");
|
||||||
|
cloudEvent.setSpecversion("1");
|
||||||
|
cloudEvent.setType("myevent");
|
||||||
|
cloudEvent.setDatacontenttype("text/plain");
|
||||||
|
|
||||||
|
//Publishing a cloud event.
|
||||||
|
client.publishEvent(new PublishEventRequest(PUBSUB_NAME, TOPIC_NAME, cloudEvent)
|
||||||
|
.setContentType("application/cloudevents+json")).block();
|
||||||
|
System.out.println("Published one cloud event.");
|
||||||
|
|
||||||
|
{
|
||||||
|
CloudEvent<String> cloudEventV2 = new CloudEvent<>();
|
||||||
|
cloudEventV2.setId("2222");
|
||||||
|
cloudEventV2.setData("message from cloudevent v2");
|
||||||
|
cloudEventV2.setSource("test");
|
||||||
|
cloudEventV2.setSpecversion("1");
|
||||||
|
cloudEventV2.setType("myevent.v2");
|
||||||
|
cloudEventV2.setDatacontenttype("text/plain");
|
||||||
|
client.publishEvent(
|
||||||
|
new PublishEventRequest(PUBSUB_NAME, TOPIC_NAME, cloudEventV2)
|
||||||
|
.setContentType("application/cloudevents+json")).block();
|
||||||
|
System.out.println("Published one cloud event for v2.");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
CloudEvent<String> cloudEventV3 = new CloudEvent<>();
|
||||||
|
cloudEventV3.setId("3333");
|
||||||
|
cloudEventV3.setData("message from cloudevent v3");
|
||||||
|
cloudEventV3.setSource("test");
|
||||||
|
cloudEventV3.setSpecversion("1");
|
||||||
|
cloudEventV3.setType("myevent.v3");
|
||||||
|
cloudEventV3.setDatacontenttype("text/plain");
|
||||||
|
client.publishEvent(
|
||||||
|
new PublishEventRequest(PUBSUB_NAME, TOPIC_NAME, cloudEventV3)
|
||||||
|
.setContentType("application/cloudevents+json")).block();
|
||||||
|
System.out.println("Published one cloud event for v3.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.sleep(2000);
|
||||||
|
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + TOPIC_NAME);
|
||||||
|
|
||||||
|
List<CloudEvent> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/testingtopic",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET,
|
||||||
|
CLOUD_EVENT_LIST_TYPE_REF
|
||||||
|
).block();
|
||||||
|
|
||||||
|
assertThat(messages)
|
||||||
|
.hasSize(13)
|
||||||
|
.extracting(CloudEvent::getData)
|
||||||
|
.filteredOn(Objects::nonNull)
|
||||||
|
.contains(
|
||||||
|
"AQ==",
|
||||||
|
"message from cloudevent"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
String expectedMessage = String.format("This is message #%d on topic %s", i, TOPIC_NAME);
|
||||||
|
assertThat(messages)
|
||||||
|
.extracting(CloudEvent::getData)
|
||||||
|
.filteredOn(Objects::nonNull)
|
||||||
|
.anyMatch(expectedMessage::equals);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(messages)
|
||||||
|
.extracting(CloudEvent::getData)
|
||||||
|
.filteredOn(LinkedHashMap.class::isInstance)
|
||||||
|
.map(data -> (String) ((LinkedHashMap<?, ?>) data).get("id"))
|
||||||
|
.contains("123");
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + TOPIC_NAME + " V2");
|
||||||
|
|
||||||
|
List<CloudEvent> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/testingtopicV2",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET,
|
||||||
|
CLOUD_EVENT_LIST_TYPE_REF
|
||||||
|
).block();
|
||||||
|
|
||||||
|
assertThat(messages)
|
||||||
|
.hasSize(1);
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + TOPIC_NAME + " V3");
|
||||||
|
|
||||||
|
List<CloudEvent> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/testingtopicV3",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET,
|
||||||
|
CLOUD_EVENT_LIST_TYPE_REF
|
||||||
|
).block();
|
||||||
|
|
||||||
|
assertThat(messages)
|
||||||
|
.hasSize(1);
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + TYPED_TOPIC_NAME);
|
||||||
|
|
||||||
|
List<CloudEvent<PubSubIT.MyObject>> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/typedtestingtopic",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET,
|
||||||
|
CLOUD_EVENT_MYOBJECT_LIST_TYPE_REF
|
||||||
|
).block();
|
||||||
|
|
||||||
|
assertThat(messages)
|
||||||
|
.extracting(CloudEvent::getData)
|
||||||
|
.filteredOn(Objects::nonNull)
|
||||||
|
.filteredOn(PubSubIT.MyObject.class::isInstance)
|
||||||
|
.map(PubSubIT.MyObject::getId)
|
||||||
|
.contains("123");
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + ANOTHER_TOPIC_NAME);
|
||||||
|
|
||||||
|
List<CloudEvent> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/anothertopic",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET,
|
||||||
|
CLOUD_EVENT_LIST_TYPE_REF
|
||||||
|
).block();
|
||||||
|
|
||||||
|
assertThat(messages)
|
||||||
|
.hasSize(10);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
String expectedMessage = String.format("This is message #%d on topic %s", i, ANOTHER_TOPIC_NAME);
|
||||||
|
assertThat(messages)
|
||||||
|
.extracting(CloudEvent::getData)
|
||||||
|
.filteredOn(Objects::nonNull)
|
||||||
|
.anyMatch(expectedMessage::equals);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should publish binary payload type successfully")
|
||||||
|
public void shouldPublishBinary() throws Exception {
|
||||||
|
|
||||||
|
DaprObjectSerializer serializer = createBinaryObjectSerializer();
|
||||||
|
|
||||||
|
try (DaprClient client = createDaprClientBuilder().withObjectSerializer(serializer).build()) {
|
||||||
|
publishOneByteSync(client, BINARY_TOPIC_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.sleep(3000);
|
||||||
|
|
||||||
|
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + BINARY_TOPIC_NAME);
|
||||||
|
final List<CloudEvent> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/binarytopic",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET, CLOUD_EVENT_LIST_TYPE_REF).block();
|
||||||
|
|
||||||
|
SoftAssertions.assertSoftly(softly -> {
|
||||||
|
softly.assertThat(messages.size()).isEqualTo(1);
|
||||||
|
softly.assertThat(messages.get(0).getData()).isNull();
|
||||||
|
softly.assertThat(messages.get(0).getBinaryData()).isEqualTo(new byte[] {1});
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void publishOneByteSync(DaprClient client, String topicName) {
|
||||||
|
client.publishEvent(
|
||||||
|
PUBSUB_NAME,
|
||||||
|
topicName,
|
||||||
|
new byte[] {1}).block();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendBulkMessagesAsText(DaprClient client, String topicName) {
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
String message = String.format("This is message #%d on topic %s", i, topicName);
|
||||||
|
client.publishEvent(PUBSUB_NAME, topicName, message).block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publishMyObjectAsserting(DaprPreviewClient previewClient) {
|
||||||
|
PubSubIT.MyObject object = new PubSubIT.MyObject();
|
||||||
|
object.setId("123");
|
||||||
|
BulkPublishResponse<PubSubIT.MyObject> response = previewClient.publishEvents(
|
||||||
|
PUBSUB_NAME,
|
||||||
|
TOPIC_BULK,
|
||||||
|
"application/json",
|
||||||
|
Collections.singletonList(object)
|
||||||
|
).block();
|
||||||
|
SoftAssertions.assertSoftly(softly -> {
|
||||||
|
softly.assertThat(response).isNotNull();
|
||||||
|
softly.assertThat(response.getFailedEntries().size()).isZero();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publishBulkStringsAsserting(DaprPreviewClient previewClient) {
|
||||||
|
List<String> messages = new ArrayList<>();
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
messages.add(String.format("This is message #%d on topic %s", i, TOPIC_BULK));
|
||||||
|
}
|
||||||
|
BulkPublishResponse<String> response = previewClient.publishEvents(PUBSUB_NAME, TOPIC_BULK, "", messages).block();
|
||||||
|
SoftAssertions.assertSoftly(softly -> {
|
||||||
|
softly.assertThat(response).isNotNull();
|
||||||
|
softly.assertThat(response.getFailedEntries().size()).isZero();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publishByteAsserting(DaprPreviewClient previewClient) {
|
||||||
|
BulkPublishResponse<byte[]> response = previewClient.publishEvents(
|
||||||
|
PUBSUB_NAME,
|
||||||
|
TOPIC_BULK,
|
||||||
|
"",
|
||||||
|
Collections.singletonList(new byte[] {1})
|
||||||
|
).block();
|
||||||
|
SoftAssertions.assertSoftly(softly -> {
|
||||||
|
assertThat(response).isNotNull();
|
||||||
|
softly.assertThat(response.getFailedEntries().size()).isZero();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publishCloudEventAsserting(DaprPreviewClient previewClient) {
|
||||||
|
CloudEvent<String> cloudEvent = new CloudEvent<>();
|
||||||
|
cloudEvent.setId("1234");
|
||||||
|
cloudEvent.setData("message from cloudevent");
|
||||||
|
cloudEvent.setSource("test");
|
||||||
|
cloudEvent.setSpecversion("1");
|
||||||
|
cloudEvent.setType("myevent");
|
||||||
|
cloudEvent.setDatacontenttype("text/plain");
|
||||||
|
|
||||||
|
BulkPublishRequest<CloudEvent<String>> req = new BulkPublishRequest<>(
|
||||||
|
PUBSUB_NAME,
|
||||||
|
TOPIC_BULK,
|
||||||
|
Collections.singletonList(
|
||||||
|
new BulkPublishEntry<>("1", cloudEvent, "application/cloudevents+json", null)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BulkPublishResponse<CloudEvent<String>> response = previewClient.publishEvents(req).block();
|
||||||
|
SoftAssertions.assertSoftly(softly -> {
|
||||||
|
softly.assertThat(response).isNotNull();
|
||||||
|
softly.assertThat(response.getFailedEntries().size()).isZero();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validatePublishedMessages(DaprClient client) {
|
||||||
|
List<CloudEvent> cloudEventMessages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/redis/testingbulktopic",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET,
|
||||||
|
CLOUD_EVENT_LIST_TYPE_REF
|
||||||
|
).block();
|
||||||
|
|
||||||
|
assertThat(cloudEventMessages)
|
||||||
|
.as("expected non-null list of cloud events")
|
||||||
|
.isNotNull()
|
||||||
|
.hasSize(13);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
String expectedMessage = String.format("This is message #%d on topic %s", i, TOPIC_BULK);
|
||||||
|
assertThat(cloudEventMessages)
|
||||||
|
.as("expected text payload to match for message %d", i)
|
||||||
|
.anySatisfy(event -> assertThat(event.getData()).isEqualTo(expectedMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(cloudEventMessages)
|
||||||
|
.filteredOn(event -> event.getData() instanceof LinkedHashMap)
|
||||||
|
.map(event -> (LinkedHashMap<?, ?>) event.getData())
|
||||||
|
.anySatisfy(map -> assertThat(map.get("id")).isEqualTo("123"));
|
||||||
|
|
||||||
|
assertThat(cloudEventMessages)
|
||||||
|
.map(CloudEvent::getData)
|
||||||
|
.anySatisfy(data -> assertThat(data).isEqualTo("AQ=="));
|
||||||
|
|
||||||
|
assertThat(cloudEventMessages)
|
||||||
|
.map(CloudEvent::getData)
|
||||||
|
.anySatisfy(data -> assertThat(data).isEqualTo("message from cloudevent"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should publish with TTL")
|
||||||
|
public void testPubSubTTLMetadata() throws Exception {
|
||||||
|
|
||||||
|
// Send a batch of messages on one topic, all to be expired in 1 second.
|
||||||
|
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
String message = String.format("This is message #%d on topic %s", i, TTL_TOPIC_NAME);
|
||||||
|
//Publishing messages
|
||||||
|
client.publishEvent(
|
||||||
|
PUBSUB_NAME,
|
||||||
|
TTL_TOPIC_NAME,
|
||||||
|
message,
|
||||||
|
Map.of(Metadata.TTL_IN_SECONDS, "1"))
|
||||||
|
.block();
|
||||||
|
System.out.printf("Published message: '%s' to topic '%s' pubsub_name '%s'%n", message, TOPIC_NAME, PUBSUB_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sleeps for two seconds to let them expire.
|
||||||
|
Thread.sleep(2000);
|
||||||
|
|
||||||
|
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + TTL_TOPIC_NAME);
|
||||||
|
final List
|
||||||
|
messages = client.invokeMethod(PUBSUB_APP_ID, "messages/" + TTL_TOPIC_NAME, null, HttpExtension.GET, List.class).block();
|
||||||
|
assertThat(messages).hasSize(0);
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should publish long values")
|
||||||
|
public void testLongValues() throws Exception {
|
||||||
|
|
||||||
|
Random random = new Random(590518626939830271L);
|
||||||
|
Set<PubSubIT.ConvertToLong> values = new HashSet<>();
|
||||||
|
values.add(new PubSubIT.ConvertToLong().setVal(590518626939830271L));
|
||||||
|
PubSubIT.ConvertToLong val;
|
||||||
|
for (int i = 0; i < NUM_MESSAGES - 1; i++) {
|
||||||
|
do {
|
||||||
|
val = new PubSubIT.ConvertToLong().setVal(random.nextLong());
|
||||||
|
} while (values.contains(val));
|
||||||
|
values.add(val);
|
||||||
|
}
|
||||||
|
Iterator<PubSubIT.ConvertToLong> valuesIt = values.iterator();
|
||||||
|
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||||
|
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||||
|
PubSubIT.ConvertToLong value = valuesIt.next();
|
||||||
|
System.out.println("The long value sent " + value.getValue());
|
||||||
|
//Publishing messages
|
||||||
|
client.publishEvent(
|
||||||
|
PUBSUB_NAME,
|
||||||
|
LONG_TOPIC_NAME,
|
||||||
|
value,
|
||||||
|
Map.of(Metadata.TTL_IN_SECONDS, "30")).block();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep((long) (1000 * Math.random()));
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<PubSubIT.ConvertToLong> actual = new HashSet<>();
|
||||||
|
try (DaprClient client = createDaprClientBuilder().build()) {
|
||||||
|
callWithRetry(() -> {
|
||||||
|
System.out.println("Checking results for topic " + LONG_TOPIC_NAME);
|
||||||
|
final List<CloudEvent<PubSubIT.ConvertToLong>> messages = client.invokeMethod(
|
||||||
|
PUBSUB_APP_ID,
|
||||||
|
"messages/testinglongvalues",
|
||||||
|
null,
|
||||||
|
HttpExtension.GET, CLOUD_EVENT_LONG_LIST_TYPE_REF).block();
|
||||||
|
assertNotNull(messages);
|
||||||
|
for (CloudEvent<PubSubIT.ConvertToLong> message : messages) {
|
||||||
|
actual.add(message.getData());
|
||||||
|
}
|
||||||
|
assertThat(values).isEqualTo(actual);
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DaprClientBuilder createDaprClientBuilder() {
|
||||||
|
return new DaprClientBuilder()
|
||||||
|
.withPropertyOverride(Properties.HTTP_ENDPOINT, "http://localhost:" + DAPR_CONTAINER.getHttpPort())
|
||||||
|
.withPropertyOverride(Properties.GRPC_ENDPOINT, "http://localhost:" + DAPR_CONTAINER.getGrpcPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DaprObjectSerializer createJacksonObjectSerializer() {
|
||||||
|
return new DaprObjectSerializer() {
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(Object o) throws JsonProcessingException {
|
||||||
|
return OBJECT_MAPPER.writeValueAsBytes(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T deserialize(byte[] data, TypeRef<T> type) throws IOException {
|
||||||
|
return OBJECT_MAPPER.readValue(data, OBJECT_MAPPER.constructType(type.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return "application/json";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull DaprObjectSerializer createBinaryObjectSerializer() {
|
||||||
|
return new DaprObjectSerializer() {
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(Object o) {
|
||||||
|
return (byte[]) o;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T deserialize(byte[] data, TypeRef<T> type) {
|
||||||
|
return (T) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return "application/octet-stream";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The Dapr Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.dapr.it.testcontainers.pubsub.http;
|
||||||
|
|
||||||
|
import io.dapr.Rule;
|
||||||
|
import io.dapr.Topic;
|
||||||
|
import io.dapr.client.domain.BulkSubscribeAppResponse;
|
||||||
|
import io.dapr.client.domain.BulkSubscribeAppResponseEntry;
|
||||||
|
import io.dapr.client.domain.BulkSubscribeAppResponseStatus;
|
||||||
|
import io.dapr.client.domain.BulkSubscribeMessage;
|
||||||
|
import io.dapr.client.domain.BulkSubscribeMessageEntry;
|
||||||
|
import io.dapr.client.domain.CloudEvent;
|
||||||
|
import io.dapr.it.pubsub.http.PubSubIT;
|
||||||
|
import io.dapr.springboot.annotations.BulkSubscribe;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SpringBoot Controller to handle input binding.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class SubscriberController {
|
||||||
|
|
||||||
|
private final Map<String, List<CloudEvent<?>>> messagesByTopic = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
@GetMapping(path = "/messages/{topic}")
|
||||||
|
public List<CloudEvent<?>> getMessagesByTopic(@PathVariable("topic") String topic) {
|
||||||
|
return messagesByTopic.getOrDefault(topic, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<CloudEvent> messagesReceivedBulkPublishTopic = new ArrayList();
|
||||||
|
private static final List<CloudEvent> messagesReceivedTestingTopic = new ArrayList();
|
||||||
|
private static final List<CloudEvent> messagesReceivedTestingTopicV2 = new ArrayList();
|
||||||
|
private static final List<CloudEvent> messagesReceivedTestingTopicV3 = new ArrayList();
|
||||||
|
private static final List<BulkSubscribeAppResponse> responsesReceivedTestingTopicBulkSub = new ArrayList<>();
|
||||||
|
|
||||||
|
@GetMapping(path = "/messages/redis/testingbulktopic")
|
||||||
|
public List<CloudEvent> getMessagesReceivedBulkTopic() {
|
||||||
|
return messagesReceivedBulkPublishTopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping(path = "/messages/testingtopic")
|
||||||
|
public List<CloudEvent> getMessagesReceivedTestingTopic() {
|
||||||
|
return messagesReceivedTestingTopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = "/messages/testingtopicV2")
|
||||||
|
public List<CloudEvent> getMessagesReceivedTestingTopicV2() {
|
||||||
|
return messagesReceivedTestingTopicV2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = "/messages/testingtopicV3")
|
||||||
|
public List<CloudEvent> getMessagesReceivedTestingTopicV3() {
|
||||||
|
return messagesReceivedTestingTopicV3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = "/messages/topicBulkSub")
|
||||||
|
public List<BulkSubscribeAppResponse> getMessagesReceivedTestingTopicBulkSub() {
|
||||||
|
System.out.println("res size: " + responsesReceivedTestingTopicBulkSub.size());
|
||||||
|
return responsesReceivedTestingTopicBulkSub;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "testingtopic", pubsubName = "pubsub")
|
||||||
|
@PostMapping("/route1")
|
||||||
|
public Mono<Void> handleMessage(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
String contentType = envelope.getDatacontenttype() == null ? "" : envelope.getDatacontenttype();
|
||||||
|
System.out.println("Testing topic Subscriber got message: " + message + "; Content-type: " + contentType);
|
||||||
|
messagesReceivedTestingTopic.add(envelope);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "testingbulktopic", pubsubName = "pubsub")
|
||||||
|
@PostMapping("/route1_redis")
|
||||||
|
public Mono<Void> handleBulkTopicMessage(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
String contentType = envelope.getDatacontenttype() == null ? "" : envelope.getDatacontenttype();
|
||||||
|
System.out.println("Testing bulk publish topic Subscriber got message: " + message + "; Content-type: " + contentType);
|
||||||
|
messagesReceivedBulkPublishTopic.add(envelope);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "testingtopic", pubsubName = "pubsub",
|
||||||
|
rule = @Rule(match = "event.type == 'myevent.v2'", priority = 2))
|
||||||
|
@PostMapping(path = "/route1_v2")
|
||||||
|
public Mono<Void> handleMessageV2(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
String contentType = envelope.getDatacontenttype() == null ? "" : envelope.getDatacontenttype();
|
||||||
|
System.out.println("Testing topic Subscriber got message: " + message + "; Content-type: " + contentType);
|
||||||
|
messagesReceivedTestingTopicV2.add(envelope);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "testingtopic", pubsubName = "pubsub",
|
||||||
|
rule = @Rule(match = "event.type == 'myevent.v3'", priority = 1))
|
||||||
|
@PostMapping(path = "/route1_v3")
|
||||||
|
public Mono<Void> handleMessageV3(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
String contentType = envelope.getDatacontenttype() == null ? "" : envelope.getDatacontenttype();
|
||||||
|
System.out.println("Testing topic Subscriber got message: " + message + "; Content-type: " + contentType);
|
||||||
|
messagesReceivedTestingTopicV3.add(envelope);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "typedtestingtopic", pubsubName = "pubsub")
|
||||||
|
@PostMapping(path = "/route1b")
|
||||||
|
public Mono<Void> handleMessageTyped(@RequestBody(required = false) CloudEvent<PubSubIT.MyObject> envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String id = envelope.getData() == null ? "" : envelope.getData().getId();
|
||||||
|
String contentType = envelope.getDatacontenttype() == null ? "" : envelope.getDatacontenttype();
|
||||||
|
System.out.println("Testing typed topic Subscriber got message with ID: " + id + "; Content-type: " + contentType);
|
||||||
|
messagesByTopic.compute("typedtestingtopic", merge(envelope));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "binarytopic", pubsubName = "pubsub")
|
||||||
|
@PostMapping(path = "/route2")
|
||||||
|
public Mono<Void> handleBinaryMessage(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
String contentType = envelope.getDatacontenttype() == null ? "" : envelope.getDatacontenttype();
|
||||||
|
System.out.println("Binary topic Subscriber got message: " + message + "; Content-type: " + contentType);
|
||||||
|
messagesByTopic.compute("binarytopic", merge(envelope));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "#{'another'.concat('topic')}", pubsubName = "${pubsubName:pubsub}")
|
||||||
|
@PostMapping(path = "/route3")
|
||||||
|
public Mono<Void> handleMessageAnotherTopic(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
System.out.println("Another topic Subscriber got message: " + message);
|
||||||
|
messagesByTopic.compute("anothertopic", merge(envelope));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(path = "/route4")
|
||||||
|
public Mono<Void> handleMessageTTLTopic(@RequestBody(required = false) CloudEvent envelope) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
String message = envelope.getData() == null ? "" : envelope.getData().toString();
|
||||||
|
System.out.println("TTL topic Subscriber got message: " + message);
|
||||||
|
messagesByTopic.compute("ttltopic", merge(envelope));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Topic(name = "testinglongvalues", pubsubName = "pubsub")
|
||||||
|
@PostMapping(path = "/testinglongvalues")
|
||||||
|
public Mono<Void> handleMessageLongValues(@RequestBody(required = false) CloudEvent<PubSubIT.ConvertToLong> cloudEvent) {
|
||||||
|
return Mono.fromRunnable(() -> {
|
||||||
|
try {
|
||||||
|
Long message = cloudEvent.getData().getValue();
|
||||||
|
System.out.println("Subscriber got: " + message);
|
||||||
|
messagesByTopic.compute("testinglongvalues", merge(cloudEvent));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive messages using the bulk subscribe API.
|
||||||
|
* The maxBulkSubCount and maxBulkSubAwaitDurationMs are adjusted to ensure
|
||||||
|
* that all the test messages arrive in a single batch.
|
||||||
|
*
|
||||||
|
* @param bulkMessage incoming bulk of messages from the message bus.
|
||||||
|
* @return status for each message received.
|
||||||
|
*/
|
||||||
|
@BulkSubscribe(maxMessagesCount = 100, maxAwaitDurationMs = 100)
|
||||||
|
@Topic(name = "topicBulkSub", pubsubName = "pubsub")
|
||||||
|
@PostMapping(path = "/routeBulkSub")
|
||||||
|
public Mono<BulkSubscribeAppResponse> handleMessageBulk(
|
||||||
|
@RequestBody(required = false) BulkSubscribeMessage<CloudEvent<String>> bulkMessage) {
|
||||||
|
return Mono.fromCallable(() -> {
|
||||||
|
System.out.println("bulkMessage: " + bulkMessage.getEntries().size());
|
||||||
|
|
||||||
|
if (bulkMessage.getEntries().size() == 0) {
|
||||||
|
BulkSubscribeAppResponse response = new BulkSubscribeAppResponse(new ArrayList<>());
|
||||||
|
responsesReceivedTestingTopicBulkSub.add(response);
|
||||||
|
System.out.println("res size: " + responsesReceivedTestingTopicBulkSub.size());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BulkSubscribeAppResponseEntry> entries = new ArrayList<>();
|
||||||
|
for (BulkSubscribeMessageEntry<?> entry: bulkMessage.getEntries()) {
|
||||||
|
try {
|
||||||
|
System.out.printf("Bulk Subscriber got entry ID: %s\n", entry.getEntryId());
|
||||||
|
entries.add(new BulkSubscribeAppResponseEntry(entry.getEntryId(), BulkSubscribeAppResponseStatus.SUCCESS));
|
||||||
|
} catch (Exception e) {
|
||||||
|
entries.add(new BulkSubscribeAppResponseEntry(entry.getEntryId(), BulkSubscribeAppResponseStatus.RETRY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BulkSubscribeAppResponse response = new BulkSubscribeAppResponse(entries);
|
||||||
|
responsesReceivedTestingTopicBulkSub.add(response);
|
||||||
|
System.out.println("res size: " + responsesReceivedTestingTopicBulkSub.size());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private BiFunction<String, List<CloudEvent<?>>, List<CloudEvent<?>>> merge(final CloudEvent<?> item) {
|
||||||
|
return (key, value) -> {
|
||||||
|
final List<CloudEvent<?>> list = value == null ? new ArrayList<>() : value;
|
||||||
|
list.add(item);
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = "/health")
|
||||||
|
public void health() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.dapr.it.testcontainers.pubsub.http;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class TestPubSubApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(TestPubSubApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue