<commit_before>package brooklyn.entity.webapp

import static brooklyn.test.TestUtils.*
import static java.util.concurrent.TimeUnit.*
import static org.testng.Assert.*

import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.TimeUnit

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.testng.annotations.AfterMethod
import org.testng.annotations.BeforeMethod
import org.testng.annotations.DataProvider
import org.testng.annotations.Test

import brooklyn.entity.basic.JavaApp
import brooklyn.entity.webapp.jboss.JBoss6Server
import brooklyn.entity.webapp.jboss.JBoss7Server
import brooklyn.entity.webapp.tomcat.Tomcat7SshSetup
import brooklyn.entity.webapp.tomcat.TomcatServer
import brooklyn.event.SensorEvent
import brooklyn.event.SensorEventListener
import brooklyn.location.basic.LocalhostMachineProvisioningLocation
import brooklyn.management.SubscriptionContext
import brooklyn.management.SubscriptionHandle
import brooklyn.test.entity.TestApplication
import brooklyn.util.internal.Repeater
import brooklyn.util.internal.TimeExtras

/**
 * Tests that implementations of JavaWebApp can start up and shutdown, 
 * post request and error count metrics and deploy wars, etc.
 * 
 * Currently tests TomcatServer, JBoss6Server and JBoss7Server.
 */
class WebAppIntegrationTest {

    private static final Logger logger = LoggerFactory.getLogger(WebAppIntegrationTest.class)
    
    static { TimeExtras.init() }
    
    // Don't use 8080 since that is commonly used by testing software
    static int DEFAULT_HTTP_PORT = 7880
    
    // Port increment for JBoss 6.
    final static int PORT_INCREMENT = 400
    
    @BeforeMethod(groups=["Integration"])
    public void failIfHttpPortInUse() {
        if (isPortInUse(DEFAULT_HTTP_PORT, 5000L)) {
            fail "someone is already listening on port $DEFAULT_HTTP_PORT; tests assume that port $DEFAULT_HTTP_PORT is free on localhost"
        }
    }
    
    @AfterMethod(groups=["Integration"])
    public void ensureTomcatIsShutDown() {
        Socket shutdownSocket = null;
        SocketException gotException = null;

        boolean socketClosed = new Repeater("Checking Tomcat has shut down")
            .repeat({
                if (shutdownSocket) shutdownSocket.close();
                try { shutdownSocket = new Socket(InetAddress.localHost, Tomcat7SshSetup.DEFAULT_FIRST_SHUTDOWN_PORT); }
                catch (SocketException e) { gotException = e; return; }
                gotException = null
            })
            .every(100, TimeUnit.MILLISECONDS)
            .until({ gotException })
            .limitIterationsTo(25)
            .run();

        if (socketClosed == false) {
            logger.error "Tomcat did not shut down - this is a failure of the last test run";
            logger.warn "I'm sending a message to the Tomcat shutdown port";
            OutputStreamWriter writer = new OutputStreamWriter(shutdownSocket.getOutputStream());
            writer.write("SHUTDOWN\r\n");
            writer.flush();
            writer.close();
            shutdownSocket.close();
            throw new Exception("Last test run did not shut down Tomcat")
        }
    }
    
    /**
     * Provides instances of TomcatServer and JBoss{6,7}Server to the tests below.
     */
    @DataProvider(name="basicEntities")
    public Object[][] basicEntities() {
        TomcatServer tomcat = [owner: new TestApplication(), httpPort: DEFAULT_HTTP_PORT]
        JBoss6Server jboss6 = [owner: new TestApplication(), portIncrement: PORT_INCREMENT]
        JBoss7Server jboss7 = [owner: new TestApplication(), httpPort: DEFAULT_HTTP_PORT]
        return [[tomcat], [jboss6], [jboss7]]
    }

    /**
     * Checks an entity can start, set SERVICE_UP to true and shutdown again.
     */
    @Test(groups=["Integration"], dataProvider="basicEntities")
    public void canStartAndStop(JavaWebApp entity) {
        entity.start([ new LocalhostMachineProvisioningLocation(name:'london') ])
        executeUntilSucceedsWithFinallyBlock ([:], {
            assertTrue entity.getAttribute(JavaApp.SERVICE_UP)
        }, {
            entity.stop()
            assertFalse entity.getAttribute(JavaApp.SERVICE_UP)
        })
    }
    
    /**
     * Checks that an entity correctly sets request and error count metrics by
     * connecting to a non-existent URL several times.
     */
    @Test(groups=["Integration"], dataProvider="basicEntities")
    public void publishesRequestAndErrorCountMetrics(JavaWebApp entity) {
        entity.start([ new LocalhostMachineProvisioningLocation(name:'london') ])
        String url = entity.getAttribute(JavaWebApp.ROOT_URL) + "does_not_exist"
        
        executeUntilSucceeds(timeout: 10*SECONDS, {
            assertTrue entity.getAttribute(JavaApp.SERVICE_UP)
        })
        
        10.times {
            def connection = connectToURL(url)
            int status = ((HttpURLConnection) connection).getResponseCode()
            log.info "connection to {} gives {}", url, status
        }
        
        executeUntilSucceedsWithShutdown(entity, {
            def requestCount = entity.getAttribute(JavaWebApp.REQUEST_COUNT)
            def errorCount = entity.getAttribute(JavaWebApp.ERROR_COUNT)
            logger.info "req=$requestCount, err=$errorCount"
            
            if (errorCount == null) {
                return new BooleanWithMessage(false, "errorCount not set yet ($errorCount)")
            } else {
                logger.info "$errorCount errors in total"
                assertTrue errorCount > 0
                assertEquals requestCount, errorCount
            }
            true
        }, useGroovyTruth:true, timeout:60*SECONDS)
    }
    
    /**
     * Checks an entity publishes correct requests/second figures and that these figures
     * fall to zero after a period of no activity.
     */
    @Test(groups=["Integration"], dataProvider="basicEntities")
    public void publishesRequestsPerSecondMetric(JavaWebApp entity) {
        entity.start([ new LocalhostMachineProvisioningLocation(name:'london') ])<commit_msg>Relax assertions for WebAppIntegrationTest.publishesRequestAndErrorCountMetrics.  Test passes locally at least.<commit_after>package brooklyn.entity.webapp

import static brooklyn.test.TestUtils.*
import static java.util.concurrent.TimeUnit.*
import static org.testng.Assert.*

import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.TimeUnit

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.testng.annotations.AfterMethod
import org.testng.annotations.BeforeMethod
import org.testng.annotations.DataProvider
import org.testng.annotations.Test

import brooklyn.entity.basic.JavaApp
import brooklyn.entity.webapp.jboss.JBoss6Server
import brooklyn.entity.webapp.jboss.JBoss7Server
import brooklyn.entity.webapp.tomcat.Tomcat7SshSetup
import brooklyn.entity.webapp.tomcat.TomcatServer
import brooklyn.event.SensorEvent
import brooklyn.event.SensorEventListener
import brooklyn.location.basic.LocalhostMachineProvisioningLocation
import brooklyn.management.SubscriptionContext
import brooklyn.management.SubscriptionHandle
import brooklyn.test.entity.TestApplication
import brooklyn.util.internal.Repeater
import brooklyn.util.internal.TimeExtras

/**
 * Tests that implementations of JavaWebApp can start up and shutdown, 
 * post request and error count metrics and deploy wars, etc.
 * 
 * Currently tests TomcatServer, JBoss6Server and JBoss7Server.
 */
class WebAppIntegrationTest {

    private static final Logger logger = LoggerFactory.getLogger(WebAppIntegrationTest.class)
    
    static { TimeExtras.init() }
    
    // Don't use 8080 since that is commonly used by testing software
    static int DEFAULT_HTTP_PORT = 7880
    
    // Port increment for JBoss 6.
    final static int PORT_INCREMENT = 400
    
    @BeforeMethod(groups=["Integration"])
    public void failIfHttpPortInUse() {
        if (isPortInUse(DEFAULT_HTTP_PORT, 5000L)) {
            fail "someone is already listening on port $DEFAULT_HTTP_PORT; tests assume that port $DEFAULT_HTTP_PORT is free on localhost"
        }
    }
    
    @AfterMethod(groups=["Integration"])
    public void ensureTomcatIsShutDown() {
        Socket shutdownSocket = null;
        SocketException gotException = null;

        boolean socketClosed = new Repeater("Checking Tomcat has shut down")
            .repeat({
                if (shutdownSocket) shutdownSocket.close();
                try { shutdownSocket = new Socket(InetAddress.localHost, Tomcat7SshSetup.DEFAULT_FIRST_SHUTDOWN_PORT); }
                catch (SocketException e) { gotException = e; return; }
                gotException = null
            })
            .every(100, TimeUnit.MILLISECONDS)
            .until({ gotException })
            .limitIterationsTo(25)
            .run();

        if (socketClosed == false) {
            logger.error "Tomcat did not shut down - this is a failure of the last test run";
            logger.warn "I'm sending a message to the Tomcat shutdown port";
            OutputStreamWriter writer = new OutputStreamWriter(shutdownSocket.getOutputStream());
            writer.write("SHUTDOWN\r\n");
            writer.flush();
            writer.close();
            shutdownSocket.close();
            throw new Exception("Last test run did not shut down Tomcat")
        }
    }
    
    /**
     * Provides instances of TomcatServer and JBoss{6,7}Server to the tests below.
     */
    @DataProvider(name="basicEntities")
    public Object[][] basicEntities() {
        TomcatServer tomcat = [owner: new TestApplication(), httpPort: DEFAULT_HTTP_PORT]
        JBoss6Server jboss6 = [owner: new TestApplication(), portIncrement: PORT_INCREMENT]
        JBoss7Server jboss7 = [owner: new TestApplication(), httpPort: DEFAULT_HTTP_PORT]
        return [[tomcat], [jboss6], [jboss7]]
    }

    /**
     * Checks an entity can start, set SERVICE_UP to true and shutdown again.
     */
    @Test(groups=["Integration"], dataProvider="basicEntities")
    public void canStartAndStop(JavaWebApp entity) {
        entity.start([ new LocalhostMachineProvisioningLocation(name:'london') ])
        executeUntilSucceedsWithFinallyBlock ([:], {
            assertTrue entity.getAttribute(JavaApp.SERVICE_UP)
        }, {
            entity.stop()
            assertFalse entity.getAttribute(JavaApp.SERVICE_UP)
        })
    }
    
    /**
     * Checks that an entity correctly sets request and error count metrics by
     * connecting to a non-existent URL several times.
     */
    @Test(groups=["Integration"], dataProvider="basicEntities")
    public void publishesRequestAndErrorCountMetrics(JavaWebApp entity) {
        entity.start([ new LocalhostMachineProvisioningLocation(name:'london') ])
        String url = entity.getAttribute(JavaWebApp.ROOT_URL) + "does_not_exist"
        
        executeUntilSucceeds(timeout: 10*SECONDS, {
            assertTrue entity.getAttribute(JavaApp.SERVICE_UP)
        })
        
        final int num_reqs = 10
        num_reqs.times {
            def connection = connectToURL(url)
            int status = ((HttpURLConnection) connection).getResponseCode()
            log.info "connection to {} gives {}", url, status
        }
        
        executeUntilSucceedsWithShutdown(entity, {
            def requestCount = entity.getAttribute(JavaWebApp.REQUEST_COUNT)
            def errorCount = entity.getAttribute(JavaWebApp.ERROR_COUNT)
            logger.info "req=$requestCount, err=$errorCount"
            
            if (errorCount == null) {
                return new BooleanWithMessage(false, "errorCount not set yet ($errorCount)")
            } else {
                assertEquals errorCount, num_reqs
                // AS 7 seems to take a very long time to report error counts,
                // hence not using ==.  >= in case error pages include a favicon, etc.
                assertTrue requestCount >= errorCount
            }
            true
        }, useGroovyTruth:true, timeout:20*SECONDS)
    }
    
    /**
     * Checks an entity publishes correct requests/second figures and that these figures
     * fall to zero after a period of no activity.
     */
    @Test(groups=["Integration"], dataProvider="basicEntities")
    public void publishesRequestsPerSecondMetric(JavaWebApp entity) {
        entity.start([ new LocalhostMachineProvisioningLocation(name:'london') ])
{'fraction_non_alphanumeric': 0.08515248796147673, 'fraction_numerical': 0.007062600321027288, 'mean_word_length': 2.917321596982081, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '259853', 'n_tokens_mistral': 3452, 'n_tokens_neox': 3359, 'n_words': 843}