Browse Source

Merge pull request #9097 from dashevchenko/emailFeatureFix

Email feature fix
pull/9119/head^2
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
21d1258fc7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 48
      application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java
  2. 95
      application/src/test/java/org/thingsboard/server/service/mail/TbMailSenderTest.java

48
application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java

@ -23,18 +23,18 @@ import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSendException;
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;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.time.Duration;
import java.time.Instant;
@ -50,6 +50,7 @@ public class TbMailSender extends JavaMailSenderImpl {
private static final String MAIL_PROP = "mail.";
private final TbMailContextComponent ctx;
private final Lock lock;
private final Boolean oauth2Enabled;
private volatile String accessToken;
private volatile long tokenExpires;
@ -70,14 +71,39 @@ public class TbMailSender extends JavaMailSenderImpl {
setJavaMailProperties(createJavaMailProperties(jsonConfig));
}
@SneakyThrows
public Boolean getOauth2Enabled() {
return oauth2Enabled;
}
public long getTokenExpires() {
return tokenExpires;
}
@Override
protected void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) throws MailException {
updateOauth2PasswordIfExpired();
doSendSuper(mimeMessages, originalMessages);
}
public void doSendSuper(MimeMessage[] mimeMessages, Object[] originalMessages) {
super.doSend(mimeMessages, originalMessages);
}
@Override
public void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) {
if (oauth2Enabled && (System.currentTimeMillis() > tokenExpires)){
public void testConnection() throws MessagingException {
updateOauth2PasswordIfExpired();
testConnectionSuper();
}
public void testConnectionSuper() throws MessagingException {
super.testConnection();
}
public void updateOauth2PasswordIfExpired() {
if (getOauth2Enabled() && (System.currentTimeMillis() > getTokenExpires())){
refreshAccessToken();
setPassword(accessToken);
}
super.doSend(mimeMessages, originalMessages);
}
private Properties createJavaMailProperties(JsonNode jsonConfig) {
@ -125,10 +151,10 @@ public class TbMailSender extends JavaMailSenderImpl {
return javaMailProperties;
}
public void refreshAccessToken() throws ThingsboardException {
public void refreshAccessToken() {
lock.lock();
try {
if (System.currentTimeMillis() > tokenExpires) {
if (System.currentTimeMillis() > getTokenExpires()) {
AdminSettings settings = ctx.getAdminSettingsService().findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
JsonNode jsonValue = settings.getJsonValue();
@ -151,8 +177,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();
}

95
application/src/test/java/org/thingsboard/server/service/mail/TbMailSenderTest.java

@ -0,0 +1,95 @@
/**
* Copyright © 2016-2023 The Thingsboard 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 org.thingsboard.server.service.mail;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mockito;
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 java.util.stream.Stream;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.willCallRealMethod;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
public class TbMailSenderTest {
private TbMailSender tbMailSender;
@BeforeEach
void setUp() {
tbMailSender = mock(TbMailSender.class);
}
@Test
public void testDoSendSendMail() {
MimeMessage mimeMsg = new MimeMessage(Session.getInstance(new Properties()));
List<MimeMessage> mimeMessages = new ArrayList<>(1);
mimeMessages.add(mimeMsg);
willCallRealMethod().given(tbMailSender).doSend(any(), any());
tbMailSender.doSend(mimeMessages.toArray(new MimeMessage[0]), null);
Mockito.verify(tbMailSender, times(1)).updateOauth2PasswordIfExpired();
Mockito.verify(tbMailSender, times(1)).doSendSuper(any(), any());
}
@Test
public void testTestConnection() throws MessagingException {
willCallRealMethod().given(tbMailSender).testConnection();
tbMailSender.testConnection();
Mockito.verify(tbMailSender, times(1)).updateOauth2PasswordIfExpired();
Mockito.verify(tbMailSender, times(1)).testConnectionSuper();
}
@ParameterizedTest
@MethodSource("provideSenderConfiguration")
public void testUpdateOauth2PasswordIfExpiredIfOauth2Enabled(boolean oauth2, long expiresIn, boolean passwordUpdateNeeded) {
willReturn(oauth2).given(tbMailSender).getOauth2Enabled();
willReturn(expiresIn).given(tbMailSender).getTokenExpires();
willCallRealMethod().given(tbMailSender).updateOauth2PasswordIfExpired();
tbMailSender.updateOauth2PasswordIfExpired();
if (passwordUpdateNeeded) {
Mockito.verify(tbMailSender, times(1)).refreshAccessToken();
Mockito.verify(tbMailSender, times(1)).setPassword(any());
} else {
Mockito.verify(tbMailSender, Mockito.never()).refreshAccessToken();
Mockito.verify(tbMailSender, Mockito.never()).setPassword(any());
}
}
private static Stream<Arguments> provideSenderConfiguration() {
return Stream.of(
Arguments.of(true, 0L, true),
Arguments.of(true, System.currentTimeMillis() + 5000, false),
Arguments.of(false, 0L, false),
Arguments.of(false, System.currentTimeMillis() + 5000, false)
);
}
}
Loading…
Cancel
Save