test: bootstrap wcs demo domain

This commit is contained in:
zgw
2026-07-30 11:17:37 +08:00
parent 2623935b11
commit 010bea9e5e
6 changed files with 491 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
package com.ft546.wcs.demo.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class DispatchQueueEntry {
public enum QueueType {
BUSINESS,
AVOIDANCE
}
private final String queueId;
private final String taskId;
private final String vehicleId;
private final QueueType queueType;
private final String startSite;
private final String endSite;
private final int priority;
private int issued;
private int executionStatus;
private List<String> path;
private DispatchQueueEntry(
String queueId,
String taskId,
String vehicleId,
QueueType queueType,
String startSite,
String endSite,
int priority
) {
this.queueId = queueId;
this.taskId = taskId;
this.vehicleId = vehicleId;
this.queueType = queueType;
this.startSite = startSite;
this.endSite = endSite;
this.priority = priority;
this.issued = 0;
this.executionStatus = 1;
this.path = Collections.emptyList();
}
public static DispatchQueueEntry business(DispatchTask task, String vehicleId) {
if (task == null) {
throw new IllegalArgumentException("task must not be null");
}
if (vehicleId == null || vehicleId.trim().isEmpty()) {
throw new IllegalArgumentException("vehicle id must not be blank");
}
return new DispatchQueueEntry(
task.getTaskId(),
task.getTaskId(),
vehicleId,
QueueType.BUSINESS,
task.getSourceSite(),
task.getTargetSite(),
task.getPriority()
);
}
public void markIssued(List<String> issuedPath) {
if (issued != 0) {
throw new IllegalStateException("queue has already been issued");
}
if (issuedPath == null || issuedPath.isEmpty()) {
throw new IllegalArgumentException("issued path must not be empty");
}
this.path = Collections.unmodifiableList(new ArrayList<String>(issuedPath));
this.issued = 1;
this.executionStatus = 3;
}
public void markCompleted() {
if (issued == 0) {
throw new IllegalStateException("unissued queue cannot complete");
}
this.executionStatus = 4;
}
public String getQueueId() {
return queueId;
}
public String getTaskId() {
return taskId;
}
public String getVehicleId() {
return vehicleId;
}
public QueueType getQueueType() {
return queueType;
}
public String getStartSite() {
return startSite;
}
public String getEndSite() {
return endSite;
}
public int getPriority() {
return priority;
}
public int getIssued() {
return issued;
}
public int getExecutionStatus() {
return executionStatus;
}
public boolean isIssued() {
return issued == 1;
}
public List<String> getPath() {
return path;
}
}

View File

@@ -0,0 +1,69 @@
package com.ft546.wcs.demo.model;
public final class DispatchTask {
public enum TaskType {
INBOUND,
OUTBOUND,
RELOCATION
}
private final String taskId;
private final TaskType type;
private final String sourceSite;
private final String targetSite;
private final int floor;
private final int priority;
public DispatchTask(
String taskId,
TaskType type,
String sourceSite,
String targetSite,
int floor,
int priority
) {
this.taskId = requireText(taskId, "task id");
if (type == null) {
throw new IllegalArgumentException("task type must not be null");
}
this.type = type;
this.sourceSite = requireText(sourceSite, "source site");
this.targetSite = requireText(targetSite, "target site");
if (floor <= 0) {
throw new IllegalArgumentException("floor must be positive");
}
this.floor = floor;
this.priority = priority;
}
public String getTaskId() {
return taskId;
}
public TaskType getType() {
return type;
}
public String getSourceSite() {
return sourceSite;
}
public String getTargetSite() {
return targetSite;
}
public int getFloor() {
return floor;
}
public int getPriority() {
return priority;
}
private static String requireText(String value, String name) {
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException(name + " must not be blank");
}
return value;
}
}

View File

@@ -0,0 +1,66 @@
package com.ft546.wcs.demo.model;
import java.util.Objects;
public final class Site {
private final String id;
private final int floor;
private final int x;
private final int y;
private final String channel;
public Site(String id, int floor, int x, int y, String channel) {
this.id = requireText(id, "site id");
if (floor <= 0) {
throw new IllegalArgumentException("floor must be positive");
}
this.floor = floor;
this.x = x;
this.y = y;
this.channel = requireText(channel, "channel");
}
public String getId() {
return id;
}
public int getFloor() {
return floor;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String getChannel() {
return channel;
}
private static String requireText(String value, String name) {
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException(name + " must not be blank");
}
return value;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Site)) {
return false;
}
Site site = (Site) other;
return id.equals(site.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@@ -0,0 +1,98 @@
package com.ft546.wcs.demo.model;
public final class VehicleSnapshot {
private final String vehicleId;
private final int floor;
private final String currentSite;
private final int workMode;
private final int status;
private final int battery;
private final boolean connected;
private final boolean allowSend;
private final boolean cargo;
public VehicleSnapshot(
String vehicleId,
int floor,
String currentSite,
int workMode,
int status,
int battery,
boolean connected,
boolean allowSend,
boolean cargo
) {
this.vehicleId = requireText(vehicleId, "vehicle id");
if (floor <= 0) {
throw new IllegalArgumentException("floor must be positive");
}
this.floor = floor;
this.currentSite = requireText(currentSite, "current site");
this.workMode = workMode;
this.status = status;
if (battery < 0 || battery > 100) {
throw new IllegalArgumentException("battery must be between 0 and 100");
}
this.battery = battery;
this.connected = connected;
this.allowSend = allowSend;
this.cargo = cargo;
}
public String getVehicleId() {
return vehicleId;
}
public int getFloor() {
return floor;
}
public String getCurrentSite() {
return currentSite;
}
public int getWorkMode() {
return workMode;
}
public int getStatus() {
return status;
}
public int getBattery() {
return battery;
}
public boolean isConnected() {
return connected;
}
public boolean isAllowSend() {
return allowSend;
}
public boolean isCargo() {
return cargo;
}
public VehicleSnapshot at(String siteId, int newFloor) {
return new VehicleSnapshot(
vehicleId,
newFloor,
siteId,
workMode,
status,
battery,
connected,
allowSend,
cargo
);
}
private static String requireText(String value, String name) {
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException(name + " must not be blank");
}
return value;
}
}

View File

@@ -0,0 +1,80 @@
package com.ft546.wcs.demo;
import com.ft546.wcs.demo.model.DispatchQueueEntry;
import com.ft546.wcs.demo.model.DispatchTask;
import com.ft546.wcs.demo.model.Site;
import com.ft546.wcs.demo.model.VehicleSnapshot;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class QueueLifecycleTest {
@Test
void queueUsesLegacyLifecycleCodes() {
DispatchTask task = new DispatchTask(
"T-1",
DispatchTask.TaskType.OUTBOUND,
"A",
"B",
1,
2
);
DispatchQueueEntry queue = DispatchQueueEntry.business(task, "1");
assertEquals(0, queue.getIssued());
assertEquals(1, queue.getExecutionStatus());
queue.markIssued(Arrays.asList("A", "B"));
assertEquals(1, queue.getIssued());
assertEquals(3, queue.getExecutionStatus());
queue.markCompleted();
assertEquals(4, queue.getExecutionStatus());
}
@Test
void queueCopiesPathAndRejectsCompletionBeforeIssue() {
DispatchTask task = new DispatchTask(
"T-2",
DispatchTask.TaskType.INBOUND,
"A",
"B",
1,
2
);
DispatchQueueEntry queue = DispatchQueueEntry.business(task, "1");
List<String> path = new java.util.ArrayList<String>(Arrays.asList("A", "B"));
assertThrows(IllegalStateException.class, queue::markCompleted);
queue.markIssued(path);
path.add("C");
assertEquals(Arrays.asList("A", "B"), queue.getPath());
assertThrows(UnsupportedOperationException.class, () -> queue.getPath().add("D"));
}
@Test
void domainInputsRejectInvalidValues() {
assertThrows(IllegalArgumentException.class,
() -> new Site("", 1, 0, 0, "C1"));
assertThrows(IllegalArgumentException.class,
() -> new VehicleSnapshot("1", 1, "A", 5, 1, 101, true, true, false));
assertThrows(IllegalArgumentException.class,
() -> new DispatchTask("", DispatchTask.TaskType.OUTBOUND, "A", "B", 1, 2));
VehicleSnapshot snapshot = new VehicleSnapshot(
"1", 1, "A", 5, 1, 80, true, true, false
);
assertTrue(snapshot.isConnected());
assertEquals("1", snapshot.getVehicleId());
}
}