/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2011 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.ow2.jonas.audit.internal.webauditor.filters;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;

import javax.management.MBeanServer;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.ow2.util.auditreport.api.IAuditID;
import org.ow2.util.auditreport.api.ICurrentInvocationID;
import org.ow2.util.auditreport.impl.AuditIDImpl;
import org.ow2.util.auditreport.impl.CurrentInvocationID;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * A {@code HttpAuditFilterTestCase} is ...
 *
 * @author Guillaume Sauthier
 */
public class HttpAuditFilterTestCase {

    private ICurrentInvocationID current;

    @BeforeTest
    public void setUp() throws Exception {
        current = CurrentInvocationID.getInstance();
    }

    @BeforeMethod
    public void eraseAuditIdInThreadLocal() throws Exception {
        // Erase any audit ID in place
        current.setAuditID(null);
    }

    @Test
    public void testNewInvocationIdIsCreated() throws Exception {
        MBeanServer mbeanServer = mock(MBeanServer.class);
        HttpServletRequest request = mock(HttpServletRequest.class);
        HttpServletResponse response = mock(HttpServletResponse.class);

        StringBuffer sb = new StringBuffer("a/static/resource.html");

        when(request.getRequestURI()).thenReturn(sb.toString());
        when(request.getRequestURL()).thenReturn(sb);
        when(request.getParameterMap()).thenReturn(new HashMap());
        when(request.getParameterNames()).thenReturn(Collections.enumeration(Collections.<Object>emptyList()));

        HttpAuditFilter filter = new HttpAuditFilter(mbeanServer);

        filter.doFilter(request, response, new FilterChain() {
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
                IAuditID audit = current.getAuditID();
                assertThat(audit, notNullValue());
            }
        });

        // after, check that it has been cleared
        assertThat(current.getAuditID(), nullValue());
    }

    @Test
    public void testNewInvocationIdIsCreatedEvenIfOneIsAlreadyInstalled() throws Exception {
        MBeanServer mbeanServer = mock(MBeanServer.class);
        HttpServletRequest request = mock(HttpServletRequest.class);
        HttpServletResponse response = mock(HttpServletResponse.class);

        StringBuffer sb = new StringBuffer("a/static/resource.html");

        when(request.getRequestURI()).thenReturn(sb.toString());
        when(request.getRequestURL()).thenReturn(sb);
        when(request.getParameterMap()).thenReturn(new HashMap());
        when(request.getParameterNames()).thenReturn(Collections.enumeration(Collections.<Object>emptyList()));

        HttpAuditFilter filter = new HttpAuditFilter(mbeanServer);

        // Install an ID the the ThreadLocal
        final IAuditID existing = new AuditIDImpl();
        existing.generate();
        current.setAuditID(existing);

        // Filter the request
        filter.doFilter(request, response, new FilterChain() {
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
                IAuditID audit = current.getAuditID();
                assertThat(audit, notNullValue());
                assertThat(audit, is( not( equalTo(existing) ) ));
            }
        });

        // after, check that it has been cleared
        assertThat( current.getAuditID(), nullValue() );

    }

    @Test
    public void testInvocationIdIsReadFromHeaders() throws Exception {
        MBeanServer mbeanServer = mock(MBeanServer.class);
        HttpServletRequest request = mock(HttpServletRequest.class);
        HttpServletResponse response = mock(HttpServletResponse.class);

        StringBuffer sb = new StringBuffer("a/static/resource.html");

        when(request.getRequestURI()).thenReturn(sb.toString());
        when(request.getRequestURL()).thenReturn(sb);
        when(request.getParameterMap()).thenReturn(new HashMap());
        when(request.getParameterNames()).thenReturn(Collections.enumeration(Collections.<Object>emptyList()));
        when(request.getHeader(HttpAuditFilter.HEADER_INVOCATION_ID)).thenReturn("parent/n:local/0");

        HttpAuditFilter filter = new HttpAuditFilter(mbeanServer);

        filter.doFilter(request, response, new FilterChain() {
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
                IAuditID audit = current.getAuditID();
                assertThat(audit, notNullValue());

                // Check that parent ID is the one transferred on the wire
                assertThat(audit.getParentID(), is( equalTo("parent/n") ));
            }
        });

        // after, check that it has been cleared
        assertThat(current.getAuditID(), nullValue());
    }

}
