From 3a2d60cfaa78d71565de228bcd303f5cede5e9a1 Mon Sep 17 00:00:00 2001 From: Andres Becerra Date: Fri, 9 Feb 2024 11:45:55 +0000 Subject: [PATCH 1/2] SCRUM-3693: roll down MaTI DB between environments --- pom.xml | 2 +- .../mati/controller/AdminResource.java | 52 ++++++++++---- .../mati/interfaces/AdminRESTInterface.java | 30 +++----- .../SubdomainSequenceRepository.java | 1 + .../mati/rolldownrepository/DBRoller.java | 68 +++++++++++++++++++ src/main/resources/application.yml | 19 +++++- .../mati/controller/AdminResourceITCase.java | 60 +++++----------- .../controller/IdentifierResourceITCase.java | 10 +-- .../controller/SubdomainResourceITCase.java | 2 + src/test/resources/junit-platform.properties | 2 + 10 files changed, 159 insertions(+), 87 deletions(-) create mode 100644 src/main/java/org/alliancegenome/mati/rolldownrepository/DBRoller.java create mode 100644 src/test/resources/junit-platform.properties diff --git a/pom.xml b/pom.xml index 43df782..3603640 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ UTF-8 quarkus-bom io.quarkus.platform - 3.6.5 + 3.7.2 3.1.2 diff --git a/src/main/java/org/alliancegenome/mati/controller/AdminResource.java b/src/main/java/org/alliancegenome/mati/controller/AdminResource.java index a86ed82..3ecc3b2 100644 --- a/src/main/java/org/alliancegenome/mati/controller/AdminResource.java +++ b/src/main/java/org/alliancegenome/mati/controller/AdminResource.java @@ -2,27 +2,35 @@ import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; +import jakarta.transaction.Transactional; import jakarta.ws.rs.core.Response; import org.alliancegenome.mati.configuration.ErrorResponse; -import org.alliancegenome.mati.entity.SubdomainEntity; import org.alliancegenome.mati.interfaces.AdminRESTInterface; -import org.alliancegenome.mati.repository.SubdomainRepository; import org.alliancegenome.mati.repository.SubdomainSequenceRepository; +import org.alliancegenome.mati.rolldownrepository.DBRoller; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import java.util.List; import java.util.Map; /** - * Controller for administrative endpoints + * Controller for: + * getting the current values of the counters (subdomains) + * and rolling down the MaTI database */ @RequestScoped public class AdminResource implements AdminRESTInterface { @Inject SubdomainSequenceRepository subdomainSequenceRepository; + @Inject - SubdomainRepository subdomainRepository; + DBRoller dbRoller; + + @ConfigProperty(name = "NET") + String NET; - public Response getCounters(String auth_header) { + public Response getCounters() { Map counters = subdomainSequenceRepository.getSubdomainCounters(); if (counters.isEmpty()) { ErrorResponse.ErrorMessage errorMessage = new ErrorResponse.ErrorMessage("admin.getCounters","No subdomains in database"); @@ -32,20 +40,34 @@ public Response getCounters(String auth_header) { return Response.ok().entity(counters).build(); } - public Response setCounter(String auth_header, String subdomain, int value) { - SubdomainEntity subdomainEntity = subdomainRepository.findByName(subdomain); - if (subdomainEntity == null) { - ErrorResponse.ErrorMessage errorMessage = new ErrorResponse.ErrorMessage("admin.setCounter","ID subdomain " + subdomain +" not found"); - ErrorResponse errorResponse = new ErrorResponse(errorMessage); - return Response.status(Response.Status.BAD_REQUEST).entity(errorResponse).build(); + /** + * rolls down the status of Mati counters for the curation application + * @param auth_header with authorization + * @return a success/failure HTTP response + */ + @Transactional + public Response rolldown_for_curation(String auth_header) { + if (NET.equals("alpha")) { + return Response.ok().build(); } - boolean isDone = subdomainSequenceRepository.setSubdomainCounter(subdomainEntity, value); - if (isDone) { + List subdomains = List.of("disease_annotation"); + return rolldown(subdomains); + } + + /** + * rolls down the status of Mati counters from one environment to another + * prod -> beta + * beta -> alpha + * @param subdomains the list of subdomains to roll down + * @return a success/failure HTTP response + */ + private Response rolldown(List subdomains) { + Map counters = subdomainSequenceRepository.getSubdomainCounters(); + if (dbRoller.setSubdomainCounters(subdomains, counters)) { return Response.ok().build(); } else { - return Response.notModified("Failure changing the value").build(); + return Response.notModified("Failure changing the values").build(); } } - } diff --git a/src/main/java/org/alliancegenome/mati/interfaces/AdminRESTInterface.java b/src/main/java/org/alliancegenome/mati/interfaces/AdminRESTInterface.java index f51a5e9..ef98ad9 100644 --- a/src/main/java/org/alliancegenome/mati/interfaces/AdminRESTInterface.java +++ b/src/main/java/org/alliancegenome/mati/interfaces/AdminRESTInterface.java @@ -13,40 +13,28 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Tag(name = "Admin", description = "Administrative tasks") -@Authenticated public interface AdminRESTInterface { /** * Gets the counters for all the subdomains * - * @param auth_header Authorization Header * @return an HTTP response */ @Operation(summary = "Get Counter Values") @Path("/counters") @GET - Response getCounters(@NotNull @HeaderParam("Authorization") String auth_header); - + Response getCounters(); /** - * Sets the counters for a subdomain - * + * Rolls down the counters to another environment + * prod to beta, beta to alpha * @param auth_header Authorization Header - * @param subdomain the subdomain to change - * @param value the value to assign * @return an HTTP response */ - @Operation(summary = "Set Counter Value") - @Path("/counter") - @PUT - Response setCounter( - @NotNull(message = "Header does not have Authorization") @HeaderParam("Authorization") - String auth_header, - - @NotNull(message = "Header does not have subdomain") @HeaderParam("subdomain") - String subdomain, - - @NotNull(message = "Header does not have increment value") @HeaderParam("value") - int value - ); + @Operation(summary = "Roll down") + @Path("/rolldown_for_curation") + @POST + @Authenticated + Response rolldown_for_curation( + @NotNull(message = "Header does not have Authorization") @HeaderParam("Authorization") String auth_header); } diff --git a/src/main/java/org/alliancegenome/mati/repository/SubdomainSequenceRepository.java b/src/main/java/org/alliancegenome/mati/repository/SubdomainSequenceRepository.java index 4dfed55..986c310 100644 --- a/src/main/java/org/alliancegenome/mati/repository/SubdomainSequenceRepository.java +++ b/src/main/java/org/alliancegenome/mati/repository/SubdomainSequenceRepository.java @@ -1,5 +1,6 @@ package org.alliancegenome.mati.repository; +import io.quarkus.hibernate.orm.PersistenceUnit; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.persistence.EntityManager; diff --git a/src/main/java/org/alliancegenome/mati/rolldownrepository/DBRoller.java b/src/main/java/org/alliancegenome/mati/rolldownrepository/DBRoller.java new file mode 100644 index 0000000..30876dc --- /dev/null +++ b/src/main/java/org/alliancegenome/mati/rolldownrepository/DBRoller.java @@ -0,0 +1,68 @@ +package org.alliancegenome.mati.rolldownrepository; + +import io.quarkus.hibernate.orm.PersistenceUnit; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Rolls-down the MaTI database from one environment to other + * prod -> beta + * beta -> alpha + */ +@RequestScoped +public class DBRoller { + + @PersistenceUnit("rolldown") + @Inject + EntityManager entityManager; + + /** + * Creates the SQL sentences for setting the PostgreSQL sequences values + * @param subdomains the list of subdomains + * @param counters a dictionary mapping subdomains to values (e.g. subdomain_person -> 120 ) + * @return a list of SQL statements. For example: + * [ SETVAL('subdomain_name1_seq',10) ... SETVAL('subdomain_nameN_seq',N) ] + */ + private List prepareSETVALStatements(List subdomains, Map counters) { + List setVALStatements = new ArrayList<>(); + for (String subdomain : subdomains) { + if (counters.containsKey(subdomain)) { + Long counter = counters.get(subdomain); + if (counter > 0) { + setVALStatements.add("SETVAL('subdomain_" + subdomain + "_seq'," + counter + ")"); + } + } + } + return setVALStatements; + } + + /** + * Rolls down the values from one environment to other + * @param subdomains the list of subdomains + * @param counters a dictionary mapping subdomains to values (e.g. subdomain_reference -> 20 ) + * @return a success/failure value + */ + public boolean setSubdomainCounters(List subdomains, Map counters) { + List setStatements = prepareSETVALStatements(subdomains, counters); + if (!setStatements.isEmpty()) { + String body = String.join(",", setStatements); + String sql = "SELECT " + body; + Query query = entityManager.createNativeQuery(sql); + try { + int num_queries = query.getResultList().size(); + if (num_queries == setStatements.size()) { + return true; + } + } catch (Exception e) { + return false; + } + } + return true; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 46f8203..8333fa9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,17 +20,27 @@ quarkus: access-control-max-age: -1 headers: "*" datasource: + db-kind: postgresql jdbc: driver: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/mati username: postgres - password: postgres + rolldown: + db-kind: postgresql + jdbc: + url: jdbc:postgresql://localhost:5432/roll + username: postgres flyway: migrate-at-start: true hibernate-orm: dialect: org.hibernate.dialect.PostgreSQLDialect database: generation: none + packages: ['org.alliancegenome.mati.entity','org.alliancegenome.mati.repository','io.quarkus.hibernate.orm.panache'] + rolldown: + packages: ['org.alliancegenome.mati.rolldownrepository'] + datasource: rolldown + validate-in-dev-mode: false swagger-ui: always-include: true smallrye-openapi.management.enabled: false @@ -48,5 +58,8 @@ quarkus: "%test": quarkus.datasource.jdbc: - driver: org.testcontainers.jdbc.ContainerDatabaseDriver - url: jdbc:tc:postgresql:13:///mati + driver: org.testcontainers.jdbc.ContainerDatabaseDriver + url: jdbc:tc:postgresql:13:///mati + quarkus.datasource.rolldown.jdbc: + driver: org.testcontainers.jdbc.ContainerDatabaseDriver + url: jdbc:tc:postgresql:13:///roll diff --git a/src/test/java/org/alliancegenome/mati/controller/AdminResourceITCase.java b/src/test/java/org/alliancegenome/mati/controller/AdminResourceITCase.java index b970b31..57db2ba 100644 --- a/src/test/java/org/alliancegenome/mati/controller/AdminResourceITCase.java +++ b/src/test/java/org/alliancegenome/mati/controller/AdminResourceITCase.java @@ -10,57 +10,31 @@ import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; +/** + * Tests the /api/admin/counters endpoint + * It runs *after* the IdentifierResourceITcase tests + * that mint some identifiers + */ @QuarkusIntegrationTest @QuarkusTestResource(PostgresResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Order(3) public class AdminResourceITCase { - private String authorization; - @BeforeAll - void setup() { - authorization = "Bearer: " + OktaHelper.fetchOktaToken(); - } - - @Test - public void setCounterDA() { - setCounterandCheckStatus("disease_annotation", 2); - } - - @Test - public void setCounterPerson() { - setCounterandCheckStatus("person", 4); - } - - @Test - public void setCounterResource() { - setCounterandCheckStatus("resource", 8); - } @Test public void getCounters() { Map counters = given(). - contentType(JSON). - header("Accept", "application/json"). - header("Authorization", authorization). - when(). - get("http://localhost:8081/api/admin/counters"). - then(). - statusCode(200) - .extract().body().as(Map.class); - - Assertions.assertEquals(counters.get("disease_annotation"), 2); + contentType(JSON). + header("Accept", "application/json"). + when(). + get("http://localhost:8081/api/admin/counters"). + then(). + statusCode(200) + .extract().body().as(Map.class); + + Assertions.assertEquals(counters.get("disease_annotation"), 5); Assertions.assertEquals(counters.get("person"), 4); - Assertions.assertEquals(counters.get("resource"), 8); - } - - private void setCounterandCheckStatus(String subdomain, int value) { - given(). - contentType(JSON). - header("Authorization", authorization). - header("subdomain", subdomain). - header("value", value). - when(). - put("http://localhost:8081/api/admin/counter"). - then(). - statusCode(200); + Assertions.assertEquals(counters.get("resource"), 6); + Assertions.assertEquals(counters.get("reference"), 3); } } diff --git a/src/test/java/org/alliancegenome/mati/controller/IdentifierResourceITCase.java b/src/test/java/org/alliancegenome/mati/controller/IdentifierResourceITCase.java index d82f499..4a10390 100644 --- a/src/test/java/org/alliancegenome/mati/controller/IdentifierResourceITCase.java +++ b/src/test/java/org/alliancegenome/mati/controller/IdentifierResourceITCase.java @@ -6,16 +6,18 @@ import org.alliancegenome.mati.configuration.PostgresResource; import org.alliancegenome.mati.entity.IdentifiersRange; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.*; import static io.restassured.RestAssured.given; +/** + * Tests the /api/identifier (PUT, POST) endpoints + * for minting identifiers + */ @QuarkusIntegrationTest @QuarkusTestResource(PostgresResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Order(2) class IdentifierResourceITCase { private String authorization; diff --git a/src/test/java/org/alliancegenome/mati/controller/SubdomainResourceITCase.java b/src/test/java/org/alliancegenome/mati/controller/SubdomainResourceITCase.java index 7bf576d..570daff 100644 --- a/src/test/java/org/alliancegenome/mati/controller/SubdomainResourceITCase.java +++ b/src/test/java/org/alliancegenome/mati/controller/SubdomainResourceITCase.java @@ -9,6 +9,7 @@ import org.alliancegenome.mati.entity.SubdomainEntity; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import java.util.List; @@ -18,6 +19,7 @@ @QuarkusIntegrationTest @QuarkusTestResource(PostgresResource.class) +@Order(1) class SubdomainResourceITCase { @BeforeEach diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 0000000..be47bad --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1,2 @@ +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation From aa3437d656683110203a0173956ff28a73e5cc25 Mon Sep 17 00:00:00 2001 From: Andres Becerra Date: Fri, 9 Feb 2024 11:50:26 +0000 Subject: [PATCH 2/2] SCRUM-3693: remove local development user from yaml --- src/main/resources/application.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8333fa9..05f7076 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -24,12 +24,10 @@ quarkus: jdbc: driver: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/mati - username: postgres rolldown: db-kind: postgresql jdbc: url: jdbc:postgresql://localhost:5432/roll - username: postgres flyway: migrate-at-start: true hibernate-orm: