Commit 9a898a81fd19cc28de2a4b57ea0791b1a0acbbe5

Authored by 芋道源码
Committed by Gitee
2 parents 319c73fe c69fbe54

!783 ✅ 增加 system 和 infra 的代码覆盖率,提升稳定性

Merge pull request !783 from 芋道源码/feature/vo-optimize
Showing 53 changed files with 1767 additions and 447 deletions
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
4 4 import cn.hutool.core.util.ZipUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 8 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
8 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
9 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
... ... @@ -66,7 +67,7 @@ public class CodegenController {
66 67 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
67 68 public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
68 69 List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
69   - return success(CodegenConvert.INSTANCE.convertList05(list));
  70 + return success(BeanUtils.toBean(list, CodegenTableRespVO.class));
70 71 }
71 72  
72 73 @GetMapping("/table/page")
... ... @@ -74,7 +75,7 @@ public class CodegenController {
74 75 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
75 76 public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
76 77 PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
77   - return success(CodegenConvert.INSTANCE.convertPage(pageResult));
  78 + return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class));
78 79 }
79 80  
80 81 @GetMapping("/detail")
... ... @@ -82,7 +83,7 @@ public class CodegenController {
82 83 @Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
83 84 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
84 85 public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
85   - CodegenTableDO table = codegenService.getCodegenTablePage(tableId);
  86 + CodegenTableDO table = codegenService.getCodegenTable(tableId);
86 87 List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
87 88 // 拼装返回
88 89 return success(CodegenConvert.INSTANCE.convert(table, columns));
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java
1 1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo;
2 2  
3   -import cn.hutool.core.util.ObjectUtil;
4   -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnBaseVO;
5   -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableBaseVO;
6   -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
7   -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
8   -import com.fasterxml.jackson.annotation.JsonIgnore;
  3 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
  4 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableSaveReqVO;
9 5 import io.swagger.v3.oas.annotations.media.Schema;
10 6 import lombok.Data;
11   -import lombok.EqualsAndHashCode;
12   -import lombok.ToString;
13 7  
14 8 import javax.validation.Valid;
15   -import javax.validation.constraints.AssertTrue;
16 9 import javax.validation.constraints.NotNull;
17 10 import java.util.List;
18 11  
... ... @@ -22,55 +15,10 @@ public class CodegenUpdateReqVO {
22 15  
23 16 @Valid // 校验内嵌的字段
24 17 @NotNull(message = "表定义不能为空")
25   - private Table table;
  18 + private CodegenTableSaveReqVO table;
26 19  
27 20 @Valid // 校验内嵌的字段
28 21 @NotNull(message = "字段定义不能为空")
29   - private List<Column> columns;
30   -
31   - @Schema(description = "更新表定义")
32   - @Data
33   - @EqualsAndHashCode(callSuper = true)
34   - @ToString(callSuper = true)
35   - @Valid
36   - public static class Table extends CodegenTableBaseVO {
37   -
38   - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
39   - private Long id;
40   -
41   - @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
42   - @JsonIgnore
43   - public boolean isParentMenuIdValid() {
44   - // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
45   - return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
46   - || getParentMenuId() != null;
47   - }
48   -
49   - @AssertTrue(message = "关联的父表信息不全")
50   - @JsonIgnore
51   - public boolean isSubValid() {
52   - return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
53   - || (ObjectUtil.isAllNotEmpty(getMasterTableId(), getSubJoinColumnId(), getSubJoinMany()));
54   - }
55   -
56   - @AssertTrue(message = "关联的树表信息不全")
57   - @JsonIgnore
58   - public boolean isTreeValid() {
59   - return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.TREE)
60   - || (ObjectUtil.isAllNotEmpty(getTreeParentColumnId(), getTreeNameColumnId()));
61   - }
62   -
63   - }
64   -
65   - @Schema(description = "更新表定义")
66   - @Data
67   - @EqualsAndHashCode(callSuper = true)
68   - @ToString(callSuper = true)
69   - public static class Column extends CodegenColumnBaseVO {
70   -
71   - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
72   - private Long id;
73   -
74   - }
  22 + private List<CodegenColumnSaveReqVO> columns;
75 23  
76 24 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java
... ... @@ -2,20 +2,70 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7 5  
8 6 import java.time.LocalDateTime;
9 7  
10 8 @Schema(description = "管理后台 - 代码生成字段定义 Response VO")
11 9 @Data
12   -@EqualsAndHashCode(callSuper = true)
13   -@ToString(callSuper = true)
14   -public class CodegenColumnRespVO extends CodegenColumnBaseVO {
  10 +public class CodegenColumnRespVO {
15 11  
16 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 13 private Long id;
18 14  
  15 + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Long tableId;
  17 +
  18 + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
  19 + private String columnName;
  20 +
  21 + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
  22 + private String dataType;
  23 +
  24 + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
  25 + private String columnComment;
  26 +
  27 + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  28 + private Boolean nullable;
  29 +
  30 + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  31 + private Boolean primaryKey;
  32 +
  33 + @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + private Boolean autoIncrement;
  35 +
  36 + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  37 + private Integer ordinalPosition;
  38 +
  39 + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
  40 + private String javaType;
  41 +
  42 + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
  43 + private String javaField;
  44 +
  45 + @Schema(description = "字典类型", example = "sys_gender")
  46 + private String dictType;
  47 +
  48 + @Schema(description = "数据示例", example = "1024")
  49 + private String example;
  50 +
  51 + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  52 + private Boolean createOperation;
  53 +
  54 + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  55 + private Boolean updateOperation;
  56 +
  57 + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  58 + private Boolean listOperation;
  59 +
  60 + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
  61 + private String listOperationCondition;
  62 +
  63 + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  64 + private Boolean listOperationResult;
  65 +
  66 + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
  67 + private String htmlType;
  68 +
19 69 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 70 private LocalDateTime createTime;
21 71  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnBaseVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java
... ... @@ -5,12 +5,12 @@ import lombok.Data;
5 5  
6 6 import javax.validation.constraints.NotNull;
7 7  
8   -/**
9   -* 代码生成字段定义 Base VO,提供给添加、修改、详细的子 VO 使用
10   -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
11   -*/
  8 +@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO")
12 9 @Data
13   -public class CodegenColumnBaseVO {
  10 +public class CodegenColumnSaveReqVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  13 + private Long id;
14 14  
15 15 @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 16 @NotNull(message = "表编号不能为空")
... ... @@ -38,7 +38,7 @@ public class CodegenColumnBaseVO {
38 38  
39 39 @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
40 40 @NotNull(message = "是否自增不能为空")
41   - private String autoIncrement;
  41 + private Boolean autoIncrement;
42 42  
43 43 @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
44 44 @NotNull(message = "排序不能为空")
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java
... ... @@ -2,20 +2,64 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7 5  
8 6 import java.time.LocalDateTime;
9 7  
10 8 @Schema(description = "管理后台 - 代码生成表定义 Response VO")
11 9 @Data
12   -@EqualsAndHashCode(callSuper = true)
13   -@ToString(callSuper = true)
14   -public class CodegenTableRespVO extends CodegenTableBaseVO {
  10 +public class CodegenTableRespVO {
15 11  
16 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 13 private Long id;
18 14  
  15 + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer scene;
  17 +
  18 + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
  19 + private String tableName;
  20 +
  21 + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
  22 + private String tableComment;
  23 +
  24 + @Schema(description = "备注", example = "我是备注")
  25 + private String remark;
  26 +
  27 + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
  28 + private String moduleName;
  29 +
  30 + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
  31 + private String businessName;
  32 +
  33 + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
  34 + private String className;
  35 +
  36 + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
  37 + private String classComment;
  38 +
  39 + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  40 + private String author;
  41 +
  42 + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  43 + private Integer templateType;
  44 +
  45 + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  46 + private Integer frontType;
  47 +
  48 + @Schema(description = "父菜单编号", example = "1024")
  49 + private Long parentMenuId;
  50 +
  51 + @Schema(description = "主表的编号", example = "2048")
  52 + private Long masterTableId;
  53 + @Schema(description = "子表关联主表的字段编号", example = "4096")
  54 + private Long subJoinColumnId;
  55 + @Schema(description = "主表与子表是否一对多", example = "4096")
  56 + private Boolean subJoinMany;
  57 +
  58 + @Schema(description = "树表的父字段编号", example = "8192")
  59 + private Long treeParentColumnId;
  60 + @Schema(description = "树表的名字字段编号", example = "16384")
  61 + private Long treeNameColumnId;
  62 +
19 63 @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
20 64 private Integer dataSourceConfigId;
21 65  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java
1 1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
2 2  
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  5 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 7 import io.swagger.v3.oas.annotations.media.Schema;
4 8 import lombok.Data;
5 9  
  10 +import javax.validation.constraints.AssertTrue;
6 11 import javax.validation.constraints.NotNull;
7 12  
8   -/**
9   - * 代码生成 Base VO,提供给添加、修改、详细的子 VO 使用
10   - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
11   - */
  13 +@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO")
12 14 @Data
13   -public class CodegenTableBaseVO {
  15 +public class CodegenTableSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Long id;
14 19  
15 20 @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 21 @NotNull(message = "导入类型不能为空")
... ... @@ -70,4 +75,26 @@ public class CodegenTableBaseVO {
70 75 @Schema(description = "树表的名字字段编号", example = "16384")
71 76 private Long treeNameColumnId;
72 77  
  78 + @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
  79 + @JsonIgnore
  80 + public boolean isParentMenuIdValid() {
  81 + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
  82 + return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
  83 + || getParentMenuId() != null;
  84 + }
  85 +
  86 + @AssertTrue(message = "关联的父表信息不全")
  87 + @JsonIgnore
  88 + public boolean isSubValid() {
  89 + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
  90 + || (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany));
  91 + }
  92 +
  93 + @AssertTrue(message = "关联的树表信息不全")
  94 + @JsonIgnore
  95 + public boolean isTreeValid() {
  96 + return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE)
  97 + || (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId));
  98 + }
  99 +
73 100 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
1 1 package cn.iocoder.yudao.module.infra.convert.codegen;
2 2  
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
5 6 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO;
6   -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
7 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO;
8 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO;
9   -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
10 9 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
11 10 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
12 11 import com.baomidou.mybatisplus.generator.config.po.TableField;
... ... @@ -20,7 +19,6 @@ import org.mapstruct.factory.Mappers;
20 19  
21 20 import java.util.List;
22 21 import java.util.Map;
23   -import java.util.stream.Collectors;
24 22  
25 23 @Mapper
26 24 public interface CodegenConvert {
... ... @@ -54,40 +52,18 @@ public interface CodegenConvert {
54 52 return jdbcType.name();
55 53 }
56 54  
57   - // ========== CodegenTableDO 相关 ==========
58   -
59   - List<CodegenTableRespVO> convertList05(List<CodegenTableDO> list);
60   -
61   - CodegenTableRespVO convert(CodegenTableDO bean);
62   -
63   - PageResult<CodegenTableRespVO> convertPage(PageResult<CodegenTableDO> page);
64   -
65   - // ========== CodegenTableDO 相关 ==========
66   -
67   - List<CodegenColumnRespVO> convertList02(List<CodegenColumnDO> list);
68   -
69   - CodegenTableDO convert(CodegenUpdateReqVO.Table bean);
70   -
71   - List<CodegenColumnDO> convertList03(List<CodegenUpdateReqVO.Column> columns);
72   -
73   - List<DatabaseTableRespVO> convertList04(List<TableInfo> list);
74   -
75 55 // ========== 其它 ==========
76 56  
77 57 default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) {
78 58 CodegenDetailRespVO respVO = new CodegenDetailRespVO();
79   - respVO.setTable(convert(table));
80   - respVO.setColumns(convertList02(columns));
  59 + respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class));
  60 + respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class));
81 61 return respVO;
82 62 }
83 63  
84 64 default List<CodegenPreviewRespVO> convert(Map<String, String> codes) {
85   - return codes.entrySet().stream().map(entry -> {
86   - CodegenPreviewRespVO respVO = new CodegenPreviewRespVO();
87   - respVO.setFilePath(entry.getKey());
88   - respVO.setCode(entry.getValue());
89   - return respVO;
90   - }).collect(Collectors.toList());
  65 + return CollectionUtils.convertList(codes.entrySet(),
  66 + entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue()));
91 67 }
92 68  
93 69 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java
... ... @@ -70,7 +70,7 @@ public interface CodegenService {
70 70 * @param id 表编号
71 71 * @return 表定义
72 72 */
73   - CodegenTableDO getCodegenTablePage(Long id);
  73 + CodegenTableDO getCodegenTable(Long id);
74 74  
75 75 /**
76 76 * 获得指定表的字段定义数组
... ... @@ -91,7 +91,6 @@ public interface CodegenService {
91 91 /**
92 92 * 获得数据库自带的表定义列表
93 93 *
94   - *
95 94 * @param dataSourceConfigId 数据源的配置编号
96 95 * @param name 表名称
97 96 * @param comment 表描述
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java
... ... @@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.infra.service.codegen;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
8 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
9 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
10 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
11   -import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
12 11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
13 12 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
14 13 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
... ... @@ -22,6 +21,7 @@ import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
22 21 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
23 22 import com.baomidou.mybatisplus.generator.config.po.TableField;
24 23 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  24 +import com.google.common.annotations.VisibleForTesting;
25 25 import org.springframework.stereotype.Service;
26 26 import org.springframework.transaction.annotation.Transactional;
27 27  
... ... @@ -31,6 +31,8 @@ import java.util.function.BiPredicate;
31 31 import java.util.stream.Collectors;
32 32  
33 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
34 36 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
35 37  
36 38 /**
... ... @@ -69,7 +71,7 @@ public class CodegenServiceImpl implements CodegenService {
69 71 return ids;
70 72 }
71 73  
72   - public Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
  74 + private Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
73 75 // 从数据库中,获得数据库表结构
74 76 TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName);
75 77 // 导入
... ... @@ -103,7 +105,8 @@ public class CodegenServiceImpl implements CodegenService {
103 105 return table.getId();
104 106 }
105 107  
106   - private void validateTableInfo(TableInfo tableInfo) {
  108 + @VisibleForTesting
  109 + void validateTableInfo(TableInfo tableInfo) {
107 110 if (tableInfo == null) {
108 111 throw exception(CODEGEN_IMPORT_TABLE_NULL);
109 112 }
... ... @@ -139,10 +142,10 @@ public class CodegenServiceImpl implements CodegenService {
139 142 }
140 143  
141 144 // 更新 table 表定义
142   - CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable());
  145 + CodegenTableDO updateTableObj = BeanUtils.toBean(updateReqVO.getTable(), CodegenTableDO.class);
143 146 codegenTableMapper.updateById(updateTableObj);
144 147 // 更新 column 字段定义
145   - List<CodegenColumnDO> updateColumnObjs = CodegenConvert.INSTANCE.convertList03(updateReqVO.getColumns());
  148 + List<CodegenColumnDO> updateColumnObjs = BeanUtils.toBean(updateReqVO.getColumns(), CodegenColumnDO.class);
146 149 updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj));
147 150 }
148 151  
... ... @@ -161,29 +164,28 @@ public class CodegenServiceImpl implements CodegenService {
161 164 }
162 165  
163 166 private void syncCodegen0(Long tableId, TableInfo tableInfo) {
164   - // 校验导入的表和字段非空
  167 + // 1. 校验导入的表和字段非空
165 168 validateTableInfo(tableInfo);
166 169 List<TableField> tableFields = tableInfo.getFields();
167 170  
168   - // 构建 CodegenColumnDO 数组,只同步新增的字段
  171 + // 2. 构建 CodegenColumnDO 数组,只同步新增的字段
169 172 List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
170   - Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName);
  173 + Set<String> codegenColumnNames = convertSet(codegenColumns, CodegenColumnDO::getColumnName);
171 174  
172   - //计算需要修改的字段,插入时重新插入,删除时将原来的删除
173   - BiPredicate<TableField, CodegenColumnDO> pr =
  175 + // 3.1 计算需要【修改】的字段,插入时重新插入,删除时将原来的删除
  176 + Map<String, CodegenColumnDO> codegenColumnDOMap = convertMap(codegenColumns, CodegenColumnDO::getColumnName);
  177 + BiPredicate<TableField, CodegenColumnDO> primaryKeyPredicate =
174 178 (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType())
175 179 && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable()
176 180 && tableField.isKeyFlag() == codegenColumn.getPrimaryKey()
177 181 && tableField.getComment().equals(codegenColumn.getColumnComment());
178   - Map<String, CodegenColumnDO> codegenColumnDOMap = CollectionUtils.convertMap(codegenColumns, CodegenColumnDO::getColumnName);
179   - //需要修改的字段
180 182 Set<String> modifyFieldNames = tableFields.stream()
181 183 .filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null
182   - && !pr.test(tableField, codegenColumnDOMap.get(tableField.getColumnName())))
  184 + && !primaryKeyPredicate.test(tableField, codegenColumnDOMap.get(tableField.getColumnName())))
183 185 .map(TableField::getColumnName)
184 186 .collect(Collectors.toSet());
185   - // 计算需要删除的字段
186   - Set<String> tableFieldNames = CollectionUtils.convertSet(tableFields, TableField::getName);
  187 + // 3.2 计算需要【删除】的字段
  188 + Set<String> tableFieldNames = convertSet(tableFields, TableField::getName);
187 189 Set<Long> deleteColumnIds = codegenColumns.stream()
188 190 .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName()))
189 191 .map(CodegenColumnDO::getId).collect(Collectors.toSet());
... ... @@ -193,10 +195,10 @@ public class CodegenServiceImpl implements CodegenService {
193 195 throw exception(CODEGEN_SYNC_NONE_CHANGE);
194 196 }
195 197  
196   - // 插入新增的字段
  198 + // 4.1 插入新增的字段
197 199 List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
198 200 codegenColumnMapper.insertBatch(columns);
199   - // 删除不存在的字段
  201 + // 4.2 删除不存在的字段
200 202 if (CollUtil.isNotEmpty(deleteColumnIds)) {
201 203 codegenColumnMapper.deleteBatchIds(deleteColumnIds);
202 204 }
... ... @@ -227,7 +229,7 @@ public class CodegenServiceImpl implements CodegenService {
227 229 }
228 230  
229 231 @Override
230   - public CodegenTableDO getCodegenTablePage(Long id) {
  232 + public CodegenTableDO getCodegenTable(Long id) {
231 233 return codegenTableMapper.selectById(id);
232 234 }
233 235  
... ... @@ -277,10 +279,10 @@ public class CodegenServiceImpl implements CodegenService {
277 279 public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
278 280 List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
279 281 // 移除在 Codegen 中,已经存在的
280   - Set<String> existsTables = CollectionUtils.convertSet(
  282 + Set<String> existsTables = convertSet(
281 283 codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);
282 284 tables.removeIf(table -> existsTables.contains(table.getName()));
283   - return CodegenConvert.INSTANCE.convertList04(tables);
  285 + return BeanUtils.toBean(tables, DatabaseTableRespVO.class);
284 286 }
285 287  
286 288 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobService.java
... ... @@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO;
7 7 import org.quartz.SchedulerException;
8 8  
9 9 import javax.validation.Valid;
10   -import java.util.Collection;
11   -import java.util.List;
12 10  
13 11 /**
14 12 * 定时任务 Service 接口
... ... @@ -63,14 +61,6 @@ public interface JobService {
63 61 JobDO getJob(Long id);
64 62  
65 63 /**
66   - * 获得定时任务列表
67   - *
68   - * @param ids 编号
69   - * @return 定时任务列表
70   - */
71   - List<JobDO> getJobList(Collection<Long> ids);
72   -
73   - /**
74 64 * 获得定时任务分页
75 65 *
76 66 * @param pageReqVO 分页查询
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java
... ... @@ -148,11 +148,6 @@ public class JobServiceImpl implements JobService {
148 148 }
149 149  
150 150 @Override
151   - public List<JobDO> getJobList(Collection<Long> ids) {
152   - return jobMapper.selectBatchIds(ids);
153   - }
154   -
155   - @Override
156 151 public PageResult<JobDO> getJobPage(JobPageReqVO pageReqVO) {
157 152 return jobMapper.selectPage(pageReqVO);
158 153 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
... ... @@ -269,7 +269,7 @@ const queryParams = reactive({
269 269 #foreach ($column in $columns)
270 270 #if ($column.listOperation)
271 271 #if ($column.listOperationCondition != 'BETWEEN')
272   - $column.javaField: null,
  272 + $column.javaField: undefined,
273 273 #end
274 274 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
275 275 $column.javaField: [],
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen;
  2 +
  3 +import cn.hutool.core.collection.ListUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  13 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  14 +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
  15 +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
  16 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
  17 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  18 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  19 +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
  20 +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
  21 +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
  22 +import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
  23 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  24 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  25 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  26 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  27 +import org.junit.jupiter.api.Test;
  28 +import org.springframework.boot.test.mock.mockito.MockBean;
  29 +import org.springframework.context.annotation.Import;
  30 +
  31 +import javax.annotation.Resource;
  32 +import java.util.Arrays;
  33 +import java.util.Collections;
  34 +import java.util.List;
  35 +import java.util.Map;
  36 +
  37 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  38 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  39 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  40 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  41 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  42 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  43 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  44 +import static org.junit.jupiter.api.Assertions.*;
  45 +import static org.mockito.ArgumentMatchers.*;
  46 +import static org.mockito.Mockito.mock;
  47 +import static org.mockito.Mockito.when;
  48 +
  49 +/**
  50 + * {@link CodegenServiceImpl} 的单元测试类
  51 + *
  52 + * @author 芋道源码
  53 + */
  54 +@Import(CodegenServiceImpl.class)
  55 +public class CodegenServiceImplTest extends BaseDbUnitTest {
  56 +
  57 + @Resource
  58 + private CodegenServiceImpl codegenService;
  59 +
  60 + @Resource
  61 + private CodegenTableMapper codegenTableMapper;
  62 + @Resource
  63 + private CodegenColumnMapper codegenColumnMapper;
  64 +
  65 + @MockBean
  66 + private DatabaseTableService databaseTableService;
  67 +
  68 + @MockBean
  69 + private AdminUserApi userApi;
  70 +
  71 + @MockBean
  72 + private CodegenBuilder codegenBuilder;
  73 + @MockBean
  74 + private CodegenEngine codegenEngine;
  75 +
  76 + @MockBean
  77 + private CodegenProperties codegenProperties;
  78 +
  79 + @Test
  80 + public void testCreateCodegenList() {
  81 + // 准备参数
  82 + Long userId = randomLongId();
  83 + CodegenCreateListReqVO reqVO = randomPojo(CodegenCreateListReqVO.class,
  84 + o -> o.setDataSourceConfigId(1L).setTableNames(Collections.singletonList("t_yunai")));
  85 + // mock 方法(TableInfo)
  86 + TableInfo tableInfo = mock(TableInfo.class);
  87 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  88 + .thenReturn(tableInfo);
  89 + when(tableInfo.getComment()).thenReturn("芋艿");
  90 + // mock 方法(TableInfo fields)
  91 + TableField field01 = mock(TableField.class);
  92 + when(field01.getComment()).thenReturn("主键");
  93 + TableField field02 = mock(TableField.class);
  94 + when(field02.getComment()).thenReturn("名字");
  95 + List<TableField> fields = Arrays.asList(field01, field02);
  96 + when(tableInfo.getFields()).thenReturn(fields);
  97 + // mock 方法(CodegenTableDO)
  98 + CodegenTableDO table = randomPojo(CodegenTableDO.class);
  99 + when(codegenBuilder.buildTable(same(tableInfo))).thenReturn(table);
  100 + // mock 方法(AdminUserRespDTO)
  101 + AdminUserRespDTO user = randomPojo(AdminUserRespDTO.class, o -> o.setNickname("芋头"));
  102 + when(userApi.getUser(eq(userId))).thenReturn(user);
  103 + // mock 方法(CodegenColumnDO)
  104 + List<CodegenColumnDO> columns = randomPojoList(CodegenColumnDO.class);
  105 + when(codegenBuilder.buildColumns(eq(table.getId()), same(fields)))
  106 + .thenReturn(columns);
  107 + // mock 方法(CodegenProperties)
  108 + when(codegenProperties.getFrontType()).thenReturn(CodegenFrontTypeEnum.VUE3.getType());
  109 +
  110 + // 调用
  111 + List<Long> result = codegenService.createCodegenList(userId, reqVO);
  112 + // 断言
  113 + assertEquals(1, result.size());
  114 + // 断言(CodegenTableDO)
  115 + CodegenTableDO dbTable = codegenTableMapper.selectList().get(0);
  116 + assertPojoEquals(table, dbTable);
  117 + assertEquals(1L, dbTable.getDataSourceConfigId());
  118 + assertEquals(CodegenSceneEnum.ADMIN.getScene(), dbTable.getScene());
  119 + assertEquals(CodegenFrontTypeEnum.VUE3.getType(), dbTable.getFrontType());
  120 + assertEquals("芋头", dbTable.getAuthor());
  121 + // 断言(CodegenColumnDO)
  122 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  123 + assertEquals(columns.size(), dbColumns.size());
  124 + assertTrue(dbColumns.get(0).getPrimaryKey());
  125 + for (int i = 0; i < dbColumns.size(); i++) {
  126 + assertPojoEquals(columns.get(i), dbColumns.get(i));
  127 + }
  128 + }
  129 +
  130 + @Test
  131 + public void testValidateTableInfo() {
  132 + // 情况一
  133 + assertServiceException(() -> codegenService.validateTableInfo(null),
  134 + CODEGEN_IMPORT_TABLE_NULL);
  135 + // 情况二
  136 + TableInfo tableInfo = mock(TableInfo.class);
  137 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  138 + CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL);
  139 + // 情况三
  140 + when(tableInfo.getComment()).thenReturn("芋艿");
  141 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  142 + CODEGEN_IMPORT_COLUMNS_NULL);
  143 + // 情况四
  144 + TableField field = mock(TableField.class);
  145 + when(field.getName()).thenReturn("name");
  146 + when(tableInfo.getFields()).thenReturn(Collections.singletonList(field));
  147 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  148 + CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName());
  149 + }
  150 +
  151 + @Test
  152 + public void testUpdateCodegen_notExists() {
  153 + // 准备参数
  154 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class);
  155 + // mock 方法
  156 +
  157 + // 调用,并断言
  158 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  159 + CODEGEN_TABLE_NOT_EXISTS);
  160 + }
  161 +
  162 + @Test
  163 + public void testUpdateCodegen_sub_masterNotExists() {
  164 + // mock 数据
  165 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  166 + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  167 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  168 + codegenTableMapper.insert(table);
  169 + // 准备参数
  170 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  171 + o -> o.getTable().setId(table.getId())
  172 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()));
  173 +
  174 + // 调用,并断言
  175 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  176 + CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId());
  177 + }
  178 +
  179 + @Test
  180 + public void testUpdateCodegen_sub_columnNotExists() {
  181 + // mock 数据
  182 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  183 + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  184 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  185 + codegenTableMapper.insert(subTable);
  186 + // mock 数据(master)
  187 + CodegenTableDO masterTable = randomPojo(CodegenTableDO.class,
  188 + o -> o.setTemplateType(CodegenTemplateTypeEnum.MASTER_ERP.getType())
  189 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  190 + codegenTableMapper.insert(masterTable);
  191 + // 准备参数
  192 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  193 + o -> o.getTable().setId(subTable.getId())
  194 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  195 + .setMasterTableId(masterTable.getId()));
  196 +
  197 + // 调用,并断言
  198 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  199 + CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId());
  200 + }
  201 +
  202 + @Test
  203 + public void testUpdateCodegen_success() {
  204 + // mock 数据
  205 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  206 + o -> o.setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
  207 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  208 + codegenTableMapper.insert(table);
  209 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  210 + codegenColumnMapper.insert(column01);
  211 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  212 + codegenColumnMapper.insert(column02);
  213 + // 准备参数
  214 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  215 + o -> o.getTable().setId(table.getId())
  216 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
  217 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  218 + CodegenColumnSaveReqVO columnVO01 = randomPojo(CodegenColumnSaveReqVO.class,
  219 + o -> o.setId(column01.getId()).setTableId(table.getId()));
  220 + CodegenColumnSaveReqVO columnVO02 = randomPojo(CodegenColumnSaveReqVO.class,
  221 + o -> o.setId(column02.getId()).setTableId(table.getId()));
  222 + updateReqVO.setColumns(Arrays.asList(columnVO01, columnVO02));
  223 +
  224 + // 调用
  225 + codegenService.updateCodegen(updateReqVO);
  226 + // 断言
  227 + CodegenTableDO dbTable = codegenTableMapper.selectById(table.getId());
  228 + assertPojoEquals(updateReqVO.getTable(), dbTable);
  229 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  230 + assertEquals(2, dbColumns.size());
  231 + assertPojoEquals(columnVO01, dbColumns.get(0));
  232 + assertPojoEquals(columnVO02, dbColumns.get(1));
  233 + }
  234 +
  235 + @Test
  236 + public void testSyncCodegenFromDB() {
  237 + // mock 数据(CodegenTableDO)
  238 + CodegenTableDO table = randomPojo(CodegenTableDO.class, o -> o.setTableName("t_yunai")
  239 + .setDataSourceConfigId(1L).setScene(CodegenSceneEnum.ADMIN.getScene()));
  240 + codegenTableMapper.insert(table);
  241 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
  242 + .setColumnName("id"));
  243 + codegenColumnMapper.insert(column01);
  244 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
  245 + .setColumnName("name"));
  246 + codegenColumnMapper.insert(column02);
  247 + // 准备参数
  248 + Long tableId = table.getId();
  249 + // mock 方法(TableInfo)
  250 + TableInfo tableInfo = mock(TableInfo.class);
  251 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  252 + .thenReturn(tableInfo);
  253 + when(tableInfo.getComment()).thenReturn("芋艿");
  254 + // mock 方法(TableInfo fields)
  255 + TableField field01 = mock(TableField.class);
  256 + when(field01.getComment()).thenReturn("主键");
  257 + TableField field03 = mock(TableField.class);
  258 + when(field03.getComment()).thenReturn("分类");
  259 + List<TableField> fields = Arrays.asList(field01, field03);
  260 + when(tableInfo.getFields()).thenReturn(fields);
  261 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  262 + .thenReturn(tableInfo);
  263 + // mock 方法(CodegenTableDO)
  264 + List<CodegenColumnDO> newColumns = randomPojoList(CodegenColumnDO.class);
  265 + when(codegenBuilder.buildColumns(eq(table.getId()), argThat(tableFields -> {
  266 + assertEquals(2, tableFields.size());
  267 + assertSame(tableInfo.getFields(), tableFields);
  268 + return true;
  269 + }))).thenReturn(newColumns);
  270 +
  271 + // 调用
  272 + codegenService.syncCodegenFromDB(tableId);
  273 + // 断言
  274 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  275 + assertEquals(newColumns.size(), dbColumns.size());
  276 + assertPojoEquals(newColumns.get(0), dbColumns.get(0));
  277 + assertPojoEquals(newColumns.get(1), dbColumns.get(1));
  278 + }
  279 +
  280 + @Test
  281 + public void testDeleteCodegen_notExists() {
  282 + assertServiceException(() -> codegenService.deleteCodegen(randomLongId()),
  283 + CODEGEN_TABLE_NOT_EXISTS);
  284 + }
  285 +
  286 + @Test
  287 + public void testDeleteCodegen_success() {
  288 + // mock 数据
  289 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  290 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  291 + codegenTableMapper.insert(table);
  292 + CodegenColumnDO column = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  293 + codegenColumnMapper.insert(column);
  294 + // 准备参数
  295 + Long tableId = table.getId();
  296 +
  297 + // 调用
  298 + codegenService.deleteCodegen(tableId);
  299 + // 断言
  300 + assertNull(codegenTableMapper.selectById(tableId));
  301 + assertEquals(0, codegenColumnMapper.selectList().size());
  302 + }
  303 +
  304 + @Test
  305 + public void testGetCodegenTableList() {
  306 + // mock 数据
  307 + CodegenTableDO table01 = randomPojo(CodegenTableDO.class,
  308 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  309 + codegenTableMapper.insert(table01);
  310 + CodegenTableDO table02 = randomPojo(CodegenTableDO.class,
  311 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  312 + codegenTableMapper.insert(table02);
  313 + // 准备参数
  314 + Long dataSourceConfigId = table01.getDataSourceConfigId();
  315 +
  316 + // 调用
  317 + List<CodegenTableDO> result = codegenService.getCodegenTableList(dataSourceConfigId);
  318 + // 断言
  319 + assertEquals(1, result.size());
  320 + assertPojoEquals(table01, result.get(0));
  321 + }
  322 +
  323 + @Test
  324 + public void testGetCodegenTablePage() {
  325 + // mock 数据
  326 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> {
  327 + o.setTableName("t_yunai");
  328 + o.setTableComment("芋艿");
  329 + o.setClassName("SystemYunai");
  330 + o.setCreateTime(buildTime(2021, 3, 10));
  331 + }).setScene(CodegenSceneEnum.ADMIN.getScene());
  332 + codegenTableMapper.insert(tableDO);
  333 + // 测试 tableName 不匹配
  334 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableName(randomString())));
  335 + // 测试 tableComment 不匹配
  336 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableComment(randomString())));
  337 + // 测试 className 不匹配
  338 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setClassName(randomString())));
  339 + // 测试 createTime 不匹配
  340 + codegenTableMapper.insert(cloneIgnoreId(tableDO, logDO -> logDO.setCreateTime(buildTime(2021, 4, 10))));
  341 + // 准备参数
  342 + CodegenTablePageReqVO reqVO = new CodegenTablePageReqVO();
  343 + reqVO.setTableName("yunai");
  344 + reqVO.setTableComment("芋");
  345 + reqVO.setClassName("Yunai");
  346 + reqVO.setCreateTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31));
  347 +
  348 + // 调用
  349 + PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(reqVO);
  350 + // 断言,只查到了一条符合条件的
  351 + assertEquals(1, pageResult.getTotal());
  352 + assertEquals(1, pageResult.getList().size());
  353 + assertPojoEquals(tableDO, pageResult.getList().get(0));
  354 + }
  355 +
  356 + @Test
  357 + public void testGetCodegenTable() {
  358 + // mock 数据
  359 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  360 + codegenTableMapper.insert(tableDO);
  361 + // 准备参数
  362 + Long id = tableDO.getId();
  363 +
  364 + // 调用
  365 + CodegenTableDO result = codegenService.getCodegenTable(id);
  366 + // 断言
  367 + assertPojoEquals(tableDO, result);
  368 + }
  369 +
  370 + @Test
  371 + public void testGetCodegenColumnListByTableId() {
  372 + // mock 数据
  373 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class);
  374 + codegenColumnMapper.insert(column01);
  375 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class);
  376 + codegenColumnMapper.insert(column02);
  377 + // 准备参数
  378 + Long tableId = column01.getTableId();
  379 +
  380 + // 调用
  381 + List<CodegenColumnDO> result = codegenService.getCodegenColumnListByTableId(tableId);
  382 + // 断言
  383 + assertEquals(1, result.size());
  384 + assertPojoEquals(column01, result.get(0));
  385 + }
  386 +
  387 + @Test
  388 + public void testGenerationCodes_tableNotExists() {
  389 + assertServiceException(() -> codegenService.generationCodes(randomLongId()),
  390 + CODEGEN_TABLE_NOT_EXISTS);
  391 + }
  392 +
  393 + @Test
  394 + public void testGenerationCodes_columnNotExists() {
  395 + // mock 数据(CodegenTableDO)
  396 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  397 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  398 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  399 + codegenTableMapper.insert(table);
  400 + // 准备参数
  401 + Long tableId = table.getId();
  402 +
  403 + // 调用,并断言
  404 + assertServiceException(() -> codegenService.generationCodes(tableId),
  405 + CODEGEN_COLUMN_NOT_EXISTS);
  406 + }
  407 +
  408 + @Test
  409 + public void testGenerationCodes_sub_tableNotExists() {
  410 + // mock 数据(CodegenTableDO)
  411 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  412 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  413 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  414 + codegenTableMapper.insert(table);
  415 + // mock 数据(CodegenColumnDO)
  416 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  417 + codegenColumnMapper.insert(column01);
  418 + // 准备参数
  419 + Long tableId = table.getId();
  420 +
  421 + // 调用,并断言
  422 + assertServiceException(() -> codegenService.generationCodes(tableId),
  423 + CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE);
  424 + }
  425 +
  426 + @Test
  427 + public void testGenerationCodes_sub_columnNotExists() {
  428 + // mock 数据(CodegenTableDO)
  429 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  430 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  431 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  432 + codegenTableMapper.insert(table);
  433 + // mock 数据(CodegenColumnDO)
  434 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  435 + codegenColumnMapper.insert(column01);
  436 + // mock 数据(sub CodegenTableDO)
  437 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  438 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  439 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  440 + .setMasterTableId(table.getId()));
  441 + codegenTableMapper.insert(subTable);
  442 + // 准备参数
  443 + Long tableId = table.getId();
  444 +
  445 + // 调用,并断言
  446 + assertServiceException(() -> codegenService.generationCodes(tableId),
  447 + CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId());
  448 + }
  449 +
  450 + @Test
  451 + public void testGenerationCodes_one_success() {
  452 + // mock 数据(CodegenTableDO)
  453 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  454 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  455 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()));
  456 + codegenTableMapper.insert(table);
  457 + // mock 数据(CodegenColumnDO)
  458 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  459 + codegenColumnMapper.insert(column01);
  460 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  461 + codegenColumnMapper.insert(column02);
  462 + // mock 执行生成
  463 + Map<String, String> codes = MapUtil.of(randomString(), randomString());
  464 + when(codegenEngine.execute(eq(table), argThat(columns -> {
  465 + assertEquals(2, columns.size());
  466 + assertEquals(column01, columns.get(0));
  467 + assertEquals(column02, columns.get(1));
  468 + return true;
  469 + }), isNull(), isNull())).thenReturn(codes);
  470 + // 准备参数
  471 + Long tableId = table.getId();
  472 +
  473 + // 调用
  474 + Map<String, String> result = codegenService.generationCodes(tableId);
  475 + // 断言
  476 + assertSame(codes, result);
  477 + }
  478 +
  479 + @Test
  480 + public void testGenerationCodes_master_success() {
  481 + // mock 数据(CodegenTableDO)
  482 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  483 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  484 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  485 + codegenTableMapper.insert(table);
  486 + // mock 数据(CodegenColumnDO)
  487 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  488 + codegenColumnMapper.insert(column01);
  489 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  490 + codegenColumnMapper.insert(column02);
  491 + // mock 数据(sub CodegenTableDO)
  492 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  493 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  494 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  495 + .setMasterTableId(table.getId())
  496 + .setSubJoinColumnId(1024L));
  497 + codegenTableMapper.insert(subTable);
  498 + // mock 数据(sub CodegenColumnDO)
  499 + CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId()));
  500 + codegenColumnMapper.insert(subColumn01);
  501 + // mock 执行生成
  502 + Map<String, String> codes = MapUtil.of(randomString(), randomString());
  503 + when(codegenEngine.execute(eq(table), argThat(columns -> {
  504 + assertEquals(2, columns.size());
  505 + assertEquals(column01, columns.get(0));
  506 + assertEquals(column02, columns.get(1));
  507 + return true;
  508 + }), argThat(tables -> {
  509 + assertEquals(1, tables.size());
  510 + assertPojoEquals(subTable, tables.get(0));
  511 + return true;
  512 + }), argThat(columns -> {
  513 + assertEquals(1, columns.size());
  514 + assertPojoEquals(subColumn01, columns.size());
  515 + return true;
  516 + }))).thenReturn(codes);
  517 + // 准备参数
  518 + Long tableId = table.getId();
  519 +
  520 + // 调用
  521 + Map<String, String> result = codegenService.generationCodes(tableId);
  522 + // 断言
  523 + assertSame(codes, result);
  524 + }
  525 +
  526 + @Test
  527 + public void testGetDatabaseTableList() {
  528 + // 准备参数
  529 + Long dataSourceConfigId = randomLongId();
  530 + String name = randomString();
  531 + String comment = randomString();
  532 + // mock 方法
  533 + TableInfo tableInfo01 = mock(TableInfo.class);
  534 + when(tableInfo01.getName()).thenReturn("t_yunai");
  535 + when(tableInfo01.getComment()).thenReturn("芋艿");
  536 + TableInfo tableInfo02 = mock(TableInfo.class);
  537 + when(tableInfo02.getName()).thenReturn("t_yunai_02");
  538 + when(tableInfo02.getComment()).thenReturn("芋艿_02");
  539 + when(databaseTableService.getTableList(eq(dataSourceConfigId), eq(name), eq(comment)))
  540 + .thenReturn(ListUtil.toList(tableInfo01, tableInfo02));
  541 + // mock 数据
  542 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class,
  543 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  544 + .setTableName("t_yunai_02")
  545 + .setDataSourceConfigId(dataSourceConfigId));
  546 + codegenTableMapper.insert(tableDO);
  547 +
  548 + // 调用
  549 + List<DatabaseTableRespVO> result = codegenService.getDatabaseTableList(dataSourceConfigId, name, comment);
  550 + // 断言
  551 + assertEquals(1, result.size());
  552 + assertEquals("t_yunai", result.get(0).getName());
  553 + assertEquals("芋艿", result.get(0).getComment());
  554 + }
  555 +
  556 +}
0 557 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen.inner;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  5 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  6 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  7 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  8 +import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
  9 +import org.apache.ibatis.type.JdbcType;
  10 +import org.junit.jupiter.api.Test;
  11 +import org.mockito.InjectMocks;
  12 +
  13 +import java.util.Collections;
  14 +import java.util.List;
  15 +
  16 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  17 +import static org.junit.jupiter.api.Assertions.*;
  18 +import static org.mockito.Mockito.mock;
  19 +import static org.mockito.Mockito.when;
  20 +
  21 +public class CodegenBuilderTest extends BaseMockitoUnitTest {
  22 +
  23 + @InjectMocks
  24 + private CodegenBuilder codegenBuilder;
  25 +
  26 + @Test
  27 + public void testBuildTable() {
  28 + // 准备参数
  29 + TableInfo tableInfo = mock(TableInfo.class);
  30 + // mock 方法
  31 + when(tableInfo.getName()).thenReturn("system_user");
  32 + when(tableInfo.getComment()).thenReturn("用户");
  33 +
  34 + // 调用
  35 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo);
  36 + // 断言
  37 + assertEquals("system_user", table.getTableName());
  38 + assertEquals("用户", table.getTableComment());
  39 + assertEquals("system", table.getModuleName());
  40 + assertEquals("user", table.getBusinessName());
  41 + assertEquals("User", table.getClassName());
  42 + assertEquals("用户", table.getClassComment());
  43 + }
  44 +
  45 + @Test
  46 + public void testBuildColumns() {
  47 + // 准备参数
  48 + Long tableId = randomLongId();
  49 + TableField tableField = mock(TableField.class);
  50 + List<TableField> tableFields = Collections.singletonList(tableField);
  51 + // mock 方法
  52 + TableField.MetaInfo metaInfo = mock(TableField.MetaInfo.class);
  53 + when(tableField.getMetaInfo()).thenReturn(metaInfo);
  54 + when(metaInfo.getJdbcType()).thenReturn(JdbcType.BIGINT);
  55 + when(tableField.getComment()).thenReturn("编号");
  56 + when(tableField.isKeyFlag()).thenReturn(true);
  57 + when(tableField.isKeyIdentityFlag()).thenReturn(true);
  58 + IColumnType columnType = mock(IColumnType.class);
  59 + when(tableField.getColumnType()).thenReturn(columnType);
  60 + when(columnType.getType()).thenReturn("Long");
  61 + when(tableField.getName()).thenReturn("id2");
  62 + when(tableField.getPropertyName()).thenReturn("id");
  63 +
  64 + // 调用
  65 + List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
  66 + // 断言
  67 + assertEquals(1, columns.size());
  68 + CodegenColumnDO column = columns.get(0);
  69 + assertEquals(tableId, column.getTableId());
  70 + assertEquals("id2", column.getColumnName());
  71 + assertEquals("BIGINT", column.getDataType());
  72 + assertEquals("编号", column.getColumnComment());
  73 + assertFalse(column.getNullable());
  74 + assertTrue(column.getPrimaryKey());
  75 + assertTrue(column.getAutoIncrement());
  76 + assertEquals(1, column.getOrdinalPosition());
  77 + assertEquals("Long", column.getJavaType());
  78 + assertEquals("id", column.getJavaField());
  79 + assertNull(column.getDictType());
  80 + assertNotNull(column.getExample());
  81 + assertFalse(column.getCreateOperation());
  82 + assertTrue(column.getUpdateOperation());
  83 + assertFalse(column.getListOperation());
  84 + assertEquals("=", column.getListOperationCondition());
  85 + assertTrue(column.getListOperationResult());
  86 + assertEquals("input", column.getHtmlType());
  87 + }
  88 +
  89 +}
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/package-info.java deleted
1   -/**
2   - * 占位,无其它作用
3   - */
4   -package cn.iocoder.yudao.module.infra.service.codegen;
5 0 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImplTest.java
... ... @@ -10,8 +10,11 @@ import org.junit.jupiter.api.Test;
10 10 import org.springframework.context.annotation.Import;
11 11  
12 12 import javax.annotation.Resource;
  13 +import java.time.Duration;
13 14 import java.time.LocalDateTime;
  15 +import java.util.List;
14 16  
  17 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
15 18 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
16 19 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
17 20 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
... ... @@ -93,6 +96,28 @@ public class JobLogServiceImplTest extends BaseDbUnitTest {
93 96 }
94 97  
95 98 @Test
  99 + public void testCleanJobLog() {
  100 + // mock 数据
  101 + JobLogDO log01 = randomPojo(JobLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3))))
  102 + .setExecuteIndex(1);
  103 + jobLogMapper.insert(log01);
  104 + JobLogDO log02 = randomPojo(JobLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1))))
  105 + .setExecuteIndex(1);
  106 + jobLogMapper.insert(log02);
  107 + // 准备参数
  108 + Integer exceedDay = 2;
  109 + Integer deleteLimit = 1;
  110 +
  111 + // 调用
  112 + Integer count = jobLogService.cleanJobLog(exceedDay, deleteLimit);
  113 + // 断言
  114 + assertEquals(1, count);
  115 + List<JobLogDO> logs = jobLogMapper.selectList();
  116 + assertEquals(1, logs.size());
  117 + assertEquals(log02, logs.get(0));
  118 + }
  119 +
  120 + @Test
96 121 public void testGetJobLog() {
97 122 // mock 数据
98 123 JobLogDO dbJobLog = randomPojo(JobLogDO.class, o -> o.setExecuteIndex(1));
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java
... ... @@ -12,9 +12,10 @@ import org.junit.jupiter.api.Test;
12 12 import org.springframework.context.annotation.Import;
13 13  
14 14 import javax.annotation.Resource;
  15 +import java.time.Duration;
  16 +import java.util.List;
15 17  
16   -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
17   -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  18 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
18 19 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
19 20 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
20 21 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
... ... @@ -74,6 +75,26 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest {
74 75 }
75 76  
76 77 @Test
  78 + public void testCleanJobLog() {
  79 + // mock 数据
  80 + ApiAccessLogDO log01 = randomPojo(ApiAccessLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3))));
  81 + apiAccessLogMapper.insert(log01);
  82 + ApiAccessLogDO log02 = randomPojo(ApiAccessLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1))));
  83 + apiAccessLogMapper.insert(log02);
  84 + // 准备参数
  85 + Integer exceedDay = 2;
  86 + Integer deleteLimit = 1;
  87 +
  88 + // 调用
  89 + Integer count = apiAccessLogService.cleanAccessLog(exceedDay, deleteLimit);
  90 + // 断言
  91 + assertEquals(1, count);
  92 + List<ApiAccessLogDO> logs = apiAccessLogMapper.selectList();
  93 + assertEquals(1, logs.size());
  94 + assertEquals(log02, logs.get(0));
  95 + }
  96 +
  97 + @Test
77 98 public void testCreateApiAccessLog() {
78 99 // 准备参数
79 100 ApiAccessLogCreateReqDTO createDTO = randomPojo(ApiAccessLogCreateReqDTO.class);
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java
... ... @@ -12,10 +12,11 @@ import org.junit.jupiter.api.Test;
12 12 import org.springframework.context.annotation.Import;
13 13  
14 14 import javax.annotation.Resource;
  15 +import java.time.Duration;
  16 +import java.util.List;
15 17  
16 18 import static cn.hutool.core.util.RandomUtil.randomEle;
17   -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
18   -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  19 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
19 20 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
20 21 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
21 22 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
... ... @@ -50,13 +51,13 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest {
50 51 // 测试 userId 不匹配
51 52 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserId(3344L)));
52 53 // 测试 userType 不匹配
53   - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
  54 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
54 55 // 测试 applicationName 不匹配
55   - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setApplicationName("test")));
  56 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setApplicationName("test")));
56 57 // 测试 requestUrl 不匹配
57   - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
  58 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setRequestUrl("bar")));
58 59 // 测试 exceptionTime 不匹配:构造一个早期时间 2021-02-06 00:00:00
59   - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
  60 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setExceptionTime(buildTime(2021, 2, 6))));
60 61 // 测试 progressStatus 不匹配
61 62 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus())));
62 63 // 准备参数
... ... @@ -139,4 +140,24 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest {
139 140 API_ERROR_LOG_NOT_FOUND);
140 141 }
141 142  
  143 + @Test
  144 + public void testCleanJobLog() {
  145 + // mock 数据
  146 + ApiErrorLogDO log01 = randomPojo(ApiErrorLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3))));
  147 + apiErrorLogMapper.insert(log01);
  148 + ApiErrorLogDO log02 = randomPojo(ApiErrorLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1))));
  149 + apiErrorLogMapper.insert(log02);
  150 + // 准备参数
  151 + Integer exceedDay = 2;
  152 + Integer deleteLimit = 1;
  153 +
  154 + // 调用
  155 + Integer count = apiErrorLogService.cleanErrorLog(exceedDay, deleteLimit);
  156 + // 断言
  157 + assertEquals(1, count);
  158 + List<ApiErrorLogDO> logs = apiErrorLogMapper.selectList();
  159 + assertEquals(1, logs.size());
  160 + assertEquals(log02, logs.get(0));
  161 + }
  162 +
142 163 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/index
... ... @@ -197,11 +197,11 @@ const total = ref(0) // 列表的总页数
197 197 const queryParams = reactive({
198 198 pageNo: 1,
199 199 pageSize: 10,
200   - name: null,
201   - birthday: null,
  200 + name: undefined,
  201 + birthday: undefined,
202 202 birthday: [],
203   - sex: null,
204   - enabled: null,
  203 + sex: undefined,
  204 + enabled: undefined,
205 205 createTime: []
206 206 })
207 207 const queryFormRef = ref() // 搜索的表单
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/index
... ... @@ -192,11 +192,11 @@ const total = ref(0) // 列表的总页数
192 192 const queryParams = reactive({
193 193 pageNo: 1,
194 194 pageSize: 10,
195   - name: null,
196   - birthday: null,
  195 + name: undefined,
  196 + birthday: undefined,
197 197 birthday: [],
198   - sex: null,
199   - enabled: null,
  198 + sex: undefined,
  199 + enabled: undefined,
200 200 createTime: []
201 201 })
202 202 const queryFormRef = ref() // 搜索的表单
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/index
... ... @@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
177 177 const queryParams = reactive({
178 178 pageNo: 1,
179 179 pageSize: 10,
180   - name: null,
181   - birthday: null,
  180 + name: undefined,
  181 + birthday: undefined,
182 182 birthday: [],
183   - sex: null,
184   - enabled: null,
  183 + sex: undefined,
  184 + enabled: undefined,
185 185 createTime: []
186 186 })
187 187 const queryFormRef = ref() // 搜索的表单
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/vue/index
... ... @@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
177 177 const queryParams = reactive({
178 178 pageNo: 1,
179 179 pageSize: 10,
180   - name: null,
181   - birthday: null,
  180 + name: undefined,
  181 + birthday: undefined,
182 182 birthday: [],
183   - sex: null,
184   - enabled: null,
  183 + sex: undefined,
  184 + enabled: undefined,
185 185 createTime: []
186 186 })
187 187 const queryFormRef = ref() // 搜索的表单
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/vue/index
... ... @@ -106,7 +106,7 @@ const { t } = useI18n() // 国际化
106 106 const loading = ref(true) // 列表的加载中
107 107 const list = ref([]) // 列表的数据
108 108 const queryParams = reactive({
109   - name: null
  109 + name: undefined
110 110 })
111 111 const queryFormRef = ref() // 搜索的表单
112 112 const exportLoading = ref(false) // 导出的加载中
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql
... ... @@ -8,3 +8,5 @@ DELETE FROM &quot;infra_api_error_log&quot;;
8 8 DELETE FROM "infra_file_config";
9 9 DELETE FROM "infra_test_demo";
10 10 DELETE FROM "infra_data_source_config";
  11 +DELETE FROM "infra_codegen_table";
  12 +DELETE FROM "infra_codegen_column";
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql
... ... @@ -170,3 +170,59 @@ CREATE TABLE IF NOT EXISTS &quot;infra_data_source_config&quot; (
170 170 "deleted" bit NOT NULL DEFAULT FALSE,
171 171 PRIMARY KEY ("id")
172 172 ) COMMENT '数据源配置表';
  173 +
  174 +CREATE TABLE IF NOT EXISTS "infra_codegen_table" (
  175 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  176 + "data_source_config_id" bigint not null,
  177 + "scene" tinyint not null DEFAULT 1,
  178 + "table_name" varchar(200) NOT NULL,
  179 + "table_comment" varchar(500) NOT NULL,
  180 + "remark" varchar(500) NOT NULL,
  181 + "module_name" varchar(30) NOT NULL,
  182 + "business_name" varchar(30) NOT NULL,
  183 + "class_name" varchar(100) NOT NULL,
  184 + "class_comment" varchar(50) NOT NULL,
  185 + "author" varchar(50) NOT NULL,
  186 + "template_type" tinyint not null DEFAULT 1,
  187 + "front_type" tinyint not null,
  188 + "parent_menu_id" bigint not null,
  189 + "master_table_id" bigint not null,
  190 + "sub_join_column_id" bigint not null,
  191 + "sub_join_many" bit not null,
  192 + "tree_parent_column_id" bigint not null,
  193 + "tree_name_column_id" bigint not null,
  194 + "creator" varchar(64) DEFAULT '',
  195 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  196 + "updater" varchar(64) DEFAULT '',
  197 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  198 + "deleted" bit NOT NULL DEFAULT FALSE,
  199 + PRIMARY KEY ("id")
  200 +) COMMENT '代码生成表定义表';
  201 +
  202 +CREATE TABLE IF NOT EXISTS "infra_codegen_column" (
  203 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  204 + "table_id" bigint not null,
  205 + "column_name" varchar(200) NOT NULL,
  206 + "data_type" varchar(100) NOT NULL,
  207 + "column_comment" varchar(500) NOT NULL,
  208 + "nullable" tinyint not null,
  209 + "primary_key" tinyint not null,
  210 + "auto_increment" varchar(5) not null,
  211 + "ordinal_position" int not null,
  212 + "java_type" varchar(32) NOT NULL,
  213 + "java_field" varchar(64) NOT NULL,
  214 + "dict_type" varchar(200) NOT NULL,
  215 + "example" varchar(64) NOT NULL,
  216 + "create_operation" bit not null,
  217 + "update_operation" bit not null,
  218 + "list_operation" bit not null,
  219 + "list_operation_condition" varchar(32) not null,
  220 + "list_operation_result" bit not null,
  221 + "html_type" varchar(32) NOT NULL,
  222 + "creator" varchar(64) DEFAULT '',
  223 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  224 + "updater" varchar(64) DEFAULT '',
  225 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  226 + "deleted" bit NOT NULL DEFAULT FALSE,
  227 + PRIMARY KEY ("id")
  228 +) COMMENT '代码生成表字段定义表';
173 229 \ No newline at end of file
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.dict;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -66,7 +67,8 @@ public class DictDataController {
66 67 @Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地")
67 68 // 无需添加权限认证,因为前端全局都需要
68 69 public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDataList() {
69   - List<DictDataDO> list = dictDataService.getDictDataList();
  70 + List<DictDataDO> list = dictDataService.getDictDataList(
  71 + CommonStatusEnum.ENABLE.getStatus(), null);
70 72 return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class));
71 73 }
72 74  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java
... ... @@ -23,7 +23,7 @@ public class SocialUserPageReqVO extends PageParam {
23 23 @Schema(description = "用户昵称", example = "李四")
24 24 private String nickname;
25 25  
26   - @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w\n")
  26 + @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w")
27 27 private String openid;
28 28  
29 29 @Schema(description = "创建时间")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java
... ... @@ -14,8 +14,7 @@ import java.util.Set;
14 14 @Data
15 15 public class UserSaveReqVO {
16 16  
17   - @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
18   - @NotNull(message = "用户编号不能为空")
  17 + @Schema(description = "用户编号", example = "1024")
19 18 private Long id;
20 19  
21 20 @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/AppDictDataController.java
1 1 package cn.iocoder.yudao.module.system.controller.app.dict;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 6 import cn.iocoder.yudao.module.system.controller.app.dict.vo.AppDictDataRespVO;
... ... @@ -32,7 +33,8 @@ public class AppDictDataController {
32 33 @Operation(summary = "根据字典类型查询字典数据信息")
33 34 @Parameter(name = "type", description = "字典类型", required = true, example = "common_status")
34 35 public CommonResult<List<AppDictDataRespVO>> getDictDataListByType(@RequestParam("type") String type) {
35   - List<DictDataDO> list = dictDataService.getEnabledDictDataListByType(type);
  36 + List<DictDataDO> list = dictDataService.getDictDataList(
  37 + CommonStatusEnum.ENABLE.getStatus(), type);
36 38 return success(BeanUtils.toBean(list, AppDictDataRespVO.class));
37 39 }
38 40  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictDataMapper.java
... ... @@ -40,10 +40,10 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; {
40 40 .orderByDesc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort)));
41 41 }
42 42  
43   - default List<DictDataDO> selectListByTypeAndStatus(String dictType, Integer status) {
44   - return selectList(new LambdaQueryWrapper<DictDataDO>()
45   - .eq(DictDataDO::getDictType, dictType)
46   - .eq(DictDataDO::getStatus, status));
  43 + default List<DictDataDO> selectListByStatusAndDictType(Integer status, String dictType) {
  44 + return selectList(new LambdaQueryWrapperX<DictDataDO>()
  45 + .eqIfPresent(DictDataDO::getStatus, status)
  46 + .eqIfPresent(DictDataDO::getDictType, dictType));
47 47 }
48 48  
49 49 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostService.java
1 1 package cn.iocoder.yudao.module.system.service.dept;
2 2  
3   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 4 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
6 5 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
... ... @@ -10,8 +9,6 @@ import org.springframework.lang.Nullable;
10 9 import java.util.Collection;
11 10 import java.util.List;
12 11  
13   -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
14   -
15 12 /**
16 13 * 岗位 Service 接口
17 14 *
... ... @@ -44,12 +41,10 @@ public interface PostService {
44 41 /**
45 42 * 获得岗位列表
46 43 *
47   - * @param ids 岗位编号数组。如果为空,不进行筛选
  44 + * @param ids 岗位编号数组
48 45 * @return 部门列表
49 46 */
50   - default List<PostDO> getPostList(@Nullable Collection<Long> ids) {
51   - return getPostList(ids, asSet(CommonStatusEnum.ENABLE.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
52   - }
  47 + List<PostDO> getPostList(@Nullable Collection<Long> ids);
53 48  
54 49 /**
55 50 * 获得符合条件的岗位列表
... ... @@ -58,7 +53,8 @@ public interface PostService {
58 53 * @param statuses 状态数组。如果为空,不进行筛选
59 54 * @return 部门列表
60 55 */
61   - List<PostDO> getPostList(@Nullable Collection<Long> ids, @Nullable Collection<Integer> statuses);
  56 + List<PostDO> getPostList(@Nullable Collection<Long> ids,
  57 + @Nullable Collection<Integer> statuses);
62 58  
63 59 /**
64 60 * 获得岗位分页列表
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImpl.java
... ... @@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated;
13 13  
14 14 import javax.annotation.Resource;
15 15 import java.util.Collection;
  16 +import java.util.Collections;
16 17 import java.util.List;
17 18 import java.util.Map;
18 19  
... ... @@ -108,6 +109,14 @@ public class PostServiceImpl implements PostService {
108 109 }
109 110  
110 111 @Override
  112 + public List<PostDO> getPostList(Collection<Long> ids) {
  113 + if (CollUtil.isEmpty(ids)) {
  114 + return Collections.emptyList();
  115 + }
  116 + return postMapper.selectBatchIds(ids);
  117 + }
  118 +
  119 + @Override
111 120 public List<PostDO> getPostList(Collection<Long> ids, Collection<Integer> statuses) {
112 121 return postMapper.selectList(ids, statuses);
113 122 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
5 5 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
6 6 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
  7 +import org.springframework.lang.Nullable;
7 8  
8 9 import java.util.Collection;
9 10 import java.util.List;
... ... @@ -40,9 +41,11 @@ public interface DictDataService {
40 41 /**
41 42 * 获得字典数据列表
42 43 *
  44 + * @param status 状态
  45 + * @param dictType 字典类型
43 46 * @return 字典数据全列表
44 47 */
45   - List<DictDataDO> getDictDataList();
  48 + List<DictDataDO> getDictDataList(@Nullable Integer status, @Nullable String dictType);
46 49  
47 50 /**
48 51 * 获得字典数据分页列表
... ... @@ -53,14 +56,6 @@ public interface DictDataService {
53 56 PageResult<DictDataDO> getDictDataPage(DictDataPageReqVO pageReqVO);
54 57  
55 58 /**
56   - * 获得字典数据列表
57   - *
58   - * @param dictType 字典类型
59   - * @return 字典数据列表
60   - */
61   - List<DictDataDO> getEnabledDictDataListByType(String dictType);
62   -
63   - /**
64 59 * 获得字典数据详情
65 60 *
66 61 * @param id 字典数据编号
... ... @@ -74,7 +69,7 @@ public interface DictDataService {
74 69 * @param dictType 字典类型
75 70 * @return 数据数量
76 71 */
77   - long countByDictType(String dictType);
  72 + long getDictDataCountByDictType(String dictType);
78 73  
79 74 /**
80 75 * 校验字典数据们是否有效。如下情况,视为无效:
... ... @@ -103,4 +98,5 @@ public interface DictDataService {
103 98 * @return 字典数据
104 99 */
105 100 DictDataDO parseDictData(String dictType, String label);
  101 +
106 102 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java
... ... @@ -46,8 +46,8 @@ public class DictDataServiceImpl implements DictDataService {
46 46 private DictDataMapper dictDataMapper;
47 47  
48 48 @Override
49   - public List<DictDataDO> getDictDataList() {
50   - List<DictDataDO> list = dictDataMapper.selectList(DictDataDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
  49 + public List<DictDataDO> getDictDataList(Integer status, String dictType) {
  50 + List<DictDataDO> list = dictDataMapper.selectListByStatusAndDictType(status, dictType);
51 51 list.sort(COMPARATOR_TYPE_AND_SORT);
52 52 return list;
53 53 }
... ... @@ -58,13 +58,6 @@ public class DictDataServiceImpl implements DictDataService {
58 58 }
59 59  
60 60 @Override
61   - public List<DictDataDO> getEnabledDictDataListByType(String dictType) {
62   - List<DictDataDO> list = dictDataMapper.selectListByTypeAndStatus(dictType, CommonStatusEnum.ENABLE.getStatus());
63   - list.sort(COMPARATOR_TYPE_AND_SORT);
64   - return list;
65   - }
66   -
67   - @Override
68 61 public DictDataDO getDictData(Long id) {
69 62 return dictDataMapper.selectById(id);
70 63 }
... ... @@ -106,7 +99,7 @@ public class DictDataServiceImpl implements DictDataService {
106 99 }
107 100  
108 101 @Override
109   - public long countByDictType(String dictType) {
  102 + public long getDictDataCountByDictType(String dictType) {
110 103 return dictDataMapper.selectCountByDictType(dictType);
111 104 }
112 105  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImpl.java
... ... @@ -80,7 +80,7 @@ public class DictTypeServiceImpl implements DictTypeService {
80 80 // 校验是否存在
81 81 DictTypeDO dictType = validateDictTypeExists(id);
82 82 // 校验是否有字典数据
83   - if (dictDataService.countByDictType(dictType.getType()) > 0) {
  83 + if (dictDataService.getDictDataCountByDictType(dictType.getType()) > 0) {
84 84 throw exception(DICT_TYPE_HAS_CHILDREN);
85 85 }
86 86 // 删除字典类型
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java
... ... @@ -48,7 +48,7 @@ public interface NotifySendService {
48 48 String templateCode, Map<String, Object> templateParams);
49 49  
50 50 default void sendBatchNotify(List<String> mobiles, List<Long> userIds, Integer userType,
51   - String templateCode, Map<String, Object> templateParams) {
  51 + String templateCode, Map<String, Object> templateParams) {
52 52 throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
53 53 }
54 54  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
... ... @@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
6 6 import cn.hutool.extra.spring.SpringUtil;
7 7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
8 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
10 11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
11 12 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
... ... @@ -27,7 +28,6 @@ import javax.annotation.Resource;
27 28 import java.util.*;
28 29  
29 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
31 31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
32 32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
33 33  
... ... @@ -198,7 +198,7 @@ public class RoleServiceImpl implements RoleService {
198 198 }
199 199 // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题
200 200 RoleServiceImpl self = getSelf();
201   - return convertList(ids, self::getRoleFromCache);
  201 + return CollectionUtils.convertList(ids, self::getRoleFromCache);
202 202 }
203 203  
204 204 @Override
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/bo/RoleCreateReqBO.java deleted
1   -package cn.iocoder.yudao.module.system.service.permission.bo;
2   -
3   -import lombok.Data;
4   -
5   -import javax.validation.constraints.NotBlank;
6   -import javax.validation.constraints.NotNull;
7   -import javax.validation.constraints.Size;
8   -
9   -/**
10   - * 角色创建 Request BO
11   - *
12   - * @author 芋道源码
13   - */
14   -@Data
15   -public class RoleCreateReqBO {
16   -
17   - /**
18   - * 租户编号
19   - */
20   - @NotNull(message = "租户编号不能为空")
21   - private Long tenantId;
22   -
23   - /**
24   - * 角色名称
25   - */
26   - @NotBlank(message = "角色名称不能为空")
27   - @Size(max = 30, message = "角色名称长度不能超过30个字符")
28   - private String name;
29   -
30   - /**
31   - * 角色标志
32   - */
33   - @NotBlank(message = "角色标志不能为空")
34   - @Size(max = 100, message = "角色标志长度不能超过100个字符")
35   - private String code;
36   -
37   - /**
38   - * 显示顺序
39   - */
40   - @NotNull(message = "显示顺序不能为空")
41   - private Integer sort;
42   -
43   - /**
44   - * 角色类型
45   - */
46   - @NotNull(message = "角色类型不能为空")
47   - private Integer type;
48   -
49   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
... ... @@ -142,7 +142,8 @@ public class SocialClientServiceImpl implements SocialClientService {
142 142 * @param userType 用户类型
143 143 * @return AuthRequest 对象
144 144 */
145   - private AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
  145 + @VisibleForTesting
  146 + AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
146 147 // 1. 先查找默认的配置项,从 application-*.yaml 中读取
147 148 AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource());
148 149 Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType));
... ... @@ -180,7 +181,8 @@ public class SocialClientServiceImpl implements SocialClientService {
180 181 * @param userType 用户类型
181 182 * @return WxMpService 对象
182 183 */
183   - private WxMpService getWxMpService(Integer userType) {
  184 + @VisibleForTesting
  185 + WxMpService getWxMpService(Integer userType) {
184 186 // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象
185 187 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
186 188 SocialTypeEnum.WECHAT_MP.getType(), userType);
... ... @@ -198,7 +200,7 @@ public class SocialClientServiceImpl implements SocialClientService {
198 200 * @param clientSecret 微信公众号 secret
199 201 * @return WxMpService 对象
200 202 */
201   - private WxMpService buildWxMpService(String clientId, String clientSecret) {
  203 + public WxMpService buildWxMpService(String clientId, String clientSecret) {
202 204 // 第一步,创建 WxMpRedisConfigImpl 对象
203 205 WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
204 206 new RedisTemplateWxRedisOps(stringRedisTemplate),
... ... @@ -231,7 +233,8 @@ public class SocialClientServiceImpl implements SocialClientService {
231 233 * @param userType 用户类型
232 234 * @return WxMpService 对象
233 235 */
234   - private WxMaService getWxMaService(Integer userType) {
  236 + @VisibleForTesting
  237 + WxMaService getWxMaService(Integer userType) {
235 238 // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象
236 239 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
237 240 SocialTypeEnum.WECHAT_MINI_APP.getType(), userType);
... ... @@ -311,7 +314,6 @@ public class SocialClientServiceImpl implements SocialClientService {
311 314 * @param userType 用户类型
312 315 * @param socialType 社交类型
313 316 */
314   - @VisibleForTesting
315 317 private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) {
316 318 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
317 319 socialType, userType);
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
1 1 package cn.iocoder.yudao.module.system.service.social;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.collection.ListUtil;
5 4 import cn.hutool.core.lang.Assert;
6 5 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
9 8 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
10 9 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
11   -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
12 10 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
13 11 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
14 12 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
... ... @@ -22,14 +20,14 @@ import org.springframework.validation.annotation.Validated;
22 20  
23 21 import javax.annotation.Resource;
24 22 import javax.validation.constraints.NotNull;
25   -import java.util.Collection;
26 23 import java.util.Collections;
27 24 import java.util.List;
28 25  
29 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
31 28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
32   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  29 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;
  30 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
33 31  
34 32 /**
35 33 * 社交用户 Service 实现类
... ... @@ -61,7 +59,7 @@ public class SocialUserServiceImpl implements SocialUserService {
61 59 }
62 60  
63 61 @Override
64   - @Transactional
  62 + @Transactional(rollbackFor = Exception.class)
65 63 public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
66 64 // 获得社交用户
67 65 SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(),
... ... @@ -110,7 +108,6 @@ public class SocialUserServiceImpl implements SocialUserService {
110 108 return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId());
111 109 }
112 110  
113   - // TODO 芋艿:调整下单测
114 111 /**
115 112 * 授权获得对应的社交用户
116 113 * 如果授权失败,则会抛出 {@link ServiceException} 异常
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImplTest.java
... ... @@ -156,6 +156,24 @@ public class PostServiceImplTest extends BaseDbUnitTest {
156 156 @Test
157 157 public void testGetPostList() {
158 158 // mock 数据
  159 + PostDO postDO01 = randomPojo(PostDO.class);
  160 + postMapper.insert(postDO01);
  161 + // 测试 id 不匹配
  162 + PostDO postDO02 = randomPojo(PostDO.class);
  163 + postMapper.insert(postDO02);
  164 + // 准备参数
  165 + List<Long> ids = singletonList(postDO01.getId());
  166 +
  167 + // 调用
  168 + List<PostDO> list = postService.getPostList(ids);
  169 + // 断言
  170 + assertEquals(1, list.size());
  171 + assertPojoEquals(postDO01, list.get(0));
  172 + }
  173 +
  174 + @Test
  175 + public void testGetPostList_idsAndStatus() {
  176 + // mock 数据
159 177 PostDO postDO01 = randomPojo(PostDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
160 178 postMapper.insert(postDO01);
161 179 // 测试 status 不匹配
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImplTest.java
... ... @@ -50,10 +50,15 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
50 50 DictDataDO dictDataDO03 = randomDictDataDO().setDictType("yunai").setSort(3)
51 51 .setStatus(CommonStatusEnum.DISABLE.getStatus());
52 52 dictDataMapper.insert(dictDataDO03);
  53 + DictDataDO dictDataDO04 = randomDictDataDO().setDictType("yunai2").setSort(3)
  54 + .setStatus(CommonStatusEnum.DISABLE.getStatus());
  55 + dictDataMapper.insert(dictDataDO04);
53 56 // 准备参数
  57 + Integer status = CommonStatusEnum.ENABLE.getStatus();
  58 + String dictType = "yunai";
54 59  
55 60 // 调用
56   - List<DictDataDO> dictDataDOList = dictDataService.getDictDataList();
  61 + List<DictDataDO> dictDataDOList = dictDataService.getDictDataList(status, dictType);
57 62 // 断言
58 63 assertEquals(2, dictDataDOList.size());
59 64 assertPojoEquals(dictDataDO02, dictDataDOList.get(0));
... ... @@ -236,7 +241,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
236 241 }
237 242  
238 243 @Test
239   - public void testCountByDictType() {
  244 + public void testGetDictDataCountByDictType() {
240 245 // mock 数据
241 246 dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("yunai")));
242 247 dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("tudou")));
... ... @@ -245,7 +250,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
245 250 String dictType = "yunai";
246 251  
247 252 // 调用
248   - long count = dictDataService.countByDictType(dictType);
  253 + long count = dictDataService.getDictDataCountByDictType(dictType);
249 254 // 校验
250 255 assertEquals(2L, count);
251 256 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImplTest.java
... ... @@ -158,7 +158,7 @@ public class DictTypeServiceImplTest extends BaseDbUnitTest {
158 158 // 准备参数
159 159 Long id = dbDictType.getId();
160 160 // mock 方法
161   - when(dictDataService.countByDictType(eq(dbDictType.getType()))).thenReturn(1L);
  161 + when(dictDataService.getDictDataCountByDictType(eq(dbDictType.getType()))).thenReturn(1L);
162 162  
163 163 // 调用, 并断言异常
164 164 assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN);
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImplTest.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 6 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
7 7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
8 8 import org.assertj.core.util.Lists;
  9 +import org.junit.jupiter.api.Assertions;
9 10 import org.junit.jupiter.api.Test;
10 11 import org.mockito.InjectMocks;
11 12 import org.mockito.Mock;
... ... @@ -172,5 +173,18 @@ class NotifySendServiceImplTest extends BaseMockitoUnitTest {
172 173 NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code");
173 174 }
174 175  
  176 + @Test
  177 + public void testSendBatchNotify() {
  178 + // 准备参数
  179 + // mock 方法
  180 +
  181 + // 调用
  182 + UnsupportedOperationException exception = Assertions.assertThrows(
  183 + UnsupportedOperationException.class,
  184 + () -> notifySendService.sendBatchNotify(null, null, null, null, null)
  185 + );
  186 + // 断言
  187 + assertEquals("暂时不支持该操作,感兴趣可以实现该功能哟!", exception.getMessage());
  188 + }
175 189  
176 190 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java
... ... @@ -13,6 +13,8 @@ import org.springframework.boot.test.mock.mockito.MockBean;
13 13 import org.springframework.context.annotation.Import;
14 14  
15 15 import javax.annotation.Resource;
  16 +import java.util.Collection;
  17 +import java.util.Collections;
16 18 import java.util.List;
17 19 import java.util.Set;
18 20  
... ... @@ -186,6 +188,40 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
186 188 }
187 189  
188 190 @Test
  191 + public void testGetMenuIdListByPermissionFromCache() {
  192 + // mock 数据
  193 + MenuDO menu100 = randomPojo(MenuDO.class);
  194 + menuMapper.insert(menu100);
  195 + MenuDO menu101 = randomPojo(MenuDO.class);
  196 + menuMapper.insert(menu101);
  197 + // 准备参数
  198 + String permission = menu100.getPermission();
  199 +
  200 + // 调用
  201 + List<Long> ids = menuService.getMenuIdListByPermissionFromCache(permission);
  202 + // 断言
  203 + assertEquals(1, ids.size());
  204 + assertEquals(menu100.getId(), ids.get(0));
  205 + }
  206 +
  207 + @Test
  208 + public void testGetMenuList_ids() {
  209 + // mock 数据
  210 + MenuDO menu100 = randomPojo(MenuDO.class);
  211 + menuMapper.insert(menu100);
  212 + MenuDO menu101 = randomPojo(MenuDO.class);
  213 + menuMapper.insert(menu101);
  214 + // 准备参数
  215 + Collection<Long> ids = Collections.singleton(menu100.getId());
  216 +
  217 + // 调用
  218 + List<MenuDO> list = menuService.getMenuList(ids);
  219 + // 断言
  220 + assertEquals(1, list.size());
  221 + assertPojoEquals(menu100, list.get(0));
  222 + }
  223 +
  224 + @Test
189 225 public void testGetMenu() {
190 226 // mock 数据
191 227 MenuDO menu = randomPojo(MenuDO.class);
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java
... ... @@ -234,6 +234,39 @@ public class RoleServiceImplTest extends BaseDbUnitTest {
234 234 }
235 235  
236 236 @Test
  237 + public void testGetRoleList() {
  238 + // mock 数据
  239 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
  240 + roleMapper.insert(dbRole01);
  241 + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
  242 + roleMapper.insert(dbRole02);
  243 +
  244 + // 调用
  245 + List<RoleDO> list = roleService.getRoleList();
  246 + // 断言
  247 + assertEquals(2, list.size());
  248 + assertPojoEquals(dbRole01, list.get(0));
  249 + assertPojoEquals(dbRole02, list.get(1));
  250 + }
  251 +
  252 + @Test
  253 + public void testGetRoleList_ids() {
  254 + // mock 数据
  255 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
  256 + roleMapper.insert(dbRole01);
  257 + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
  258 + roleMapper.insert(dbRole02);
  259 + // 准备参数
  260 + Collection<Long> ids = singleton(dbRole01.getId());
  261 +
  262 + // 调用
  263 + List<RoleDO> list = roleService.getRoleList(ids);
  264 + // 断言
  265 + assertEquals(1, list.size());
  266 + assertPojoEquals(dbRole01, list.get(0));
  267 + }
  268 +
  269 + @Test
237 270 public void testGetRoleListFromCache() {
238 271 try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
239 272 springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class)))
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.sensitiveword;
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
  6 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
6 7 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7 8 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
8 9 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO;
... ... @@ -13,6 +14,8 @@ import org.junit.jupiter.api.Test;
13 14 import org.springframework.context.annotation.Import;
14 15  
15 16 import javax.annotation.Resource;
  17 +import java.time.Duration;
  18 +import java.time.LocalDateTime;
16 19 import java.util.Arrays;
17 20 import java.util.List;
18 21  
... ... @@ -79,6 +82,35 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
79 82 }
80 83  
81 84 @Test
  85 + public void testRefreshLocalCache() {
  86 + // mock 数据
  87 + SensitiveWordDO wordDO1 = randomPojo(SensitiveWordDO.class, o -> o.setName("傻瓜")
  88 + .setTags(singletonList("论坛")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  89 + wordDO1.setUpdateTime(LocalDateTime.now());
  90 + sensitiveWordMapper.insert(wordDO1);
  91 + sensitiveWordService.initLocalCache();
  92 + // mock 数据 ②
  93 + SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋")
  94 + .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  95 + wordDO2.setUpdateTime(LocalDateTimeUtils.addTime(Duration.ofMinutes(1))); // 避免时间相同
  96 + sensitiveWordMapper.insert(wordDO2);
  97 +
  98 + // 调用
  99 + sensitiveWordService.refreshLocalCache();
  100 + // 断言 sensitiveWordTagsCache 缓存
  101 + assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTagSet());
  102 + // 断言 sensitiveWordCache
  103 + assertEquals(2, sensitiveWordService.getSensitiveWordCache().size());
  104 + assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0));
  105 + assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1));
  106 + // 断言 tagSensitiveWordTries 缓存
  107 + assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie());
  108 + assertEquals(2, sensitiveWordService.getTagSensitiveWordTries().size());
  109 + assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛"));
  110 + assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜"));
  111 + }
  112 +
  113 + @Test
82 114 public void testCreateSensitiveWord_success() {
83 115 // 准备参数
84 116 SensitiveWordSaveVO reqVO = randomPojo(SensitiveWordSaveVO.class)
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java
... ... @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
16 16 import cn.iocoder.yudao.module.system.service.member.MemberService;
17 17 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
18 18 import org.assertj.core.util.Lists;
  19 +import org.junit.jupiter.api.Assertions;
19 20 import org.junit.jupiter.api.Test;
20 21 import org.mockito.InjectMocks;
21 22 import org.mockito.Mock;
... ... @@ -35,7 +36,7 @@ import static org.mockito.Mockito.*;
35 36 public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
36 37  
37 38 @InjectMocks
38   - private SmsSendServiceImpl smsService;
  39 + private SmsSendServiceImpl smsSendService;
39 40  
40 41 @Mock
41 42 private AdminUserService adminUserService;
... ... @@ -80,7 +81,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
80 81 eq(content), eq(templateParams))).thenReturn(smsLogId);
81 82  
82 83 // 调用
83   - Long resultSmsLogId = smsService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams);
  84 + Long resultSmsLogId = smsSendService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams);
84 85 // 断言
85 86 assertEquals(smsLogId, resultSmsLogId);
86 87 // 断言调用
... ... @@ -119,7 +120,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
119 120 eq(content), eq(templateParams))).thenReturn(smsLogId);
120 121  
121 122 // 调用
122   - Long resultSmsLogId = smsService.sendSingleSmsToMember(null, userId, templateCode, templateParams);
  123 + Long resultSmsLogId = smsSendService.sendSingleSmsToMember(null, userId, templateCode, templateParams);
123 124 // 断言
124 125 assertEquals(smsLogId, resultSmsLogId);
125 126 // 断言调用
... ... @@ -159,7 +160,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
159 160 eq(content), eq(templateParams))).thenReturn(smsLogId);
160 161  
161 162 // 调用
162   - Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
  163 + Long resultSmsLogId = smsSendService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
163 164 // 断言
164 165 assertEquals(smsLogId, resultSmsLogId);
165 166 // 断言调用
... ... @@ -199,7 +200,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
199 200 eq(content), eq(templateParams))).thenReturn(smsLogId);
200 201  
201 202 // 调用
202   - Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
  203 + Long resultSmsLogId = smsSendService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
203 204 // 断言
204 205 assertEquals(smsLogId, resultSmsLogId);
205 206 // 断言调用
... ... @@ -214,7 +215,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
214 215 // mock 方法
215 216  
216 217 // 调用,并断言异常
217   - assertServiceException(() -> smsService.validateSmsTemplate(templateCode),
  218 + assertServiceException(() -> smsSendService.validateSmsTemplate(templateCode),
218 219 SMS_SEND_TEMPLATE_NOT_EXISTS);
219 220 }
220 221  
... ... @@ -227,7 +228,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
227 228 // mock 方法
228 229  
229 230 // 调用,并断言异常
230   - assertServiceException(() -> smsService.buildTemplateParams(template, templateParams),
  231 + assertServiceException(() -> smsSendService.buildTemplateParams(template, templateParams),
231 232 SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code");
232 233 }
233 234  
... ... @@ -237,11 +238,25 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
237 238 // mock 方法
238 239  
239 240 // 调用,并断言异常
240   - assertServiceException(() -> smsService.validateMobile(null),
  241 + assertServiceException(() -> smsSendService.validateMobile(null),
241 242 SMS_SEND_MOBILE_NOT_EXISTS);
242 243 }
243 244  
244 245 @Test
  246 + public void testSendBatchNotify() {
  247 + // 准备参数
  248 + // mock 方法
  249 +
  250 + // 调用
  251 + UnsupportedOperationException exception = Assertions.assertThrows(
  252 + UnsupportedOperationException.class,
  253 + () -> smsSendService.sendBatchSms(null, null, null, null, null)
  254 + );
  255 + // 断言
  256 + assertEquals("暂时不支持该操作,感兴趣可以实现该功能哟!", exception.getMessage());
  257 + }
  258 +
  259 + @Test
245 260 @SuppressWarnings("unchecked")
246 261 public void testDoSendSms() throws Throwable {
247 262 // 准备参数
... ... @@ -255,7 +270,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
255 270 eq(message.getTemplateParams()))).thenReturn(sendResult);
256 271  
257 272 // 调用
258   - smsService.doSendSms(message);
  273 + smsSendService.doSendSms(message);
259 274 // 断言
260 275 verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
261 276 eq(sendResult.getSuccess()), eq(sendResult.getApiCode()),
... ... @@ -274,7 +289,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
274 289 List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class);
275 290  
276 291 // 调用
277   - smsService.receiveSmsStatus(channelCode, text);
  292 + smsSendService.receiveSmsStatus(channelCode, text);
278 293 // 断言
279 294 receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
280 295 eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode())));
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.sms;
2 2  
  3 +import cn.hutool.core.map.MapUtil;
3 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
... ... @@ -8,8 +9,8 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
8 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
9 10 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
10 11 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
11   -import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO;
12 12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
  13 +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO;
13 14 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
14 15 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
15 16 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
... ... @@ -21,6 +22,7 @@ import org.springframework.context.annotation.Import;
21 22  
22 23 import javax.annotation.Resource;
23 24 import java.util.List;
  25 +import java.util.Map;
24 26 import java.util.function.Consumer;
25 27  
26 28 import static cn.hutool.core.util.RandomUtil.randomEle;
... ... @@ -49,6 +51,19 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
49 51 private SmsClient smsClient;
50 52  
51 53 @Test
  54 + public void testFormatSmsTemplateContent() {
  55 + // 准备参数
  56 + String content = "正在进行登录操作{operation},您的验证码是{code}";
  57 + Map<String, Object> params = MapUtil.<String, Object>builder("operation", "登录")
  58 + .put("code", "1234").build();
  59 +
  60 + // 调用
  61 + String result = smsTemplateService.formatSmsTemplateContent(content, params);
  62 + // 断言
  63 + assertEquals("正在进行登录操作登录,您的验证码是1234", result);
  64 + }
  65 +
  66 + @Test
52 67 public void testParseTemplateContentParams() {
53 68 // 准备参数
54 69 String content = "正在进行登录操作{operation},您的验证码是{code}";
... ... @@ -157,6 +172,34 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
157 172 }
158 173  
159 174 @Test
  175 + public void testGetSmsTemplate() {
  176 + // mock 数据
  177 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
  178 + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
  179 + // 准备参数
  180 + Long id = dbSmsTemplate.getId();
  181 +
  182 + // 调用
  183 + SmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplate(id);
  184 + // 校验
  185 + assertPojoEquals(dbSmsTemplate, smsTemplate);
  186 + }
  187 +
  188 + @Test
  189 + public void testGetSmsTemplateByCodeFromCache() {
  190 + // mock 数据
  191 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
  192 + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
  193 + // 准备参数
  194 + String code = dbSmsTemplate.getCode();
  195 +
  196 + // 调用
  197 + SmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplateByCodeFromCache(code);
  198 + // 校验
  199 + assertPojoEquals(dbSmsTemplate, smsTemplate);
  200 + }
  201 +
  202 + @Test
160 203 public void testGetSmsTemplatePage() {
161 204 // mock 数据
162 205 SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到
... ... @@ -202,6 +245,22 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
202 245 }
203 246  
204 247 @Test
  248 + public void testGetSmsTemplateCountByChannelId() {
  249 + // mock 数据
  250 + SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> o.setChannelId(1L));
  251 + smsTemplateMapper.insert(dbSmsTemplate);
  252 + // 测试 channelId 不匹配
  253 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
  254 + // 准备参数
  255 + Long channelId = 1L;
  256 +
  257 + // 调用
  258 + Long count = smsTemplateService.getSmsTemplateCountByChannelId(channelId);
  259 + // 断言
  260 + assertEquals(1, count);
  261 + }
  262 +
  263 + @Test
205 264 public void testValidateSmsChannel_success() {
206 265 // 准备参数
207 266 Long channelId = randomLongId();
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.social;
2 2  
  3 +import cn.binarywang.wx.miniapp.api.WxMaService;
  4 +import cn.binarywang.wx.miniapp.api.WxMaUserService;
  5 +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  6 +import cn.hutool.core.util.ReflectUtil;
  7 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  8 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 10 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 11 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
6 12 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
7 13 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
8 14 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
9   -import org.junit.jupiter.api.Disabled;
  15 +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
  16 +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
  17 +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
  18 +import com.xingyuv.jushauth.config.AuthConfig;
  19 +import com.xingyuv.jushauth.model.AuthResponse;
  20 +import com.xingyuv.jushauth.model.AuthUser;
  21 +import com.xingyuv.jushauth.request.AuthDefaultRequest;
  22 +import com.xingyuv.jushauth.request.AuthRequest;
  23 +import com.xingyuv.jushauth.utils.AuthStateUtils;
  24 +import com.xingyuv.justauth.AuthRequestFactory;
  25 +import me.chanjar.weixin.common.bean.WxJsapiSignature;
  26 +import me.chanjar.weixin.common.error.WxErrorException;
  27 +import me.chanjar.weixin.mp.api.WxMpService;
10 28 import org.junit.jupiter.api.Test;
  29 +import org.mockito.MockedStatic;
  30 +import org.springframework.boot.test.mock.mockito.MockBean;
11 31 import org.springframework.context.annotation.Import;
  32 +import org.springframework.data.redis.core.StringRedisTemplate;
12 33  
13 34 import javax.annotation.Resource;
14 35  
  36 +import static cn.hutool.core.util.RandomUtil.randomEle;
15 37 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
16 38 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
17 39 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
18   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
19   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
20   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLIENT_NOT_EXISTS;
  40 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  41 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
21 42 import static org.junit.jupiter.api.Assertions.*;
  43 +import static org.mockito.Mockito.*;
22 44  
23   -// TODO 芋艿:单测后续补充下;
24 45 /**
25 46 * {@link SocialClientServiceImpl} 的单元测试类
26 47 *
27 48 * @author 芋道源码
28 49 */
29 50 @Import(SocialClientServiceImpl.class)
30   -@Disabled
31 51 public class SocialClientServiceImplTest extends BaseDbUnitTest {
32 52  
33 53 @Resource
... ... @@ -36,10 +56,305 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
36 56 @Resource
37 57 private SocialClientMapper socialClientMapper;
38 58  
  59 + @MockBean
  60 + private AuthRequestFactory authRequestFactory;
  61 +
  62 + @MockBean
  63 + private WxMpService wxMpService;
  64 + @MockBean
  65 + private WxMpProperties wxMpProperties;
  66 + @MockBean
  67 + private StringRedisTemplate stringRedisTemplate;
  68 + @MockBean
  69 + private WxMaService wxMaService;
  70 + @MockBean
  71 + private WxMaProperties wxMaProperties;
  72 +
  73 + @Test
  74 + public void testGetAuthorizeUrl() {
  75 + try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {
  76 + // 准备参数
  77 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  78 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  79 + String redirectUri = "sss";
  80 + // mock 获得对应的 AuthRequest 实现
  81 + AuthRequest authRequest = mock(AuthRequest.class);
  82 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  83 + // mock 方法
  84 + authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman");
  85 + when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.iocoder.cn?redirect_uri=yyy");
  86 +
  87 + // 调用
  88 + String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
  89 + // 断言
  90 + assertEquals("https://www.iocoder.cn?redirect_uri=sss", url);
  91 + }
  92 + }
  93 +
  94 + @Test
  95 + public void testAuthSocialUser_success() {
  96 + // 准备参数
  97 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  98 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  99 + String code = randomString();
  100 + String state = randomString();
  101 + // mock 方法(AuthRequest)
  102 + AuthRequest authRequest = mock(AuthRequest.class);
  103 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  104 + // mock 方法(AuthResponse)
  105 + AuthUser authUser = randomPojo(AuthUser.class);
  106 + AuthResponse<?> authResponse = new AuthResponse<>(2000, null, authUser);
  107 + when(authRequest.login(argThat(authCallback -> {
  108 + assertEquals(code, authCallback.getCode());
  109 + assertEquals(state, authCallback.getState());
  110 + return true;
  111 + }))).thenReturn(authResponse);
  112 +
  113 + // 调用
  114 + AuthUser result = socialClientService.getAuthUser(socialType, userType, code, state);
  115 + // 断言
  116 + assertSame(authUser, result);
  117 + }
  118 +
  119 + @Test
  120 + public void testAuthSocialUser_fail() {
  121 + // 准备参数
  122 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  123 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  124 + String code = randomString();
  125 + String state = randomString();
  126 + // mock 方法(AuthRequest)
  127 + AuthRequest authRequest = mock(AuthRequest.class);
  128 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  129 + // mock 方法(AuthResponse)
  130 + AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);
  131 + when(authRequest.login(argThat(authCallback -> {
  132 + assertEquals(code, authCallback.getCode());
  133 + assertEquals(state, authCallback.getState());
  134 + return true;
  135 + }))).thenReturn(authResponse);
  136 +
  137 + // 调用并断言
  138 + assertServiceException(
  139 + () -> socialClientService.getAuthUser(socialType, userType, code, state),
  140 + SOCIAL_USER_AUTH_FAILURE, "模拟失败");
  141 + }
  142 +
  143 + @Test
  144 + public void testBuildAuthRequest_clientNull() {
  145 + // 准备参数
  146 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  147 + Integer userType = randomPojo(SocialTypeEnum.class).getType();
  148 + // mock 获得对应的 AuthRequest 实现
  149 + AuthRequest authRequest = mock(AuthDefaultRequest.class);
  150 + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config");
  151 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  152 +
  153 + // 调用
  154 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
  155 + // 断言
  156 + assertSame(authRequest, result);
  157 + assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config"));
  158 + }
  159 +
  160 + @Test
  161 + public void testBuildAuthRequest_clientDisable() {
  162 + // 准备参数
  163 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  164 + Integer userType = randomPojo(SocialTypeEnum.class).getType();
  165 + // mock 获得对应的 AuthRequest 实现
  166 + AuthRequest authRequest = mock(AuthDefaultRequest.class);
  167 + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config");
  168 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  169 + // mock 数据
  170 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
  171 + .setUserType(userType).setSocialType(socialType));
  172 + socialClientMapper.insert(client);
  173 +
  174 + // 调用
  175 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
  176 + // 断言
  177 + assertSame(authRequest, result);
  178 + assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config"));
  179 + }
  180 +
  181 + @Test
  182 + public void testBuildAuthRequest_clientEnable() {
  183 + // 准备参数
  184 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  185 + Integer userType = randomPojo(SocialTypeEnum.class).getType();
  186 + // mock 获得对应的 AuthRequest 实现
  187 + AuthConfig authConfig = mock(AuthConfig.class);
  188 + AuthRequest authRequest = mock(AuthDefaultRequest.class);
  189 + ReflectUtil.setFieldValue(authRequest, "config", authConfig);
  190 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  191 + // mock 数据
  192 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
  193 + .setUserType(userType).setSocialType(socialType));
  194 + socialClientMapper.insert(client);
  195 +
  196 + // 调用
  197 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
  198 + // 断言
  199 + assertSame(authRequest, result);
  200 + assertNotSame(authConfig, ReflectUtil.getFieldValue(authRequest, "config"));
  201 + }
  202 +
  203 + // =================== 微信公众号独有 ===================
  204 +
  205 + @Test
  206 + public void testCreateWxMpJsapiSignature() throws WxErrorException {
  207 + // 准备参数
  208 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  209 + String url = randomString();
  210 + // mock 方法
  211 + WxJsapiSignature signature = randomPojo(WxJsapiSignature.class);
  212 + when(wxMpService.createJsapiSignature(eq(url))).thenReturn(signature);
  213 +
  214 + // 调用
  215 + WxJsapiSignature result = socialClientService.createWxMpJsapiSignature(userType, url);
  216 + // 断言
  217 + assertSame(signature, result);
  218 + }
  219 +
  220 + @Test
  221 + public void testGetWxMpService_clientNull() {
  222 + // 准备参数
  223 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  224 + // mock 方法
  225 +
  226 + // 调用
  227 + WxMpService result = socialClientService.getWxMpService(userType);
  228 + // 断言
  229 + assertSame(wxMpService, result);
  230 + }
  231 +
  232 + @Test
  233 + public void testGetWxMpService_clientDisable() {
  234 + // 准备参数
  235 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  236 + // mock 数据
  237 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
  238 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType()));
  239 + socialClientMapper.insert(client);
  240 +
  241 + // 调用
  242 + WxMpService result = socialClientService.getWxMpService(userType);
  243 + // 断言
  244 + assertSame(wxMpService, result);
  245 + }
  246 +
  247 + @Test
  248 + public void testGetWxMpService_clientEnable() {
  249 + // 准备参数
  250 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  251 + // mock 数据
  252 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
  253 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType()));
  254 + socialClientMapper.insert(client);
  255 + // mock 方法
  256 + WxMpProperties.ConfigStorage configStorage = mock(WxMpProperties.ConfigStorage.class);
  257 + when(wxMpProperties.getConfigStorage()).thenReturn(configStorage);
  258 +
  259 + // 调用
  260 + WxMpService result = socialClientService.getWxMpService(userType);
  261 + // 断言
  262 + assertNotSame(wxMpService, result);
  263 + assertEquals(client.getClientId(), result.getWxMpConfigStorage().getAppId());
  264 + assertEquals(client.getClientSecret(), result.getWxMpConfigStorage().getSecret());
  265 + }
  266 +
  267 + // =================== 微信小程序独有 ===================
  268 +
  269 + @Test
  270 + public void testGetWxMaPhoneNumberInfo_success() throws WxErrorException {
  271 + // 准备参数
  272 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  273 + String phoneCode = randomString();
  274 + // mock 方法
  275 + WxMaUserService userService = mock(WxMaUserService.class);
  276 + when(wxMaService.getUserService()).thenReturn(userService);
  277 + WxMaPhoneNumberInfo phoneNumber = randomPojo(WxMaPhoneNumberInfo.class);
  278 + when(userService.getPhoneNoInfo(eq(phoneCode))).thenReturn(phoneNumber);
  279 +
  280 + // 调用
  281 + WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
  282 + // 断言
  283 + assertSame(phoneNumber, result);
  284 + }
  285 +
  286 + @Test
  287 + public void testGetWxMaPhoneNumberInfo_exception() throws WxErrorException {
  288 + // 准备参数
  289 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  290 + String phoneCode = randomString();
  291 + // mock 方法
  292 + WxMaUserService userService = mock(WxMaUserService.class);
  293 + when(wxMaService.getUserService()).thenReturn(userService);
  294 + WxErrorException wxErrorException = randomPojo(WxErrorException.class);
  295 + when(userService.getPhoneNoInfo(eq(phoneCode))).thenThrow(wxErrorException);
  296 +
  297 + // 调用并断言异常
  298 + assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode),
  299 + SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
  300 + }
  301 +
  302 + @Test
  303 + public void testGetWxMaService_clientNull() {
  304 + // 准备参数
  305 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  306 + // mock 方法
  307 +
  308 + // 调用
  309 + WxMaService result = socialClientService.getWxMaService(userType);
  310 + // 断言
  311 + assertSame(wxMaService, result);
  312 + }
  313 +
  314 + @Test
  315 + public void testGetWxMaService_clientDisable() {
  316 + // 准备参数
  317 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  318 + // mock 数据
  319 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
  320 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()));
  321 + socialClientMapper.insert(client);
  322 +
  323 + // 调用
  324 + WxMaService result = socialClientService.getWxMaService(userType);
  325 + // 断言
  326 + assertSame(wxMaService, result);
  327 + }
  328 +
  329 + @Test
  330 + public void testGetWxMaService_clientEnable() {
  331 + // 准备参数
  332 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  333 + // mock 数据
  334 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
  335 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()));
  336 + socialClientMapper.insert(client);
  337 + // mock 方法
  338 + WxMaProperties.ConfigStorage configStorage = mock(WxMaProperties.ConfigStorage.class);
  339 + when(wxMaProperties.getConfigStorage()).thenReturn(configStorage);
  340 +
  341 + // 调用
  342 + WxMaService result = socialClientService.getWxMaService(userType);
  343 + // 断言
  344 + assertNotSame(wxMaService, result);
  345 + assertEquals(client.getClientId(), result.getWxMaConfig().getAppid());
  346 + assertEquals(client.getClientSecret(), result.getWxMaConfig().getSecret());
  347 + }
  348 +
  349 + // =================== 客户端管理 ===================
  350 +
39 351 @Test
40 352 public void testCreateSocialClient_success() {
41 353 // 准备参数
42   - SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class)
  354 + SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class,
  355 + o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
  356 + .setUserType(randomEle(UserTypeEnum.values()).getValue())
  357 + .setStatus(randomCommonStatus()))
43 358 .setId(null); // 防止 id 被赋值
44 359  
45 360 // 调用
... ... @@ -59,6 +374,9 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
59 374 // 准备参数
60 375 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> {
61 376 o.setId(dbSocialClient.getId()); // 设置更新的 ID
  377 + o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
  378 + .setUserType(randomEle(UserTypeEnum.values()).getValue())
  379 + .setStatus(randomCommonStatus());
62 380 });
63 381  
64 382 // 调用
... ... @@ -101,40 +419,47 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
101 419 }
102 420  
103 421 @Test
104   - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  422 + public void testGetSocialClient() {
  423 + // mock 数据
  424 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
  425 + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
  426 + // 准备参数
  427 + Long id = dbSocialClient.getId();
  428 +
  429 + // 调用
  430 + SocialClientDO socialClient = socialClientService.getSocialClient(id);
  431 + // 校验数据正确
  432 + assertPojoEquals(dbSocialClient, socialClient);
  433 + }
  434 +
  435 + @Test
105 436 public void testGetSocialClientPage() {
106 437 // mock 数据
107 438 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到
108   - o.setName(null);
109   - o.setSocialType(null);
110   - o.setUserType(null);
111   - o.setClientId(null);
112   - o.setClientSecret(null);
113   - o.setStatus(null);
114   - o.setCreateTime(null);
  439 + o.setName("芋头");
  440 + o.setSocialType(SocialTypeEnum.GITEE.getType());
  441 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  442 + o.setClientId("yudao");
  443 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
115 444 });
116 445 socialClientMapper.insert(dbSocialClient);
117 446 // 测试 name 不匹配
118   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(null)));
  447 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString())));
119 448 // 测试 socialType 不匹配
120   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(null)));
  449 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType())));
121 450 // 测试 userType 不匹配
122   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(null)));
  451 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
123 452 // 测试 clientId 不匹配
124   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId(null)));
125   - // 测试 clientSecret 不匹配
126   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientSecret(null)));
  453 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao")));
127 454 // 测试 status 不匹配
128   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(null)));
129   - // 测试 createTime 不匹配
130   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setCreateTime(null)));
  455 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
131 456 // 准备参数
132 457 SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
133   - reqVO.setName(null);
134   - reqVO.setSocialType(null);
135   - reqVO.setUserType(null);
136   - reqVO.setClientId(null);
137   - reqVO.setStatus(null);
  458 + reqVO.setName("芋");
  459 + reqVO.setSocialType(SocialTypeEnum.GITEE.getType());
  460 + reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
  461 + reqVO.setClientId("yu");
  462 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
138 463  
139 464 // 调用
140 465 PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.social;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 6 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
6 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
7 9 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
8 10 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
9 11 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
10 12 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
11 13 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
12   -import com.xingyuv.jushauth.enums.AuthResponseStatus;
13   -import com.xingyuv.jushauth.model.AuthCallback;
14   -import com.xingyuv.jushauth.model.AuthResponse;
15 14 import com.xingyuv.jushauth.model.AuthUser;
16   -import com.xingyuv.jushauth.request.AuthRequest;
17   -import com.xingyuv.justauth.AuthRequestFactory;
18   -import org.junit.jupiter.api.Disabled;
19 15 import org.junit.jupiter.api.Test;
20 16 import org.springframework.boot.test.mock.mockito.MockBean;
21 17 import org.springframework.context.annotation.Import;
... ... @@ -23,18 +19,27 @@ import org.springframework.context.annotation.Import;
23 19 import javax.annotation.Resource;
24 20 import java.util.List;
25 21  
26   -import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.hutool.core.util.RandomUtil.randomEle;
  23 +import static cn.hutool.core.util.RandomUtil.randomLong;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
27 26 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  27 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
28 28 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
29 29 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
30 30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
31   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE;
  31 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
32 32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
33 33 import static org.junit.jupiter.api.Assertions.assertEquals;
34   -import static org.mockito.Mockito.*;
  34 +import static org.mockito.Mockito.eq;
  35 +import static org.mockito.Mockito.when;
35 36  
  37 +/**
  38 + * {@link SocialUserServiceImpl} 的单元测试类
  39 + *
  40 + * @author 芋道源码
  41 + */
36 42 @Import(SocialUserServiceImpl.class)
37   -@Disabled // TODO 芋艿:后续统一修复
38 43 public class SocialUserServiceImplTest extends BaseDbUnitTest {
39 44  
40 45 @Resource
... ... @@ -46,119 +51,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
46 51 private SocialUserBindMapper socialUserBindMapper;
47 52  
48 53 @MockBean
49   - private AuthRequestFactory authRequestFactory;
50   -
51   - // TODO 芋艿:后续统一修复
52   -// @Test
53   -// public void testGetAuthorizeUrl() {
54   -// try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {
55   -// // 准备参数
56   -// Integer type = SocialTypeEnum.WECHAT_MP.getType();
57   -// String redirectUri = "sss";
58   -// // mock 获得对应的 AuthRequest 实现
59   -// AuthRequest authRequest = mock(AuthRequest.class);
60   -// when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
61   -// // mock 方法
62   -// authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman");
63   -// when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.iocoder.cn?redirect_uri=yyy");
64   -//
65   -// // 调用
66   -// String url = socialUserService.getAuthorizeUrl(type, redirectUri);
67   -// // 断言
68   -// assertEquals("https://www.iocoder.cn?redirect_uri=sss", url);
69   -// }
70   -// }
71   -
72   - @Test
73   - public void testAuthSocialUser_exists() {
74   - // 准备参数
75   - Integer socialType = SocialTypeEnum.GITEE.getType();
76   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
77   - String code = "tudou";
78   - String state = "yuanma";
79   - // mock 方法
80   - SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
81   - socialUserMapper.insert(socialUser);
82   -
83   - // 调用
84   - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
85   - // 断言
86   - assertPojoEquals(socialUser, result);
87   - }
88   -
89   - @Test
90   - public void testAuthSocialUser_authFailure() {
91   - // 准备参数
92   - Integer socialType = SocialTypeEnum.GITEE.getType();
93   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
94   - // mock 方法
95   - AuthRequest authRequest = mock(AuthRequest.class);
96   - when(authRequestFactory.get(anyString())).thenReturn(authRequest);
97   - AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);
98   - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
99   -
100   - // 调用并断言
101   - assertServiceException(
102   - () -> socialUserService.authSocialUser(socialType, userType, randomString(10), randomString(10)),
103   - SOCIAL_USER_AUTH_FAILURE, "模拟失败");
104   - }
105   -
106   - @Test
107   - public void testAuthSocialUser_insert() {
108   - // 准备参数
109   - Integer socialType = SocialTypeEnum.GITEE.getType();
110   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
111   - String code = "tudou";
112   - String state = "yuanma";
113   - // mock 方法
114   - AuthRequest authRequest = mock(AuthRequest.class);
115   - when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);
116   - AuthUser authUser = randomPojo(AuthUser.class);
117   - AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);
118   - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
119   -
120   - // 调用
121   - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
122   - // 断言
123   - assertBindSocialUser(socialType, result, authResponse.getData());
124   - assertEquals(code, result.getCode());
125   - assertEquals(state, result.getState());
126   - }
127   -
128   - @Test
129   - public void testAuthSocialUser_update() {
130   - // 准备参数
131   - Integer socialType = SocialTypeEnum.GITEE.getType();
132   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
133   - String code = "tudou";
134   - String state = "yuanma";
135   - // mock 数据
136   - socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
137   - // mock 方法
138   - AuthRequest authRequest = mock(AuthRequest.class);
139   - when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);
140   - AuthUser authUser = randomPojo(AuthUser.class);
141   - authUser.getToken().setOpenId("test_openid");
142   - AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);
143   - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
144   -
145   - // 调用
146   - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
147   - // 断言
148   - assertBindSocialUser(socialType, result, authResponse.getData());
149   - assertEquals(code, result.getCode());
150   - assertEquals(state, result.getState());
151   - }
152   -
153   - private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
154   - assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
155   - assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
156   - assertEquals(authUser.getNickname(), socialUser.getNickname());
157   - assertEquals(authUser.getAvatar(), socialUser.getAvatar());
158   - assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
159   - assertEquals(type, socialUser.getType());
160   - assertEquals(authUser.getUuid(), socialUser.getOpenid());
161   - }
  54 + private SocialClientService socialClientService;
162 55  
163 56 @Test
164 57 public void testGetSocialUserList() {
... ... @@ -260,4 +153,136 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
260 153 assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid());
261 154 }
262 155  
  156 + @Test
  157 + public void testAuthSocialUser_exists() {
  158 + // 准备参数
  159 + Integer socialType = SocialTypeEnum.GITEE.getType();
  160 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  161 + String code = "tudou";
  162 + String state = "yuanma";
  163 + // mock 方法
  164 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
  165 + socialUserMapper.insert(socialUser);
  166 +
  167 + // 调用
  168 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  169 + // 断言
  170 + assertPojoEquals(socialUser, result);
  171 + }
  172 +
  173 + @Test
  174 + public void testAuthSocialUser_notNull() {
  175 + // mock 数据
  176 + SocialUserDO socialUser = randomPojo(SocialUserDO.class,
  177 + o -> o.setType(SocialTypeEnum.GITEE.getType()).setCode("tudou").setState("yuanma"));
  178 + socialUserMapper.insert(socialUser);
  179 + // 准备参数
  180 + Integer socialType = SocialTypeEnum.GITEE.getType();
  181 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  182 + String code = "tudou";
  183 + String state = "yuanma";
  184 +
  185 + // 调用
  186 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  187 + // 断言
  188 + assertPojoEquals(socialUser, result);
  189 + }
  190 +
  191 + @Test
  192 + public void testAuthSocialUser_insert() {
  193 + // 准备参数
  194 + Integer socialType = SocialTypeEnum.GITEE.getType();
  195 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  196 + String code = "tudou";
  197 + String state = "yuanma";
  198 + // mock 方法
  199 + AuthUser authUser = randomPojo(AuthUser.class);
  200 + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
  201 +
  202 + // 调用
  203 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  204 + // 断言
  205 + assertBindSocialUser(socialType, result, authUser);
  206 + assertEquals(code, result.getCode());
  207 + assertEquals(state, result.getState());
  208 + }
  209 +
  210 + @Test
  211 + public void testAuthSocialUser_update() {
  212 + // 准备参数
  213 + Integer socialType = SocialTypeEnum.GITEE.getType();
  214 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  215 + String code = "tudou";
  216 + String state = "yuanma";
  217 + // mock 数据
  218 + socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
  219 + // mock 方法
  220 + AuthUser authUser = randomPojo(AuthUser.class);
  221 + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
  222 +
  223 + // 调用
  224 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  225 + // 断言
  226 + assertBindSocialUser(socialType, result, authUser);
  227 + assertEquals(code, result.getCode());
  228 + assertEquals(state, result.getState());
  229 + }
  230 +
  231 + private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
  232 + assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
  233 + assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
  234 + assertEquals(authUser.getNickname(), socialUser.getNickname());
  235 + assertEquals(authUser.getAvatar(), socialUser.getAvatar());
  236 + assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
  237 + assertEquals(type, socialUser.getType());
  238 + assertEquals(authUser.getUuid(), socialUser.getOpenid());
  239 + }
  240 +
  241 + @Test
  242 + public void testGetSocialUser_id() {
  243 + // mock 数据
  244 + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class);
  245 + socialUserMapper.insert(socialUserDO);
  246 + // 参数准备
  247 + Long id = socialUserDO.getId();
  248 +
  249 + // 调用
  250 + SocialUserDO dbSocialUserDO = socialUserService.getSocialUser(id);
  251 + // 断言
  252 + assertPojoEquals(socialUserDO, dbSocialUserDO);
  253 + }
  254 +
  255 + @Test
  256 + public void testGetSocialUserPage() {
  257 + // mock 数据
  258 + SocialUserDO dbSocialUser = randomPojo(SocialUserDO.class, o -> { // 等会查询到
  259 + o.setType(SocialTypeEnum.GITEE.getType());
  260 + o.setNickname("芋艿");
  261 + o.setOpenid("yudaoyuanma");
  262 + o.setCreateTime(buildTime(2020, 1, 15));
  263 + });
  264 + socialUserMapper.insert(dbSocialUser);
  265 + // 测试 type 不匹配
  266 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setType(SocialTypeEnum.DINGTALK.getType())));
  267 + // 测试 nickname 不匹配
  268 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setNickname(randomString())));
  269 + // 测试 openid 不匹配
  270 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setOpenid("java")));
  271 + // 测试 createTime 不匹配
  272 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setCreateTime(buildTime(2020, 1, 21))));
  273 + // 准备参数
  274 + SocialUserPageReqVO reqVO = new SocialUserPageReqVO();
  275 + reqVO.setType(SocialTypeEnum.GITEE.getType());
  276 + reqVO.setNickname("芋");
  277 + reqVO.setOpenid("yudao");
  278 + reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20));
  279 +
  280 + // 调用
  281 + PageResult<SocialUserDO> pageResult = socialUserService.getSocialUserPage(reqVO);
  282 + // 断言
  283 + assertEquals(1, pageResult.getTotal());
  284 + assertEquals(1, pageResult.getList().size());
  285 + assertPojoEquals(dbSocialUser, pageResult.getList().get(0));
  286 + }
  287 +
263 288 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
... ... @@ -332,6 +332,18 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
332 332 }
333 333  
334 334 @Test
  335 + public void testGetTenantByWebsite() {
  336 + // mock 数据
  337 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setWebsite("https://www.iocoder.cn"));
  338 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  339 +
  340 + // 调用
  341 + TenantDO result = tenantService.getTenantByWebsite("https://www.iocoder.cn");
  342 + // 校验存在
  343 + assertPojoEquals(result, dbTenant);
  344 + }
  345 +
  346 + @Test
335 347 public void testGetTenantListByPackageId() {
336 348 // mock 数据
337 349 TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L));
... ...
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql
... ... @@ -361,13 +361,14 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_client&quot; (
361 361 "user_type" int NOT NULL,
362 362 "client_id" varchar(255) NOT NULL,
363 363 "client_secret" varchar(255) NOT NULL,
  364 + "agent_id" varchar(255) NOT NULL,
364 365 "status" int NOT NULL,
365 366 "creator" varchar(64) DEFAULT '',
366 367 "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
367 368 "updater" varchar(64) DEFAULT '',
368 369 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
369 370 "deleted" bit NOT NULL DEFAULT FALSE,
370   - "tenant_id" bigint NOT NULL,
  371 + "tenant_id" bigint not null default '0',
371 372 PRIMARY KEY ("id")
372 373 ) COMMENT '社交客户端表';
373 374  
... ...