diff --git a/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java b/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java index 6f98748dac..39c547c4f2 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java @@ -28,8 +28,6 @@ import org.springframework.lang.Nullable; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; -import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.mail.MailOauth2Provider; import org.thingsboard.server.dao.exception.IncorrectParameterException; @@ -71,24 +69,28 @@ public class TbMailSender extends JavaMailSenderImpl { } @Override - public void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) { + protected void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) { updateOauth2PasswordIfExpired(); + doSendSuper(mimeMessages, originalMessages); + } + + protected void doSendSuper(MimeMessage[] mimeMessages, Object[] originalMessages) { super.doSend(mimeMessages, originalMessages); } @Override public void testConnection() throws MessagingException { updateOauth2PasswordIfExpired(); + testConnectionSuper(); + } + + public void testConnectionSuper() throws MessagingException { super.testConnection(); } - private void updateOauth2PasswordIfExpired() { + public void updateOauth2PasswordIfExpired() { if (oauth2Enabled && (System.currentTimeMillis() > tokenExpires)){ - try { - refreshAccessToken(); - } catch (ThingsboardException e) { - throw new RuntimeException(e); - } + refreshAccessToken(); setPassword(accessToken); } } @@ -138,7 +140,7 @@ public class TbMailSender extends JavaMailSenderImpl { return javaMailProperties; } - public void refreshAccessToken() throws ThingsboardException { + public void refreshAccessToken() { lock.lock(); try { if (System.currentTimeMillis() > tokenExpires) { @@ -164,8 +166,8 @@ public class TbMailSender extends JavaMailSenderImpl { tokenExpires = System.currentTimeMillis() + (tokenResponse.getExpiresInSeconds().intValue() * 1000); } } catch (Exception e) { - log.warn("Unable to retrieve access token: {}", e.getMessage()); - throw new ThingsboardException("Error while retrieving access token: " + e.getMessage(), ThingsboardErrorCode.GENERAL); + log.error("Unable to retrieve access token: {}", e.getMessage()); + throw new RuntimeException("Error while retrieving access token: " + e.getMessage()); } finally { lock.unlock(); } diff --git a/application/src/test/java/org/thingsboard/server/service/mail/TbMailSenderTest.java b/application/src/test/java/org/thingsboard/server/service/mail/TbMailSenderTest.java new file mode 100644 index 0000000000..9beb8a4dd8 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/mail/TbMailSenderTest.java @@ -0,0 +1,98 @@ +package org.thingsboard.server.service.mail; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.JacksonUtil; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.internet.MimeMessage; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; + +@RunWith(MockitoJUnitRunner.class) +public class TbMailSenderTest { + + @Test + public void testDoSendSendMail() { + ObjectNode jsonConfig = getBasicMailConfig(); + TbMailSender tbMailSender = spy(new TbMailSender(mock(TbMailContextComponent.class), jsonConfig)); + + MimeMessage mimeMsg = new MimeMessage(Session.getInstance(new Properties())); + List mimeMessages = new ArrayList<>(1); + mimeMessages.add(mimeMsg); + + Mockito.doNothing().when(tbMailSender).updateOauth2PasswordIfExpired(); + Mockito.doNothing().when(tbMailSender).doSendSuper(any(), any()); + + tbMailSender.doSend(mimeMessages.toArray(new MimeMessage[0]), null); + + Mockito.verify(tbMailSender, times(1)).updateOauth2PasswordIfExpired(); + } + + @Test + public void testTestConnection() throws MessagingException { + ObjectNode jsonConfig = getBasicMailConfig(); + TbMailSender tbMailSender = spy(new TbMailSender(mock(TbMailContextComponent.class), jsonConfig)); + + Mockito.doNothing().when(tbMailSender).updateOauth2PasswordIfExpired(); + Mockito.doNothing().when(tbMailSender).testConnectionSuper(); + + tbMailSender.testConnection(); + + Mockito.verify(tbMailSender, times(1)).updateOauth2PasswordIfExpired(); + } + + @Test + public void testUpdateOauth2PasswordIfExpiredIfOauth2Enabled() { + ObjectNode jsonConfig = getOauth2Config(); + TbMailSender tbMailSender = spy(new TbMailSender(mock(TbMailContextComponent.class), jsonConfig)); + + Mockito.doNothing().when(tbMailSender).refreshAccessToken(); + + tbMailSender.updateOauth2PasswordIfExpired(); + + Mockito.verify(tbMailSender, times(1)).refreshAccessToken(); + Mockito.verify(tbMailSender, times(1)).setPassword(any()); + } + + @Test + public void testUpdateOauth2PasswordIfExpiredIfOauth2Disabled() { + ObjectNode jsonConfig = getBasicMailConfig(); + TbMailSender tbMailSender = spy(new TbMailSender(mock(TbMailContextComponent.class), jsonConfig)); + + tbMailSender.updateOauth2PasswordIfExpired(); + + Mockito.verify(tbMailSender, Mockito.never()).refreshAccessToken(); + Mockito.verify(tbMailSender, Mockito.never()).setPassword(any()); + } + + private static ObjectNode getOauth2Config() { + ObjectNode jsonConfig = JacksonUtil.newObjectNode(); + jsonConfig.put("smtpProtocol", "smtps"); + jsonConfig.put("timeout", "1000"); + jsonConfig.put("enableOauth2", true); + jsonConfig.put("smtpHost", "smtp.gmail.com"); + jsonConfig.put("smtpPort", "465"); + jsonConfig.put("username", "testUser"); + return jsonConfig; + } + + private static ObjectNode getBasicMailConfig() { + ObjectNode jsonConfig = JacksonUtil.newObjectNode(); + jsonConfig.put("smtpProtocol", "smtps"); + jsonConfig.put("timeout", "1000"); + jsonConfig.put("smtpHost", "smtp.gmail.com"); + jsonConfig.put("smtpPort", "465"); + jsonConfig.put("username", "testUser"); + return jsonConfig; + } +}