Skip to content

Commit

Permalink
SCRUM-3693: roll down MaTI DB between environments
Browse files Browse the repository at this point in the history
  • Loading branch information
abecerra committed Feb 9, 2024
1 parent 47e38b8 commit 1b46566
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 89 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.6.5</quarkus.platform.version>
<quarkus.platform.version>3.7.2</quarkus.platform.version>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
</properties>

Expand Down
51 changes: 36 additions & 15 deletions src/main/java/org/alliancegenome/mati/controller/AdminResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,34 @@

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;

private static final String NET = System.getenv("NET");;

public Response getCounters(String auth_header) {
public Response getCounters() {
Map<String,Long> counters = subdomainSequenceRepository.getSubdomainCounters();
if (counters.isEmpty()) {
ErrorResponse.ErrorMessage errorMessage = new ErrorResponse.ErrorMessage("admin.getCounters","No subdomains in database");
Expand All @@ -32,20 +39,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<String> 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<String> subdomains) {
Map<String,Long> 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();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> prepareSETVALStatements(List<String> subdomains, Map<String,Long> counters) {
List<String> 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<String> subdomains, Map<String,Long> counters) {
List<String> 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;
}
}
21 changes: 16 additions & 5 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ okta:
client:
id: ""
secret: ""
scopes: admin
scopes: ""

quarkus:
http:
Expand All @@ -20,17 +20,25 @@ 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
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
Expand All @@ -48,5 +56,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
Original file line number Diff line number Diff line change
Expand Up @@ -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<String,Integer> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -18,6 +19,7 @@

@QuarkusIntegrationTest
@QuarkusTestResource(PostgresResource.class)
@Order(1)
class SubdomainResourceITCase {

@BeforeEach
Expand Down
2 changes: 2 additions & 0 deletions src/test/resources/junit-platform.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
junit.jupiter.testclass.order.default = \
org.junit.jupiter.api.ClassOrderer$OrderAnnotation

0 comments on commit 1b46566

Please sign in to comment.