ortools review on some design issues and fixed flaky test
All checks were successful
Build, test and publish / verify (push) Successful in 1m34s
All checks were successful
Build, test and publish / verify (push) Successful in 1m34s
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
package nl.agilecc.agiledancers;
|
||||
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
import com.tngtech.archunit.core.domain.JavaModifier;
|
||||
import com.tngtech.archunit.junit.AnalyzeClasses;
|
||||
import com.tngtech.archunit.junit.ArchTest;
|
||||
import com.tngtech.archunit.lang.ArchRule;
|
||||
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
||||
import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
|
||||
@@ -15,6 +15,31 @@ class ArchitectureTest {
|
||||
private static final String ROOT = "nl.agilecc.agiledancers";
|
||||
private static final String API_MODEL = ROOT + ".rest.apimodel";
|
||||
|
||||
// Exclude Lombok builders and compiler-generated enum-switch helper classes.
|
||||
@ArchTest
|
||||
static final ArchRule handwritten_types_are_top_level = classes()
|
||||
.that().areNotAnnotatedWith("lombok.Generated")
|
||||
.and().doNotHaveModifier(JavaModifier.SYNTHETIC)
|
||||
.should().beTopLevelClasses();
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule service_records_reside_in_service_model = classes()
|
||||
.that().resideInAPackage(ROOT + ".service..")
|
||||
.and().areRecords()
|
||||
.should().resideInAPackage(ROOT + ".service.model");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule service_interfaces_reside_in_service_port = classes()
|
||||
.that().resideInAPackage(ROOT + ".service..")
|
||||
.and().areInterfaces()
|
||||
.should().resideInAPackage(ROOT + ".service.port");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule scheduling_port_uses_domain_types = classes()
|
||||
.that().resideInAPackage(ROOT + ".service.port..")
|
||||
.should().onlyDependOnClassesThat()
|
||||
.resideInAnyPackage(ROOT + ".service.port..", ROOT + ".model..", "java..");
|
||||
|
||||
// API model classes and records use the Request, Response, View, Dto or DTO suffix.
|
||||
@ArchTest
|
||||
static final ArchRule api_models_reside_in_the_api_model_package = classes()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package nl.agilecc.agiledancers;
|
||||
|
||||
import nl.agilecc.agiledancers.model.scheduling.SchedulingResult;
|
||||
import nl.agilecc.agiledancers.service.model.*;
|
||||
import nl.agilecc.agiledancers.service.port.SchedulingEngine;
|
||||
import nl.agilecc.agiledancers.model.*;
|
||||
import nl.agilecc.agiledancers.model.specifications.*;
|
||||
import nl.agilecc.agiledancers.service.*;
|
||||
@@ -80,11 +83,11 @@ class SchedulingTest {
|
||||
service.endScheduling(show.getId());
|
||||
var fresh = service.beginScheduling(school, show.getId());
|
||||
assertThrows(ManagementException.class, () -> service.finishScheduling(school, fresh,
|
||||
new SchoolManagementService.SchedulingResult(false, List.of(List.of(), List.of()))));
|
||||
new SchedulingResult(false, List.of(List.of(), List.of()))));
|
||||
assertEquals(before, show.getDayParts().stream().map(DayPart::getDanceGroups).toList());
|
||||
// Feasible results are accepted without requiring proof of optimality.
|
||||
var valid = new OrToolsSchedulingEngine().solve(fresh);
|
||||
assertDoesNotThrow(() -> service.finishScheduling(school, fresh, new SchoolManagementService.SchedulingResult(false, valid.assignments())));
|
||||
assertDoesNotThrow(() -> service.finishScheduling(school, fresh, new SchedulingResult(false, valid.assignments())));
|
||||
service.endScheduling(show.getId());
|
||||
}
|
||||
@Test void staleDaypartCountChangesAndDeletedShowsAreRejected() {
|
||||
|
||||
@@ -3,9 +3,7 @@ package nl.agilecc.agiledancers;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.restassured.response.ValidatableResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
@@ -171,7 +169,7 @@ class SchoolManagementResourceTest {
|
||||
String exported = given().get(school + "/export").then().statusCode(200).extract().asString();
|
||||
given().contentType("application/json").body(exported).post(SCHOOLS + "/import?replaceId=" + school.substring(school.lastIndexOf('/') + 1))
|
||||
.then().statusCode(200);
|
||||
given().get(school + "/export").then().body(equalTo(exported));
|
||||
given().get(school + "/export").then().body("$", equalTo(io.restassured.path.json.JsonPath.from(exported).getMap("$")));
|
||||
} finally { given().delete(school); }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package nl.agilecc.agiledancers;
|
||||
|
||||
import nl.agilecc.agiledancers.service.model.*;
|
||||
import nl.agilecc.agiledancers.service.*;
|
||||
import nl.agilecc.agiledancers.model.specifications.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -9,12 +10,12 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SchoolSnapshotTest {
|
||||
private SchoolSnapshot complete() {
|
||||
return new SchoolSnapshot(2, UUID.randomUUID(), "Studio", List.of(new SchoolSnapshot.Person("a", "Sam", LocalDate.of(2010,1,1))),
|
||||
List.of(new SchoolSnapshot.Trainer("c", "Alex")),
|
||||
List.of(new SchoolSnapshot.Group("g", "Hiphop", DanceGroupType.REGULAR, 0, 99, List.of(DanceGroupStyle.HIPHOP), List.of("a"), "c"),
|
||||
new SchoolSnapshot.Group("h", "Jazz", DanceGroupType.REGULAR, 0, 99, List.of(), List.of("a"), "c")),
|
||||
List.of(new SchoolSnapshot.Performance("s", "Show",
|
||||
List.of(new SchoolSnapshot.Part(LocalDate.of(2027,1,1), DayPartType.MORNING, List.of("g", "h"))), ShowConfiguration.defaults(1))));
|
||||
return new SchoolSnapshot(2, UUID.randomUUID(), "Studio", List.of(new Person("a", "Sam", LocalDate.of(2010,1,1))),
|
||||
List.of(new Trainer("c", "Alex")),
|
||||
List.of(new Group("g", "Hiphop", DanceGroupType.REGULAR, 0, 99, List.of(DanceGroupStyle.HIPHOP), List.of("a"), "c"),
|
||||
new Group("h", "Jazz", DanceGroupType.REGULAR, 0, 99, List.of(), List.of("a"), "c")),
|
||||
List.of(new Performance("s", "Show",
|
||||
List.of(new Part(LocalDate.of(2027,1,1), DayPartType.MORNING, List.of("g", "h"))), ShowConfiguration.defaults(1))));
|
||||
}
|
||||
@Test void roundTripAfterRestartPreservesAllFieldsAndSharedRelationships() {
|
||||
var snapshot = complete();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package nl.agilecc.agiledancers.service;
|
||||
|
||||
import nl.agilecc.agiledancers.service.port.SchedulingEngine;
|
||||
import nl.agilecc.agiledancers.model.*;
|
||||
import nl.agilecc.agiledancers.model.specifications.*;
|
||||
import nl.agilecc.agiledancers.solver.OrToolsSchedulingEngine;
|
||||
@@ -23,7 +24,7 @@ class SchedulingServiceTest {
|
||||
var before = schools.exportSchool(school);
|
||||
for (SchedulingEngine failure : List.<SchedulingEngine>of(
|
||||
input -> { throw new IllegalStateException("Native failure"); },
|
||||
input -> { throw new ManagementException(ManagementException.Kind.INVALID_INPUT, "No valid result before the limit"); },
|
||||
input -> { throw new ManagementException(ManagementExceptionKind.INVALID_INPUT, "No valid result before the limit"); },
|
||||
input -> null)) {
|
||||
scheduling.engine = failure;
|
||||
assertThrows(ManagementException.class, () -> scheduling.schedule(school, show.getId()));
|
||||
@@ -51,7 +52,7 @@ class SchedulingServiceTest {
|
||||
var first = executor.submit(() -> scheduling.schedule(school, show.getId()));
|
||||
try {
|
||||
assertTrue(entered.await(10, TimeUnit.SECONDS));
|
||||
assertEquals(ManagementException.Kind.CONFLICT, assertThrows(ManagementException.class,
|
||||
assertEquals(ManagementExceptionKind.CONFLICT, assertThrows(ManagementException.class,
|
||||
() -> scheduling.schedule(school, show.getId())).getKind());
|
||||
schools.createGroup(school, "New group", DanceGroupType.REGULAR, 0, 99, Set.of());
|
||||
} finally { release.countDown(); }
|
||||
|
||||
Reference in New Issue
Block a user