diff --git a/test/org/apache/catalina/valves/TestHealthCheckValve.java b/test/org/apache/catalina/valves/TestHealthCheckValve.java index 5424805bb549..62a5c0eb3a99 100644 --- a/test/org/apache/catalina/valves/TestHealthCheckValve.java +++ b/test/org/apache/catalina/valves/TestHealthCheckValve.java @@ -113,4 +113,49 @@ public void service(ServletRequest request, ServletResponse response) { } + @Test + public void testGetSetProperties() { + HealthCheckValve valve = new HealthCheckValve(); + + // Default path + Assert.assertEquals("/health", valve.getPath()); + + valve.setPath("/ready"); + Assert.assertEquals("/ready", valve.getPath()); + + // Default checkContainersAvailable + Assert.assertTrue(valve.getCheckContainersAvailable()); + + valve.setCheckContainersAvailable(false); + Assert.assertFalse(valve.getCheckContainersAvailable()); + + valve.setCheckContainersAvailable(true); + Assert.assertTrue(valve.getCheckContainersAvailable()); + } + + + @Test + public void testCustomPath() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + HealthCheckValve healthCheckValve = new HealthCheckValve(); + healthCheckValve.setPath("/ready"); + ctx.getParent().getPipeline().addValve(healthCheckValve); + + tomcat.start(); + + ByteChunk result = new ByteChunk(); + + // Default /health should NOT match + int rc = getUrl("http://localhost:" + getPort() + "/health", result, null); + Assert.assertEquals(HttpServletResponse.SC_NOT_FOUND, rc); + + result.recycle(); + + // Custom /ready should match + rc = getUrl("http://localhost:" + getPort() + "/ready", result, null); + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + Assert.assertTrue(result.toString().contains("UP")); + } } diff --git a/test/org/apache/catalina/valves/TestJsonAccessLogValve.java b/test/org/apache/catalina/valves/TestJsonAccessLogValve.java new file mode 100644 index 000000000000..52b6e962f08f --- /dev/null +++ b/test/org/apache/catalina/valves/TestJsonAccessLogValve.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.valves; + +import java.nio.charset.StandardCharsets; + +import jakarta.servlet.http.HttpServletResponse; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; + +/** + * Tests for {@link JsonAccessLogValve}. + */ +public class TestJsonAccessLogValve extends TomcatBaseTest { + + @Test + public void testDefaultPatternProducesValidJson() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "hello", new HelloWorldServlet()); + ctx.addServletMappingDecoded("/", "hello"); + + JsonAccessLogValve valve = new JsonAccessLogValve(); + valve.setDirectory(getTemporaryDirectory().getAbsolutePath()); + valve.setPrefix("access_json_test"); + valve.setSuffix(".log"); + ctx.getParent().getPipeline().addValve(valve); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + res.setCharset(StandardCharsets.UTF_8); + int rc = getUrl("http://localhost:" + getPort() + "/", res, null); + + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + Assert.assertEquals(HelloWorldServlet.RESPONSE_TEXT, res.toString()); + } + + + @Test + public void testCommonPatternProducesValidJson() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "hello", new HelloWorldServlet()); + ctx.addServletMappingDecoded("/", "hello"); + + JsonAccessLogValve valve = new JsonAccessLogValve(); + valve.setPattern("common"); + valve.setDirectory(getTemporaryDirectory().getAbsolutePath()); + valve.setPrefix("access_json_common"); + valve.setSuffix(".log"); + ctx.getParent().getPipeline().addValve(valve); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + res.setCharset(StandardCharsets.UTF_8); + int rc = getUrl("http://localhost:" + getPort() + "/", res, null); + + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + } + + + @Test + public void testCombinedPatternProducesValidJson() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "hello", new HelloWorldServlet()); + ctx.addServletMappingDecoded("/", "hello"); + + JsonAccessLogValve valve = new JsonAccessLogValve(); + valve.setPattern("combined"); + valve.setDirectory(getTemporaryDirectory().getAbsolutePath()); + valve.setPrefix("access_json_combined"); + valve.setSuffix(".log"); + ctx.getParent().getPipeline().addValve(valve); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + res.setCharset(StandardCharsets.UTF_8); + int rc = getUrl("http://localhost:" + getPort() + "/", res, null); + + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + } + + + @Test + public void testCustomPatternWithRequestHeaders() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "hello", new HelloWorldServlet()); + ctx.addServletMappingDecoded("/", "hello"); + + JsonAccessLogValve valve = new JsonAccessLogValve(); + // Pattern includes request header and response header elements + valve.setPattern("%h %s %{User-Agent}i %{Content-Type}o"); + valve.setDirectory(getTemporaryDirectory().getAbsolutePath()); + valve.setPrefix("access_json_headers"); + valve.setSuffix(".log"); + ctx.getParent().getPipeline().addValve(valve); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + res.setCharset(StandardCharsets.UTF_8); + int rc = getUrl("http://localhost:" + getPort() + "/", res, null); + + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + } + + + @Test + public void testPatternWithCookiesAndSessionAttributes() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "hello", new HelloWorldServlet()); + ctx.addServletMappingDecoded("/", "hello"); + + JsonAccessLogValve valve = new JsonAccessLogValve(); + // Pattern includes cookies, request attributes, and session attributes + valve.setPattern("%h %s %{JSESSIONID}c %{testAttr}r %{testSession}s"); + valve.setDirectory(getTemporaryDirectory().getAbsolutePath()); + valve.setPrefix("access_json_cookies"); + valve.setSuffix(".log"); + ctx.getParent().getPipeline().addValve(valve); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + res.setCharset(StandardCharsets.UTF_8); + int rc = getUrl("http://localhost:" + getPort() + "/", res, null); + + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + } + + + @Test + public void testCreateLogElementsOutputFormat() { + JsonAccessLogValve valve = new JsonAccessLogValve(); + valve.setPattern("%h %s %b"); + + // Use createLogElements via the internal API + AbstractAccessLogValve.AccessLogElement[] elements = + valve.createLogElements(); + + // Verify that elements array is valid and has at least + // opening brace + 3 fields + separators + closing brace + Assert.assertNotNull(elements); + Assert.assertTrue("Should have at least some elements", + elements.length > 0); + } +} diff --git a/test/org/apache/catalina/valves/TestJsonErrorReportValve.java b/test/org/apache/catalina/valves/TestJsonErrorReportValve.java index 4770a9380210..7d5345205e96 100644 --- a/test/org/apache/catalina/valves/TestJsonErrorReportValve.java +++ b/test/org/apache/catalina/valves/TestJsonErrorReportValve.java @@ -409,4 +409,69 @@ public void service(ServletRequest request, ServletResponse response) { new IllegalStateException("Root cause")); } } + + + @Test + public void testJsonErrorThrowableWithNullMessage() throws Exception { + Tomcat tomcat = getTomcatInstance(); + ((StandardHost) tomcat.getHost()).setErrorReportValveClass(JSON_VALVE); + + Context ctx = getProgrammaticRootContext(); + + // Throwable with null message + Tomcat.addServlet(ctx, "nullMsg", new ExceptionServlet(null)); + ctx.addServletMappingDecoded("/", "nullMsg"); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + res.setCharset(StandardCharsets.UTF_8); + int rc = getUrl("http://localhost:" + getPort(), res, null); + + Assert.assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc); + + String body = res.toString(); + JSONParser parser = new JSONParser(body); + LinkedHashMap json = parser.parseObject(); + + Assert.assertEquals("Exception Report", json.get("type")); + Assert.assertEquals(500, ((Number) json.get("status")).intValue()); + // message should be empty since throwable.getMessage() is null + Assert.assertEquals("", json.get("message")); + Assert.assertNotNull(json.get("throwable")); + } + + + @Test + public void testJsonErrorWithSetPropertyAndGetProperty() { + JsonErrorReportValve valve = new JsonErrorReportValve(); + + // Inherited from ErrorReportValve + Assert.assertTrue(valve.setProperty("errorCode.404", "/error404.json")); + Assert.assertEquals("/error404.json", valve.getProperty("errorCode.404")); + + Assert.assertTrue(valve.setProperty( + "exceptionType.java.lang.NullPointerException", "/npe.json")); + Assert.assertEquals("/npe.json", valve.getProperty( + "exceptionType.java.lang.NullPointerException")); + + // Unknown property returns false/null + Assert.assertFalse(valve.setProperty("unknown.key", "value")); + Assert.assertNull(valve.getProperty("unknown.key")); + } + + + @Test + public void testJsonErrorShowReportShowServerInfoInherited() throws Exception { + JsonErrorReportValve valve = new JsonErrorReportValve(); + + // These are inherited from ErrorReportValve + Assert.assertTrue(valve.isShowReport()); + valve.setShowReport(false); + Assert.assertFalse(valve.isShowReport()); + + Assert.assertTrue(valve.isShowServerInfo()); + valve.setShowServerInfo(false); + Assert.assertFalse(valve.isShowServerInfo()); + } }