fix: 收口融合 QA 构建与验收安全基线
This commit is contained in:
1 parent
47bc6604e5
commit
5560a3ac04
28 files changed
+22947
-352
No files matched your search
+5
-7
@@ -16,7 +16,7 @@
|
||||
<ruoyi.version>3.9.2</ruoyi.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<java.version>21</java.version>
|
||||
<spring-boot.version>4.1.0</spring-boot.version>
|
||||
<mybatis-spring-boot.version>4.1.0</mybatis-spring-boot.version>
|
||||
<druid.version>1.2.28</druid.version>
|
||||
@@ -137,9 +137,8 @@
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- KingbaseES(人大金仓)驱动:官方未提供公网 Maven 仓库,驱动包直接放置在
|
||||
ruoyi-admin/lib 目录,由 ruoyi-admin 模块的 kingbase profile 以 system scope 引入。
|
||||
若 jar 文件名或版本变更,请同步修改 kingbase.version 属性及 ruoyi-admin 中的 systemPath。 -->
|
||||
<!-- Approved vendor JDBC artifact: privately provision cn.com.kingbase:kingbase8.
|
||||
See scripts/bootstrap/install-kingbase-jdbc.sh; no vendor binary in Git. -->
|
||||
<dependency>
|
||||
<groupId>cn.com.kingbase</groupId>
|
||||
<artifactId>kingbase8</artifactId>
|
||||
@@ -224,8 +223,7 @@
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<parameters>true</parameters>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<release>${java.version}</release>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -262,4 +260,4 @@
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -94,7 +94,7 @@
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<!-- KingbaseES(人大金仓):驱动包置于 ruoyi-admin/lib 目录,直接按文件路径引入 -->
|
||||
<!-- KingbaseES: provision approved cn.com.kingbase:kingbase8 privately before build. -->
|
||||
<profile>
|
||||
<id>kingbase</id>
|
||||
<activation>
|
||||
@@ -104,31 +104,8 @@
|
||||
<dependency>
|
||||
<groupId>cn.com.kingbase</groupId>
|
||||
<artifactId>kingbase8</artifactId>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/kingbase8-${kingbase.version}.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- 打 war 包时把外部驱动一起放进 WEB-INF/lib -->
|
||||
<webResources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/lib</directory>
|
||||
<targetPath>WEB-INF/lib</targetPath>
|
||||
<filtering>false</filtering>
|
||||
<includes>
|
||||
<include>kingbase8-${kingbase.version}.jar</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</webResources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@@ -139,8 +116,6 @@
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<addResources>true</addResources>
|
||||
<!-- KingbaseES 等 system scope 驱动需要打进可执行 jar -->
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -163,4 +138,4 @@
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -7,18 +7,6 @@
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.2</version>
|
||||
</parent>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>9</source>
|
||||
<target>9</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
@@ -132,4 +120,4 @@
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -7,18 +7,6 @@
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.2</version>
|
||||
</parent>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>16</source>
|
||||
<target>16</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-iot</artifactId>
|
||||
|
||||
+7
-24
@@ -224,14 +224,8 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
boolean isTransferInsert = accommodation.getRemark() != null && accommodation.getRemark().contains("调房迁入");
|
||||
if (!isTransferInsert && TrainAccommodation.STATUS_CHECKED_IN.equals(accommodation.getAccommodationStatus()))
|
||||
{
|
||||
try
|
||||
{
|
||||
iotLockAuthBridgeService.reconcileCheckin(accommodation.getAccommodationId(), accommodation.getCreateBy());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("IoT lock auth reconcile on checkin failed for accommodation {}: {}", accommodation.getAccommodationId(), ex.getMessage());
|
||||
}
|
||||
// Intent persistence failure must abort the surrounding accommodation transaction.
|
||||
iotLockAuthBridgeService.reconcileCheckin(accommodation.getAccommodationId(), accommodation.getCreateBy());
|
||||
}
|
||||
}
|
||||
else if (accessAuthorizationOrchestrator != null)
|
||||
@@ -302,6 +296,7 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int checkIn(Long accommodationId, String operator)
|
||||
{
|
||||
TrainAccommodation exist = trainAccommodationMapper.selectTrainAccommodationByAccommodationId(accommodationId);
|
||||
@@ -320,14 +315,8 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
boolean useIot = "iot".equalsIgnoreCase(authEngine) && iotLockAuthBridgeService != null;
|
||||
if (useIot)
|
||||
{
|
||||
try
|
||||
{
|
||||
iotLockAuthBridgeService.reconcileCheckin(accommodationId, operator);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("IoT lock auth reconcile on checkIn failed for accommodation {}: {}", accommodationId, ex.getMessage());
|
||||
}
|
||||
// Intent persistence failure must abort the surrounding accommodation transaction.
|
||||
iotLockAuthBridgeService.reconcileCheckin(accommodationId, operator);
|
||||
}
|
||||
else if (accessAuthorizationOrchestrator != null)
|
||||
{
|
||||
@@ -457,14 +446,8 @@ public class TrainAccommodationServiceImpl implements ITrainAccommodationService
|
||||
|
||||
if ("iot".equalsIgnoreCase(authEngine) && iotLockAuthBridgeService != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
iotLockAuthBridgeService.reconcileTransfer(oldAccommodationId, newAcc.getAccommodationId(), operator);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.error("IoT lock auth transfer reconcile failed for old {} -> new {}: {}", oldAccommodationId, newAcc.getAccommodationId(), ex.getMessage());
|
||||
}
|
||||
// Intent persistence failure must abort the surrounding accommodation transaction.
|
||||
iotLockAuthBridgeService.reconcileTransfer(oldAccommodationId, newAcc.getAccommodationId(), operator);
|
||||
}
|
||||
|
||||
return newAcc;
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.ruoyi.train.service.impl;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.train.domain.TrainAccommodation;
|
||||
import com.ruoyi.train.integration.lock.service.ITrainLockAuthBridgeService;
|
||||
import com.ruoyi.train.mapper.TrainAccommodationMapper;
|
||||
import com.ruoyi.train.mapper.TrainDormitoryInfoMapper;
|
||||
|
||||
/** Actual business entry-point exception/transaction declarations, not a database rollback proof. */
|
||||
public class Round5vAccommodationAtomicityTest {
|
||||
private final RuntimeException failure = new IllegalStateException("synthetic-intent-persistence-failure");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T proxy(Class<T> type, InvocationHandler handler) {
|
||||
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[]{type}, handler);
|
||||
}
|
||||
private void inject(Object object, String name, Object value) throws Exception {
|
||||
Field field = TrainAccommodationServiceImpl.class.getDeclaredField(name);
|
||||
field.setAccessible(true); field.set(object,value);
|
||||
}
|
||||
private TrainAccommodationServiceImpl service(boolean transfer) throws Exception {
|
||||
TrainAccommodationServiceImpl service = transfer ? new TrainAccommodationServiceImpl() {
|
||||
@Override public int insertTrainAccommodation(TrainAccommodation value) {
|
||||
value.setAccommodationId(2L); return 1; // isolate transfer exception boundary only
|
||||
}
|
||||
} : new TrainAccommodationServiceImpl();
|
||||
TrainAccommodation old = new TrainAccommodation(); old.setAccommodationId(1L);
|
||||
old.setAccommodationStatus(TrainAccommodation.STATUS_CHECKED_IN); old.setDormId("QA_A"); old.setEnrollmentId(3L);
|
||||
inject(service,"trainAccommodationMapper",proxy(TrainAccommodationMapper.class,(p,m,a)-> {
|
||||
if (m.getName().equals("selectTrainAccommodationByAccommodationId")) return old;
|
||||
if (m.getReturnType()==int.class) return 1;
|
||||
return null;
|
||||
}));
|
||||
inject(service,"trainDormitoryInfoMapper",proxy(TrainDormitoryInfoMapper.class,(p,m,a)->null));
|
||||
service.setAuthEngine("iot");
|
||||
service.setIotLockAuthBridgeService(proxy(ITrainLockAuthBridgeService.class,(p,m,a)-> { throw failure; }));
|
||||
return service;
|
||||
}
|
||||
@Test public void checkinDoesNotSwallowIntentPersistenceFailure() throws Exception {
|
||||
try { service(false).checkIn(1L,"qa-test"); fail("Failure must propagate"); }
|
||||
catch (RuntimeException expected) { assertSame(failure,expected); }
|
||||
}
|
||||
@Test public void transferDoesNotSwallowIntentPersistenceFailure() throws Exception {
|
||||
try { service(true).transfer(1L,"QA_B","1","qa-test"); fail("Failure must propagate"); }
|
||||
catch (RuntimeException expected) { assertSame(failure,expected); }
|
||||
}
|
||||
@Test public void checkoutStillPropagatesIntentPersistenceFailure() throws Exception {
|
||||
try { service(false).checkOut(1L,"qa-test"); fail("Failure must propagate"); }
|
||||
catch (RuntimeException expected) { assertSame(failure,expected); }
|
||||
}
|
||||
@Test public void checkinDeclaresRollbackBoundary() throws Exception {
|
||||
Transactional annotation = TrainAccommodationServiceImpl.class.getMethod("checkIn",Long.class,String.class).getAnnotation(Transactional.class);
|
||||
assertNotNull(annotation); assertTrue(Arrays.asList(annotation.rollbackFor()).contains(Exception.class));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user