package io.undertow.server.handlers;

import io.undertow.Handlers;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.testutils.DefaultServer;
import io.undertow.testutils.HttpClientUtils;
import io.undertow.testutils.TestHttpClient;

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(DefaultServer.class)
public class ExceptionHandlerTestCase {

    @Test
    public void testExceptionMappers() throws IOException {
        HttpHandler pathHandler = Handlers.path()
                .addExactPath("/", new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        exchange.getResponseSender().send("expected");
                    }
                })
                .addExactPath("/exceptionParent", new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        throw new ParentException();
                    }
                })
                .addExactPath("/exceptionChild", new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        throw new ChildException();
                    }
                })
                .addExactPath("/exceptionAnotherChild", new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        throw new AnotherChildException();
                    }
                })
                .addExactPath("/illegalArgumentException", new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        throw new IllegalArgumentException();
                    }
                });

        HttpHandler exceptionHandler = Handlers.exceptionHandler(pathHandler)
                .addExceptionHandler(ChildException.class, new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        exchange.getResponseSender().send("child exception handled");
                    }
                })
                .addExceptionHandler(ParentException.class, new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        exchange.getResponseSender().send("parent exception handled");
                    }
                })
                .addExceptionHandler(Throwable.class, new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        exchange.getResponseSender().send("catch all throwables");
                    }
                });
        DefaultServer.setRootHandler(exceptionHandler);

        TestHttpClient client = new TestHttpClient();
        try {
            HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/");
            HttpResponse result = client.execute(get);
            Assert.assertEquals(200, result.getStatusLine().getStatusCode());
            Assert.assertEquals("expected", HttpClientUtils.readResponse(result));

            get = new HttpGet(DefaultServer.getDefaultServerURL() + "/exceptionParent");
            result = client.execute(get);
            Assert.assertEquals(200, result.getStatusLine().getStatusCode());
            Assert.assertEquals("parent exception handled", HttpClientUtils.readResponse(result));

            get = new HttpGet(DefaultServer.getDefaultServerURL() + "/exceptionChild");
            result = client.execute(get);
            Assert.assertEquals(200, result.getStatusLine().getStatusCode());
            Assert.assertEquals("child exception handled", HttpClientUtils.readResponse(result));

            get = new HttpGet(DefaultServer.getDefaultServerURL() + "/exceptionAnotherChild");
            result = client.execute(get);
            Assert.assertEquals(200, result.getStatusLine().getStatusCode());
            Assert.assertEquals("parent exception handled", HttpClientUtils.readResponse(result));

            get = new HttpGet(DefaultServer.getDefaultServerURL() + "/illegalArgumentException");
            result = client.execute(get);
            Assert.assertEquals(200, result.getStatusLine().getStatusCode());
            Assert.assertEquals("catch all throwables", HttpClientUtils.readResponse(result));

        } finally {
            client.getConnectionManager().shutdown();
        }
    }

    @Test
    public void testReThrowUnmatchedException() throws IOException {
        HttpHandler pathHandler = Handlers.path()
                .addExactPath("/", new HttpHandler() {
                    @Override
                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        throw new IllegalArgumentException();
                    }
                });

        // intentionally not adding any exception handlers
        HttpHandler exceptionHandler = Handlers.exceptionHandler(pathHandler);
        DefaultServer.setRootHandler(exceptionHandler);

        TestHttpClient client = new TestHttpClient();
        try {
            HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/");
            HttpResponse result = client.execute(get);
            Assert.assertEquals(500, result.getStatusLine().getStatusCode());
            HttpClientUtils.readResponse(result);
        } finally {
            client.getConnectionManager().shutdown();
        }
    }

    private static class ParentException extends Exception {}
    private static class ChildException extends ParentException {}
    private static class AnotherChildException extends ParentException {}

}

@@ -5435,32 +5435,38 @@
 andlers%0A        
+final 
 HttpHandler exce
@@ -5557,32 +5557,523 @@
 Handler(
-exceptionHandler
+new HttpHandler() %7B%0A            @Override%0A            public void handleRequest(HttpServerExchange exchange) throws Exception %7B%0A                Throwable throwable = exchange.getAttachment(ExceptionHandler.THROWABLE);%0A                Assert.assertNull(throwable);%0A                exceptionHandler.handleRequest(exchange);%0A                throwable = exchange.getAttachment(ExceptionHandler.THROWABLE);%0A                Assert.assertTrue(throwable instanceof IllegalArgumentException);%0A            %7D%0A        %7D
 );%0A%0A    

Test that the throwable attachment gets set on the ExceptionHandler