/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This 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 software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.test.web.test;

import java.net.HttpURLConnection;
import java.net.URL;
import javax.management.ObjectName;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.jboss.test.JBossTestCase;
import org.jboss.test.JBossTestSetup;
import org.jboss.test.util.web.HttpUtils;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.Header;

/** Tests of servlet container integration into the JBoss server. This test
 requires than a web container be integrated into the JBoss server. The tests
 currently do NOT use the java.net.HttpURLConnection and associated http client
 and  these do not return valid HTTP error codes so if a failure occurs it
 is best to connect the webserver using a browser to look for additional error
 info.

 The secure access tests require a user named 'jduke' with a password of 'theduke'
 with a role of 'AuthorizedUser' in the servlet container.
 
 @author Scott.Stark@jboss.org
 @version $Revision: 1.17.2.14 $
 */
public class WebIntegrationUnitTestCase extends JBossTestCase
{
   private static String REALM = "JBossTest Servlets";
   private String baseURL = HttpUtils.getBaseURL(); 
   private String baseURLNoAuth = HttpUtils.getBaseURLNoAuth(); 
   
   public WebIntegrationUnitTestCase(String name)
   {
      super(name);
   }
   
   /** Access the http://localhost/jbosstest/APIServlet to test the
    * getRealPath method
    */
   public void testRealPath() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/APIServlet?op=testGetRealPath");
      HttpUtils.accessURL(url);
   }

   /** Access the http://localhost/jbosstest/APIServlet to test the
    * HttpSessionListener events
    */
   public void testHttpSessionListener() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/APIServlet?op=testSessionListener");
      HttpUtils.accessURL(url);
   }

   /** Access the http://localhost/jbosstest/EJBOnStartupServlet
    */
   public void testEJBOnStartupServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/EJBOnStartupServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/ENCServlet
    */
   public void testENCServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/ENCServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/EJBServlet
    */
   public void testEJBServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/EJBServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/EntityServlet
    */
   public void testEntityServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/EntityServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/StatefulSessionServlet
    */
   public void testStatefulSessionServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/StatefulSessionServlet");
      HttpUtils.accessURL(url);
      // Need a mechanism to force passivation...
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/UserTransactionServlet
    */
   public void testUserTransactionServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/UserTransactionServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/SpeedServlet
    */
   public void testSpeedServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/SpeedServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/snoop.jsp
    */
   public void testSnoopJSP() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/snoop.jsp");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/snoop.jsp
    */
   public void testSnoopJSPByPattern() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/test-snoop.snp");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/test-jsp-mapping
    */
   public void testSnoopJSPByMapping() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/test-jsp-mapping");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/classpath.jsp
    */
   public void testJSPClasspath() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/classpath.jsp");
      HttpUtils.accessURL(url);
   }

   /** Access the http://localhost/jbosstest/ClientLoginServlet
    */
   public void testClientLoginServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/ClientLoginServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/restricted/UserInRoleServlet to
    * test isUserInRole.
    */
   public void testUserInRoleServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/restricted/UserInRoleServlet");
      HttpMethodBase request = HttpUtils.accessURL(url);
      Header errors = request.getResponseHeader("X-ExpectedUserRoles-Errors");
      log.info("X-ExpectedUserRoles-Errors: "+errors);
      assertTrue("X-ExpectedUserRoles-Errors("+errors+") is null", errors == null);
      errors = request.getResponseHeader("X-UnexpectedUserRoles-Errors");
      log.info("X-UnexpectedUserRoles-Errors: "+errors);
      assertTrue("X-UnexpectedUserRoles-Errors("+errors+") is null", errors == null);
   }
   /** Access the http://localhost/jbosstest/restricted/SecureServlet
    */
   public void testSecureServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/restricted/SecureServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/restricted/SubjectServlet
    */
   public void testSubjectServlet() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/restricted/SubjectServlet");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/restricted/SecureServlet
    */
   public void testSecureServletAndUnsecureAccess() throws Exception
   {
      getLog().info("+++ testSecureServletAndUnsecureAccess");
      URL url = new URL(baseURL+"jbosstest/restricted/SecureServlet");
      getLog().info("Accessing SecureServlet with valid login");
      HttpUtils.accessURL(url);
      String baseURL2 = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
      URL url2 = new URL(baseURL2+"jbosstest/restricted/UnsecureEJBServlet");
      getLog().info("Accessing SecureServlet with no login");
      HttpUtils.accessURL(url2, REALM, HttpURLConnection.HTTP_UNAUTHORIZED);
   }
   /** Access the http://localhost/jbosstest/restricted/SecureServlet
    */
   public void testSecureServletWithBadPass() throws Exception
   {
      String baseURL = "http://jduke:badpass@localhost:" + Integer.getInteger("web.port", 8080) + '/';
      URL url = new URL(baseURL+"jbosstest/restricted/SecureServlet");
      HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_UNAUTHORIZED);
   }
   /** Access the http://localhost/jbosstest/restricted/SecureServlet
    */
   public void testSecureServletWithNoLogin() throws Exception
   {
      String baseURL = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
      URL url = new URL(baseURL+"jbosstest/restricted/SecureServlet");
      HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_UNAUTHORIZED);
   }
   /** Access the http://localhost/jbosstest-not/unrestricted/SecureServlet
    */
   public void testNotJbosstest() throws Exception
   {
      String baseURL = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
      URL url = new URL(baseURL+"jbosstest-not/unrestricted/SecureServlet");
      HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);
   }
   /** Access the http://localhost/jbosstest/restricted/SecureEJBAccess
    */
   public void testSecureEJBAccess() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/restricted/SecureEJBAccess");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/restricted/include_ejb.jsp
    */
   public void testIncludeEJB() throws Exception
   {
      URL url = new URL(baseURL+"jbosstest/restricted/include_ejb.jsp");
      HttpUtils.accessURL(url);
   }
   /** Access the http://localhost/jbosstest/UnsecureEJBAccess with method=echo
    * to test that an unsecured servlet cannot access a secured EJB method
    * that requires a valid permission. This should fail.
    */
   public void testUnsecureEJBAccess() throws Exception
   {
      URL url = new URL(baseURLNoAuth+"jbosstest/UnsecureEJBAccess?method=echo");
      HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_INTERNAL_ERROR);
   }
   /** Access the http://localhost/jbosstest/UnsecureEJBAccess with method=unchecked
    * to test that an unsecured servlet can access a secured EJB method that
    * only requires an authenticated user. This requires unauthenticated
    * identity support by the web security domain.
    */
   public void testUnsecureAnonEJBAccess() throws Exception
   {
      URL url = new URL(baseURLNoAuth+"jbosstest/UnsecureEJBAccess?method=unchecked");
      HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);
   }

   public void testUnsecureRunAsServlet() throws Exception
   {
      URL url = new URL(baseURLNoAuth+"jbosstest/UnsecureRunAsServlet?method=checkRunAs");
      HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);      
   }

   /** Deploy a second ear that include a notjbosstest-web.war to test ears
    with the same war names conflicting.
    Access the http://localhost/jbosstest-not2/unrestricted/SecureServlet
    */
   public void testNotJbosstest2() throws Exception
   {
      try 
      {
         deploy("jbosstest-web2.ear");
         String baseURL = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
         URL url = new URL(baseURL+"jbosstest-not2/unrestricted/SecureServlet");
         HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);
      }
      finally
      {
         undeploy("jbosstest-web2.ear");
      } // end of try-finally
   }

   /** Deploy a bad war and then redploy with a fixed war to test failed war
    * cleanup.
    * Access the http://localhost/redeploy/index.html
    */
   public void testBadWarRedeploy() throws Exception
   {
      try
      {
         deploy("bad-web.war");
         fail("The bad-web.war deployment did not fail");
      }
      catch(Exception e)
      {
         getLog().debug("bad-web.war failed as expected", e);
      }
      finally
      {
         undeploy("bad-web.war");
      } // end of try-finally
      try 
      {
         deploy("good-web.war");
         String baseURL = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
         URL url = new URL(baseURL+"redeploy/index.html");
         HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);
      }
      finally
      {
         undeploy("good-web.war");
      } // end of try-finally
   }

   /** Test of a war that accesses classes referred to via the war manifest
    * classpath. Access the http://localhost/manifest/classpath.jsp
    */
   public void testWarManifest() throws Exception
   {
      deploy("manifest-web.ear");
      try
      {
         String baseURL = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
         URL url = new URL(baseURL+"manifest/classpath.jsp");
         HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);
      }
      finally
      {
         undeploy("jbosstest-good.ear");
      }
   }

   public void testBadEarRedeploy() throws Exception
   {
      try
      {
         deploy("jbosstest-bad.ear");
         fail("The jbosstest-bad.ear deployment did not fail");
      }
      catch(Exception e)
      {
         getLog().debug("jbosstest-bad.ear failed as expected", e);
      }
      finally
      {
         undeploy("jbosstest-bad.ear");
      } // end of finally
      try 
      {
         deploy("jbosstest-good.ear");
         String baseURL = "http://localhost:" + Integer.getInteger("web.port", 8080) + '/';
         URL url = new URL(baseURL+"redeploy/index.html");
         HttpUtils.accessURL(url, REALM, HttpURLConnection.HTTP_OK);
      }
      finally
      {
         undeploy("jbosstest-good.ear");
      } // end of try-finally
      
   }

   /**
    * Setup the test suite.
    */
   public static Test suite() throws Exception
   {
      TestSuite suite = new TestSuite();
      suite.addTest(new TestSuite(WebIntegrationUnitTestCase.class));

      // Create an initializer for the test suite
      Test wrapper = new JBossTestSetup(suite)
      {
         protected void setUp() throws Exception
         {
            super.setUp();
            deploy("jbosstest-web.ear");
            flushAuthCache("jbosstest-web");
         }
         protected void tearDown() throws Exception
         {
            undeploy("jbosstest-web.ear");
            super.tearDown();

            // Remove all the messages created during this test
            getServer().invoke
            (
               new ObjectName("jboss.mq.destination:service=Queue,name=testQueue"),
               "removeAllMessages",
               new Object[0],
               new String[0]
            );
         
         }
      };
      return wrapper;
   }

}
