From a356191ef7d195b8793ea8f9b7740442832a500a Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Fri, 16 Feb 2024 16:35:55 -0500 Subject: [PATCH] simplified implementation, got tests working --- .../io/cryostat/events/EventTemplates.java | 44 +++------- .../io/cryostat/events/S3TemplateService.java | 2 +- .../java/itest/CustomEventTemplateTest.java | 88 +++++++++---------- 3 files changed, 56 insertions(+), 78 deletions(-) diff --git a/src/main/java/io/cryostat/events/EventTemplates.java b/src/main/java/io/cryostat/events/EventTemplates.java index 4f1c0b159..c778d25bd 100644 --- a/src/main/java/io/cryostat/events/EventTemplates.java +++ b/src/main/java/io/cryostat/events/EventTemplates.java @@ -15,21 +15,20 @@ */ package io.cryostat.events; -import java.io.ByteArrayInputStream; +import java.io.IOException; import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; +import io.cryostat.core.sys.FileSystem; +import io.cryostat.core.templates.MutableTemplateService.InvalidEventTemplateException; +import io.cryostat.core.templates.MutableTemplateService.InvalidXmlException; import io.cryostat.core.templates.Template; import io.cryostat.core.templates.TemplateType; import io.cryostat.targets.Target; import io.cryostat.util.HttpMimeType; import io.smallrye.common.annotation.Blocking; -import io.smallrye.mutiny.Uni; -import io.vertx.core.Vertx; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.ws.rs.BadRequestException; @@ -58,7 +57,7 @@ public class EventTemplates { "Cryostat", TemplateType.TARGET); - @Inject Vertx vertx; + @Inject FileSystem fs; @Inject TargetTemplateService.Factory targetTemplateServiceFactory; @Inject S3TemplateService customTemplateService; @Inject Logger logger; @@ -86,30 +85,15 @@ public Response postTemplatesV1(@RestForm("template") FileUpload body) { @POST @Path("/api/v3/event_templates") @RolesAllowed("write") - public Uni postTemplates(@RestForm("template") FileUpload body) { - CompletableFuture cf = new CompletableFuture<>(); - var path = body.filePath(); - vertx.fileSystem() - .readFile(path.toString()) - .onComplete( - ar -> { - var str = ar.result().toString(); - try (var stream = - new ByteArrayInputStream( - str.getBytes(StandardCharsets.UTF_8))) { - customTemplateService.addTemplate(stream); - cf.complete(null); - } catch (Exception e) { - logger.error(e); - cf.completeExceptionally(e); - } - }) - .onFailure( - ar -> { - logger.error(ar.getCause()); - cf.completeExceptionally(ar.getCause()); - }); - return Uni.createFrom().future(cf); + public void postTemplates(@RestForm("template") FileUpload body) throws IOException { + if (body == null || body.filePath() == null || !"template".equals(body.name())) { + throw new BadRequestException(); + } + try (var stream = fs.newInputStream(body.filePath())) { + customTemplateService.addTemplate(stream); + } catch (InvalidEventTemplateException | InvalidXmlException e) { + throw new BadRequestException(e); + } } @DELETE diff --git a/src/main/java/io/cryostat/events/S3TemplateService.java b/src/main/java/io/cryostat/events/S3TemplateService.java index 6abf8dbc2..f71171bce 100644 --- a/src/main/java/io/cryostat/events/S3TemplateService.java +++ b/src/main/java/io/cryostat/events/S3TemplateService.java @@ -264,7 +264,7 @@ public Template addTemplate(InputStream stream) "Template has no configuration label attribute")); } - String templateName = labelAttr.getExplicitValue(); + String templateName = labelAttr.getExplicitValue().replaceAll("[\\W]+", "_"); XMLTagInstance root = model.getRoot(); root.setValue(JFCGrammar.ATTRIBUTE_LABEL_MANDATORY, templateName); diff --git a/src/test/java/itest/CustomEventTemplateTest.java b/src/test/java/itest/CustomEventTemplateTest.java index 557a94340..94c8e7a02 100644 --- a/src/test/java/itest/CustomEventTemplateTest.java +++ b/src/test/java/itest/CustomEventTemplateTest.java @@ -15,8 +15,7 @@ */ package itest; -import java.io.File; - +import io.quarkus.test.junit.DisabledOnIntegrationTest; import io.quarkus.test.junit.QuarkusTest; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; @@ -27,11 +26,10 @@ import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @QuarkusTest -@Disabled("TODO") +@DisabledOnIntegrationTest("classpath resources are not loadable in integration test") public class CustomEventTemplateTest extends StandardSelfTest { static final String INVALID_TEMPLATE_FILE_NAME = "invalidTemplate.xml"; @@ -43,37 +41,33 @@ public class CustomEventTemplateTest extends StandardSelfTest { @Test public void shouldThrowIfTemplateUploadNameInvalid() throws Exception { ClassLoader classLoader = getClass().getClassLoader(); - File invalidTemplate = - new File(classLoader.getResource(INVALID_TEMPLATE_FILE_NAME).getFile()); - String path = invalidTemplate.getAbsolutePath(); - - MultipartForm form = - MultipartForm.create() - .attribute("invalidTemplateAttribute", INVALID_TEMPLATE_FILE_NAME) - .binaryFileUpload( - TEMPLATE_NAME, INVALID_TEMPLATE_FILE_NAME, path, MEDIA_TYPE); + try (var stream = classLoader.getResourceAsStream(INVALID_TEMPLATE_FILE_NAME)) { + var buf = Buffer.buffer(stream.readAllBytes()); + MultipartForm form = + MultipartForm.create() + .binaryFileUpload( + TEMPLATE_NAME, INVALID_TEMPLATE_FILE_NAME, buf, MEDIA_TYPE); - HttpResponse resp = - webClient.extensions().post(REQ_URL, form, REQUEST_TIMEOUT_SECONDS); - MatcherAssert.assertThat(resp.statusCode(), Matchers.equalTo(400)); + HttpResponse resp = + webClient.extensions().post(REQ_URL, form, REQUEST_TIMEOUT_SECONDS); + MatcherAssert.assertThat(resp.statusCode(), Matchers.equalTo(400)); + } } @Test public void shouldThrowWhenPostingInvalidTemplate() throws Exception { ClassLoader classLoader = getClass().getClassLoader(); - File invalidTemplate = - new File(classLoader.getResource(INVALID_TEMPLATE_FILE_NAME).getFile()); - String path = invalidTemplate.getAbsolutePath(); - - MultipartForm form = - MultipartForm.create() - .attribute("template", INVALID_TEMPLATE_FILE_NAME) - .binaryFileUpload( - TEMPLATE_NAME, INVALID_TEMPLATE_FILE_NAME, path, MEDIA_TYPE); + try (var stream = classLoader.getResourceAsStream(INVALID_TEMPLATE_FILE_NAME)) { + var buf = Buffer.buffer(stream.readAllBytes()); + MultipartForm form = + MultipartForm.create() + .binaryFileUpload( + TEMPLATE_NAME, INVALID_TEMPLATE_FILE_NAME, buf, MEDIA_TYPE); - HttpResponse resp = - webClient.extensions().post(REQ_URL, form, REQUEST_TIMEOUT_SECONDS); - MatcherAssert.assertThat(resp.statusCode(), Matchers.equalTo(400)); + HttpResponse resp = + webClient.extensions().post(REQ_URL, form, REQUEST_TIMEOUT_SECONDS); + MatcherAssert.assertThat(resp.statusCode(), Matchers.equalTo(400)); + } } @Test @@ -88,19 +82,16 @@ public void testDeleteRecordingThrowsOnNonExistentTemplate() throws Exception { } @Test - public void testPostedTemplateCanBeDeleted() throws Exception { - try { - ClassLoader classLoader = getClass().getClassLoader(); - File customEventTemplate = - new File(classLoader.getResource(TEMPLATE_FILE_NAME).getFile()); - String path = customEventTemplate.getAbsolutePath(); + public void testPostedTemplateNameIsSanitizedAndCanBeDeleted() throws Exception { + ClassLoader classLoader = getClass().getClassLoader(); + try (var stream = classLoader.getResourceAsStream(TEMPLATE_FILE_NAME)) { + var buf = Buffer.buffer(stream.readAllBytes()); MultipartForm form = MultipartForm.create() - .attribute("template", TEMPLATE_FILE_NAME) - .binaryFileUpload("template", TEMPLATE_FILE_NAME, path, MEDIA_TYPE); + .binaryFileUpload("template", TEMPLATE_FILE_NAME, buf, MEDIA_TYPE); HttpResponse postResp = webClient.extensions().post(REQ_URL, form, REQUEST_TIMEOUT_SECONDS); - MatcherAssert.assertThat(postResp.statusCode(), Matchers.equalTo(200)); + MatcherAssert.assertThat(postResp.statusCode(), Matchers.equalTo(204)); HttpResponse getResp = webClient @@ -113,20 +104,23 @@ public void testPostedTemplateCanBeDeleted() throws Exception { boolean foundSanitizedTemplate = false; for (Object o : getResp.bodyAsJsonArray()) { JsonObject json = (JsonObject) o; + var name = json.getString("name"); foundSanitizedTemplate = - foundSanitizedTemplate - || json.getString("name").equals("Custom Event Template"); + foundSanitizedTemplate || name.equals("Custom_Event_Template"); } Assertions.assertTrue(foundSanitizedTemplate); } finally { - webClient - .extensions() - .delete( - String.format( - "%s/%s", - REQ_URL, - URLEncodedUtils.formatSegments("/Template_To_Sanitize")), - REQUEST_TIMEOUT_SECONDS); + var delResp = + webClient + .extensions() + .delete( + String.format( + "%s%s", + REQ_URL, + URLEncodedUtils.formatSegments( + "Custom_Event_Template")), + REQUEST_TIMEOUT_SECONDS); + MatcherAssert.assertThat(delResp.statusCode(), Matchers.equalTo(204)); } } }