Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions test/org/apache/catalina/valves/TestHealthCheckValve.java
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
}
178 changes: 178 additions & 0 deletions test/org/apache/catalina/valves/TestJsonAccessLogValve.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
65 changes: 65 additions & 0 deletions test/org/apache/catalina/valves/TestJsonErrorReportValve.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, Object> 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());
}
}