Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

fix: resolve health check issue when provided TopicARN #186

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class SnsBinderHealthIndicator extends AbstractHealthIndicator {

private final SnsMessageHandlerBinder snsMessageHandlerBinder;
private final BindingServiceProperties bindingServiceProperties;
private static final String ARN_PREFIX = "arn";

public SnsBinderHealthIndicator(final SnsMessageHandlerBinder snsMessageHandlerBinder, final BindingServiceProperties bindingServiceProperties) {
Assert.notNull(snsMessageHandlerBinder, "SnsMessageHandlerBinder must not be null");
Expand All @@ -31,13 +32,14 @@ protected void doHealthCheck(Health.Builder builder) {
.thenApply(List::stream)
.join()
.map(Topic::topicArn)
.map(topicArn -> topicArn.substring(topicArn.lastIndexOf(':') + 1))
.map(SnsBinderHealthIndicator::extractTopicNameFromTopicArn)
.collect(Collectors.toSet());

var availableDeclaredTopics = bindingServiceProperties.getBindings().values().stream()
.filter(bindingProperties -> "sns".equalsIgnoreCase(bindingProperties.getBinder()))
.map(BindingProperties::getDestination)
.allMatch(declaredTopic -> availableTopics.contains(declaredTopic));
.map(SnsBinderHealthIndicator::extractTopicNameFromTopicArn)
.allMatch(availableTopics::contains);

if (availableDeclaredTopics) {
builder.up();
Expand All @@ -46,4 +48,7 @@ protected void doHealthCheck(Health.Builder builder) {
}
}

public static String extractTopicNameFromTopicArn(String topicArn){
return topicArn.startsWith(ARN_PREFIX) ? topicArn.substring(topicArn.lastIndexOf(':') + 1) : topicArn;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
package de.idealo.spring.stream.binder.sns.health;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import de.idealo.spring.stream.binder.sns.SnsMessageHandlerBinder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -21,13 +11,20 @@
import org.springframework.boot.actuate.health.Status;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.BindingServiceProperties;

import software.amazon.awssdk.services.sns.SnsAsyncClient;
import software.amazon.awssdk.services.sns.model.AuthorizationErrorException;
import software.amazon.awssdk.services.sns.model.ListTopicsResponse;
import software.amazon.awssdk.services.sns.model.Topic;

import de.idealo.spring.stream.binder.sns.SnsMessageHandlerBinder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class SnsBinderHealthIndicatorTest {
Expand All @@ -48,12 +45,30 @@ class SnsBinderHealthIndicatorTest {
void setUp() {
lenient().when(snsMessageHandlerBinder.getAmazonSNS()).thenReturn(amazonSNS);
}
private final String ARN_PATH_PREFIX = "arn:partition:service:region:account-id:";
private final String TOPIC_NAME = "topicName";
private final String TOPIC_ARN = ARN_PATH_PREFIX + TOPIC_NAME;

@Test
void shouldSucceedIfProvidedTopicArnInsteadOfTopicName() {
when(amazonSNS.listTopics()).thenReturn(CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(Topic.builder().topicArn(TOPIC_ARN).build()).build()));
final BindingProperties binderProperties = new BindingProperties();
binderProperties.setDestination(TOPIC_ARN);
binderProperties.setBinder("sns");
when(bindingServiceProperties.getBindings()).thenReturn(Collections.singletonMap("doesn't matter", binderProperties));

Health.Builder builder = new Health.Builder();

healthIndicator.doHealthCheck(builder);

assertThat(builder.build().getStatus()).isEqualTo(Status.UP);
}

@Test
void reportsTrueWhenAllTopicsCanBeListed() {
when(amazonSNS.listTopics()).thenReturn(CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(Topic.builder().topicArn("blablabla:somemorebla:topicName").build()).build()));
when(amazonSNS.listTopics()).thenReturn(CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(Topic.builder().topicArn(TOPIC_ARN).build()).build()));
final BindingProperties binderProperties = new BindingProperties();
binderProperties.setDestination("topicName");
binderProperties.setDestination(TOPIC_NAME);
binderProperties.setBinder("sns");
when(bindingServiceProperties.getBindings()).thenReturn(Collections.singletonMap("doesn't matter", binderProperties));

Expand All @@ -68,12 +83,12 @@ void reportsTrueWhenAllTopicsCanBeListed() {
void reportsTrueWhenMoreTopicsThenDestinationsArePresent() {
when(amazonSNS.listTopics()).thenReturn(
CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(
Topic.builder().topicArn("blablabla:somemorebla:topicName1").build(),
Topic.builder().topicArn("blablabla:somemorebla:topicName2").build())
Topic.builder().topicArn(TOPIC_ARN + "1").build(),
Topic.builder().topicArn(TOPIC_ARN + "2").build())
.build())
);
final BindingProperties binderProperties = new BindingProperties();
binderProperties.setDestination("topicName1");
binderProperties.setDestination(TOPIC_NAME + "1");
binderProperties.setBinder("sns");
when(bindingServiceProperties.getBindings()).thenReturn(Collections.singletonMap("doesn't matter", binderProperties));

Expand All @@ -88,18 +103,18 @@ void reportsTrueWhenMoreTopicsThenDestinationsArePresent() {
void filtersOutNonSnsBinders() {
when(amazonSNS.listTopics()).thenReturn(
CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(
Topic.builder().topicArn("blablabla:somemorebla:topicName1").build(),
Topic.builder().topicArn("blablabla:somemorebla:topicName2").build())
Topic.builder().topicArn(TOPIC_ARN + "1").build(),
Topic.builder().topicArn(TOPIC_ARN + "2").build())
.build())
);
Map<String, BindingProperties> bindings = new HashMap<>();
final BindingProperties binderPropertiesSns = new BindingProperties();
binderPropertiesSns.setDestination("topicName1");
binderPropertiesSns.setDestination(TOPIC_NAME + "1");
binderPropertiesSns.setBinder("sns");
bindings.put("doesn't matter", binderPropertiesSns);

final BindingProperties binderPropertiesKafka = new BindingProperties();
binderPropertiesKafka.setDestination("topicName2");
binderPropertiesKafka.setDestination(TOPIC_NAME + "2");
binderPropertiesKafka.setBinder("kafka");
bindings.put("still doesn't matter", binderPropertiesKafka);
when(bindingServiceProperties.getBindings()).thenReturn(bindings);
Expand All @@ -113,9 +128,9 @@ void filtersOutNonSnsBinders() {

@Test
void reportsFalseWhenAnExpectedTopicIsNotPresent() {
when(amazonSNS.listTopics()).thenReturn(CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(Topic.builder().topicArn("blablabla:somemorebla:wrongTopicName").build()).build()));
when(amazonSNS.listTopics()).thenReturn(CompletableFuture.completedFuture(ListTopicsResponse.builder().topics(Topic.builder().topicArn(ARN_PATH_PREFIX + "wrongTopicName").build()).build()));
final BindingProperties binderProperties = new BindingProperties();
binderProperties.setDestination("topicName");
binderProperties.setDestination(TOPIC_NAME);
binderProperties.setBinder("sns");
when(bindingServiceProperties.getBindings()).thenReturn(Collections.singletonMap("doesn't matter", binderProperties));

Expand Down