Skip to content

Commit

Permalink
test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
iimpulse committed Nov 9, 2023
1 parent 87cd971 commit f99c9d6
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 66 deletions.
2 changes: 1 addition & 1 deletion oan-model/src/main/java/org/jax/oan/core/Phenotype.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
public class Phenotype extends OntologyClass {

private PhenotypeMetadata metadata;
private String category;
private String category = "";

public Phenotype(TermId id, String name) {
super(id, name);
Expand Down
19 changes: 18 additions & 1 deletion oan-rest/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id("com.github.johnrengelman.shadow") version "8.1.1"
id("io.micronaut.application") version "4.0.3"
id("io.micronaut.aot") version "4.0.3"
id('jacoco')
}

version = "0.1"
Expand All @@ -22,11 +23,16 @@ dependencies {
implementation("io.micronaut.neo4j:micronaut-neo4j-bolt")
implementation("io.micronaut.serde:micronaut-serde-jackson")
implementation("io.swagger.core.v3:swagger-annotations")
implementation("builders.dsl:spreadsheet-builder-poi:3.0.1")
compileOnly("org.graalvm.nativeimage:svm")
runtimeOnly("ch.qos.logback:logback-classic")

testImplementation("io.micronaut:micronaut-http-client")
testImplementation("io.micronaut.test:micronaut-test-rest-assured")
testRuntimeOnly("org.neo4j.test:neo4j-harness")
testImplementation('org.hamcrest:hamcrest-all:1.3')
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation("io.micronaut.test:micronaut-test-junit5")
testImplementation("org.mockito:mockito-junit-jupiter")
}


Expand Down Expand Up @@ -60,4 +66,15 @@ micronaut {
}


test {
finalizedBy jacocoTestReport // report is always generated after tests run
}

jacocoTestReport {
dependsOn test // tests are required to run before generating the report
reports {
xml.required = false
csv.required = false
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,15 @@ public AnnotationController(PhenotypeService phenotypeService, GeneService geneS
public HttpResponse<?> all(@Schema(minLength = 1, maxLength = 20, type = "string", pattern = ".*") @PathVariable String id) {
try {
TermId termId = TermId.of(id);
switch (SupportedEntity.from(termId)){
case PHENOTYPE:
return HttpResponse.ok(phenotypeService.findAll(termId));
case DISEASE:
return HttpResponse.ok(diseaseService.findAll(termId));
case GENE:
return HttpResponse.ok(geneService.findAll(termId));
default:
throw new OntologyAnnotationNetworkRuntimeException("Term Identifier not supported.");
}
return switch (SupportedEntity.from(termId)) {
case PHENOTYPE -> HttpResponse.ok(phenotypeService.findAll(termId));
case DISEASE -> HttpResponse.ok(diseaseService.findAll(termId));
case GENE -> HttpResponse.ok(geneService.findAll(termId));
default ->
throw new HttpStatusException(HttpStatus.BAD_REQUEST, String.format("%s is not a supported term identifier.", id));
};
} catch(PhenolRuntimeException e){
throw new OntologyAnnotationNetworkRuntimeException();
throw new HttpStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
}
}

Expand All @@ -89,8 +86,8 @@ public SystemFile download(
} else {
throw new HttpStatusException(HttpStatus.BAD_REQUEST, String.format("Downloading %s associations for %s is not supported.", entity, termId.getValue()));
}
} catch(PhenolRuntimeException e){
throw new OntologyAnnotationNetworkRuntimeException();
} catch(PhenolRuntimeException | OntologyAnnotationNetworkRuntimeException e){
throw new HttpStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jax.oan.service;

import jakarta.inject.Singleton;
import jakarta.validation.constraints.NotNull;
import org.jax.oan.core.DiseaseAnnotationDto;
import org.jax.oan.core.Gene;
import org.jax.oan.core.Phenotype;
Expand Down
39 changes: 14 additions & 25 deletions oan-rest/src/main/java/org/jax/oan/service/DownloadService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jax.oan.service;

import builders.dsl.spreadsheet.builder.poi.PoiSpreadsheetBuilder;
import io.micronaut.http.server.types.files.SystemFile;
import jakarta.inject.Singleton;
import org.jax.oan.core.*;
Expand All @@ -12,9 +11,9 @@

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;

@Singleton
public class DownloadService {
Expand All @@ -34,29 +33,29 @@ public SystemFile associations(TermId termId, SupportedEntity source, SupportedE
case DISEASE -> {
if (target.equals(SupportedEntity.PHENOTYPE)){
List<Phenotype> phenotypes = this.diseaseRepository.findPhenotypesByDisease(termId);
return buildFile(String.format("phenotypes_for_%s.xlsx", termId.getValue()), phenotypes);
return buildFile(String.format("phenotypes_for_%s", termId.getValue()), phenotypes);

} else {
List<Gene> genes = this.diseaseRepository.findGenesByDisease(termId);
return buildFile(String.format("genes_for_%s.xlsx", termId.getValue()), genes);
return buildFile(String.format("genes_for_%s", termId.getValue()), genes);
}
}
case GENE -> {
if(target.equals(SupportedEntity.DISEASE)){
List<Disease> diseases = this.geneRepository.findDiseasesByGene(termId);
return buildFile(String.format("dieases_for_%s.xlsx", termId.getValue()), diseases);
return buildFile(String.format("diseases_for_%s", termId.getValue()), diseases);
} else {
List<Phenotype> phenotypes = this.geneRepository.findPhenotypesByGene(termId);
return buildFile(String.format("phenotypes_for_%s.xlsx", termId.getValue()), phenotypes);
return buildFile(String.format("phenotypes_for_%s", termId.getValue()), phenotypes);
}
}
case PHENOTYPE -> {
if(target.equals(SupportedEntity.DISEASE)){
List<Disease> diseases = this.phenotypeRepository.findDiseasesByTerm(termId);
return buildFile(String.format("dieases_for_%s.xlsx", termId.getValue()), diseases);
return buildFile(String.format("dieases_for_%s", termId.getValue()), diseases);
} else {
List<Gene> genes = this.phenotypeRepository.findGenesByTerm(termId);
return buildFile(String.format("genes_for_%s.xlsx", termId.getValue()), genes);
return buildFile(String.format("genes_for_%s", termId.getValue()), genes);
}
}
default -> throw new OntologyAnnotationNetworkRuntimeException(String.format("Downloading %s association for %s failed because source type is not supported.", target.toString().toLowerCase(), termId.getValue()));
Expand All @@ -65,23 +64,13 @@ public SystemFile associations(TermId termId, SupportedEntity source, SupportedE

public SystemFile buildFile(String filename, List<? extends OntologyClass> targetList){
try {
String prefix = filename.split("\\.")[0];
File file = File.createTempFile(prefix, ".xlsx");
PoiSpreadsheetBuilder.create(file).build(w -> {
w.sheet("associations", s -> {
s.row(r -> Stream.of("id", "name")
.forEach(header -> r.cell(cd -> {
cd.value(header);
})
));
for (OntologyClass target : targetList.stream().sorted(Comparator.comparing((OntologyClass o) -> o.getName())).toList()) {
s.row(r -> {
r.cell(target.getId());
r.cell(target.getName());
});
}
});
});
File file = File.createTempFile(filename, ".tsv");
try (PrintWriter pw = new PrintWriter(file)) {
pw.println(String.format("%s \t %s", "id", "name"));
for (OntologyClass target : targetList.stream().sorted(Comparator.comparing((OntologyClass o) -> o.getName())).toList()) {
pw.println(String.format("%s \t %s", target.getId(), target.getName()));
}
}
return new SystemFile(file).attach(filename);
} catch (IOException e) {
e.printStackTrace();
Expand Down
12 changes: 2 additions & 10 deletions oan-rest/src/main/java/org/jax/oan/service/GeneService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,8 @@ public GeneService(GeneRepository geneRepository) {
}

public GeneAnnotationDto findAll(TermId termId){
List<Disease> diseases = findDiseasesByGene(termId);
List<Phenotype> phenotypes = findPhenotypesByGene(termId);
List<Disease> diseases = this.geneRepository.findDiseasesByGene(termId);
List<Phenotype> phenotypes = this.geneRepository.findPhenotypesByGene(termId);
return new GeneAnnotationDto(diseases, phenotypes);
}

public List<Phenotype> findPhenotypesByGene(TermId termId) {
return this.geneRepository.findPhenotypesByGene(termId);
}

public List<Disease> findDiseasesByGene(TermId termId){
return this.geneRepository.findDiseasesByGene(termId);
}
}
19 changes: 3 additions & 16 deletions oan-rest/src/main/java/org/jax/oan/service/PhenotypeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,9 @@ public PhenotypeService(PhenotypeRepository phenotypeRepository) {
}

public PhenotypeAnnotationDto findAll(TermId termId){
List<Disease> diseases = findDiseases(termId);
List<Gene> genes = findGenes(termId);
List<Assay> assays = findAssays(termId);
List<Disease> diseases = this.phenotypeRepository.findDiseasesByTerm(termId);
List<Gene> genes = this.phenotypeRepository.findGenesByTerm(termId);
List<Assay> assays = this.phenotypeRepository.findAssaysByTerm(termId);
return new PhenotypeAnnotationDto(diseases, genes, assays);
}

public List<Disease> findDiseases(TermId termId) {
return this.phenotypeRepository.findDiseasesByTerm(termId);
}

public List<Gene> findGenes(TermId termId) {
return this.phenotypeRepository.findGenesByTerm(termId);
}

public List<Assay> findAssays(TermId termId) {
return this.phenotypeRepository.findAssaysByTerm(termId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package org.jax.oan.controller;

import io.micronaut.http.server.types.files.SystemFile;
import io.micronaut.runtime.EmbeddedApplication;
import io.micronaut.test.annotation.MockBean;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import io.restassured.specification.RequestSpecification;
import jakarta.inject.Inject;
import org.jax.oan.core.*;
import org.jax.oan.service.DiseaseService;
import org.jax.oan.service.DownloadService;
import org.jax.oan.service.GeneService;
import org.jax.oan.service.PhenotypeService;
import org.junit.jupiter.api.Test;
import org.monarchinitiative.phenol.ontology.data.TermId;

import static org.hamcrest.CoreMatchers.*;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@MicronautTest
class AnnotationControllerTest {

@Inject
EmbeddedApplication<?> application;

@Inject
private PhenotypeService phenotypeService;
@Inject
private GeneService geneService;

@Inject
private DiseaseService diseaseService;

@Inject
private DownloadService downloadService;

@Test
void positive_by_disease(RequestSpecification spec) {
when(diseaseService.findAll(TermId.of("OMIM:039293")))
.thenReturn(new DiseaseAnnotationDto(Map.of("limbs", phenotypes()), genes()));
spec.when().get("/api/annotation/OMIM:039293").then()
.statusCode(200).body("genes.id",
hasItems("NCBIGene:00093", "NCBIGene:02002"));
}

@Test
void positive_by_phenotype(RequestSpecification spec) {
when(phenotypeService.findAll(TermId.of("HP:0000001")))
.thenReturn(new PhenotypeAnnotationDto(diseases(), genes(), assays()));
spec.when().get("/api/annotation/HP:0000001").then()
.statusCode(200)
.body("diseases.id", hasItems("MONDO:099233", "DECIPHER:434444"))
.body("genes.id", hasItems("NCBIGene:00093", "NCBIGene:02002"))
.body("assays.id", hasItem("LOINC:55555"));

}

@Test
void positive_by_gene(RequestSpecification spec) {
when(geneService.findAll(TermId.of("NCBIGene:093232")))
.thenReturn(new GeneAnnotationDto(diseases(), phenotypes()));
spec.when().get("/api/annotation/NCBIGene:093232").then()
.statusCode(200)
.body("diseases.id", hasItems("MONDO:099233", "DECIPHER:434444"))
.body("phenotypes.id", hasItems("HP:099233", "HP:434444"));
}

@Test
void negative_by_no_prefix(RequestSpecification spec){
spec.when().get("/api/annotation/FAKE:093232").then().statusCode(400);
}

@Test
void negative_by_incorrect_term(RequestSpecification spec){
spec.when().get("/api/annotation/not-right").then().statusCode(400);
}

@Test
void positive_download_file(RequestSpecification spec) throws IOException {
when(downloadService.associations(TermId.of("OMIM:0392932"), SupportedEntity.DISEASE, SupportedEntity.GENE))
.thenReturn(buildSimpleSpreadSheet());
spec.when().get("/api/annotation/OMIM:0392932/download/gene").then()
.statusCode(200).contentType("text/tab-separated-values");
}

@Test
void negative_download_file_no_prefix(RequestSpecification spec){
spec.when().get("/api/annotation/FAKE:093232/download/gene").then().statusCode(400);
}

@Test
void negative_download_file_incorrect_term(RequestSpecification spec){
spec.when().get("/api/annotation/not-right/download/disease").then().statusCode(400);
}

@Test
void negative_download_file_bad_type(RequestSpecification spec){
spec.when().get("/api/annotation/OMIM:0392932/download/disease").then().statusCode(400);
}

private static List<Gene> genes(){
return List.of(
new Gene(TermId.of("NCBIGene:00093"),"TP4"),
new Gene(TermId.of("NCBIGene:02002"),"YZ")
);
}

private static List<Disease> diseases(){
return List.of(
new Disease(TermId.of("MONDO:099233"),"Really bad one"),
new Disease(TermId.of("DECIPHER:434444"),"Kinda bad one")
);
}

private static List<Phenotype> phenotypes(){
return List.of(
new Phenotype(TermId.of("HP:099233"),"Long legs"),
new Phenotype(TermId.of("HP:434444"),"Big bicep small arm")
);
}

private static List<Assay> assays(){
return List.of(
new Assay(TermId.of("LOINC:55555"),"Special bicep test")
);
}

private static SystemFile buildSimpleSpreadSheet() throws IOException {
File file = File.createTempFile("test", ".tsv");
try (PrintWriter pw = new PrintWriter(file)) {
pw.println(String.format("%s \t %s", "id", "name"));
pw.println(String.format("%s \t %s", "NCBIGene:301", "TX2"));
}
return new SystemFile(file).attach(file.getName());
}

@MockBean(DiseaseService.class)
DiseaseService diseaseService() {
return mock(DiseaseService.class);
}

@MockBean(GeneService.class)
GeneService geneService() {
return mock(GeneService.class);
}

@MockBean(PhenotypeService.class)
PhenotypeService phenotypeService() {
return mock(PhenotypeService.class);
}

@MockBean(DownloadService.class)
DownloadService downloadService() {
return mock(DownloadService.class);
}
}
Loading

0 comments on commit f99c9d6

Please sign in to comment.