Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External profiles in procedural scheduling #1560

Merged
merged 12 commits into from
Oct 11, 2024
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
- name: Assemble
run: ./gradlew assemble --parallel
- name: Build scheduling procedure jars for testing
run: ./gradlew procedural:examples:foo-procedures:buildAllSchedulingProcedureJars
run: ./gradlew e2e-tests:buildAllSchedulingProcedureJars
- name: Start Services
run: |
docker compose -f ./e2e-tests/docker-compose-test.yml up -d --build
Expand Down
76 changes: 73 additions & 3 deletions e2e-tests/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

plugins {
id 'java-library'
id 'jacoco'
id 'com.gradleup.shadow' version '8.3.0'
}

java {
Expand Down Expand Up @@ -54,12 +57,17 @@ task e2eTest(type: Test) {
}

dependencies {
testImplementation project(":procedural:timeline")
annotationProcessor project(':procedural:processor')

implementation project(":procedural:scheduling")
implementation project(":procedural:timeline")
implementation project(':merlin-sdk')
implementation project(':type-utils')
implementation project(':contrib')

testImplementation project(":procedural:remote")
testImplementation "com.zaxxer:HikariCP:5.1.0"
testImplementation("org.postgresql:postgresql:42.6.0")
testImplementation project(':merlin-driver')
testImplementation project(':type-utils')

testImplementation 'com.microsoft.playwright:playwright:1.37.0'

Expand All @@ -69,3 +77,65 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0'
}

tasks.register('buildAllSchedulingProcedureJars') {
group = 'SchedulingProcedureJars'

dependsOn "generateSchedulingProcedureJarTasks"
dependsOn {
tasks.findAll { task -> task.name.startsWith('buildSchedulingProcedureJar_') }
}
}

tasks.create("generateSchedulingProcedureJarTasks") {
group = 'SchedulingProcedureJars'

final proceduresDir = findFirstMatchingBuildDir("generated/procedures")

if (proceduresDir == null) {
println "No procedures folder found"
return
}
println "Generating jar tasks for the following procedures directory: ${proceduresDir}"

final files = file(proceduresDir).listFiles()
if (files.length == 0) {
println "No procedures available within folder ${proceduresDir}"
return
}

files.toList().each { file ->
final nameWithoutExtension = file.name.replace(".java", "")
final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}"

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

tasks.create(taskName, ShadowJar) {
group = 'SchedulingProcedureJars'
configurations = [project.configurations.compileClasspath]
from sourceSets.main.output
archiveBaseName = "" // clear
archiveClassifier.set(nameWithoutExtension) // set output jar name
manifest {
attributes 'Main-Class': getMainClassFromGeneratedFile(file)
}
minimize()
}
}
}

private String findFirstMatchingBuildDir(String pattern) {
String found = null
final generatedDir = file("build/generated/sources")
generatedDir.mkdirs()
generatedDir.eachDirRecurse { dir -> if (dir.path.contains(pattern)) found = dir.path }
return found
}

private static String getMainClassFromGeneratedFile(File file) {
final fileString = file.toString()
final prefix = "build/generated/sources/annotationProcessor/java/main/"
final index = fileString.indexOf(prefix) + prefix.length()
final trimmed = fileString.substring(index).replace(".java", "")
return trimmed.replace("/", ".")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@WithMappers(BasicValueMappers.class)
package gov.nasa.jpl.aerie.e2e.procedural.scheduling;

import gov.nasa.jpl.aerie.contrib.serialization.rulesets.BasicValueMappers;
import gov.nasa.ammos.aerie.procedural.scheduling.annotations.WithMappers;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package gov.nasa.jpl.aerie.e2e.procedural.scheduling.procedures;

import gov.nasa.ammos.aerie.procedural.scheduling.plan.EditablePlan;
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.NewDirective;
import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.AnyDirective;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart;
import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue;
import org.jetbrains.annotations.NotNull;

import java.util.Map;

/**
* Waits 24hrs into the plan, then places `quantity` number of BiteBanana activities,
* one every 6hrs.
*/
@SchedulingProcedure
public record DumbRecurrenceGoal(int quantity) implements Goal {
@Override
public void run(@NotNull final EditablePlan plan) {
final var firstTime = Duration.hours(24);
final var step = Duration.hours(6);

var currentTime = firstTime;
for (var i = 0; i < quantity; i++) {
plan.create(
new NewDirective(
new AnyDirective(Map.of("biteSize", SerializedValue.of(1))),
"It's a bite banana activity",
"BiteBanana",
new DirectiveStart.Absolute(currentTime)
)
);
currentTime = currentTime.plus(step);
}
plan.commit();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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.EditablePlan;
import gov.nasa.ammos.aerie.procedural.timeline.collections.profiles.Booleans;
import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart;
import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue;
import org.jetbrains.annotations.NotNull;

import java.util.Map;

@SchedulingProcedure
public record ExternalProfileGoal() implements Goal {
@Override
public void run(@NotNull final EditablePlan plan) {
final var myBoolean = plan.resource("/my_boolean", Booleans.deserializer());
for (final var interval: myBoolean.highlightTrue()) {
plan.create(
"BiteBanana",
new DirectiveStart.Absolute(interval.start),
Map.of("biteSize", SerializedValue.of(1))
);
}

plan.commit();
}
}
Loading
Loading