You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

83 lines
4.7 KiB

package com.mydreamjob.auth.sms;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.*;
import com.aliyun.teautil.models.RuntimeOptions;
import com.mydreamjob.common.exception.BusinessException;
import com.mydreamjob.common.exception.ErrorCode;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
class AliyunSmsCodeSenderTest {
private Client client;
private AliyunSmsCodeSender sender;
private static final String PHONE="19900009890", CODE="652901";
@BeforeEach void setup() {
client=mock(Client.class);
var config=new AliyunSmsProperties();
config.setAccessKeyId("test-key-not-real"); config.setAccessKeySecret("test-secret-not-real");
config.setSignName("测试签名"); config.setTemplateCode("SMS_TEST_ONLY");
sender=new AliyunSmsCodeSender(client,config);
}
private SendSmsResponse response(int http,String code) {
return new SendSmsResponse().setStatusCode(http).setBody(new SendSmsResponseBody().setCode(code));
}
@Test void acceptedRequestUsesApprovedSignAndTemplateAndNeverRetries() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(response(200,"OK"));
sender.sendVerificationCode(PHONE,"login",CODE);
var req=ArgumentCaptor.forClass(SendSmsRequest.class);
var runtime=ArgumentCaptor.forClass(RuntimeOptions.class);
verify(client,times(1)).sendSmsWithOptions(req.capture(),runtime.capture());
assertThat(req.getValue().getPhoneNumbers()).isEqualTo(PHONE);
assertThat(req.getValue().getSignName()).isEqualTo("测试签名");
assertThat(req.getValue().getTemplateCode()).isEqualTo("SMS_TEST_ONLY");
assertThat(req.getValue().getTemplateParam()).isEqualTo("{\"code\":\"652901\"}");
assertThat(runtime.getValue().getAutoretry()).isFalse();
assertThat(runtime.getValue().getConnectTimeout()).isEqualTo(3000);
assertThat(runtime.getValue().getReadTimeout()).isEqualTo(5000);
}
@Test void eachExistingPurposeCanSend() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(response(200,"OK"));
for(String purpose:new String[]{"login","password-set","password-reset","company-register"})
sender.sendVerificationCode(PHONE,purpose,CODE);
verify(client,times(4)).sendSmsWithOptions(any(),any());
}
@Test void providerBusinessRejectionNeverReturnsSuccess() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(response(200,"isv.BUSINESS_LIMIT_CONTROL"));
assertSafeFailure();
}
@Test void httpFailureEvenWithOkIsRejected() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(response(500,"OK")); assertSafeFailure();
}
@Test void emptyResponseIsRejected() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(null); assertSafeFailure();
}
@Test void emptyBodyIsRejected() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(new SendSmsResponse().setStatusCode(200)); assertSafeFailure();
}
@Test void missingStatusIsRejected() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenReturn(new SendSmsResponse().setBody(new SendSmsResponseBody().setCode("OK"))); assertSafeFailure();
}
@Test void exceptionContainingSecretsIsDiscardedAndNotRetried() throws Exception {
when(client.sendSmsWithOptions(any(),any())).thenThrow(new java.net.SocketTimeoutException(PHONE+CODE+"test-secret-not-real"));
assertSafeFailure(); verify(client,times(1)).sendSmsWithOptions(any(),any());
}
@Test void invalidInputsNeverCallProvider() {
for(String[] args:new String[][]{{null,"login",CODE},{"bad","login",CODE},{PHONE,null,CODE},
{PHONE,"anything",CODE},{PHONE,"login",null},{PHONE,"login","1234"},{PHONE,"login","\"malicious"}}) {
assertThatThrownBy(()->sender.sendVerificationCode(args[0],args[1],args[2])).isInstanceOf(BusinessException.class);
}
verifyNoInteractions(client);
}
private void assertSafeFailure() {
assertThatThrownBy(()->sender.sendVerificationCode(PHONE,"login",CODE)).isInstanceOf(BusinessException.class)
.satisfies(error->{
assertThat(((BusinessException)error).getErrorCodeInt()).isEqualTo(ErrorCode.SMS_SEND_FAILED.getCode());
assertThat(error).hasNoCause().hasMessage("sms send failed");
});
}
}