Skip to content

Commit 9ca0ea8

Browse files
Add support for procedural constraint/goal effective arguments
1 parent cb37d27 commit 9ca0ea8

File tree

37 files changed

+917
-42
lines changed

37 files changed

+917
-42
lines changed

deployment/hasura/metadata/actions.graphql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ type Query {
101101
): [EffectiveArgumentsResponse!]!
102102
}
103103

104+
type Query {
105+
getConstraintProcedureEffectiveArgumentsBulk(
106+
arguments: [ProcedureEffectiveArgumentsInput!]!
107+
): [ProcedureEffectiveArgumentsResponse!]!
108+
}
109+
110+
type Query {
111+
getSchedulingProcedureEffectiveArgumentsBulk(
112+
arguments: [ProcedureEffectiveArgumentsInput!]!
113+
): [ProcedureEffectiveArgumentsResponse!]!
114+
}
115+
104116
type Query {
105117
getActivityTypeScript(missionModelId: Int!, activityTypeName: String!): DslTypescriptResponse
106118
}
@@ -213,6 +225,20 @@ type EffectiveArgumentsResponse {
213225
typeName: String
214226
}
215227

228+
input ProcedureEffectiveArgumentsInput {
229+
id: Int!
230+
revision: Int!
231+
arguments: ProcedureArguments!
232+
}
233+
234+
type ProcedureEffectiveArgumentsResponse {
235+
success: Boolean!
236+
arguments: ProcedureArguments!
237+
errors: [String!]
238+
id: Int!
239+
revision: Int!
240+
}
241+
216242
type AddExternalDatasetResponse {
217243
datasetId: Int!
218244
}
@@ -341,6 +367,8 @@ scalar ModelArguments
341367

342368
scalar ActivityArguments
343369

370+
scalar ProcedureArguments
371+
344372
scalar ProfileSet
345373

346374
scalar SchedulingFailureReason

deployment/hasura/metadata/actions.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ actions:
9898
- role: aerie_admin
9999
- role: user
100100
- role: viewer
101+
- name: getConstraintProcedureEffectiveArgumentsBulk
102+
definition:
103+
kind: ""
104+
handler: "{{AERIE_MERLIN_URL}}/getConstraintProcedureEffectiveArgumentsBulk"
105+
timeout: 300
106+
permissions:
107+
- role: aerie_admin
108+
- role: user
109+
- role: viewer
101110
- name: getActivityTypeScript
102111
definition:
103112
kind: ""
@@ -157,6 +166,15 @@ actions:
157166
permissions:
158167
- role: aerie_admin
159168
- role: user
169+
- name: getSchedulingProcedureEffectiveArgumentsBulk
170+
definition:
171+
kind: ""
172+
handler: "{{AERIE_SCHEDULER_URL}}/getSchedulingProcedureEffectiveArgumentsBulk"
173+
timeout: 300
174+
permissions:
175+
- role: aerie_admin
176+
- role: user
177+
- role: viewer
160178
- name: constraintsDslTypescript
161179
definition:
162180
kind: ""

e2e-tests/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ dependencies {
6060
annotationProcessor project(':procedural:processor')
6161

6262
implementation project(":procedural:scheduling")
63+
implementation project(":procedural:constraints")
6364
implementation project(":procedural:timeline")
6465
implementation project(':merlin-sdk')
6566
implementation project(':type-utils')
@@ -104,7 +105,7 @@ tasks.create("generateProcedureJarTasks") {
104105
}
105106

106107
files.toList().each { file ->
107-
final nameWithoutExtension = file.name.replace(".java", "")
108+
final nameWithoutExtension = file.name.replace(".java", "").replace("Mapper", "")
108109
final taskName = "buildProcedureJar_${nameWithoutExtension}"
109110

110111
println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar"

e2e-tests/src/main/java/gov/nasa/jpl/aerie/e2e/procedural/scheduling/procedures/DumbRecurrenceGoalWithTemplateDefaults.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void run(@NotNull final EditablePlan plan) {
4040
}
4141

4242
public static @Template DumbRecurrenceGoalWithTemplateDefaults create() {
43-
return new DumbRecurrenceGoalWithTemplateDefaults(10, 10);
43+
return new DumbRecurrenceGoalWithTemplateDefaults(3, 5);
4444
}
4545
}
4646

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package gov.nasa.jpl.aerie.e2e.procedural.scheduling.procedures;
2+
3+
import gov.nasa.ammos.aerie.procedural.constraints.Constraint;
4+
import gov.nasa.ammos.aerie.procedural.constraints.Violations;
5+
import gov.nasa.ammos.aerie.procedural.constraints.annotations.ConstraintProcedure;
6+
import gov.nasa.ammos.aerie.procedural.scheduling.annotations.WithDefaults;
7+
import gov.nasa.ammos.aerie.procedural.timeline.collections.profiles.Real;
8+
import gov.nasa.ammos.aerie.procedural.timeline.plan.Plan;
9+
import gov.nasa.ammos.aerie.procedural.timeline.plan.SimulationResults;
10+
import org.jetbrains.annotations.NotNull;
11+
12+
@ConstraintProcedure
13+
public record FruitThresholdConstraint(int lowerBound, int upperBound) implements Constraint {
14+
@NotNull
15+
@Override
16+
public Violations run(@NotNull Plan plan, @NotNull SimulationResults simResults) {
17+
final var fruit = simResults.resource("/fruit", Real.deserializer());
18+
19+
return Violations.on(
20+
fruit.lessThan(upperBound).and(fruit.greaterThan(lowerBound)),
21+
false
22+
);
23+
}
24+
25+
@WithDefaults
26+
public static class Template{
27+
public int lowerBound = 5;
28+
}
29+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package gov.nasa.jpl.aerie.e2e.procedural.constraints;
2+
3+
import gov.nasa.jpl.aerie.e2e.procedural.scheduling.ProceduralSchedulingSetup;
4+
import gov.nasa.jpl.aerie.e2e.types.ConstraintInvocationId;
5+
import gov.nasa.jpl.aerie.e2e.utils.GatewayRequests;
6+
import org.apache.commons.lang3.tuple.Pair;
7+
import org.junit.jupiter.api.AfterEach;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
11+
import javax.json.Json;
12+
import java.io.IOException;
13+
import java.util.List;
14+
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertTrue;
17+
18+
public class BasicConstraintTests extends ProceduralSchedulingSetup {
19+
private ConstraintInvocationId fruitTresholdConstraintId;
20+
21+
@BeforeEach
22+
void localBeforeEach() throws IOException {
23+
try (final var gateway = new GatewayRequests(playwright)) {
24+
final int fruitTresholdConstraintJarId = gateway.uploadJarFile("build/libs/FruitThresholdConstraint.jar");
25+
// Add Scheduling Procedure
26+
fruitTresholdConstraintId = hasura.createConstraintSpecProcedure(
27+
"Test Constraint Procedure 1",
28+
fruitTresholdConstraintJarId,
29+
planId
30+
);
31+
}
32+
}
33+
34+
@AfterEach
35+
void localAfterEach() throws IOException {
36+
hasura.deleteConstraint(fruitTresholdConstraintId.id());
37+
}
38+
39+
/**
40+
* Run a spec with one procedure in it with required params but no args set
41+
* Should fail because one argument is provided in the template but not the other
42+
*/
43+
@Test
44+
void executeConstraintRunWithoutArguments() throws IOException {
45+
hasura.awaitSimulation(planId);
46+
final var resp = hasura.checkConstraints(planId);
47+
assertEquals(1, resp.constraintsRun().size());
48+
assertEquals(1, resp.constraintsRun().getFirst().errors().size());
49+
resp.constraintsRun().getFirst().errors().getFirst().message().contains("gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException: Invalid arguments for input type \"FruitThresholdConstraint\": extraneous arguments: [], unconstructable arguments: [], missing arguments: [MissingArgument[parameterName=upperBound, schema=IntSchema[]]], valid arguments: [ValidArgument[parameterName=lowerBound, serializedValue=NumericValue[value=5]]]");
50+
}
51+
52+
/**
53+
* Run a constraint that has one template argument and requires one other argument
54+
*/
55+
@Test
56+
void executeConstraintRunWithArguments() throws IOException {
57+
final var args = Json.createObjectBuilder().add("upperBound", 10).build();
58+
hasura.updateConstraintArguments(fruitTresholdConstraintId.invocationId(), args);
59+
hasura.awaitSimulation(planId);
60+
final var resp = hasura.checkConstraints(planId);
61+
assertTrue(resp.constraintsRun().getFirst().success());
62+
}
63+
64+
/**
65+
* Queries the procedural constraints arguments.
66+
*/
67+
@Test
68+
void effectiveArgumentsQuery() throws IOException {
69+
final var effectiveArgs = hasura.getEffectiveProceduralConstraintsArgumentsBulk(
70+
List.of(Pair.of(fruitTresholdConstraintId.id(), Json.createObjectBuilder().add("upperBound", 10).build())));
71+
assertEquals(1, effectiveArgs.size());
72+
assertTrue(effectiveArgs.get(0).success());
73+
assertTrue(effectiveArgs.get(0).arguments().isPresent());
74+
assertTrue(effectiveArgs.get(0).errors().isEmpty());
75+
76+
// Check returned Arguments
77+
final var args = effectiveArgs.get(0).arguments().get();
78+
assertEquals(2, args.size());
79+
assertEquals(10, args.getInt("upperBound"));
80+
assertEquals(5, args.getInt("lowerBound"));
81+
}
82+
}

e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/procedural/scheduling/BasicTests.java renamed to e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/procedural/scheduling/BasicSchedulingTests.java

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
import static org.junit.jupiter.api.Assertions.assertEquals;
1414
import static org.junit.jupiter.api.Assertions.assertTrue;
1515

16-
public class BasicTests extends ProceduralSchedulingSetup {
17-
private int procedureJarId;
18-
private GoalInvocationId procedureId;
16+
public class BasicSchedulingTests extends ProceduralSchedulingSetup {
17+
private int dumbRecurrenceGoalJarId;
18+
private GoalInvocationId dumbRecurrenceGoalId;
1919

2020
@BeforeEach
2121
void localBeforeEach() throws IOException {
2222
try (final var gateway = new GatewayRequests(playwright)) {
23-
procedureJarId = gateway.uploadJarFile("build/libs/DumbRecurrenceGoal.jar");
23+
dumbRecurrenceGoalJarId = gateway.uploadJarFile("build/libs/DumbRecurrenceGoal.jar");
2424
// Add Scheduling Procedure
25-
procedureId = hasura.createSchedulingSpecProcedure(
26-
"Test Scheduling Procedure",
27-
procedureJarId,
25+
dumbRecurrenceGoalId = hasura.createSchedulingSpecProcedure(
26+
"Test Scheduling Procedure 1",
27+
dumbRecurrenceGoalJarId,
2828
specId,
2929
0
3030
);
@@ -33,7 +33,7 @@ void localBeforeEach() throws IOException {
3333

3434
@AfterEach
3535
void localAfterEach() throws IOException {
36-
hasura.deleteSchedulingGoal(procedureId.goalId());
36+
hasura.deleteSchedulingGoal(dumbRecurrenceGoalId.goalId());
3737
}
3838

3939
/**
@@ -44,7 +44,7 @@ void proceduralUploadWorks() throws IOException {
4444
final var ids = hasura.getSchedulingSpecGoalIds(specId);
4545

4646
assertEquals(1, ids.size());
47-
assertEquals(procedureId.goalId(), ids.getFirst());
47+
assertEquals(dumbRecurrenceGoalId.goalId(), ids.getFirst());
4848
}
4949

5050
/**
@@ -55,17 +55,17 @@ void proceduralUploadWorks() throws IOException {
5555
void executeSchedulingRunWithoutArguments() throws IOException {
5656
final var resp = hasura.awaitFailingScheduling(specId);
5757
final var message = resp.reason().getString("message");
58-
assertTrue(message.contains("java.lang.RuntimeException: Record missing key Component[name=biteSize"));
58+
assertTrue(message.contains("java.lang.RuntimeException: gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException: Invalid arguments for input type \"DumbRecurrenceGoal\": extraneous arguments: [], unconstructable arguments: [], missing arguments: [MissingArgument[parameterName=biteSize, schema=IntSchema[]]], valid arguments: [ValidArgument[parameterName=quantity, serializedValue=NumericValue[value=360]]]"));
5959
}
6060

6161
/**
6262
* Run a spec with one procedure in it
6363
*/
6464
@Test
6565
void executeSchedulingRunWithArguments() throws IOException {
66-
final var args = Json.createObjectBuilder().add("biteSize", 2).build();
66+
final var args = Json.createObjectBuilder().add("quantity", 2).add("biteSize", 1).build();
6767

68-
hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);
68+
hasura.updateSchedulingSpecGoalArguments(dumbRecurrenceGoalId.invocationId(), args);
6969

7070
hasura.awaitScheduling(specId);
7171

@@ -88,10 +88,10 @@ void executeSchedulingRunWithArguments() throws IOException {
8888
*/
8989
@Test
9090
void executeMultipleInvocationsOfSameProcedure() throws IOException {
91-
final var args = Json.createObjectBuilder().add("quantity", 2).build();
92-
hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);
91+
final var args = Json.createObjectBuilder().add("quantity", 2).add("biteSize", 1).build();
92+
hasura.updateSchedulingSpecGoalArguments(dumbRecurrenceGoalId.invocationId(), args);
9393

94-
final var secondInvocationId = hasura.insertGoalInvocation(procedureId.goalId(), specId);
94+
final var secondInvocationId = hasura.insertGoalInvocation(dumbRecurrenceGoalId.goalId(), specId);
9595
hasura.updateSchedulingSpecGoalArguments(secondInvocationId.invocationId(), args);
9696

9797
hasura.awaitScheduling(specId);
@@ -107,12 +107,12 @@ void executeMultipleInvocationsOfSameProcedure() throws IOException {
107107
*/
108108
@Test
109109
void executeMultipleProcedures() throws IOException {
110-
final var args = Json.createObjectBuilder().add("quantity", 2).build();
111-
hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);
110+
final var args = Json.createObjectBuilder().add("quantity", 2).add("biteSize", 1).build();
111+
hasura.updateSchedulingSpecGoalArguments(dumbRecurrenceGoalId.invocationId(), args);
112112

113113
final var secondProcedure = hasura.createSchedulingSpecProcedure(
114114
"Test Scheduling Procedure 2",
115-
procedureJarId,
115+
dumbRecurrenceGoalJarId,
116116
specId,
117117
1);
118118

@@ -131,8 +131,8 @@ void executeMultipleProcedures() throws IOException {
131131
*/
132132
@Test
133133
void executeEDSLAndProcedure() throws IOException {
134-
final var args = Json.createObjectBuilder().add("quantity", 4).build();
135-
hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);
134+
final var args = Json.createObjectBuilder().add("quantity", 4).add("biteSize", 1).build();
135+
hasura.updateSchedulingSpecGoalArguments(dumbRecurrenceGoalId.invocationId(), args);
136136

137137
final String recurrenceGoalDefinition =
138138
"""
@@ -161,8 +161,8 @@ export default function myGoal() {
161161
*/
162162
@Test
163163
void saveActivityName() throws IOException {
164-
final var args = Json.createObjectBuilder().add("quantity", 2).build();
165-
hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);
164+
final var args = Json.createObjectBuilder().add("quantity", 2).add("biteSize", 1).build();
165+
hasura.updateSchedulingSpecGoalArguments(dumbRecurrenceGoalId.invocationId(), args);
166166

167167
hasura.awaitScheduling(specId);
168168

0 commit comments

Comments
 (0)