Skip to content

Commit

Permalink
Merge pull request #1068 from NASA-AMMOS/add-java-bindings-tests
Browse files Browse the repository at this point in the history
Add Bindings Tests for Java Endpoints
  • Loading branch information
Mythicaeda authored Aug 8, 2023
2 parents cbd187d + e47e35c commit 28d0ffa
Show file tree
Hide file tree
Showing 12 changed files with 754 additions and 237 deletions.
639 changes: 639 additions & 0 deletions e2e-tests/src/tests/bindings.test.ts

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions e2e-tests/src/types/user.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
type User = {
username: string;
default_role: string;
allowed_roles: string[];
session: Record<string, string>;
};

type UserInsert = Omit<User, "allowed_roles" | "session">

type UserAllowedRole = {
username: string,
allowed_role: string;
}

type Permission = "NO_CHECK" | "OWNER" | "MISSION_MODEL_OWNER" | "PLAN_OWNER" | "PLAN_COLLABORATOR" | "PLAN_OWNER_COLLABORATOR"

type ActionPermissionSet = {
simulate: Permission | null,
schedule: Permission | null,
insert_ext_dataset: Permission | null,
check_constraints: Permission | null,
create_expansion_set: Permission | null,
create_expansion_rule: Permission | null,
expand_all_activities: Permission | null,
resource_samples: Permission | null,
sequence_seq_json_bulk: Permission | null
}
51 changes: 51 additions & 0 deletions e2e-tests/src/utilities/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,57 @@ const gql = {
}
`,

CREATE_USER: `#graphql
mutation createUser($user: users_insert_input!, $allowed_roles: [users_allowed_roles_insert_input!]!) {
insert_users_one(object: $user) {
default_role
username
}
insert_users_allowed_roles(objects: $allowed_roles) {
returning {
allowed_role
username
}
}
}
`,

DELETE_USER: `#graphql
mutation deleteUser($username: String!) {
delete_users_by_pk(username: $username) {
username
default_role
}
}
`,

ADD_PLAN_COLLABORATOR: `#graphql
mutation addPlanCollaborator($collaborator: plan_collaborators_insert_input!) {
insert_plan_collaborators_one(object: $collaborator) {
collaborator
plan_id
}
}
`,

GET_ROLE_ACTION_PERMISSIONS: `#graphl
query getRolePermissions($role: user_roles_enum!){
permissions: user_role_permission_by_pk(role: $role) {
action_permissions
}
}
`,

UPDATE_ROLE_ACTION_PERMISSIONS: `#graphl
mutation updateRolePermissions($role: user_roles_enum!, $action_permissions: jsonb!) {
permissions: update_user_role_permission_by_pk(
pk_columns: {role: $role},
_set: {action_permissions: $action_permissions})
{
action_permissions
}
}
`
};

export default gql;
36 changes: 32 additions & 4 deletions e2e-tests/src/utilities/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import time from './time.js';
* Aerie API request functions.
*/
const req = {
async createMissionModel(request: APIRequestContext, model: MissionModelInsertInput): Promise<number> {
const data = await req.hasura(request, gql.CREATE_MISSION_MODEL, { model: model });
async createMissionModel(request: APIRequestContext, model: MissionModelInsertInput, headers?: Record<string, string>): Promise<number> {
const data = await req.hasura(request, gql.CREATE_MISSION_MODEL, { model: model }, headers);
const { insert_mission_model_one } = data;
const { id: mission_model_id } = insert_mission_model_one;

Expand Down Expand Up @@ -126,8 +126,8 @@ const req = {
}
},

async createPlan(request: APIRequestContext, model: CreatePlanInput): Promise<number> {
const data = await req.hasura(request, gql.CREATE_PLAN, { plan: model });
async createPlan(request: APIRequestContext, model: CreatePlanInput, headers?: Record<string, string>): Promise<number> {
const data = await req.hasura(request, gql.CREATE_PLAN, { plan: model }, headers);
const { insert_plan_one } = data;
const { id: plan_id } = insert_plan_one;
return plan_id;
Expand Down Expand Up @@ -385,6 +385,34 @@ const req = {
const { constraint_run } = data;
return constraint_run;
},

// User-related requests
async createUser(request: APIRequestContext, user: User): Promise<void> {
const userInput: UserInsert = {username: user.username, default_role: user.default_role};
const allowedRolesInput: UserAllowedRole[] = user.allowed_roles.map(role => { return {username: user.username, allowed_role: role}})
await req.hasura(request, gql.CREATE_USER, { user: userInput, allowed_roles: allowedRolesInput } )
},

async deleteUser(request: APIRequestContext, username: string): Promise<void> {
await req.hasura(request, gql.DELETE_USER, { username })
},

async addPlanCollaborator(request: APIRequestContext, username: string, planId: number): Promise<void> {
const planCollaboratorInsertInput = {planId: planId, collaborator: username};
await req.hasura(request, gql.ADD_PLAN_COLLABORATOR, { planCollaboratorInsertInput });
},

async getActionPermissionsForRole(request: APIRequestContext, role: string): Promise<ActionPermissionSet> {
const data = await req.hasura(request, gql.GET_ROLE_ACTION_PERMISSIONS, { role });
const { permissions } = data;
const { action_permissions } = permissions;
return action_permissions;
},

async updateActionPermissionsForRole(request: APIRequestContext, role: string, permissions: ActionPermissionSet): Promise<void> {
const strippedPermissions = Object.fromEntries(Object.entries(permissions).filter(([_, v]) => v != null));
await req.hasura(request, gql.UPDATE_ROLE_ACTION_PERMISSIONS, { role: role, action_permissions: strippedPermissions });
}
};
/**
* Converts any activity to an Activity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

import gov.nasa.jpl.aerie.json.JsonParser;
import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity;
import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveId;
import gov.nasa.jpl.aerie.merlin.server.models.HasuraAction;
import gov.nasa.jpl.aerie.merlin.server.models.HasuraActivityDirectiveEvent;
import gov.nasa.jpl.aerie.merlin.server.models.HasuraMissionModelEvent;
import gov.nasa.jpl.aerie.merlin.server.models.PlanId;

import java.util.Optional;

Expand All @@ -24,7 +21,6 @@
import static gov.nasa.jpl.aerie.merlin.server.http.MerlinParsers.simulationDatasetIdP;
import static gov.nasa.jpl.aerie.merlin.server.http.MerlinParsers.timestampP;
import static gov.nasa.jpl.aerie.merlin.server.http.ProfileParsers.profileSetP;
import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.pgTimestampP;

public abstract class HasuraParsers {
private HasuraParsers() {}
Expand Down Expand Up @@ -96,25 +92,6 @@ private static <I extends HasuraAction.Input> JsonParser<HasuraAction<I>> hasura
untuple(missionModelId -> new HasuraMissionModelEvent(String.valueOf(missionModelId))),
$ -> tuple(Long.parseLong($.missionModelId())));

public static final JsonParser<HasuraActivityDirectiveEvent> hasuraActivityDirectiveEventTriggerP
= productP
.field("event", productP
.field("data", productP
.field("new", productP
.field("plan_id", longP)
.field("id", longP)
.field("type", stringP)
.field("arguments", mapP(serializedValueP))
.field("last_modified_arguments_at", pgTimestampP)
.rest())
.rest())
.rest())
.rest()
.map(
untuple((planId, activityDirectiveId, type, arguments, argumentsModifiedTime) ->
new HasuraActivityDirectiveEvent(new PlanId(planId), new ActivityDirectiveId(activityDirectiveId), type, arguments, argumentsModifiedTime)),
$ -> tuple($.planId().id(), $.activityDirectiveId().id(), $.activityTypeName(), $.arguments(), $.argumentsModifiedTime()));

private static final JsonParser<HasuraAction.MissionModelArgumentsInput> hasuraMissionModelArgumentsInputP
= productP
.field("missionModelId", stringP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException;
import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanDatasetException;
import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException;
import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveForValidation;
import gov.nasa.jpl.aerie.merlin.server.services.ConstraintAction;
import gov.nasa.jpl.aerie.merlin.server.models.HasuraAction;
import gov.nasa.jpl.aerie.merlin.server.models.PlanId;
Expand All @@ -32,7 +31,6 @@

import static gov.nasa.jpl.aerie.merlin.server.http.HasuraParsers.hasuraActivityActionP;
import static gov.nasa.jpl.aerie.merlin.server.http.HasuraParsers.hasuraActivityBulkActionP;
import static gov.nasa.jpl.aerie.merlin.server.http.HasuraParsers.hasuraActivityDirectiveEventTriggerP;
import static gov.nasa.jpl.aerie.merlin.server.http.HasuraParsers.hasuraConstraintsCodeAction;
import static gov.nasa.jpl.aerie.merlin.server.http.HasuraParsers.hasuraConstraintsViolationsActionP;
import static gov.nasa.jpl.aerie.merlin.server.http.HasuraParsers.hasuraUploadExternalDatasetActionP;
Expand Down Expand Up @@ -94,7 +92,6 @@ public void apply(final Javalin javalin) {
path("constraintViolations", () -> post(this::getConstraintViolations));
path("refreshModelParameters", () -> post(this::postRefreshModelParameters));
path("refreshActivityTypes", () -> post(this::postRefreshActivityTypes));
path("refreshActivityValidations", () -> post(this::postRefreshActivityValidations));
path("refreshResourceTypes", () -> post(this::postRefreshResourceTypes));
path("validateActivityArguments", () -> post(this::validateActivityArguments));
path("validateModelArguments", () -> post(this::validateModelArguments));
Expand Down Expand Up @@ -143,30 +140,6 @@ private void postRefreshActivityTypes(final Context ctx) {
}
}

private void postRefreshActivityValidations(final Context ctx) {
try {
final var input = parseJson(ctx.body(), hasuraActivityDirectiveEventTriggerP);
final var planId = input.planId();
final var serializedActivity = new SerializedActivity(input.activityTypeName(), input.arguments());
final var activityDirective = new ActivityDirectiveForValidation(input.activityDirectiveId(), input.planId(), input.argumentsModifiedTime(), serializedActivity);

final var plan = this.planService.getPlanForValidation(planId);
this.missionModelService.refreshActivityValidations(plan.missionModelId, activityDirective);
ctx.status(200);
} catch (final InvalidJsonException ex) {
ctx.status(400).result(ResponseSerializers.serializeInvalidJsonException(ex).toString());
} catch (final InvalidEntityException ex) {
ctx.status(400).result(ResponseSerializers.serializeInvalidEntityException(ex).toString());
} catch (final InstantiationException ex) {
ctx.status(400)
.result(ResponseSerializers.serializeFailures(List.of(ex.getMessage())).toString());
} catch (final NoSuchPlanException ex) {
ctx.status(404).result(ResponseSerializers.serializeNoSuchPlanException(ex).toString());
} catch (final MissionModelService.NoSuchMissionModelException ex) {
ctx.status(404).result(ResponseSerializers.serializeNoSuchMissionModelException(ex).toString());
}
}

private void postRefreshResourceTypes(Context ctx) {
try {
final var missionModelId = parseJson(ctx.body(), hasuraMissionModelEventTriggerP).missionModelId();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -300,12 +300,13 @@ public void refreshActivityTypes(final String missionModelId)
}

@Override
public void refreshResourceTypes(final String missionModelId){
public void refreshResourceTypes(final String missionModelId)
throws NoSuchMissionModelException {
try {
final var model = this.loadAndInstantiateMissionModel(missionModelId);
this.missionModelRepository.updateResourceTypes(missionModelId, model.getResources());
} catch (NoSuchMissionModelException | MissionModelRepository.NoSuchMissionModelException e) {
throw new RuntimeException(e);
} catch (MissionModelRepository.NoSuchMissionModelException e) {
throw new NoSuchMissionModelException(missionModelId);
}
}

Expand Down

This file was deleted.

Loading

0 comments on commit 28d0ffa

Please sign in to comment.