test(apitest): add e2e seed endpoints and coverage
This commit is contained in:
@@ -28,7 +28,9 @@ import com.starry.admin.modules.shop.service.IPlayClerkGiftInfoService;
|
||||
import com.starry.admin.modules.shop.service.IPlayCommodityAndLevelInfoService;
|
||||
import com.starry.admin.modules.shop.service.IPlayCommodityInfoService;
|
||||
import com.starry.admin.modules.shop.service.IPlayGiftInfoService;
|
||||
import com.starry.admin.modules.system.mapper.SysMenuMapper;
|
||||
import com.starry.admin.modules.system.mapper.SysUserMapper;
|
||||
import com.starry.admin.modules.system.module.entity.SysMenuEntity;
|
||||
import com.starry.admin.modules.system.module.entity.SysTenantEntity;
|
||||
import com.starry.admin.modules.system.module.entity.SysTenantPackageEntity;
|
||||
import com.starry.admin.modules.system.module.entity.SysUserEntity;
|
||||
@@ -37,12 +39,14 @@ import com.starry.admin.modules.system.service.ISysTenantService;
|
||||
import com.starry.admin.modules.system.service.SysUserService;
|
||||
import com.starry.admin.modules.weichat.service.WxTokenService;
|
||||
import com.starry.admin.utils.SecurityUtils;
|
||||
import com.starry.common.constant.UserConstants;
|
||||
import com.starry.common.context.CustomSecurityContextHolder;
|
||||
import com.starry.common.utils.IdUtils;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
@@ -77,6 +81,7 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
public static final String DEFAULT_GIFT_ID = "gift-basic";
|
||||
public static final String DEFAULT_GIFT_NAME = "API测试礼物";
|
||||
public static final BigDecimal DEFAULT_COMMODITY_PRICE = new BigDecimal("120.00");
|
||||
public static final BigDecimal E2E_CUSTOMER_BALANCE = new BigDecimal("1000.00");
|
||||
private static final String GIFT_TYPE_REGULAR = "1";
|
||||
private static final String GIFT_STATE_ACTIVE = "0";
|
||||
private static final BigDecimal DEFAULT_CUSTOMER_BALANCE = new BigDecimal("200.00");
|
||||
@@ -86,6 +91,7 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
private final ISysTenantService tenantService;
|
||||
private final SysUserService sysUserService;
|
||||
private final SysUserMapper sysUserMapper;
|
||||
private final SysMenuMapper sysMenuMapper;
|
||||
private final IPlayPersonnelGroupInfoService personnelGroupInfoService;
|
||||
private final IPlayClerkLevelInfoService clerkLevelInfoService;
|
||||
private final IPlayClerkUserInfoService clerkUserInfoService;
|
||||
@@ -108,6 +114,7 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
ISysTenantService tenantService,
|
||||
SysUserService sysUserService,
|
||||
SysUserMapper sysUserMapper,
|
||||
SysMenuMapper sysMenuMapper,
|
||||
IPlayPersonnelGroupInfoService personnelGroupInfoService,
|
||||
IPlayClerkLevelInfoService clerkLevelInfoService,
|
||||
IPlayClerkUserInfoService clerkUserInfoService,
|
||||
@@ -128,6 +135,7 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
this.tenantService = tenantService;
|
||||
this.sysUserService = sysUserService;
|
||||
this.sysUserMapper = sysUserMapper;
|
||||
this.sysMenuMapper = sysMenuMapper;
|
||||
this.personnelGroupInfoService = personnelGroupInfoService;
|
||||
this.clerkLevelInfoService = clerkLevelInfoService;
|
||||
this.clerkUserInfoService = clerkUserInfoService;
|
||||
@@ -149,6 +157,7 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
@Override
|
||||
@Transactional
|
||||
public void run(String... args) {
|
||||
seedPcTenantWagesMenu();
|
||||
seedTenantPackage();
|
||||
seedTenant();
|
||||
|
||||
@@ -173,6 +182,98 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
}
|
||||
}
|
||||
|
||||
private void seedPcTenantWagesMenu() {
|
||||
// Minimal menu tree for pc-tenant E2E: /play/clerk/wages -> play/clerk/wages/index.vue
|
||||
// This is apitest-only; prod/dev menus are managed by ops/admin tooling.
|
||||
SysMenuEntity playRoot = ensureMenu(
|
||||
"陪聊管理",
|
||||
"PlayManage",
|
||||
0L,
|
||||
UserConstants.TYPE_DIR,
|
||||
"/play",
|
||||
UserConstants.LAYOUT,
|
||||
50);
|
||||
|
||||
SysMenuEntity clerkDir = ensureMenu(
|
||||
"店员管理",
|
||||
"ClerkManage",
|
||||
playRoot.getMenuId(),
|
||||
UserConstants.TYPE_DIR,
|
||||
"clerk",
|
||||
"",
|
||||
1);
|
||||
|
||||
ensureMenu(
|
||||
"收益管理",
|
||||
"ClerkWages",
|
||||
clerkDir.getMenuId(),
|
||||
UserConstants.TYPE_MENU,
|
||||
"wages",
|
||||
"play/clerk/wages/index",
|
||||
1);
|
||||
}
|
||||
|
||||
private SysMenuEntity ensureMenu(
|
||||
String menuName,
|
||||
String menuCode,
|
||||
Long parentId,
|
||||
String menuType,
|
||||
String path,
|
||||
String component,
|
||||
Integer sort) {
|
||||
Optional<SysMenuEntity> existing = sysMenuMapper.selectList(Wrappers.<SysMenuEntity>lambdaQuery()
|
||||
.eq(SysMenuEntity::getDeleted, false)
|
||||
.eq(SysMenuEntity::getParentId, parentId)
|
||||
.eq(SysMenuEntity::getMenuCode, menuCode)
|
||||
.last("limit 1"))
|
||||
.stream()
|
||||
.findFirst();
|
||||
if (existing.isPresent()) {
|
||||
SysMenuEntity current = existing.get();
|
||||
boolean changed = false;
|
||||
if (!Objects.equals(current.getPath(), path)) {
|
||||
current.setPath(path);
|
||||
changed = true;
|
||||
}
|
||||
if (!Objects.equals(current.getComponent(), component)) {
|
||||
current.setComponent(component);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
current.setUpdatedBy("apitest-seed");
|
||||
current.setUpdatedTime(new Date());
|
||||
sysMenuMapper.updateById(current);
|
||||
log.info("Updated apitest sys_menu '{}' path='{}' component='{}'", menuName, path, component);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
SysMenuEntity entity = new SysMenuEntity();
|
||||
entity.setMenuName(menuName);
|
||||
entity.setMenuCode(menuCode);
|
||||
entity.setIcon("el-icon-menu");
|
||||
entity.setPermission("");
|
||||
entity.setMenuLevel(parentId == 0 ? 1L : 2L);
|
||||
entity.setSort(sort);
|
||||
entity.setParentId(parentId);
|
||||
entity.setMenuType(menuType);
|
||||
entity.setStatus(0);
|
||||
entity.setRemark(menuName);
|
||||
entity.setPath(path);
|
||||
entity.setComponent(component);
|
||||
entity.setRouterQuery("");
|
||||
entity.setIsFrame(0);
|
||||
entity.setVisible(1);
|
||||
entity.setDeleted(Boolean.FALSE);
|
||||
entity.setCreatedBy("apitest-seed");
|
||||
entity.setCreatedTime(new Date());
|
||||
entity.setUpdatedBy("apitest-seed");
|
||||
entity.setUpdatedTime(new Date());
|
||||
sysMenuMapper.insert(entity);
|
||||
log.info("Inserted apitest sys_menu '{}' path='{}' parentId={}", menuName, path, parentId);
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void seedTenantPackage() {
|
||||
long existing = tenantPackageService.count(Wrappers.<SysTenantPackageEntity>lambdaQuery()
|
||||
.eq(SysTenantPackageEntity::getPackageId, DEFAULT_PACKAGE_ID));
|
||||
@@ -496,22 +597,27 @@ public class ApiTestDataSeeder implements CommandLineRunner {
|
||||
|
||||
private void seedClerkCommodity() {
|
||||
PlayClerkCommodityEntity mapping = clerkCommodityService.getById(DEFAULT_CLERK_COMMODITY_ID);
|
||||
if (mapping != null) {
|
||||
log.info("API test clerk commodity {} already exists", DEFAULT_CLERK_COMMODITY_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
String commodityName = DEFAULT_COMMODITY_PARENT_NAME;
|
||||
PlayCommodityInfoEntity parent = commodityInfoService.getById(DEFAULT_COMMODITY_PARENT_ID);
|
||||
if (parent != null && parent.getItemName() != null) {
|
||||
commodityName = parent.getItemName();
|
||||
}
|
||||
|
||||
if (mapping != null) {
|
||||
clerkCommodityService.update(Wrappers.<PlayClerkCommodityEntity>lambdaUpdate()
|
||||
.eq(PlayClerkCommodityEntity::getId, DEFAULT_CLERK_COMMODITY_ID)
|
||||
.set(PlayClerkCommodityEntity::getCommodityId, DEFAULT_COMMODITY_PARENT_ID)
|
||||
.set(PlayClerkCommodityEntity::getCommodityName, commodityName)
|
||||
.set(PlayClerkCommodityEntity::getEnablingState, "1"));
|
||||
log.info("API test clerk commodity {} already exists, state refreshed", DEFAULT_CLERK_COMMODITY_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayClerkCommodityEntity entity = new PlayClerkCommodityEntity();
|
||||
entity.setId(DEFAULT_CLERK_COMMODITY_ID);
|
||||
entity.setTenantId(DEFAULT_TENANT_ID);
|
||||
entity.setClerkId(DEFAULT_CLERK_ID);
|
||||
entity.setCommodityId(DEFAULT_COMMODITY_ID);
|
||||
entity.setCommodityId(DEFAULT_COMMODITY_PARENT_ID);
|
||||
entity.setCommodityName(commodityName);
|
||||
entity.setEnablingState("1");
|
||||
entity.setSort(1);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,9 @@ public class WxCustomMpService {
|
||||
@Resource
|
||||
private WxMpService wxMpService;
|
||||
|
||||
@Value("${wechat.subscribe-check-enabled:true}")
|
||||
private boolean subscribeCheckEnabled;
|
||||
|
||||
@Resource
|
||||
private SysTenantServiceImpl tenantService;
|
||||
@Resource
|
||||
@@ -480,6 +483,9 @@ public class WxCustomMpService {
|
||||
if (StrUtil.isBlankIfStr(openId)) {
|
||||
throw new ServiceException("openId不能为空");
|
||||
}
|
||||
if (!subscribeCheckEnabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
WxMpUser wxMpUser = proxyWxMpService(tenantId).getUserService().userInfo(openId);
|
||||
if (!wxMpUser.getSubscribe()) {
|
||||
|
||||
@@ -78,7 +78,14 @@ apitest:
|
||||
user-header: X-Test-User
|
||||
defaults:
|
||||
tenant-id: tenant-apitest
|
||||
user-id: apitest-user
|
||||
# Must exist in DB. ApiTestDataSeeder seeds DEFAULT_ADMIN_USER_ID=user-apitest-admin.
|
||||
user-id: user-apitest-admin
|
||||
roles:
|
||||
- ROLE_TESTER
|
||||
permissions: []
|
||||
permissions:
|
||||
- withdraw:deduction:create
|
||||
- withdraw:deduction:read
|
||||
|
||||
# E2E/ApiTest: skip real WeChat subscribe check to keep flows deterministic.
|
||||
wechat:
|
||||
subscribe-check-enabled: false
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.starry.admin.api;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.starry.admin.common.apitest.ApiTestDataSeeder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@TestPropertySource(properties = "test.auth.secret=apitest-secret")
|
||||
class WxOauthAdminTestAuthApiTest extends AbstractApiTest {
|
||||
|
||||
private static final String TEST_AUTH_HEADER = "X-Test-Auth";
|
||||
private static final String TEST_AUTH_SECRET = "apitest-secret";
|
||||
|
||||
@Test
|
||||
void adminLoginByUsernameRejectsWithoutSecretHeader() throws Exception {
|
||||
mockMvc.perform(post("/wx/oauth2/admin/loginByUsername")
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header("User-Agent", "apitest")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{" +
|
||||
"\"userName\":\"" + ApiTestDataSeeder.DEFAULT_ADMIN_USERNAME + "\"," +
|
||||
"\"passWord\":\"apitest-secret\"," +
|
||||
"\"tenantKey\":\"" + ApiTestDataSeeder.DEFAULT_TENANT_KEY + "\"" +
|
||||
"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(403));
|
||||
}
|
||||
|
||||
@Test
|
||||
void adminLoginByUsernameReturnsTokenWhenSecretHeaderValid() throws Exception {
|
||||
mockMvc.perform(post("/wx/oauth2/admin/loginByUsername")
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header("User-Agent", "apitest")
|
||||
.header(TEST_AUTH_HEADER, TEST_AUTH_SECRET)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{" +
|
||||
"\"userName\":\"" + ApiTestDataSeeder.DEFAULT_ADMIN_USERNAME + "\"," +
|
||||
"\"passWord\":\"apitest-secret\"," +
|
||||
"\"tenantKey\":\"" + ApiTestDataSeeder.DEFAULT_TENANT_KEY + "\"" +
|
||||
"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(200))
|
||||
.andExpect(jsonPath("$.data.tokenHead").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.token").isNotEmpty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.starry.admin.api;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.starry.admin.common.apitest.ApiTestDataSeeder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@TestPropertySource(properties = "test.auth.secret=apitest-secret")
|
||||
class WxOauthE2eSeedOrderApiTest extends AbstractApiTest {
|
||||
|
||||
private static final String TEST_AUTH_HEADER = "X-Test-Auth";
|
||||
private static final String TEST_AUTH_SECRET = "apitest-secret";
|
||||
|
||||
@Test
|
||||
void seedOrderRejectsWithoutSecretHeader() throws Exception {
|
||||
mockMvc.perform(post("/wx/oauth2/e2e/seed/order")
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header("User-Agent", "apitest")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(403));
|
||||
}
|
||||
|
||||
@Test
|
||||
void seedOrderReturnsFixtureWhenSecretHeaderValid() throws Exception {
|
||||
mockMvc.perform(post("/wx/oauth2/e2e/seed/order")
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header("User-Agent", "apitest")
|
||||
.header(TEST_AUTH_HEADER, TEST_AUTH_SECRET)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(200))
|
||||
.andExpect(jsonPath("$.data.tenantKey").value(ApiTestDataSeeder.DEFAULT_TENANT_KEY))
|
||||
.andExpect(jsonPath("$.data.customerId").value(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID))
|
||||
.andExpect(jsonPath("$.data.customerNickname").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.clerkId").value(ApiTestDataSeeder.DEFAULT_CLERK_ID))
|
||||
.andExpect(jsonPath("$.data.clerkNickname").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.clerkLevelId").value(ApiTestDataSeeder.DEFAULT_CLERK_LEVEL_ID))
|
||||
.andExpect(jsonPath("$.data.clerkSex").value("2"))
|
||||
.andExpect(jsonPath("$.data.commodityId").value(ApiTestDataSeeder.DEFAULT_COMMODITY_ID))
|
||||
.andExpect(jsonPath("$.data.giftId").value(ApiTestDataSeeder.DEFAULT_GIFT_ID));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.starry.admin.api;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.starry.admin.common.apitest.ApiTestDataSeeder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@TestPropertySource(properties = "test.auth.secret=apitest-secret")
|
||||
class WxOauthE2eSeedWageAdjustmentApiTest extends AbstractApiTest {
|
||||
|
||||
private static final String TEST_AUTH_HEADER = "X-Test-Auth";
|
||||
private static final String TEST_AUTH_SECRET = "apitest-secret";
|
||||
|
||||
@Test
|
||||
void seedWageAdjustmentRejectsWithoutSecretHeader() throws Exception {
|
||||
mockMvc.perform(post("/wx/oauth2/e2e/seed/wage-adjustment")
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header("User-Agent", "apitest")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(403));
|
||||
}
|
||||
|
||||
@Test
|
||||
void seedWageAdjustmentReturnsFixtureWhenSecretHeaderValid() throws Exception {
|
||||
mockMvc.perform(post("/wx/oauth2/e2e/seed/wage-adjustment")
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header("User-Agent", "apitest")
|
||||
.header(TEST_AUTH_HEADER, TEST_AUTH_SECRET)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(200))
|
||||
.andExpect(jsonPath("$.data.tenantKey").value(ApiTestDataSeeder.DEFAULT_TENANT_KEY))
|
||||
.andExpect(jsonPath("$.data.adminUserName").value(ApiTestDataSeeder.DEFAULT_ADMIN_USERNAME))
|
||||
.andExpect(jsonPath("$.data.clerkId").value(ApiTestDataSeeder.DEFAULT_CLERK_ID))
|
||||
.andExpect(jsonPath("$.data.beginTime").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.endTime").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.baseAmount").value("150.00"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user