Skip to content

Commit

Permalink
Merge pull request #1216 from NASA-AMMOS/AERIE-1117---Return_Compilat…
Browse files Browse the repository at this point in the history
…ion_Errors_with_Constraints

[Aerie-1117]  Return compilation errors with constraints
  • Loading branch information
goetzrrGit authored Nov 7, 2023
2 parents 9ce0eb4 + 77865d6 commit 16c6352
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 92 deletions.

This file was deleted.

8 changes: 7 additions & 1 deletion deployment/hasura/metadata/actions.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ type Query {
}

type Query {
constraintViolations(planId: Int!, simulationDatasetId: Int): [ConstraintResult!]!
constraintViolations(planId: Int!, simulationDatasetId: Int): [ConstraintResponse!]!
}

type Query {
Expand Down Expand Up @@ -278,6 +278,12 @@ type ResourceSamplesResponse {
resourceSamples: ResourceSamples!
}

type ConstraintResponse {
success: String!
errors: [UserCodeError!]!
results: [ConstraintResult!]!
}

type ConstraintResult {
violations: [ConstraintViolation!]!,
gaps: [Interval!]!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package gov.nasa.jpl.aerie.e2e;

import com.microsoft.playwright.Playwright;
import gov.nasa.jpl.aerie.e2e.types.ConstraintError;
import gov.nasa.jpl.aerie.e2e.types.ConstraintResult;
import gov.nasa.jpl.aerie.e2e.types.ExternalDataset.ProfileInput;
import gov.nasa.jpl.aerie.e2e.types.ExternalDataset.ProfileInput.ProfileSegmentInput;
import gov.nasa.jpl.aerie.e2e.types.ValueSchema;
Expand Down Expand Up @@ -100,11 +102,13 @@ void constraintsFailNoSimData() {
@Test
void constraintsSucceedOneViolation() throws IOException {
hasura.awaitSimulation(planId);
final var constraintsResults = hasura.checkConstraints(planId);
assertEquals(1, constraintsResults.size());
final var constraintsResponses = hasura.checkConstraints(planId);
assertEquals(1, constraintsResponses.size());

// Check the Result
final var constraintResult = constraintsResults.get(0);
final var constraintResponse = constraintsResponses.get(0);
assertEquals(true,constraintResponse.success());
final ConstraintResult constraintResult = constraintResponse.result();
assertEquals(constraintId, constraintResult.constraintId());
assertEquals(constraintName, constraintResult.constraintName());

Expand Down Expand Up @@ -155,7 +159,9 @@ void constraintCachedViolation() throws IOException {

// Check results
assertTrue(cachedRun.results().isPresent());
assertEquals(constraintRuns.get(0), cachedRun.results().get());
final var constraintResponse = constraintRuns.get(0);
assertEquals(true,constraintResponse.success());
assertEquals(constraintResponse.result(), cachedRun.results().get());
}

@Test
Expand Down Expand Up @@ -217,11 +223,13 @@ void constraintsWorkMonthLongActivity() throws IOException {
"0h",
Json.createObjectBuilder().add("duration", thirtyFiveDays).build());
hasura.awaitSimulation(planId);
final var constraintResults = hasura.checkConstraints(planId);
assertEquals(1, constraintResults.size());
final var constraintsResponses = hasura.checkConstraints(planId);
assertEquals(1, constraintsResponses.size());

// Check the Result
final var constraintResult = constraintResults.get(0);
final var constraintResponse = constraintsResponses.get(0);
assertEquals(true,constraintResponse.success());
final var constraintResult = constraintResponse.result();
assertEquals(constraintId, constraintResult.constraintId());
assertEquals(constraintName, constraintResult.constraintName());

Expand Down Expand Up @@ -253,11 +261,14 @@ void runConstraintsOnOldSimulation() throws IOException {
assertEquals(0, newConstraintResults.size());

// Expect one violation on the old simulation
final var oldConstraintResults = hasura.checkConstraints(planId, oldSimDatasetId);
assertEquals(1, oldConstraintResults.size());
final var oldConstraintsResponses = hasura.checkConstraints(planId, oldSimDatasetId);
assertEquals(1, oldConstraintsResponses.size());

// Check the Result
final var constraintResult = oldConstraintResults.get(0);
final var oldConstraintResponse = oldConstraintsResponses.get(0);
assertEquals(true,oldConstraintResponse.success());
final var constraintResult = oldConstraintResponse.result();

assertEquals(constraintId, constraintResult.constraintId());
assertEquals(constraintName, constraintResult.constraintName());

Expand Down Expand Up @@ -338,12 +349,15 @@ void oneViolationCurrentSimulation() throws IOException {
// Constraint Results w/o SimDatasetId
final var noDatasetResults = hasura.checkConstraints(planId);
assertEquals(1, noDatasetResults.size());
final var ndRecord = noDatasetResults.get(0);
assertEquals(true, noDatasetResults.get(0).success());

final var ndRecord = noDatasetResults.get(0).result();

// Constraint Results w/ SimDatasetId
final var withDatasetResults = hasura.checkConstraints(planId, simDatasetId);
assertEquals(1, withDatasetResults.size());
final var wdRecord = withDatasetResults.get(0);
assertEquals(true, withDatasetResults.get(0).success());
final var wdRecord = withDatasetResults.get(0).result();

// The results should be the same
assertEquals(ndRecord, wdRecord);
Expand Down Expand Up @@ -390,9 +404,12 @@ void oneViolationOutdatedSimIdPassed() throws IOException {
hasura.deleteActivity(planId, activityId);
hasura.awaitSimulation(planId);
// Check constraints against the old simID (the one with the external dataset)
final var constraintRuns = hasura.checkConstraints(planId, simDatasetId);
assertEquals(1, constraintRuns.size());
final var record = constraintRuns.get(0);
final var constraintResponses = hasura.checkConstraints(planId, simDatasetId);
assertEquals(1, constraintResponses.size());

final var constraintResponse = constraintResponses.get(0);
assertEquals(true,constraintResponse.success());
final var record = constraintResponse.result();

// Check the Result
assertEquals(constraintName, record.constraintName());
Expand Down Expand Up @@ -437,14 +454,13 @@ void compilationFailsOutdatedSimulationSimDatasetId() throws IOException {
final int newSimDatasetId = hasura.awaitSimulation(planId).simDatasetId();
// This test causes the endpoint to throw an exception when it fails to compile the constraint,
// as it cannot find the external dataset resource in the set of known resource types.
// "input mismatch exception" is the return msg for this error
final var exception = assertThrows(RuntimeException.class, () -> hasura.checkConstraints(planId, newSimDatasetId));
final var message = exception.getMessage().split("\"message\":\"")[1].split("\"}]")[0];
// Hasura strips the cause message ("Constraint compilation failed -- Error[errors=[UserCodeError[ $ERROR ]]]")
// from the error it returns
if (!message.equals("constraint compilation exception")) {
throw exception;
}
final var constraintResponses = hasura.checkConstraints(planId);
assertEquals(1,constraintResponses.size());
final var constraintRepsonse = constraintResponses.get(0);
assertEquals(false,constraintRepsonse.success());
assertEquals(1,constraintRepsonse.errors().size());
final ConstraintError error = constraintRepsonse.errors().get(0);
assertEquals("Constraint 'fruit_equal_peel': TypeError: TS2345 Argument of type '\"/my_boolean\"' is not assignable to parameter of type 'ResourceName'.",error.message());
}

@Test
Expand All @@ -456,12 +472,14 @@ void compilationFailsOutdatedSimulationNoSimDataset() throws IOException {

// The constraint run is expected to fail with the following message because the constraint
// DSL isn't being generated for datasets that are outdated.
final var exception = assertThrows(RuntimeException.class, () -> hasura.checkConstraints(planId));
final var message = exception.getMessage().split("\"message\":\"")[1].split("\"}]")[0];
final var constraintResponses = hasura.checkConstraints(planId);
assertEquals(1,constraintResponses.size());
final var constraintRepsonse = constraintResponses.get(0);
assertEquals(false,constraintRepsonse.success());
assertEquals(1,constraintRepsonse.errors().size());
final ConstraintError error = constraintRepsonse.errors().get(0);
assertEquals("Constraint 'fruit_equal_peel': TypeError: TS2345 Argument of type '\"/my_boolean\"' is not assignable to parameter of type 'ResourceName'.",error.message());

if (!message.equals("constraint compilation exception")) {
throw exception;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public record CachedConstraintRun(
int simDatasetId,
String constraintDefinition,
boolean definitionOutdated,
Optional<ConstraintRecord> results
Optional<ConstraintResult> results
) {
public static CachedConstraintRun fromJSON(JsonObject json) {
return new CachedConstraintRun(
Expand All @@ -18,7 +18,7 @@ public static CachedConstraintRun fromJSON(JsonObject json) {
json.getBoolean("definition_outdated"),
json.getJsonObject("results").isEmpty() ?
Optional.empty() :
Optional.of(ConstraintRecord.fromJSON(json.getJsonObject("results")))
Optional.of(ConstraintResult.fromJSON(json.getJsonObject("results")))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package gov.nasa.jpl.aerie.e2e.types;

import javax.json.JsonObject;

public record ConstraintError(String message, String stack, Location location ){
record Location(int column, int line){
public static Location fromJSON(JsonObject json){
return new Location(json.getJsonNumber("column").intValue(), json.getJsonNumber("line").intValue());
}
};

public static ConstraintError fromJSON(JsonObject json){
return new ConstraintError(json.getString("message"),json.getString("stack"),Location.fromJSON(json.getJsonObject("location")));
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,15 @@
import java.util.List;

public record ConstraintRecord(
int constraintId,
String constraintName,
String type,
List<String> resourceIds,
List<ConstraintViolation> violations,
List<Interval> gaps
) {
public record ConstraintViolation(List<Integer> activityInstanceIds, List<Interval> windows) {
public static ConstraintViolation fromJSON(JsonObject json) {
return new ConstraintViolation(
json.getJsonArray("activityInstanceIds")
.getValuesAs(JsonNumber::intValue),
json.getJsonArray("windows")
.getValuesAs(Interval::fromJSON));
}
}

public record Interval(long start, long end) {
public static Interval fromJSON(JsonObject json) {
return new Interval(json.getJsonNumber("start").longValue(), json.getJsonNumber("end").longValue());
}
}

public static ConstraintRecord fromJSON(JsonObject json) {
final var resourceIds = json.getJsonArray("resourceIds").getValuesAs(JsonString::getString);
final var gaps = json.getJsonArray("gaps").getValuesAs(Interval::fromJSON);
final var violations = json.getJsonArray("violations").getValuesAs(ConstraintViolation::fromJSON);
boolean success,
ConstraintResult result,
List<ConstraintError> errors

) {
public static ConstraintRecord fromJSON(JsonObject json){
return new ConstraintRecord(
json.getInt("constraintId"),
json.getString("constraintName"),
json.getString("type"),
resourceIds,
violations,
gaps
);
json.getBoolean("success"),
json.getJsonObject("results").isEmpty() ? null : ConstraintResult.fromJSON(json.getJsonObject("results")),
json.getJsonArray("errors").getValuesAs(ConstraintError::fromJSON));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package gov.nasa.jpl.aerie.e2e.types;

import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonString;
import java.util.List;

public record ConstraintResult(int constraintId,
String constraintName,
String type,
List<String> resourceIds,
List<ConstraintResult.ConstraintViolation> violations,
List<ConstraintResult.Interval> gaps){
public record ConstraintViolation(List<Integer> activityInstanceIds, List<Interval> windows) {

public static ConstraintViolation fromJSON(JsonObject json) {
return new ConstraintViolation(
json.getJsonArray("activityInstanceIds")
.getValuesAs(JsonNumber::intValue),
json.getJsonArray("windows")
.getValuesAs(Interval::fromJSON));
}
}

public record Interval(long start, long end) {
public static Interval fromJSON(JsonObject json) {
return new Interval(json.getJsonNumber("start").longValue(), json.getJsonNumber("end").longValue());
}
}

public static ConstraintResult fromJSON(JsonObject json) {
final var resourceIds = json.getJsonArray("resourceIds").getValuesAs(JsonString::getString);
final var gaps = json.getJsonArray("gaps").getValuesAs(Interval::fromJSON);
final var violations = json.getJsonArray("violations").getValuesAs(ConstraintViolation::fromJSON);

return new ConstraintResult(
json.getInt("constraintId"),
json.getString("constraintName"),
json.getString("type"),
resourceIds,
violations,
gaps
);
}
};
33 changes: 22 additions & 11 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 @@ -28,20 +28,31 @@ mutation AssignTemplateToSimulation($simulation_id: Int!, $simulation_template_i
CHECK_CONSTRAINTS("""
query checkConstraints($planId: Int!, $simulationDatasetId: Int) {
constraintViolations(planId: $planId, simulationDatasetId: $simulationDatasetId) {
constraintId
constraintName
type
resourceIds
violations {
activityInstanceIds
windows {
start
success
results {
constraintId
constraintName
resourceIds
type
gaps {
end
start
}
violations {
activityInstanceIds
windows {
end
start
}
}
}
gaps {
start
end
errors {
message
stack
location {
column
line
}
}
}
}"""),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gov.nasa.jpl.aerie.merlin.server.exceptions;

import gov.nasa.jpl.aerie.merlin.server.services.ConstraintsDSLCompilationService;

public class ConstraintCompilationException extends Exception {
String constraintName;
ConstraintsDSLCompilationService.ConstraintsDSLCompilationResult.Error error;
public ConstraintCompilationException(String constraintName, ConstraintsDSLCompilationService.ConstraintsDSLCompilationResult.Error error) {
super("Constraint "+constraintName+" compilation failed:\n"+error.toString());
this.constraintName = constraintName;
this.error = error;
}

public String getConstraintName() {
return constraintName;
}

public ConstraintsDSLCompilationService.ConstraintsDSLCompilationResult.Error getErrors() {
return error;
}
}
Loading

0 comments on commit 16c6352

Please sign in to comment.