/*
* 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.remoting.shutdown;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import junit.framework.TestCase;

import org.apache.log4j.Logger;

/** 
 * This unit test is meant to guard against the possibility of accidentally
 * creating non-daemon threads that prevent the Remoting subsystem from 
 * terminating.
 * 
 * See JIRA issue JBREM-674 "add test case for client exiting correctly".
 * (http://jira.jboss.com/jira/browse/JBREM-674)
 * 
 * @author <a href="ron.sigal@jboss.com">Ron Sigal</a>
 * @version $Revision: 2320 $
 * <p>
 * Copyright Jan 19, 2007
 * </p>
 */
public abstract class ShutdownTestParent extends TestCase
{
   private Logger log = Logger.getLogger(ShutdownTestParent.class);

   protected boolean serverSuccessful;
   protected boolean clientSuccessful;
   
   
   public void setUp()
   {
      serverSuccessful = false;
      clientSuccessful = false;
   }
   
   /**
    * This test case verifies that the test really works.  In particular,
    * a non-daemon thread is created in the client JVM that prevents it
    * from shutting down in the expected time frame.
    * 
    * @throws Throwable
    */
   public void testHangingClient() throws Throwable
   {
      log.info("entering testShutdown()");
      
      String command = "java -cp \"" +  System.getProperty("java.class.path") + "\" ";
      command += getJVMArguments() + " ";
      String serverCommand = command + ShutdownTestServer.class.getName() + " " + getTransport();
      serverCommand += " " + getServerArgs();
      String clientCommand = command + HangingClient.class.getName() + " " + getTransport();
      clientCommand += " " + getClientArgs();
      new Executor(serverCommand, true).start();
      Thread.sleep(1000);
      new Executor(clientCommand, false).start();
      Thread.sleep(8000);
      assertTrue(serverSuccessful);
      assertFalse(clientSuccessful);
      log.info(getName() + " PASSES");
   }
   
   
   /**
    * This unit verifies that a JVM with a client, and another JVM with a server,
    * both terminate.
    * 
    * @throws Throwable
    */
   public void testClosingClient() throws Throwable
   {
      log.info("entering testShutdown()");
      
      String command = "java -cp \"" +  System.getProperty("java.class.path") + "\" ";
      command += getJVMArguments() + " ";
      String serverCommand = command + ShutdownTestServer.class.getName() + " " + getTransport();
      serverCommand += " " + getServerArgs();
      String clientCommand = command + ClosingClient.class.getName() + " " + getTransport();
      clientCommand += " " + getClientArgs();
      new Executor(serverCommand, true).start();
      Thread.sleep(1000);
      new Executor(clientCommand, false).start();
      Thread.sleep(8000);
      assertTrue(serverSuccessful);
      assertTrue(clientSuccessful);
      log.info(getName() + " PASSES");
   }
   
   
   protected String getJVMArguments()
   {
      return "";
   }
   
   
   protected String getServerArgs()
   {
      return "";
   }
   
   
   protected String getClientArgs()
   {
      return "";
   }
   
   
   abstract protected String getTransport();
   
   
   class Executor
   {
      private String command;
      private boolean server;
      private boolean successful;
      
      public Executor(String command, boolean server)
      {
         this.server = server;
         this.command = command;
      }
      
      public boolean successful()
      {
         return successful;
      }
      
      public void start() throws Exception
      {
         executeCommand(command);
      }
      
      private void executeCommand(String command) throws Exception
      {
         final String finalCommand = command;
         
         new Thread()
         {
            public void run()
            {
               try
               {
                  log.info("executing: " + finalCommand);
                  final Process local = Runtime.getRuntime().exec(finalCommand);
                  
                  final BufferedReader errStream = new BufferedReader(new InputStreamReader(local.getErrorStream()));
                  final BufferedReader inStream = new BufferedReader(new InputStreamReader(local.getInputStream()));
                  new Thread()
                  {
                     public void run()
                     {
                        try
                        {
                           String errOut = null;
                           while((errOut = errStream.readLine()) != null)
                           {
                              System.err.println(errOut);
                           }
                        }
                        catch(IOException e)
                        {
                        }
                     }
                  }.start();
                  new Thread()
                  {
                     public void run()
                     {
                        try
                        {
                           String stdOut = null;
                           while((stdOut = inStream.readLine()) != null)
                           {
                              System.out.println(stdOut);
                           }
                        }
                        catch(IOException e)
                        {
                        }
                     }
                  }.start();
                  
                  local.waitFor();
                  String clientOrServer = server ? "server" : "client";
                  log.info(clientOrServer + " exit value: " + local.exitValue());
                  successful = (local.exitValue() == 0);
                  if (server)
                     serverSuccessful = successful;
                  else
                     clientSuccessful = successful;
               }
               catch(Exception e)
               {
                  log.error("Error starting process: " + finalCommand, e);
               }
            }
         }.start();
      }
   }
}