From 6d27bac503c11196db1cc3927caab5affb52fcd7 Mon Sep 17 00:00:00 2001 From: Sean-DNAstack Date: Fri, 20 Oct 2023 17:26:12 -0400 Subject: [PATCH] Added e2e tests --- .../com/dnastack/wes/service/WesE2ETest.java | 152 +++++++++++++++++- .../dnastack/wes/service/wdl/WdlSupplier.java | 1 + .../wdl/workflow_with_all_output_types.wdl | 29 ++++ .../local/LocalBlobStorageClientTest.java | 55 +++++-- 4 files changed, 222 insertions(+), 15 deletions(-) create mode 100644 e2e-tests/src/main/resources/com/dnastack/wes/service/wdl/workflow_with_all_output_types.wdl diff --git a/e2e-tests/src/main/java/com/dnastack/wes/service/WesE2ETest.java b/e2e-tests/src/main/java/com/dnastack/wes/service/WesE2ETest.java index c7fbe97..e183fcd 100644 --- a/e2e-tests/src/main/java/com/dnastack/wes/service/WesE2ETest.java +++ b/e2e-tests/src/main/java/com/dnastack/wes/service/WesE2ETest.java @@ -7,7 +7,6 @@ import com.google.auth.oauth2.GoogleCredentials; import io.restassured.builder.MultiPartSpecBuilder; import io.restassured.http.ContentType; -import io.restassured.http.Header; import io.restassured.specification.MultiPartSpecification; import org.awaitility.core.ConditionFactory; import org.junit.jupiter.api.*; @@ -20,7 +19,6 @@ import java.util.*; import static io.restassured.RestAssured.given; -import static java.lang.String.format; import static org.awaitility.Awaitility.with; import static org.hamcrest.Matchers.*; @@ -433,6 +431,7 @@ public void uploadWorkflowAttachmentWithRunSubmission() throws Exception { public class RunMethodsWithExistingJobs { String workflowJobId; + String workflowJobIdWithAllOutputTypes; @BeforeAll public void setup() throws InterruptedException { @@ -452,6 +451,22 @@ public void setup() throws InterruptedException { .multiPart(getJsonMultipart("tags", tags)) .multiPart(getJsonMultipart("workflow_params", inputs)) .post(path) + .then() + .assertThat() + .statusCode(200) + .body("run_id",is(notNullValue())) + .extract() + .jsonPath() + .getString("run_id"); + + workflowJobIdWithAllOutputTypes = given() + .log().uri() + .log().method() + .header(getHeader(getResource(path))) + .multiPart(getWorkflowUrlMultipart("echo.wdl")) + .multiPart(getMultipartAttachment("echo.wdl",supplier.getFileContent(WdlSupplier.WORKFLOW_WITH_ALL_OUTPUT_TYPES).getBytes())) + .multiPart(getJsonMultipart("workflow_params", inputs)) + .post(path) .then() .assertThat() .statusCode(200) @@ -569,6 +584,139 @@ public void listRunsReturnsReturnsNonEmptyCollection() { //@formatter:on } + + @Test + @DisplayName("Get Run Files for existing run returns all files") + public void getRunFilesReturnsNonEmptyCollection() throws Exception { + String path = getRootPath() + "/runs/" + workflowJobIdWithAllOutputTypes + "/files"; + pollUntilJobCompletes(workflowJobIdWithAllOutputTypes); + + //@formatter:off + given() + .log().uri() + .log().method() + .header(getHeader(getResource(getRootPath() + "/runs/" + workflowJobIdWithAllOutputTypes))) + .accept(ContentType.JSON) + .get(path) + .then() + .assertThat() + .statusCode(200) + .body("runFiles.size()", greaterThan(0)) + .body("runFiles.every { it.path != null && it.file_type in ['FINAL', 'SECONDARY', 'LOG'] }", equalTo(true)); + //@formatter:on + } + + + @Test + @DisplayName("Get Run Files for non-existent run fails with status 401 or 404") + public void getRunFilesForNonExistentRunShouldFail() { + String resourcePath = getRootPath() + "/runs/" + UUID.randomUUID(); + String path = resourcePath + "/files"; + + //@formatter:off + given() + .log().uri() + .log().method() + .header(getHeader(getResource(resourcePath))) + .accept(ContentType.JSON) + .get(path) + .then() + .assertThat() + .statusCode(anyOf(equalTo(404), equalTo(401))); + //@formatter:on + } + + + @Test + @DisplayName("Delete Run Files for existing run returns all deleted files") + public void deleteRunFilesReturnsNonEmptyCollection() throws Exception { + reRunWorkflowWithAllOutputTypes(); + String path = getRootPath() + "/runs/" + workflowJobIdWithAllOutputTypes + "/files"; + pollUntilJobCompletes(workflowJobIdWithAllOutputTypes); + + //@formatter:off + given() + .log().uri() + .log().method() + .header(getHeader(getResource(getRootPath() + "/runs/" + workflowJobIdWithAllOutputTypes))) + .accept(ContentType.JSON) + .delete(path) + .then() + .assertThat() + .statusCode(200) + .body("deletions.size()", greaterThan(0)) + .body("deletions.every { it.path != null && it.file_type == 'SECONDARY' && it.state == 'DELETED' }", equalTo(true)); + //@formatter:on + } + + + @Test + @DisplayName("Delete Run Files for existing run asynchronously returns all deleted files") + public void deleteRunFilesAsyncReturnsNonEmptyCollection() throws Exception { + reRunWorkflowWithAllOutputTypes(); + String path = getRootPath() + "/runs/" + workflowJobIdWithAllOutputTypes + "/files"; + pollUntilJobCompletes(workflowJobIdWithAllOutputTypes); + + //@formatter:off + given() + .log().uri() + .log().method() + .header(getHeader(getResource(getRootPath() + "/runs/" + workflowJobIdWithAllOutputTypes))) + .accept(ContentType.JSON) + .queryParam("async", true) + .delete(path) + .then() + .assertThat() + .statusCode(200) + .body("deletions.size()", greaterThan(0)) + .body("deletions.every { it.path != null && it.file_type == 'SECONDARY' && it.state == 'ASYNC' }", equalTo(true)); + //@formatter:on + } + + + @Test + @DisplayName("Delete Run Files for non-existent run fails with status 401 or 404") + public void deleteRunFilesForNonExistentRunShouldFail() { + String resourcePath = getRootPath() + "/runs/" + UUID.randomUUID(); + String path = resourcePath + "/files"; + + //@formatter:off + given() + .log().uri() + .log().method() + .header(getHeader(getResource(resourcePath))) + .accept(ContentType.JSON) + .delete(path) + .then() + .assertThat() + .statusCode(anyOf(equalTo(404),equalTo(401))); + //@formatter:on + } + + + private void reRunWorkflowWithAllOutputTypes() { + String path = getRootPath() + "/runs"; + Map inputs = Collections.singletonMap("hello_world.name", "Some sort of String"); + + //@formatter:off + workflowJobIdWithAllOutputTypes = given() + .log().uri() + .log().method() + .header(getHeader(getResource(path))) + .multiPart(getWorkflowUrlMultipart("echo.wdl")) + .multiPart(getMultipartAttachment("echo.wdl",supplier.getFileContent(WdlSupplier.WORKFLOW_WITH_ALL_OUTPUT_TYPES).getBytes())) + .multiPart(getJsonMultipart("workflow_params", inputs)) + .post(path) + .then() + .assertThat() + .statusCode(200) + .body("run_id",is(notNullValue())) + .extract() + .jsonPath() + .getString("run_id"); + //@formatter:on + } + } } diff --git a/e2e-tests/src/main/java/com/dnastack/wes/service/wdl/WdlSupplier.java b/e2e-tests/src/main/java/com/dnastack/wes/service/wdl/WdlSupplier.java index 3cb63c9..8f6ddf0 100644 --- a/e2e-tests/src/main/java/com/dnastack/wes/service/wdl/WdlSupplier.java +++ b/e2e-tests/src/main/java/com/dnastack/wes/service/wdl/WdlSupplier.java @@ -10,6 +10,7 @@ public class WdlSupplier { public static final String WORKFLOW_WITHOUT_FILE = "workflow_without_file.wdl"; + public static final String WORKFLOW_WITH_ALL_OUTPUT_TYPES = "workflow_with_all_output_types.wdl"; public static final String WORKFLOW_WITH_IMPORTS_1 = "workflow_with_imports_1.wdl"; public static final String WORKFLOW_WITH_IMPORTS_2 = "workflow_with_imports_2.wdl"; public static final String WORKFLOW_WITH_IMPORTS_INPUTS = "workflow_with_imports.json"; diff --git a/e2e-tests/src/main/resources/com/dnastack/wes/service/wdl/workflow_with_all_output_types.wdl b/e2e-tests/src/main/resources/com/dnastack/wes/service/wdl/workflow_with_all_output_types.wdl new file mode 100644 index 0000000..c117df4 --- /dev/null +++ b/e2e-tests/src/main/resources/com/dnastack/wes/service/wdl/workflow_with_all_output_types.wdl @@ -0,0 +1,29 @@ +task echo { + String name + command { + echo "Hello ${name}" + >&2 echo "Goodbye ${name}" + echo "Bye" > "test.txt" + } + + runtime { + docker: "ubuntu" + } + + output { + File out = stdout() + File out2 = "test.txt" + Array[File] arrayOut = [out, out2] + } +} + +workflow hello_world { + String name + call echo { + input: + name = name + } + output { + File out = echo.out + } +} \ No newline at end of file diff --git a/src/test/java/com/dnastack/wes/storage/client/local/LocalBlobStorageClientTest.java b/src/test/java/com/dnastack/wes/storage/client/local/LocalBlobStorageClientTest.java index fb3017b..80f832f 100644 --- a/src/test/java/com/dnastack/wes/storage/client/local/LocalBlobStorageClientTest.java +++ b/src/test/java/com/dnastack/wes/storage/client/local/LocalBlobStorageClientTest.java @@ -15,6 +15,9 @@ class LocalBlobStorageClientTest { + private final String toWrite = "Test String"; + private final String directory = "test"; + private final String fileName = "test.txt"; @Test public void testCreateStorageClient_noStagingPath() throws IOException { @@ -36,10 +39,6 @@ public void testCreateStorageClient_withStagingPath() throws IOException { @Test public void testWritingBytesToFile() throws IOException { LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); - String toWrite = "Test String"; - String directory = "test"; - String fileName = "test.txt"; - Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); storageClient.writeBytes(new ByteArrayInputStream(toWrite.getBytes()), toWrite.length(), directory, fileName); @@ -51,9 +50,6 @@ public void testWritingBytesToFile() throws IOException { @Test public void testWritingBytesToFile_existingFileThrowsError() throws IOException { LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); - String toWrite = "Test String"; - String directory = "test"; - String fileName = "test.txt"; Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); Files.createDirectory(targetPath.getParent()); Files.write(targetPath, toWrite.getBytes(), StandardOpenOption.CREATE_NEW); @@ -66,9 +62,6 @@ public void testWritingBytesToFile_existingFileThrowsError() throws IOException @Test public void testReadingFile() throws IOException { LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); - String toWrite = "Test String"; - String directory = "test"; - String fileName = "test.txt"; Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); Files.createDirectory(targetPath.getParent()); Files.write(targetPath, toWrite.getBytes(), StandardOpenOption.CREATE_NEW); @@ -83,9 +76,6 @@ public void testReadingFile() throws IOException { @Test public void testReadingFile_withTruncation() throws IOException { LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); - String toWrite = "Test String"; - String directory = "test"; - String fileName = "test.txt"; Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); Files.createDirectory(targetPath.getParent()); Files.write(targetPath, toWrite.getBytes(), StandardOpenOption.CREATE_NEW); @@ -97,4 +87,43 @@ public void testReadingFile_withTruncation() throws IOException { Assertions.assertEquals(toWrite.substring(5), readValue); } + @Test + public void testIsFile() throws IOException { + LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); + Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); + Files.createDirectory(targetPath.getParent()); + Files.write(targetPath, toWrite.getBytes(), StandardOpenOption.CREATE_NEW); + + Assertions.assertTrue(storageClient.isFile(targetPath.toString())); + } + + @Test + public void testIsFile_noFileExists() throws IOException { + LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); + Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); + + Assertions.assertFalse(storageClient.isFile(targetPath.toString())); + } + + @Test + public void testDeletingFile() throws IOException { + LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); + Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); + Files.createDirectory(targetPath.getParent()); + Files.write(targetPath, toWrite.getBytes(), StandardOpenOption.CREATE_NEW); + + Assertions.assertTrue(Files.exists(targetPath)); + storageClient.deleteFile(targetPath.toString()); + Assertions.assertFalse(Files.exists(targetPath)); + } + + @Test + public void testDeletingFile_throwsError() throws IOException { + LocalBlobStorageClient storageClient = new LocalBlobStorageClient(); + Path targetPath = Path.of(storageClient.getStagingPath() + "/" + directory + "/" + fileName); + + Assertions.assertFalse(Files.exists(targetPath)); + Assertions.assertThrows(IOException.class, () -> storageClient.deleteFile(targetPath.toString())); + } + } \ No newline at end of file