CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-servlet

Eclipse Jetty servlet container providing comprehensive servlet, filter, and listener integration with lifecycle management and dynamic registration support.

Pending
Overview
Eval results
Files

testing.mddocs/

Testing Utilities

Eclipse Jetty's servlet testing utilities provide comprehensive support for testing servlets, filters, and web applications without requiring a full server deployment through the ServletTester class and related testing infrastructure.

ServletTester

Note: ServletTester may be deprecated and eventually removed in future Jetty versions. For new projects, consider using the combination of Server + LocalConnector + ServletContextHandler for servlet testing instead.

The ServletTester provides a lightweight testing environment for servlet-based applications.

public class ServletTester extends ContainerLifeCycle {
    // Constructors
    public ServletTester();
    public ServletTester(String contextPath);
    public ServletTester(String contextPath, int options);
    
    // Context management
    public ServletContextHandler getContext();
    public void setContextPath(String contextPath);
    public String getContextPath();
    
    // Servlet registration
    public void addServlet(Class<? extends Servlet> servlet, String pathSpec);
    public ServletHolder addServlet(String className, String pathSpec);
    
    // Filter registration
    public void addFilter(Class<? extends Filter> filter, String pathSpec, 
                          EnumSet<DispatcherType> dispatches);
    public FilterHolder addFilter(String className, String pathSpec, 
                                  EnumSet<DispatcherType> dispatches);
    
    // Request execution
    public String getResponses(String request);
    public String getResponses(String request, long idleFor, TimeUnit units);
}

Usage Examples

Basic Servlet Testing

import org.eclipse.jetty.servlet.ServletTester;
import org.eclipse.jetty.servlet.ServletHolder;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

// Test servlet implementation
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        resp.setContentType("text/plain");
        resp.getWriter().println("Hello from test servlet!");
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        String data = req.getParameter("data");
        resp.setContentType("application/json");
        resp.getWriter().println("{\"received\":\"" + data + "\"}");
    }
}

// Basic servlet test
public class BasicServletTest {
    
    @Test
    public void testSimpleGetRequest() throws Exception {
        // Create servlet tester
        ServletTester tester = new ServletTester();
        tester.setContextPath("/test");
        
        // Add servlet
        tester.addServlet(TestServlet.class, "/hello");
        
        // Start tester
        tester.start();
        
        try {
            // Create HTTP request
            String request = "GET /test/hello HTTP/1.1\r\n" +
                           "Host: localhost\r\n" +
                           "Connection: close\r\n" +
                           "\r\n";
            
            // Execute request and get response
            String response = tester.getResponses(request);
            
            // Verify response
            assertTrue(response.contains("HTTP/1.1 200 OK"));
            assertTrue(response.contains("Hello from test servlet!"));
            
        } finally {
            tester.stop();
        }
    }
    
    @Test
    public void testPostRequest() throws Exception {
        ServletTester tester = new ServletTester("/api");
        tester.addServlet(TestServlet.class, "/data");
        tester.start();
        
        try {
            String requestBody = "data=testvalue";
            String request = "POST /api/data HTTP/1.1\r\n" +
                           "Host: localhost\r\n" +
                           "Content-Type: application/x-www-form-urlencoded\r\n" +
                           "Content-Length: " + requestBody.length() + "\r\n" +
                           "Connection: close\r\n" +
                           "\r\n" +
                           requestBody;
            
            String response = tester.getResponses(request);
            
            assertTrue(response.contains("HTTP/1.1 200 OK"));
            assertTrue(response.contains("{\"received\":\"testvalue\"}"));
            
        } finally {
            tester.stop();
        }
    }
}

Filter Testing

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.DispatcherType;
import java.util.EnumSet;

// Test filter implementation
public class LoggingFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) {
        // Initialize filter
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpResp = (HttpServletResponse) response;
        
        // Add request ID header
        String requestId = "REQ-" + System.currentTimeMillis();
        httpResp.setHeader("X-Request-ID", requestId);
        
        // Log request
        System.out.println("Processing request: " + httpReq.getRequestURI() + 
                          " [" + requestId + "]");
        
        // Continue chain
        chain.doFilter(request, response);
        
        // Log response
        System.out.println("Response status: " + httpResp.getStatus() + 
                          " [" + requestId + "]");
    }
    
    @Override
    public void destroy() {
        // Cleanup filter
    }
}

// Filter test
public class FilterTest {
    
    @Test
    public void testFilterChain() throws Exception {
        ServletTester tester = new ServletTester();
        
        // Add filter
        tester.addFilter(LoggingFilter.class, "/*", 
                        EnumSet.of(DispatcherType.REQUEST));
        
        // Add servlet
        tester.addServlet(TestServlet.class, "/test");
        
        tester.start();
        
        try {
            String request = "GET /test HTTP/1.1\r\n" +
                           "Host: localhost\r\n" +
                           "Connection: close\r\n" +
                           "\r\n";
            
            String response = tester.getResponses(request);
            
            // Verify filter added header
            assertTrue(response.contains("X-Request-ID: REQ-"));
            assertTrue(response.contains("Hello from test servlet!"));
            
        } finally {
            tester.stop();
        }
    }
}

Complex Application Testing

// Complex servlet with dependencies
public class DataServlet extends HttpServlet {
    private DatabaseService dbService;
    
    @Override
    public void init() throws ServletException {
        super.init();
        // Initialize database service (mock for testing)
        String dbUrl = getInitParameter("database.url");
        this.dbService = new MockDatabaseService(dbUrl);
    }
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        String id = req.getParameter("id");
        
        if (id == null) {
            resp.sendError(400, "Missing id parameter");
            return;
        }
        
        try {
            String data = dbService.getData(id);
            if (data == null) {
                resp.sendError(404, "Data not found");
                return;
            }
            
            resp.setContentType("application/json");
            resp.getWriter().println("{\"id\":\"" + id + "\",\"data\":\"" + data + "\"}");
            
        } catch (Exception e) {
            resp.sendError(500, "Database error: " + e.getMessage());
        }
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        String data = req.getParameter("data");
        
        if (data == null || data.trim().isEmpty()) {
            resp.sendError(400, "Missing data parameter");
            return;
        }
        
        try {
            String id = dbService.saveData(data);
            resp.setContentType("application/json");
            resp.getWriter().println("{\"id\":\"" + id + "\",\"status\":\"saved\"}");
            
        } catch (Exception e) {
            resp.sendError(500, "Failed to save data: " + e.getMessage());
        }
    }
    
    @Override
    public void destroy() {
        if (dbService != null) {
            dbService.close();
        }
        super.destroy();
    }
}

// Mock database service for testing
public class MockDatabaseService {
    private final Map<String, String> data = new HashMap<>();
    private int nextId = 1;
    
    public MockDatabaseService(String url) {
        // Initialize with test data
        data.put("1", "Test data 1");
        data.put("2", "Test data 2");
    }
    
    public String getData(String id) {
        return data.get(id);
    }
    
    public String saveData(String value) {
        String id = String.valueOf(nextId++);
        data.put(id, value);
        return id;
    }
    
    public void close() {
        data.clear();
    }
}

// Complex application test
public class ComplexApplicationTest {
    
    @Test
    public void testDataRetrieval() throws Exception {
        ServletTester tester = new ServletTester("/api");
        
        // Configure servlet with init parameters
        ServletHolder dataServlet = tester.addServlet(DataServlet.class.getName(), "/data");
        dataServlet.setInitParameter("database.url", "mock://localhost");
        
        tester.start();
        
        try {
            // Test successful data retrieval
            String request = "GET /api/data?id=1 HTTP/1.1\r\n" +
                           "Host: localhost\r\n" +
                           "Connection: close\r\n" +
                           "\r\n";
            
            String response = tester.getResponses(request);
            
            assertTrue(response.contains("HTTP/1.1 200 OK"));
            assertTrue(response.contains("{\"id\":\"1\",\"data\":\"Test data 1\"}"));
            
            // Test missing data
            request = "GET /api/data?id=999 HTTP/1.1\r\n" +
                     "Host: localhost\r\n" +
                     "Connection: close\r\n" +
                     "\r\n";
            
            response = tester.getResponses(request);
            assertTrue(response.contains("HTTP/1.1 404"));
            
            // Test missing parameter
            request = "GET /api/data HTTP/1.1\r\n" +
                     "Host: localhost\r\n" +
                     "Connection: close\r\n" +
                     "\r\n";
            
            response = tester.getResponses(request);
            assertTrue(response.contains("HTTP/1.1 400"));
            
        } finally {
            tester.stop();
        }
    }
    
    @Test
    public void testDataSaving() throws Exception {
        ServletTester tester = new ServletTester("/api");
        
        ServletHolder dataServlet = tester.addServlet(DataServlet.class.getName(), "/data");
        dataServlet.setInitParameter("database.url", "mock://localhost");
        
        tester.start();
        
        try {
            String requestBody = "data=New test data";
            String request = "POST /api/data HTTP/1.1\r\n" +
                           "Host: localhost\r\n" +
                           "Content-Type: application/x-www-form-urlencoded\r\n" +
                           "Content-Length: " + requestBody.length() + "\r\n" +
                           "Connection: close\r\n" +
                           "\r\n" +
                           requestBody;
            
            String response = tester.getResponses(request);
            
            assertTrue(response.contains("HTTP/1.1 200 OK"));
            assertTrue(response.contains("\"status\":\"saved\""));
            
        } finally {
            tester.stop();
        }
    }
}

Session Testing

// Session-aware servlet
public class SessionServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        HttpSession session = req.getSession();
        
        Integer count = (Integer) session.getAttribute("count");
        if (count == null) {
            count = 0;
        }
        count++;
        session.setAttribute("count", count);
        
        resp.setContentType("text/plain");
        resp.getWriter().println("Visit count: " + count);
        resp.getWriter().println("Session ID: " + session.getId());
    }
}

// Session test
public class SessionTest {
    
    @Test
    public void testSessionHandling() throws Exception {
        ServletTester tester = new ServletTester();
        
        // Enable sessions in the context
        tester.getContext().setSessionHandler(new SessionHandler());
        tester.addServlet(SessionServlet.class, "/session");
        
        tester.start();
        
        try {
            // First request - should create session
            String request1 = "GET /session HTTP/1.1\r\n" +
                            "Host: localhost\r\n" +
                            "Connection: close\r\n" +
                            "\r\n";
            
            String response1 = tester.getResponses(request1);
            assertTrue(response1.contains("Visit count: 1"));
            
            // Extract session cookie
            String sessionCookie = extractSessionCookie(response1);
            assertNotNull(sessionCookie);
            
            // Second request with session cookie
            String request2 = "GET /session HTTP/1.1\r\n" +
                            "Host: localhost\r\n" +
                            "Cookie: " + sessionCookie + "\r\n" +
                            "Connection: close\r\n" +
                            "\r\n";
            
            String response2 = tester.getResponses(request2);
            assertTrue(response2.contains("Visit count: 2"));
            
        } finally {
            tester.stop();
        }
    }
    
    private String extractSessionCookie(String response) {
        String[] lines = response.split("\r\n");
        for (String line : lines) {
            if (line.startsWith("Set-Cookie: JSESSIONID=")) {
                return line.substring("Set-Cookie: ".length());
            }
        }
        return null;
    }
}

Async Servlet Testing

import jakarta.servlet.AsyncContext;
import jakarta.servlet.ServletException;
import java.util.concurrent.CompletableFuture;

// Async servlet implementation
public class AsyncServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        
        // Start async processing
        AsyncContext asyncContext = req.startAsync();
        asyncContext.setTimeout(5000); // 5 second timeout
        
        // Process request asynchronously
        CompletableFuture.runAsync(() -> {
            try {
                // Simulate long-running operation
                Thread.sleep(1000);
                
                HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
                response.setContentType("text/plain");
                response.getWriter().println("Async operation completed");
                
                asyncContext.complete();
                
            } catch (Exception e) {
                asyncContext.complete();
            }
        });
    }
}

// Async servlet test
public class AsyncServletTest {
    
    @Test
    public void testAsyncProcessing() throws Exception {
        ServletTester tester = new ServletTester();
        
        // Configure servlet with async support
        ServletHolder asyncServlet = tester.addServlet(AsyncServlet.class.getName(), "/async");
        asyncServlet.setAsyncSupported(true);
        
        tester.start();
        
        try {
            String request = "GET /async HTTP/1.1\r\n" +
                           "Host: localhost\r\n" +
                           "Connection: close\r\n" +
                           "\r\n";
            
            // Use timeout for async response
            String response = tester.getResponses(request, 10, TimeUnit.SECONDS);
            
            assertTrue(response.contains("HTTP/1.1 200 OK"));
            assertTrue(response.contains("Async operation completed"));
            
        } finally {
            tester.stop();
        }
    }
}

Integration Test Framework

// Base test class for servlet integration tests
public abstract class ServletIntegrationTestBase {
    protected ServletTester tester;
    
    @Before
    public void setUp() throws Exception {
        tester = createServletTester();
        configureServletTester(tester);
        tester.start();
    }
    
    @After 
    public void tearDown() throws Exception {
        if (tester != null) {
            tester.stop();
        }
    }
    
    protected ServletTester createServletTester() {
        return new ServletTester("/test");
    }
    
    protected abstract void configureServletTester(ServletTester tester);
    
    // Utility methods for common test operations
    protected String sendGetRequest(String path) throws Exception {
        return sendRequest("GET", path, null, null);
    }
    
    protected String sendPostRequest(String path, String body) throws Exception {
        return sendRequest("POST", path, "application/x-www-form-urlencoded", body);
    }
    
    protected String sendJsonRequest(String method, String path, String jsonBody) throws Exception {
        return sendRequest(method, path, "application/json", jsonBody);
    }
    
    protected String sendRequest(String method, String path, String contentType, String body) 
            throws Exception {
        StringBuilder request = new StringBuilder();
        request.append(method).append(" ").append(tester.getContextPath()).append(path)
               .append(" HTTP/1.1\r\n");
        request.append("Host: localhost\r\n");
        
        if (contentType != null) {
            request.append("Content-Type: ").append(contentType).append("\r\n");
        }
        
        if (body != null) {
            request.append("Content-Length: ").append(body.length()).append("\r\n");
        }
        
        request.append("Connection: close\r\n");
        request.append("\r\n");
        
        if (body != null) {
            request.append(body);
        }
        
        return tester.getResponses(request.toString());
    }
    
    // Response parsing utilities
    protected int getResponseStatus(String response) {
        String statusLine = response.split("\r\n")[0];
        String[] parts = statusLine.split(" ");
        return Integer.parseInt(parts[1]);
    }
    
    protected String getResponseBody(String response) {
        int bodyStart = response.indexOf("\r\n\r\n");
        if (bodyStart == -1) return "";
        return response.substring(bodyStart + 4);
    }
    
    protected String getResponseHeader(String response, String headerName) {
        String[] lines = response.split("\r\n");
        for (String line : lines) {
            if (line.toLowerCase().startsWith(headerName.toLowerCase() + ":")) {
                return line.substring(headerName.length() + 1).trim();
            }
        }
        return null;
    }
}

// Example usage of integration test framework
public class ApiServletIntegrationTest extends ServletIntegrationTestBase {
    
    @Override
    protected void configureServletTester(ServletTester tester) {
        // Add authentication filter
        tester.addFilter(AuthenticationFilter.class, "/api/*", 
                        EnumSet.of(DispatcherType.REQUEST));
        
        // Add API servlets
        ServletHolder userServlet = tester.addServlet(UserServlet.class.getName(), "/api/users/*");
        userServlet.setInitParameter("database.url", "mock://test");
        
        ServletHolder dataServlet = tester.addServlet(DataServlet.class.getName(), "/api/data/*");
        dataServlet.setInitParameter("cache.enabled", "false");
    }
    
    @Test
    public void testUserApiEndpoints() throws Exception {
        // Test user creation
        String createRequest = "{\"name\":\"John Doe\",\"email\":\"john@example.com\"}";
        String response = sendJsonRequest("POST", "/api/users", createRequest);
        
        assertEquals(201, getResponseStatus(response));
        assertTrue(getResponseBody(response).contains("\"id\":"));
        
        // Test user retrieval
        response = sendGetRequest("/api/users/1");
        assertEquals(200, getResponseStatus(response));
        assertTrue(getResponseBody(response).contains("John Doe"));
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-eclipse-jetty--jetty-servlet

docs

error-handling.md

filter-handling.md

index.md

listeners.md

monitoring.md

servlet-context.md

servlet-handling.md

testing.md

tile.json