Skip to content

Commit

Permalink
Activity deletion e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JoelCourtney committed Nov 22, 2024
1 parent d013722 commit 62049ea
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package gov.nasa.jpl.aerie.e2e.procedural.scheduling.procedures;

import gov.nasa.ammos.aerie.procedural.scheduling.Goal;
import gov.nasa.ammos.aerie.procedural.scheduling.annotations.SchedulingProcedure;
import gov.nasa.ammos.aerie.procedural.scheduling.plan.DeletedAnchorStrategy;
import gov.nasa.ammos.aerie.procedural.scheduling.plan.EditablePlan;
import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue;
import gov.nasa.jpl.aerie.types.ActivityDirectiveId;
import org.jetbrains.annotations.NotNull;

import java.util.Map;
import java.util.Optional;

/**
* Creates three activities in a chain of anchors, then deletes one.
*/
@SchedulingProcedure
public record ActivityDeletionGoal(int whichToDelete, DeletedAnchorStrategy anchorStrategy) implements Goal {
@Override
public void run(@NotNull final EditablePlan plan) {
final var ids = new ActivityDirectiveId[3];

ids[0] = plan.create(
"BiteBanana",
new DirectiveStart.Absolute(Duration.HOUR),
Map.of("biteSize", SerializedValue.of(0))
);
ids[1] = plan.create(
"BiteBanana",
new DirectiveStart.Anchor(ids[0], Duration.HOUR, DirectiveStart.Anchor.AnchorPoint.End),
Map.of("biteSize", SerializedValue.of(1))
);
ids[2] = plan.create(
"BiteBanana",
new DirectiveStart.Anchor(ids[1], Duration.HOUR, DirectiveStart.Anchor.AnchorPoint.Start),
Map.of("biteSize", SerializedValue.of(2))
);

if (whichToDelete >= 0) {
plan.delete(ids[whichToDelete], anchorStrategy);
}

plan.commit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ void executeEDSLAndProcedure() throws IOException {
final var args = Json.createObjectBuilder().add("quantity", 4).build();
hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

final String recurrenceGoalDefinition =
"""
export default function myGoal() {
return Goal.ActivityRecurrenceGoal({
activityTemplate: ActivityTemplates.PeelBanana({peelDirection: 'fromStem'}),
interval: Temporal.Duration.from({hours:1})
})}""";

hasura.createSchedulingSpecGoal(
"Recurrence Scheduling Test Goal",
recurrenceGoalDefinition,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package gov.nasa.jpl.aerie.e2e.procedural.scheduling;

import gov.nasa.jpl.aerie.e2e.types.GoalInvocationId;
import gov.nasa.jpl.aerie.e2e.utils.GatewayRequests;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import javax.json.Json;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class DeletionTests extends ProceduralSchedulingSetup {
private GoalInvocationId procedureId;

@BeforeEach
void localBeforeEach() throws IOException {
try (final var gateway = new GatewayRequests(playwright)) {
int procedureJarId = gateway.uploadJarFile("build/libs/ActivityDeletionGoal.jar");
// Add Scheduling Procedure
procedureId = hasura.createSchedulingSpecProcedure(
"Test Scheduling Procedure",
procedureJarId,
specId,
0
);
}
}

@AfterEach
void localAfterEach() throws IOException {
hasura.deleteSchedulingGoal(procedureId.goalId());
}

@Test
void createsThreeActivities() throws IOException {
final var args = Json
.createObjectBuilder()
.add("whichToDelete", -1)
.add("anchorStrategy", "Error")
.build();

hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

hasura.awaitScheduling(specId);

final var plan = hasura.getPlan(planId);
final var activities = plan.activityDirectives();

assertEquals(3, activities.size());

final AtomicReference<Integer> id1 = new AtomicReference<>();
final AtomicReference<Integer> id2 = new AtomicReference<>();
assertTrue(activities.stream().anyMatch(
it -> {
final var result = Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), null);
if (result) id1.set(it.id());
return result;
}
));

assertTrue(activities.stream().anyMatch(
it -> {
final var result = Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), id1.get());
if (result) id2.set(it.id());
return result;
}
));

assertTrue(activities.stream().anyMatch(
it -> Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), id2.get())
));
}

@Test
void deletesLast() throws IOException {
final var args = Json
.createObjectBuilder()
.add("whichToDelete", 2)
.add("anchorStrategy", "Error")
.build();

hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

hasura.awaitScheduling(specId);

final var plan = hasura.getPlan(planId);
final var activities = plan.activityDirectives();

assertEquals(2, activities.size());

final AtomicReference<Integer> id1 = new AtomicReference<>();
assertTrue(activities.stream().anyMatch(
it -> {
final var result = Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), null);
if (result) id1.set(it.id());
return result;
}
));

assertTrue(activities.stream().anyMatch(
it -> Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), id1.get())
));
}

@Test
void deletesMiddleCascade() throws IOException {
final var args = Json
.createObjectBuilder()
.add("whichToDelete", 1)
.add("anchorStrategy", "Cascade")
.build();

hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

hasura.awaitScheduling(specId);

final var plan = hasura.getPlan(planId);
final var activities = plan.activityDirectives();

assertEquals(1, activities.size());

assertTrue(activities.stream().anyMatch(
it -> Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), null)
));
}

@Test
void deletesMiddleAnchorToParent() throws IOException {
final var args = Json
.createObjectBuilder()
.add("whichToDelete", 1)
.add("anchorStrategy", "ReAnchor")
.build();

hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

hasura.awaitScheduling(specId);

final var plan = hasura.getPlan(planId);
final var activities = plan.activityDirectives();

assertEquals(2, activities.size());

final AtomicReference<Integer> id1 = new AtomicReference<>();
assertTrue(activities.stream().anyMatch(
it -> {
final var result = Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), null);
if (result) id1.set(it.id());
return result;
}
));

assertTrue(activities.stream().anyMatch(
it -> Objects.equals(it.type(), "BiteBanana")
&& Objects.equals(it.anchorId(), id1.get())
&& Objects.equals(it.startOffset(), "02:00:00")
));
}

@Test
void deletesFirstCascade() throws IOException {
final var args = Json
.createObjectBuilder()
.add("whichToDelete", 0)
.add("anchorStrategy", "Cascade")
.build();

hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

hasura.awaitScheduling(specId);

final var plan = hasura.getPlan(planId);
final var activities = plan.activityDirectives();

assertEquals(0, activities.size());
}

@Test
void deletesFirstReAnchorToPlan() throws IOException {
final var args = Json
.createObjectBuilder()
.add("whichToDelete", 0)
.add("anchorStrategy", "ReAnchor")
.build();

hasura.updateSchedulingSpecGoalArguments(procedureId.invocationId(), args);

hasura.awaitScheduling(specId);

final var plan = hasura.getPlan(planId);
final var activities = plan.activityDirectives();

assertEquals(2, activities.size());

final AtomicReference<Integer> id2 = new AtomicReference<>();
assertTrue(activities.stream().anyMatch(
it -> {
final var result = Objects.equals(it.type(), "BiteBanana")
&& Objects.equals(it.anchorId(), null)
&& Objects.equals(it.startOffset(), "02:00:00");
if (result) id2.set(it.id());
return result;
}
));

assertTrue(activities.stream().anyMatch(
it -> Objects.equals(it.type(), "BiteBanana") && Objects.equals(it.anchorId(), id2.get())
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,7 @@ public abstract class ProceduralSchedulingSetup {

// Cross-Test Constants
protected final String planStartTimestamp = "2023-01-01T00:00:00+00:00";
protected final String recurrenceGoalDefinition =
"""
export default function myGoal() {
return Goal.ActivityRecurrenceGoal({
activityTemplate: ActivityTemplates.PeelBanana({peelDirection: 'fromStem'}),
interval: Temporal.Duration.from({hours:1})
})}""";


@BeforeAll
void beforeAll() {
Expand Down
11 changes: 10 additions & 1 deletion e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/types/Plan.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ public record Plan(
int revision,
List<ActivityDirective> activityDirectives
) {
public record ActivityDirective(int id, int planId, String type, String startOffset, JsonObject arguments, String name) {
public record ActivityDirective(
int id,
int planId,
String type,
String startOffset,
JsonObject arguments,
String name,
Integer anchorId,
boolean anchoredToStart
) {
public static ActivityDirective fromJSON(JsonObject json){
return new ActivityDirective(
json.getInt("id"),
Expand Down
2 changes: 2 additions & 0 deletions e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/utils/GQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ query GetPlan($id: Int!) {
startOffset: start_offset
type
name
anchorId: anchor_id
anchoredToStart: anchored_to_start
}
constraint_specification {
constraint_id
Expand Down

0 comments on commit 62049ea

Please sign in to comment.