diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java index 8664dae42..11a810cf1 100644 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java @@ -7,7 +7,10 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import uk.co.jemos.podam.api.PodamFactory; import uk.co.jemos.podam.api.PodamFactoryImpl; +import uk.co.jemos.podam.common.AttributeStrategy; +import javax.validation.constraints.Email; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.time.LocalDateTime; import java.util.Arrays; @@ -95,6 +98,10 @@ public class RandomUtils { return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); } + public static String randomEmail() { + return randomString() + "@qq.com"; + } + @SafeVarargs public static T randomPojo(Class clazz, Consumer... consumers) { T pojo = PODAM_FACTORY.manufacturePojo(clazz); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java index a18fb137b..e2271ceb0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java @@ -20,7 +20,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Api(tags = "管理后台 - 邮件账号") +@Api(tags = "管理后台 - 邮箱账号") @RestController @RequestMapping("/system/mail-account") public class MailAccountController { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java index d05726167..ffd150135 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java @@ -3,9 +3,7 @@ package cn.iocoder.yudao.module.system.convert.mail; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.mail.MailAccount; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountBaseVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountRespVO; -import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountSimpleRespVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.*; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -17,7 +15,9 @@ public interface MailAccountConvert { MailAccountConvert INSTANCE = Mappers.getMapper(MailAccountConvert.class); - MailAccountDO convert(MailAccountBaseVO bean); + MailAccountDO convert(MailAccountCreateReqVO bean); + + MailAccountDO convert(MailAccountUpdateReqVO bean); MailAccountRespVO convert(MailAccountDO bean); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java index b5d349439..275fc8570 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -21,6 +22,7 @@ public class MailAccountDO extends BaseDO { /** * 主键 */ + @TableId private Long id; /** * 邮箱 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java index 38be2dbb3..6b147cff6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java @@ -16,7 +16,6 @@ public interface MailLogMapper extends BaseMapperX { .eqIfPresent(MailLogDO::getUserType, reqVO.getUserType()) .likeIfPresent(MailLogDO::getToMail, reqVO.getToMail()) .eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId()) - .likeIfPresent(MailLogDO::getFromMail, reqVO.getFromMail()) .eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId()) .eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus()) .betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime()) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java index bb673a7ad..4da029e47 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -47,6 +48,7 @@ public class MailAccountServiceImpl implements MailAccountService { * * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 */ + @Getter private volatile Map mailAccountCache; @Override diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java new file mode 100755 index 000000000..ffca4b1b6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; + +/** +* {@link MailAccountServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(MailAccountServiceImpl.class) +public class MailAccountServiceImplTest extends BaseDbUnitTest { + + @Resource + private MailAccountServiceImpl mailAccountService; + + @Resource + private MailAccountMapper mailAccountMapper; + + @MockBean + private MailTemplateService mailTemplateService; + @MockBean + private MailProducer mailProducer; + + @Test + public void testInitLocalCache() { + MailAccountDO accountDO1 = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(accountDO1); + MailAccountDO accountDO02 = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(accountDO02); + + // 调用 + mailAccountService.initLocalCache(); + // 断言 mailAccountCache 缓存 + Map mailAccountCache = mailAccountService.getMailAccountCache(); + assertPojoEquals(accountDO1, mailAccountCache.get(accountDO1.getId())); + assertPojoEquals(accountDO02, mailAccountCache.get(accountDO02.getId())); + } + + @Test + public void testCreateMailAccount_success() { + // 准备参数 + MailAccountCreateReqVO reqVO = randomPojo(MailAccountCreateReqVO.class, o -> o.setMail(randomEmail())); + + // 调用 + Long mailAccountId = mailAccountService.createMailAccount(reqVO); + // 断言 + assertNotNull(mailAccountId); + // 校验记录的属性是否正确 + MailAccountDO mailAccount = mailAccountMapper.selectById(mailAccountId); + assertPojoEquals(reqVO, mailAccount); + verify(mailProducer).sendMailAccountRefreshMessage(); + } + + @Test + public void testUpdateMailAccount_success() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 + // 准备参数 + MailAccountUpdateReqVO reqVO = randomPojo(MailAccountUpdateReqVO.class, o -> { + o.setId(dbMailAccount.getId()); // 设置更新的 ID + o.setMail(randomEmail()); + }); + + // 调用 + mailAccountService.updateMailAccount(reqVO); + // 校验是否更新正确 + MailAccountDO mailAccount = mailAccountMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, mailAccount); + verify(mailProducer).sendMailAccountRefreshMessage(); + } + + @Test + public void testUpdateMailAccount_notExists() { + // 准备参数 + MailAccountUpdateReqVO reqVO = randomPojo(MailAccountUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> mailAccountService.updateMailAccount(reqVO), MAIL_ACCOUNT_NOT_EXISTS); + } + + @Test + public void testDeleteMailAccount_success() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbMailAccount.getId(); + + // 调用 + mailAccountService.deleteMailAccount(id); + // 校验数据不存在了 + assertNull(mailAccountMapper.selectById(id)); + verify(mailProducer).sendMailAccountRefreshMessage(); + } + + @Test + public void testDeleteMailAccount_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> mailAccountService.deleteMailAccount(id), MAIL_ACCOUNT_NOT_EXISTS); + } + + @Test + public void testGetMailAccountPage() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class, o -> { // 等会查询到 + o.setMail("768@qq.com"); + o.setUsername("yunai"); + }); + mailAccountMapper.insert(dbMailAccount); + // 测试 mail 不匹配 + mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setMail("788@qq.com"))); + // 测试 username 不匹配 + mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setUsername("tudou"))); + // 准备参数 + MailAccountPageReqVO reqVO = new MailAccountPageReqVO(); + reqVO.setMail("768"); + reqVO.setUsername("yu"); + + // 调用 + PageResult pageResult = mailAccountService.getMailAccountPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbMailAccount, pageResult.getList().get(0)); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql index b13b191db..b4181d16c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql @@ -25,3 +25,4 @@ DELETE FROM "system_oauth2_approve"; DELETE FROM "system_oauth2_access_token"; DELETE FROM "system_oauth2_refresh_token"; DELETE FROM "system_oauth2_code"; +DELETE FROM "system_mail_account"; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql index 7590e57a3..0ce2f0c2a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql @@ -566,3 +566,19 @@ CREATE TABLE IF NOT EXISTS "system_oauth2_code" ( "deleted" bit NOT NULL DEFAULT FALSE, PRIMARY KEY ("id") ) COMMENT 'OAuth2 刷新令牌'; + +CREATE TABLE IF NOT EXISTS "system_mail_account" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "mail" varchar NOT NULL, + "username" varchar NOT NULL, + "password" varchar NOT NULL, + "host" varchar NOT NULL, + "port" int NOT NULL, + "ssl_enable" bit NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '邮箱账号表'; diff --git a/yudao-ui-admin/src/views/system/mail/account/index.vue b/yudao-ui-admin/src/views/system/mail/account/index.vue index 96e3cc461..e64563528 100755 --- a/yudao-ui-admin/src/views/system/mail/account/index.vue +++ b/yudao-ui-admin/src/views/system/mail/account/index.vue @@ -61,7 +61,7 @@ - + @@ -98,8 +98,6 @@ export default { return { // 遮罩层 loading: true, - // 导出遮罩层 - exportLoading: false, // 显示搜索条件 showSearch: true, // 总条数