-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ALS-5065] Write phenotypic and genomic data to file
- We need to be able to upload hpds query results to aws - Most of this work will be done by another service, but we need hpds to write the results to a file prior to upload
- Loading branch information
Luke Sikina
committed
Nov 16, 2023
1 parent
47b827b
commit d6c5ea1
Showing
6 changed files
with
314 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
.../main/java/edu/harvard/hms/dbmi/avillach/hpds/service/filesharing/FileSharingService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package edu.harvard.hms.dbmi.avillach.hpds.service.filesharing; | ||
|
||
import edu.harvard.hms.dbmi.avillach.hpds.data.query.Query; | ||
import edu.harvard.hms.dbmi.avillach.hpds.data.query.ResultType; | ||
import edu.harvard.hms.dbmi.avillach.hpds.processing.AsyncResult; | ||
import edu.harvard.hms.dbmi.avillach.hpds.processing.VariantListProcessor; | ||
import edu.harvard.hms.dbmi.avillach.hpds.service.QueryService; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.io.IOException; | ||
import java.time.Duration; | ||
import java.time.temporal.ChronoUnit; | ||
|
||
/** | ||
* Used for sharing data. Given a query, this service will write | ||
* phenotypic and genomic data into a directory | ||
*/ | ||
@Service | ||
public class FileSharingService { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(FileSharingService.class); | ||
|
||
@Autowired | ||
private QueryService queryService; | ||
|
||
@Autowired | ||
private FileSystemService fileWriter; | ||
|
||
@Autowired | ||
private VariantListProcessor variantListProcessor; | ||
|
||
public boolean createPhenotypicData(Query query) { | ||
AsyncResult result = queryService.getResultFor(query.getId()); | ||
if (result.status != AsyncResult.Status.SUCCESS) { | ||
return false; | ||
} | ||
return fileWriter.writeResultToFile("phenotypic_data.tsv", query.getId(), result); | ||
} | ||
|
||
public boolean createGenomicData(Query query) { | ||
String vcf = ""; | ||
try { | ||
vcf = variantListProcessor.runVcfExcerptQuery(query, true); | ||
} catch (IOException e) { | ||
LOG.error("Error running genomic query", e); | ||
return false; | ||
} | ||
|
||
return fileWriter.writeResultToFile("genomic_data.tsv", query.getId(), vcf, query.getId()); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...rc/main/java/edu/harvard/hms/dbmi/avillach/hpds/service/filesharing/FileSystemConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package edu.harvard.hms.dbmi.avillach.hpds.service.filesharing; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import java.nio.file.Path; | ||
|
||
@Configuration | ||
public class FileSystemConfig { | ||
@Value("${file_sharing_root:/gic_query_results/}") | ||
private String fileSharingRootDir; | ||
|
||
@Value("${enable_file_sharing:false}") | ||
private boolean enableFileSharing; | ||
|
||
@Bean() | ||
Path sharingRoot() { | ||
if (!enableFileSharing) { | ||
return Path.of("/dev/null"); | ||
} | ||
|
||
Path path = Path.of(fileSharingRootDir); | ||
if (!path.toFile().exists()) { | ||
throw new RuntimeException(fileSharingRootDir + " DNE."); | ||
} | ||
|
||
return path; | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
...c/main/java/edu/harvard/hms/dbmi/avillach/hpds/service/filesharing/FileSystemService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package edu.harvard.hms.dbmi.avillach.hpds.service.filesharing; | ||
|
||
import edu.harvard.hms.dbmi.avillach.hpds.processing.AsyncResult; | ||
import org.apache.commons.io.IOUtils; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
|
||
@Service | ||
public class FileSystemService { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(FileSystemService.class); | ||
|
||
@Autowired | ||
private Path sharingRoot; | ||
|
||
@Value("${enable_file_sharing:false}") | ||
private boolean enableFileSharing; | ||
|
||
public boolean writeResultToFile(String fileName, String directory, AsyncResult result) { | ||
result.stream.open(); | ||
return writeStreamToFile(fileName, result.stream, result.id); | ||
} | ||
|
||
public boolean writeResultToFile(String fileName, String directory, String result, String id) { | ||
return writeStreamToFile(fileName, new ByteArrayInputStream(result.getBytes()), id); | ||
} | ||
|
||
private boolean writeStreamToFile(String fileName, InputStream content, String queryId) { | ||
if (!enableFileSharing) { | ||
LOG.warn("Attempted to write query result to file while file sharing is disabled. No-op."); | ||
return false; | ||
} | ||
|
||
Path dirPath = Path.of(sharingRoot.toString(), queryId); | ||
Path filePath = Path.of(sharingRoot.toString(), queryId, fileName); | ||
|
||
try { | ||
LOG.info("Writing query {} to file: {}", queryId, filePath); | ||
if (!Files.exists(dirPath)) { | ||
Files.createDirectory(dirPath); | ||
} | ||
return Files.copy(content, filePath) > 0; | ||
} catch (IOException e) { | ||
LOG.error("Error writing result.", e); | ||
return false; | ||
} finally { | ||
IOUtils.closeQuietly(content); | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
...t/java/edu/harvard/hms/dbmi/avillach/hpds/service/filesharing/FileSharingServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package edu.harvard.hms.dbmi.avillach.hpds.service.filesharing; | ||
|
||
import edu.harvard.hms.dbmi.avillach.hpds.data.query.Query; | ||
import edu.harvard.hms.dbmi.avillach.hpds.processing.AsyncResult; | ||
import edu.harvard.hms.dbmi.avillach.hpds.processing.VariantListProcessor; | ||
import edu.harvard.hms.dbmi.avillach.hpds.service.QueryService; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.Mockito; | ||
import org.mockito.junit.MockitoJUnitRunner; | ||
|
||
import java.io.IOException; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class FileSharingServiceTest { | ||
|
||
@Mock | ||
QueryService queryService; | ||
|
||
@Mock | ||
FileSystemService fileWriter; | ||
|
||
@Mock | ||
VariantListProcessor variantListProcessor; | ||
|
||
@InjectMocks | ||
FileSharingService subject; | ||
|
||
@Test | ||
public void shouldCreatePhenotypicData() { | ||
Query query = new Query(); | ||
query.setId("my-id"); | ||
AsyncResult result = new AsyncResult(query, new String[]{}); | ||
result.status = AsyncResult.Status.SUCCESS; | ||
|
||
Mockito.when(queryService.getResultFor("my-id")) | ||
.thenReturn(result); | ||
Mockito.when(fileWriter.writeResultToFile("phenotypic_data.tsv", "my-id", result)) | ||
.thenReturn(true); | ||
|
||
boolean actual = subject.createPhenotypicData(query); | ||
|
||
Assert.assertTrue(actual); | ||
} | ||
|
||
@Test | ||
public void shouldNotCreatePhenotypicData() { | ||
Query query = new Query(); | ||
query.setId("my-id"); | ||
AsyncResult result = new AsyncResult(query, new String[]{}); | ||
result.status = AsyncResult.Status.ERROR; | ||
|
||
Mockito.when(queryService.getResultFor("my-id")) | ||
.thenReturn(result); | ||
|
||
boolean actual = subject.createPhenotypicData(query); | ||
|
||
Assert.assertFalse(actual); | ||
} | ||
|
||
@Test | ||
public void shouldCreateGenomicData() throws IOException { | ||
Query query = new Query(); | ||
query.setId("my-id"); | ||
String vcf = "lol lets put the whole vcf in a string"; | ||
Mockito.when(variantListProcessor.runVcfExcerptQuery(query, true)) | ||
.thenReturn(vcf); | ||
Mockito.when(fileWriter.writeResultToFile("genomic_data.tsv", "my-id", vcf, "my-id")) | ||
.thenReturn(true); | ||
|
||
boolean actual = subject.createGenomicData(query); | ||
|
||
Assert.assertTrue(actual); | ||
} | ||
|
||
@Test | ||
public void shouldNotCreateGenomicData() throws IOException { | ||
Query query = new Query(); | ||
query.setId("my-id"); | ||
Mockito.when(variantListProcessor.runVcfExcerptQuery(query, true)) | ||
.thenThrow(new IOException("oh no!")); | ||
|
||
boolean actual = subject.createGenomicData(query); | ||
|
||
Assert.assertFalse(actual); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
...st/java/edu/harvard/hms/dbmi/avillach/hpds/service/filesharing/FileSystemServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package edu.harvard.hms.dbmi.avillach.hpds.service.filesharing; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.springframework.test.util.ReflectionTestUtils; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
|
||
public class FileSystemServiceTest { | ||
|
||
@Test | ||
public void shouldWriteToFile() throws IOException { | ||
Path dir = Files.createTempDirectory("my-upload-dir"); | ||
FileSystemService subject = new FileSystemService(); | ||
ReflectionTestUtils.setField(subject, "sharingRoot", dir); | ||
ReflectionTestUtils.setField(subject, "enableFileSharing", true); | ||
String fileContent = "I just got an ad that tried to sell a baguette with moz, dressing, " + | ||
"and tomatoes as a healthy lunch, and that's just so far from the truth that it's bugging me. " + | ||
"Like, come on. It's bread and cheese and oil. I don't care how fresh the tomatoes are."; | ||
|
||
boolean actual = subject.writeResultToFile("out.tsv", dir.toAbsolutePath().toString(), fileContent, "my-id"); | ||
String actualContent = Files.readString(dir.resolve("my-id/out.tsv")); | ||
|
||
Assert.assertTrue(actual); | ||
Assert.assertEquals(fileContent, actualContent); | ||
} | ||
|
||
@Test | ||
public void shouldNotWriteToFile() throws IOException { | ||
Path dir = Files.createTempDirectory("my-upload-dir"); | ||
FileSystemService subject = new FileSystemService(); | ||
ReflectionTestUtils.setField(subject, "sharingRoot", dir); | ||
ReflectionTestUtils.setField(subject, "enableFileSharing", false); | ||
|
||
boolean actual = subject.writeResultToFile("out.tsv", dir.toAbsolutePath().toString(), "", "my-id"); | ||
|
||
Assert.assertFalse(actual); | ||
} | ||
} |