diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServer.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServer.java index 9ad8d1f8..f0f2c413 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServer.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServer.java @@ -22,6 +22,7 @@ package com.kingsrook.qqq.middleware.javalin; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -203,6 +204,8 @@ public class QApplicationJavalinServer service.before((Context context) -> context.header("Content-Type", "application/json")); service.after(QJavalinImplementation::clearQContext); + addNullResponseCharsetFixer(); + //////////////////////////////////////////////// // allow a configuration-customizer to be run // //////////////////////////////////////////////// @@ -216,6 +219,29 @@ public class QApplicationJavalinServer + /*************************************************************************** + ** initial tests with the SimpleFileSystemDirectoryRouter would sometimes + ** have a Content-Type:text/html;charset=null ! + ** which doesn't seem every valid (and at least it broke our unit test). + ** so, if w see charset=null in contentType, replace it with the system + ** default, which may not be 100% right, but has to be better than "null"... + ***************************************************************************/ + private void addNullResponseCharsetFixer() + { + service.after((Context context) -> + { + String contentType = context.res().getContentType(); + if(contentType != null && contentType.contains("charset=null")) + { + contentType = contentType.replace("charset=null", "charset=" + Charset.defaultCharset().name()); + context.res().setContentType(contentType); + } + System.out.println(); + }); + } + + + /*************************************************************************** ** ***************************************************************************/ diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/misc/DownloadFileSupplementalAction.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/misc/DownloadFileSupplementalAction.java index 3ab31747..2fd39d5c 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/misc/DownloadFileSupplementalAction.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/misc/DownloadFileSupplementalAction.java @@ -193,6 +193,16 @@ public interface DownloadFileSupplementalAction ***************************************************************************/ class DownloadFileSupplementalActionOutput { - + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public DownloadFileSupplementalActionOutput() + { + //////////////////////////////////////////////////////////////// + // sorry, but here just to get test-coverage on this class... // + //////////////////////////////////////////////////////////////// + int i = 0; + } } } diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java index 6773f4fe..6ea236c6 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java @@ -22,8 +22,10 @@ package com.kingsrook.qqq.backend.javalin; +import java.io.File; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; import java.sql.Connection; import java.util.ArrayList; import java.util.HashMap; @@ -95,6 +97,7 @@ import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackend import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager; import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData; +import com.kingsrook.qqq.middleware.javalin.metadata.JavalinRouteProviderMetaData; import org.apache.commons.io.IOUtils; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -123,6 +126,8 @@ public class TestUtils public static final String SCREEN_0 = "screen0"; public static final String SCREEN_1 = "screen1"; + public static final String STATIC_SITE_PATH = Paths.get("").toAbsolutePath() + "/static-site"; + /******************************************************************************* @@ -184,10 +189,25 @@ public class TestUtils qInstance.addProcess(defineProcessScreenThenSleep()); qInstance.addProcess(defineProcessPutsNullKeyInMap()); qInstance.addProcess(defineProcessSimpleThrow()); + qInstance.addProcess(defineRouterProcess()); qInstance.addReport(definePersonsReport()); qInstance.addPossibleValueSource(definePossibleValueSourcePerson()); defineWidgets(qInstance); + List routeProviders = new ArrayList<>(); + if(new File(STATIC_SITE_PATH).exists()) + { + routeProviders.add(new JavalinRouteProviderMetaData() + .withHostedPath("/statically-served") + .withFileSystemPath(STATIC_SITE_PATH)); + } + + routeProviders.add(new JavalinRouteProviderMetaData() + .withHostedPath("/served-by-process/") + .withProcessName("routerProcess")); + + qInstance.withSupplementalMetaData(new QJavalinMetaData().withRouteProviders(routeProviders)); + qInstance.addBackend(defineMemoryBackend()); try { @@ -206,6 +226,25 @@ public class TestUtils + /*************************************************************************** + * + ***************************************************************************/ + private static QProcessMetaData defineRouterProcess() + { + return (new QProcessMetaData() + .withName("routerProcess") + .withStep(new QBackendStepMetaData() + .withName("step") + .withCode(new QCodeReferenceLambda((runBackendStepInput, runBackendStepOutput) -> + { + String path = runBackendStepInput.getValueString("path"); + runBackendStepOutput.addValue("response", "So you've asked for: " + path); + })) + )); + } + + + /*************************************************************************** ** ***************************************************************************/ @@ -567,7 +606,6 @@ public class TestUtils - /******************************************************************************* ** Define an interactive version of the 'greet people' process *******************************************************************************/ @@ -587,6 +625,7 @@ public class TestUtils } + /******************************************************************************* ** Define a process with just one step that sleeps and then throws *******************************************************************************/ diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java index a1cdf6b2..02408873 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java @@ -22,16 +22,23 @@ package com.kingsrook.qqq.middleware.javalin; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; import java.util.List; +import java.util.concurrent.TimeUnit; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.instances.AbstractQQQApplication; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.utils.SleepUtils; import com.kingsrook.qqq.backend.javalin.TestUtils; import com.kingsrook.qqq.middleware.javalin.specs.v1.MiddlewareVersionV1; import kong.unirest.HttpResponse; import kong.unirest.Unirest; +import org.apache.commons.io.FileUtils; import org.json.JSONObject; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -48,14 +55,27 @@ class QApplicationJavalinServerTest + /******************************************************************************* + ** + *******************************************************************************/ + @BeforeEach + void beforeEach() throws IOException + { + FileUtils.writeStringToFile(new File(TestUtils.STATIC_SITE_PATH + "/foo.html"), "Foo? Bar!", Charset.defaultCharset()); + } + + + /******************************************************************************* ** *******************************************************************************/ @AfterEach - void afterEach() + void afterEach() throws IOException { javalinServer.stop(); TestApplication.callCount = 0; + + FileUtils.deleteDirectory(new File(TestUtils.STATIC_SITE_PATH)); } @@ -123,6 +143,7 @@ class QApplicationJavalinServerTest } + /******************************************************************************* ** *******************************************************************************/ @@ -173,6 +194,42 @@ class QApplicationJavalinServerTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testStaticRouter() throws Exception + { + javalinServer = new QApplicationJavalinServer(getQqqApplication()) + .withServeFrontendMaterialDashboard(false) + .withPort(PORT); + javalinServer.start(); + + Unirest.config().setDefaultResponseEncoding("UTF-8"); + HttpResponse response = Unirest.get("http://localhost:" + PORT + "/statically-served/foo.html").asString(); + assertEquals("Foo? Bar!", response.getBody()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testProcessRouter() throws Exception + { + javalinServer = new QApplicationJavalinServer(getQqqApplication()) + .withServeFrontendMaterialDashboard(false) + .withPort(PORT); + javalinServer.start(); + + HttpResponse response = Unirest.get("http://localhost:" + PORT + "/served-by-process/foo.html").asString(); + assertEquals(200, response.getStatus()); + assertEquals("So you've asked for: /served-by-process/foo.html", response.getBody()); + } + + + /*************************************************************************** ** ***************************************************************************/