/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2012 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.lib.tenant.interceptors.tests;

import org.ow2.carol.jndi.intercept.InterceptionContext;
import org.ow2.jonas.lib.tenant.context.TenantContext;
import org.ow2.jonas.lib.tenant.context.TenantCurrent;
import org.ow2.jonas.lib.tenant.interceptor.jndi.JNDITenantIdInterceptor;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.testng.Assert;

import javax.naming.InitialContext;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Test JNDI calls interception
 * @author Mohammed Boukada
 */
public class JNDITenantIdInterceptorTest {

    JNDITenantIdInterceptor jndiTenantIdInterceptor = new JNDITenantIdInterceptor("/");

    TenantContext oldTenantContext;

    @BeforeMethod
    public void setUp() throws Exception {
        oldTenantContext = TenantCurrent.getCurrent().getTenantContext();
        TenantContext tenantContext = new TenantContext("T1");
        TenantCurrent.getCurrent().setTenantContext(tenantContext);
    }

    @AfterMethod
    public void unSetTenantContext () {
        TenantCurrent.getCurrent().setTenantContext(oldTenantContext);
    }

    @Test
    public void TestIntercept() throws Exception {
        List<Method> methodNames0 = new ArrayList<Method>();
        List<Method> methodNames1 = new ArrayList<Method>();
        List<Method> methodNames2 = new ArrayList<Method>();
        List<Method> methodBinds = new ArrayList<Method>();

        for (Method m : InitialContext.class.getMethods()) {
            String methodName = m.getName();
            if (methodName.equals("bind")
                    || methodName.equals("rebind")
                    || methodName.equals("list")
                    || methodName.equals("listBindings")
                    || methodName.equals("destroySubcontext")
                    || methodName.equals("createSubcontext")
                    || methodName.equals("getNameParser")
                    || methodName.equals("composeName")) {
                methodNames0.add(m);
                if (methodName.equals("bind") || methodName.equals("rebind")) {
                    methodBinds.add(m);    
                }
            } else if (methodName.equals("lookup") || methodName.equals("lookupLink") || methodName.equals("unbind")) {
                methodNames1.add(m);
            } else if (methodName.equals("rename")) {
                methodNames2.add(m);
            }
        }

        for (Method m : methodNames0) {
            String name = m.getName();
            String expectedName = "T1/" + name;
            Object[] parameters = new Object[]{name};
            Object[] expectedParameters = new Object[]{expectedName};

            InterceptionContext interceptionContext = mock(InterceptionContext.class);
            when(interceptionContext.getMethod()).thenReturn(m);
            when(interceptionContext.getParameters()).thenReturn(parameters);

            jndiTenantIdInterceptor.intercept(interceptionContext);

            verify(interceptionContext).setParameters(expectedParameters);
            verify(interceptionContext).proceed();
        }
        
        for (Method m : methodNames1) {
            String name = m.getName();
            String expectedName = name;
            Object[] parameters = new Object[]{name};
            Object[] expectedParameters = new Object[]{expectedName};

            InterceptionContext interceptionContext = mock(InterceptionContext.class);
            when(interceptionContext.getMethod()).thenReturn(m);
            when(interceptionContext.getParameters()).thenReturn(parameters);

            jndiTenantIdInterceptor.intercept(interceptionContext);

            Assert.assertEquals(parameters[0], expectedParameters[0], "Name should not be updated");
            verify(interceptionContext).proceed();
            
            for (Method m2 : methodBinds) {
                parameters[0] = m2.getName();
                expectedParameters[0] = "T1/" + m2.getName();

                InterceptionContext interceptionContext2 = mock(InterceptionContext.class);
                when(interceptionContext2.getMethod()).thenReturn(m);
                when(interceptionContext2.getParameters()).thenReturn(parameters);

                jndiTenantIdInterceptor.intercept(interceptionContext2);

                verify(interceptionContext2).setParameters(expectedParameters);
                verify(interceptionContext2).proceed();
            }
        }
        
        for (Method m : methodNames2) {
            String name1 = m.getName();
            String name2 = name1 + name1;
            Object[] parameters = new Object[]{name1, name2};
            Object[] expectedParameters = new Object[]{name1, name2};

            InterceptionContext interceptionContext = mock(InterceptionContext.class);
            when(interceptionContext.getMethod()).thenReturn(m);
            when(interceptionContext.getParameters()).thenReturn(parameters);

            jndiTenantIdInterceptor.intercept(interceptionContext);

            Assert.assertEquals(parameters[0], expectedParameters[0], "Name should not be updated");
            Assert.assertEquals(parameters[1], expectedParameters[1], "Name should not be updated");
            verify(interceptionContext).proceed();

            for (Method m2 : methodBinds) {
                parameters[0] = m2.getName();
                parameters[1] = m2.getName() + m2.getName();
                expectedParameters[0] = "T1/" + m2.getName();
                expectedParameters[1] = "T1/" + m2.getName() + m2.getName();

                InterceptionContext interceptionContext2 = mock(InterceptionContext.class);
                when(interceptionContext2.getMethod()).thenReturn(m);
                when(interceptionContext2.getParameters()).thenReturn(parameters);

                jndiTenantIdInterceptor.intercept(interceptionContext2);

                verify(interceptionContext2).setParameters(expectedParameters);
                verify(interceptionContext2).proceed();
            }
        }
    }
}
