feat(ft546): run standard WCS as the single scheduler

This commit is contained in:
zgw
2026-08-11 16:57:55 +08:00
parent f53b250336
commit c80acf0d99
18 changed files with 737 additions and 4 deletions

View File

@@ -0,0 +1,175 @@
package com.ruoyi.project.ft546.runtime;
import com.ruoyi.project.ft546.config.Ft546WcsProperties;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.schedule.ScheduleThread;
import com.ruoyi.schedule.scheduleTask.srgv.BaseSRgvThread;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class Ft546StandardRuntimeTest {
@Test
void standardModeDoesNotConstructLegacyBusinessThreads() {
ScheduleThread runtime = runtime(Ft546WcsProperties.RuntimeMode.STANDARD);
ReflectionTestUtils.invokeMethod(runtime, "scheduleInit");
assertNull(runtime.ssjThreadCustomThread);
assertNull(runtime.sRgvThreadCustomThread);
assertNull(runtime.tsjThreadCustomThread);
assertNull(runtime.cdzThreadCustomThread);
}
@Test
void legacyModeKeepsExistingBusinessThreadInitialization() {
ScheduleThread runtime = runtime(Ft546WcsProperties.RuntimeMode.LEGACY);
ReflectionTestUtils.invokeMethod(runtime, "scheduleInit");
assertNotNull(runtime.ssjThreadCustomThread);
assertNotNull(runtime.sRgvThreadCustomThread);
assertNotNull(runtime.tsjThreadCustomThread);
assertNotNull(runtime.cdzThreadCustomThread);
}
@Test
void standardModeRejectsManualLegacySchedulerStart() {
ScheduleThread runtime = runtime(Ft546WcsProperties.RuntimeMode.STANDARD);
IllegalStateException failure = assertThrows(IllegalStateException.class,
runtime::startAllThread2);
assertEquals("legacy business scheduler is disabled in STANDARD mode",
failure.getMessage());
}
@Test
void baseSrgvThreadRefusesToRunInStandardMode() {
Object originalFactory = ReflectionTestUtils.getField(
SpringUtils.class, "beanFactory");
DefaultListableBeanFactory factory =
new DefaultListableBeanFactory();
Ft546WcsProperties properties = new Ft546WcsProperties();
properties.setRuntimeMode(Ft546WcsProperties.RuntimeMode.STANDARD);
factory.registerSingleton("ft546WcsProperties", properties);
ReflectionTestUtils.setField(SpringUtils.class, "beanFactory",
factory);
AtomicBoolean initialized = new AtomicBoolean();
BaseSRgvThread legacyThread = new BaseSRgvThread() {
@Override
public void init() {
initialized.set(true);
isRun = false;
}
};
try {
legacyThread.run();
} finally {
ReflectionTestUtils.setField(SpringUtils.class, "beanFactory",
originalFactory);
}
assertFalse(initialized.get());
}
@Test
void runtimeModeDefaultsToLegacy() {
assertEquals(Ft546WcsProperties.RuntimeMode.LEGACY,
new Ft546WcsProperties().getRuntimeMode());
}
@Test
void standardSchedulerOwnsTheCoreTick() {
AtomicInteger ticks = new AtomicInteger();
Ft546WcsScheduler scheduler = new Ft546WcsScheduler(() -> {
ticks.incrementAndGet();
return com.ruoyi.wcs.application.RuntimeTickResult
.recoveryBlocked();
});
scheduler.runScheduledTick();
assertEquals(1, ticks.get());
assertEquals(1L, scheduler.getCompletedTickCount());
}
@Test
void legacyModeDoesNotRequireStandardRuntimePorts() {
new ApplicationContextRunner()
.withUserConfiguration(Ft546AdapterConfiguration.class)
.withPropertyValues("ft546.wcs.runtime-mode=LEGACY")
.run(context -> {
assertNull(context.getStartupFailure());
assertTrue(context.getBeansOfType(
Ft546WcsScheduler.class).isEmpty());
});
}
@Test
void standardModeFailsFastWhenPersistentRuntimePortsAreMissing() {
new ApplicationContextRunner()
.withUserConfiguration(Ft546AdapterConfiguration.class)
.withPropertyValues("ft546.wcs.runtime-mode=STANDARD")
.run(context -> assertNotNull(context.getStartupFailure()));
}
@Test
void standardFactReadersStartOnlyAfterApplicationIsReady() {
AtomicInteger starts = new AtomicInteger();
ScheduleThread runtime = new ScheduleThread() {
@Override
public synchronized void startAllThread() {
starts.incrementAndGet();
}
};
Ft546WcsProperties properties = new Ft546WcsProperties();
properties.setRuntimeMode(Ft546WcsProperties.RuntimeMode.STANDARD);
ReflectionTestUtils.setField(runtime, "ft546WcsProperties",
properties);
runtime.startStandardFactReadersAfterApplicationReady();
assertEquals(1, starts.get());
}
@Test
void legacyFactReadersRemainOperatorControlledAfterApplicationReady() {
AtomicInteger starts = new AtomicInteger();
ScheduleThread runtime = new ScheduleThread() {
@Override
public synchronized void startAllThread() {
starts.incrementAndGet();
}
};
ReflectionTestUtils.setField(runtime, "ft546WcsProperties",
new Ft546WcsProperties());
runtime.startStandardFactReadersAfterApplicationReady();
assertEquals(0, starts.get());
}
private static ScheduleThread runtime(
Ft546WcsProperties.RuntimeMode mode) {
Ft546WcsProperties properties = new Ft546WcsProperties();
properties.setRuntimeMode(mode);
ScheduleThread runtime = new ScheduleThread();
ReflectionTestUtils.setField(runtime, "ft546WcsProperties",
properties);
return runtime;
}
}