Move code from spring-boot-actuator to spring-boot-mail

This commit is contained in:
Andy Wilkinson
2025-05-12 09:43:42 +01:00
committed by Phillip Webb
parent 29b745215e
commit 048cc5a6da
6 changed files with 18 additions and 12 deletions

View File

@@ -14,6 +14,9 @@ dependencies {
api("org.springframework:spring-context-support")
api("org.eclipse.angus:jakarta.mail")
compileOnly("com.fasterxml.jackson.core:jackson-annotations")
optional(project(":spring-boot-project:spring-boot-actuator"))
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-test"))
@@ -21,8 +24,11 @@ dependencies {
dockerTestImplementation("org.testcontainers:testcontainers")
dockerTestImplementation("org.testcontainers:junit-jupiter")
testCompileOnly("com.fasterxml.jackson.core:jackson-annotations")
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-autoconfigure")))
testRuntimeOnly("ch.qos.logback:logback-classic")
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2012-2025 the original author or 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
*
* https://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 org.springframework.boot.mail.actuate.health;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.util.StringUtils;
/**
* {@link HealthIndicator} for configured smtp server(s).
*
* @author Johannes Edmeier
* @author Scott Frederick
* @since 4.0.0
*/
public class MailHealthIndicator extends AbstractHealthIndicator {
private final JavaMailSenderImpl mailSender;
public MailHealthIndicator(JavaMailSenderImpl mailSender) {
super("Mail health check failed");
this.mailSender = mailSender;
}
@Override
protected void doHealthCheck(Builder builder) throws Exception {
String host = this.mailSender.getHost();
int port = this.mailSender.getPort();
StringBuilder location = new StringBuilder((host != null) ? host : "");
if (port != JavaMailSenderImpl.DEFAULT_PORT) {
location.append(":").append(port);
}
if (StringUtils.hasLength(location)) {
builder.withDetail("location", location.toString());
}
this.mailSender.testConnection();
builder.up();
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 the original author or 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
*
* https://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.
*/
/**
* Health integration for JavaMail.
*/
package org.springframework.boot.mail.actuate.health;

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2012-2025 the original author or 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
*
* https://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 org.springframework.boot.mail.actuate.health;
import java.util.Properties;
import jakarta.mail.Address;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.Provider;
import jakarta.mail.Provider.Type;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.URLName;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MailHealthIndicator}.
*
* @author Johannes Edmeier
* @author Stephane Nicoll
* @author Scott Frederick
*/
class MailHealthIndicatorTests {
private JavaMailSenderImpl mailSender;
private MailHealthIndicator indicator;
@BeforeEach
void setup() {
Session session = Session.getDefaultInstance(new Properties());
session.addProvider(new Provider(Type.TRANSPORT, "success", SuccessTransport.class.getName(), "Test", "1.0.0"));
this.mailSender = mock(JavaMailSenderImpl.class);
given(this.mailSender.getHost()).willReturn("smtp.acme.org");
given(this.mailSender.getSession()).willReturn(session);
this.indicator = new MailHealthIndicator(this.mailSender);
}
@Test
void smtpOnDefaultHostAndPortIsUp() {
given(this.mailSender.getHost()).willReturn(null);
given(this.mailSender.getPort()).willReturn(-1);
given(this.mailSender.getProtocol()).willReturn("success");
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).doesNotContainKey("location");
}
@Test
void smtpOnDefaultHostAndPortIsDown() throws MessagingException {
given(this.mailSender.getHost()).willReturn(null);
given(this.mailSender.getPort()).willReturn(-1);
willThrow(new MessagingException("A test exception")).given(this.mailSender).testConnection();
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).doesNotContainKey("location");
Object errorMessage = health.getDetails().get("error");
assertThat(errorMessage).isNotNull();
assertThat(errorMessage.toString()).contains("A test exception");
}
@Test
void smtpOnDefaultHostAndCustomPortIsUp() {
given(this.mailSender.getHost()).willReturn(null);
given(this.mailSender.getPort()).willReturn(1234);
given(this.mailSender.getProtocol()).willReturn("success");
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails().get("location")).isEqualTo(":1234");
}
@Test
void smtpOnDefaultHostAndCustomPortIsDown() throws MessagingException {
given(this.mailSender.getHost()).willReturn(null);
given(this.mailSender.getPort()).willReturn(1234);
willThrow(new MessagingException("A test exception")).given(this.mailSender).testConnection();
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails().get("location")).isEqualTo(":1234");
Object errorMessage = health.getDetails().get("error");
assertThat(errorMessage).isNotNull();
assertThat(errorMessage.toString()).contains("A test exception");
}
@Test
void smtpOnDefaultPortIsUp() {
given(this.mailSender.getPort()).willReturn(-1);
given(this.mailSender.getProtocol()).willReturn("success");
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("location", "smtp.acme.org");
}
@Test
void smtpOnDefaultPortIsDown() throws MessagingException {
given(this.mailSender.getPort()).willReturn(-1);
willThrow(new MessagingException("A test exception")).given(this.mailSender).testConnection();
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("location", "smtp.acme.org");
Object errorMessage = health.getDetails().get("error");
assertThat(errorMessage).isNotNull();
assertThat(errorMessage.toString()).contains("A test exception");
}
@Test
void smtpOnCustomPortIsUp() {
given(this.mailSender.getPort()).willReturn(1234);
given(this.mailSender.getProtocol()).willReturn("success");
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("location", "smtp.acme.org:1234");
}
@Test
void smtpOnCustomPortIsDown() throws MessagingException {
given(this.mailSender.getPort()).willReturn(1234);
willThrow(new MessagingException("A test exception")).given(this.mailSender).testConnection();
Health health = this.indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("location", "smtp.acme.org:1234");
Object errorMessage = health.getDetails().get("error");
assertThat(errorMessage).isNotNull();
assertThat(errorMessage.toString()).contains("A test exception");
}
static class SuccessTransport extends Transport {
SuccessTransport(Session session, URLName urlName) {
super(session, urlName);
}
@Override
public void connect(String host, int port, String user, String password) {
}
@Override
public void sendMessage(Message msg, Address[] addresses) {
}
}
}