/** * Copyright (c) 2008-2011 Sonatype, Inc. * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions. * * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General * Public License Version 3 as published by the Free Software Foundation. * * This program 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 Affero General Public License Version 3 * for more details. * * You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see * http://www.gnu.org/licenses. * * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation. * All other trademarks are the property of their respective owners. */ package org.sonatype.nexus.test.utils; import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import org.apache.log4j.Logger; import org.restlet.data.Response; import org.sonatype.nexus.integrationtests.AbstractNexusIntegrationTest; import org.sonatype.nexus.integrationtests.RequestFacade; import org.sonatype.nexus.rest.model.StatusResourceResponse; import org.sonatype.nexus.test.launcher.ThreadedPlexusAppBooterService; import org.testng.Assert; import com.thoughtworks.xstream.XStream; /** * Simple util class */ public class NexusStatusUtil { protected static Logger log = Logger.getLogger( NexusStatusUtil.class ); private ThreadedPlexusAppBooterService APP_BOOTER_SERVICE = null; public StatusResourceResponse getNexusStatus() throws NexusIllegalStateException { Response response; try { response = RequestFacade.doGetRequest( "service/local/status" ); } catch ( IOException e ) { throw new NexusIllegalStateException( "Unable to retrieve nexus status", e ); } if ( !response.getStatus().isSuccess() ) { throw new NexusIllegalStateException( "Error retrieving current status " + response.getStatus().toString() ); } XStream xstream = XStreamFactory.getXmlXStream(); String entityText; try { entityText = response.getEntity().getText(); } catch ( IOException e ) { throw new NexusIllegalStateException( "Unable to retrieve nexus status " + new XStream().toXML( response ), e ); } StatusResourceResponse status = (StatusResourceResponse) xstream.fromXML( entityText ); return status; } public void start( String testId ) throws Exception { int totalWaitCycles = 200 * 5; // 200 sec int retryStartCycles = 50 * 5; // 50 sec int pollingFreq = 200; // 200 ms log.info( "wait for Nexus start" ); for ( int i = 0; i < totalWaitCycles; i++ ) { if ( i % retryStartCycles == 0 ) { getAppBooterService( testId ).start(); } if ( isNexusRunning() ) { // nexus started return; } try { Thread.sleep( pollingFreq ); } catch ( InterruptedException e ) { // no problem } } try { getAppBooterService( testId ).shutdown(); } catch ( Throwable t ) { t.printStackTrace(); } throw new NexusIllegalStateException( "Unable to doHardStart(), nexus still stopped, took 200s" ); } public void stop() throws Exception { if ( APP_BOOTER_SERVICE == null ) { // app booter wasn't started, won't do it on stop return; } final ThreadedPlexusAppBooterService appBooterService = APP_BOOTER_SERVICE; try { try { appBooterService.stop(); } catch ( Exception e ) { System.err.println( "Failed to stop Nexus. The thread will most likely die with an error: " + e.getMessage() ); Assert.fail( e.getMessage() ); } finally { } if ( !waitForStop() ) { // just start over if we can't stop normally System.out.println( "Forcing Stop of appbooter" ); appBooterService.forceStop(); APP_BOOTER_SERVICE = null; } } finally { appBooterService.clean(); } } public boolean isNexusRunning() { Socket sock = null; try { sock = new Socket("localhost", AbstractNexusIntegrationTest.nexusApplicationPort); } catch ( UnknownHostException e1 ) { log.debug( "nexus application port isn't open." ); return false; } catch ( IOException e1 ) { log.debug( "nexus application port isn't open." ); return false; } finally { if ( sock != null ) { try { sock.close(); } catch ( IOException e ) { } } } try { getNexusStatus(); log.debug( "nexus is running." ); return true; } catch ( NexusIllegalStateException e ) { log.debug( "nexus application port is open, but not yet responding to requests." ); return false; } } public boolean isNexusStopped() throws NexusIllegalStateException { return !isNexusRunning(); } public boolean waitForStop() throws NexusIllegalStateException { log.info( "wait for Nexus stop" ); int totalWaitTime = 40 * 1000; // 20 sec int pollingFreq = 200; // 200 ms for ( int i = 0; i < totalWaitTime / pollingFreq; i++ ) { log.debug( "wait for Nexus stop, attempt: " + i ); if ( !isNexusRunning() ) { // nexus stopped! return true; } try { Thread.sleep( pollingFreq ); } catch ( InterruptedException e ) { // no problem } } // didn't stopped! return false; } private ThreadedPlexusAppBooterService getAppBooterService( String testId ) throws Exception { if ( APP_BOOTER_SERVICE == null ) { final File f = new File( "target/plexus-home" ); if ( !f.isDirectory() ) { f.mkdirs(); } File bundleRoot = new File( TestProperties.getAll().get( "nexus.base.dir" ) ); System.setProperty( "basedir", bundleRoot.getAbsolutePath() ); // System.setProperty( "plexus.appbooter.customizers", "org.sonatype.nexus.NexusBooterCustomizer," // + ITAppBooterCustomizer.class.getName() ); File classworldsConf = new File( bundleRoot, "conf/classworlds.conf" ); if ( !classworldsConf.isFile() ) { throw new IllegalStateException( "The bundle classworlds.conf file is not found (\"" + classworldsConf.getAbsolutePath() + "\")!" ); } System.setProperty( "classworlds.conf", classworldsConf.getAbsolutePath() ); // this is non trivial here, since we are running Nexus in _same_ JVM as tests // and the PlexusAppBooterJSWListener (actually theused WrapperManager in it) enforces then Nexus may be // started only once in same JVM! // So, we are _overrriding_ the in-bundle plexus app booter with the simplest one // since we dont need all the bells-and-whistles in Service and JSW // but we are still _reusing_ the whole bundle environment by tricking Classworlds Launcher ServerSocket socket = new ServerSocket( 0 ); int controlPort = socket.getLocalPort(); socket.close(); APP_BOOTER_SERVICE = new ThreadedPlexusAppBooterService( classworldsConf, controlPort, testId ); } return APP_BOOTER_SERVICE; } }