Skip to content

Commit

Permalink
Merge pull request #1560 from NASA-AMMOS/feat/proc-external-profiles
Browse files Browse the repository at this point in the history
External profiles in procedural scheduling
  • Loading branch information
JoelCourtney authored Oct 11, 2024
2 parents 86108a9 + 2c02928 commit 2a7ba3b
Show file tree
Hide file tree
Showing 20 changed files with 550 additions and 208 deletions.
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

0 comments on commit 2a7ba3b

Please sign in to comment.