org.sonar.api.utils.HttpDownloaderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.api.utils.HttpDownloaderTest.java

Source

/*
 * Sonar, open source software quality management tool.
 * Copyright (C) 2008-2011 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * Sonar 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 3 of the License, or (at your option) any later version.
 *
 * Sonar 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 Sonar; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.api.utils;

import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.mortbay.jetty.testing.ServletTester;
import org.sonar.api.platform.Server;

import java.io.File;
import java.io.IOException;
import java.net.*;
import java.util.Arrays;
import java.util.Properties;

import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.internal.matchers.StringContains.containsString;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@Ignore("Temporarily deactivated because it sometimes freezes on MS Windows")
public class HttpDownloaderTest {

    private static ServletTester tester;
    private static String baseUrl;

    @BeforeClass
    public static void startServer() throws Exception {
        tester = new ServletTester();
        tester.setContextPath("/");
        tester.addServlet(RedirectServlet.class, "/redirect/");
        tester.addServlet(FakeServlet.class, "/");
        baseUrl = tester.createSocketConnector(true);
        tester.start();
    }

    @AfterClass
    public static void stopServer() throws Exception {
        /* workaround for a jetty deadlock :
          1. stopping server logs a SLF4J/Logback message, but the message calls AbstractConnector.toString, which is synchronized on getLocalPort()
          2. a jetty thread tries also to stop and is locked on the same synchronized block.
            
          "3862294@qtp-17303670-1":
        at ch.qos.logback.core.AppenderBase.doAppend(AppenderBase.java:66)
        - waiting to lock <0x8be33f88> (a ch.qos.logback.core.ConsoleAppender)
        at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:60)
        at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:270)
        at ch.qos.logback.classic.Logger.callAppenders(Logger.java:257)
        at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:439)
        at ch.qos.logback.classic.Logger.filterAndLog_2(Logger.java:430)
        at ch.qos.logback.classic.Logger.debug(Logger.java:508)
        at org.mortbay.log.Slf4jLog.debug(Slf4jLog.java:40)
        at org.mortbay.log.Log.debug(Log.java:112)
        at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:77)
        - locked <0x8b8cf980> (a java.lang.Object)
        at org.mortbay.jetty.nio.SelectChannelConnector.close(SelectChannelConnector.java:136)
        - locked <0x8b8c0150> (a org.mortbay.jetty.nio.SelectChannelConnector)
        at org.mortbay.jetty.AbstractConnector$Acceptor.run(AbstractConnector.java:735)
        at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
        "main":
        at org.mortbay.jetty.nio.SelectChannelConnector.getLocalPort(SelectChannelConnector.java:188)
        - waiting to lock <0x8b8c0150> (a org.mortbay.jetty.nio.SelectChannelConnector)
        at org.mortbay.jetty.AbstractConnector.toString(AbstractConnector.java:669)
        at java.lang.String.valueOf(String.java:2826)
        at java.lang.StringBuffer.append(StringBuffer.java:219)
        - locked <0x8b7e8618> (a java.lang.StringBuffer)
        at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:237)
        at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:196)
        at ch.qos.logback.classic.spi.LoggingEvent.getFormattedMessage(LoggingEvent.java:282)
        at ch.qos.logback.classic.pattern.MessageConverter.convert(MessageConverter.java:22)
        at ch.qos.logback.classic.pattern.MessageConverter.convert(MessageConverter.java:19)
        at ch.qos.logback.core.pattern.FormattingConverter.write(FormattingConverter.java:32)
        at ch.qos.logback.core.pattern.PatternLayoutBase.writeLoopOnConverters(PatternLayoutBase.java:110)
        at ch.qos.logback.classic.PatternLayout.doLayout(PatternLayout.java:132)
        at ch.qos.logback.classic.PatternLayout.doLayout(PatternLayout.java:51)
        at ch.qos.logback.core.WriterAppender.subAppend(WriterAppender.java:261)
        at ch.qos.logback.core.WriterAppender.append(WriterAppender.java:114)
        at ch.qos.logback.core.AppenderBase.doAppend(AppenderBase.java:87)
        - locked <0x8be33f88> (a ch.qos.logback.core.ConsoleAppender)
        at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:60)
        at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:270)
        at ch.qos.logback.classic.Logger.callAppenders(Logger.java:257)
        at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:439)
        at ch.qos.logback.classic.Logger.filterAndLog_2(Logger.java:430)
        at ch.qos.logback.classic.Logger.info(Logger.java:605)
        at org.mortbay.log.Slf4jLog.info(Slf4jLog.java:67)
        at org.mortbay.log.Log.info(Log.java:154)
        at org.mortbay.jetty.AbstractConnector.doStop(AbstractConnector.java:313)
        at org.mortbay.jetty.nio.SelectChannelConnector.doStop(SelectChannelConnector.java:326)
        at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
        - locked <0x8b8ce798> (a java.lang.Object)
        at org.mortbay.jetty.Server.doStop(Server.java:280)
        at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
        - locked <0x8b8cf7b8> (a java.lang.Object)
        at org.mortbay.jetty.testing.ServletTester.stop(ServletTester.java:92)
        at org.sonar.api.utils.HttpDownloaderTest.stopServer(HttpDownloaderTest.java:62)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:120)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:103)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:169)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
            
            
            
        For this reason the ugly workaround is to wait the end of the thread before stopping...
            
        We'll have to check if Jetty 7 resolves this toString() issue.
        */
        Thread.sleep(1000);
        tester.stop();
    }

    @Test
    public void downloadBytes() throws URISyntaxException {
        byte[] bytes = new HttpDownloader().download(new URI(baseUrl));
        assertThat(bytes.length, greaterThan(10));
    }

    @Test(expected = SonarException.class)
    public void failIfServerDown() throws URISyntaxException {
        // I hope that the port 1 is not used !
        new HttpDownloader().download(new URI("http://localhost:1/unknown"));
    }

    @Test
    public void downloadToFile() throws URISyntaxException, IOException {
        File toDir = new File("target/test-tmp/org/sonar/api/utils/DownloaderTest/");
        FileUtils.forceMkdir(toDir);
        FileUtils.cleanDirectory(toDir);
        File toFile = new File(toDir, "downloadToFile.txt");

        new HttpDownloader().download(new URI(baseUrl), toFile);
        assertThat(toFile.exists(), is(true));
        assertThat(toFile.length(), greaterThan(10l));
    }

    @Test
    public void shouldNotCreateFileIfFailToDownload() throws Exception {
        File toDir = new File("target/test-tmp/org/sonar/api/utils/DownloaderTest/");
        FileUtils.forceMkdir(toDir);
        FileUtils.cleanDirectory(toDir);
        File toFile = new File(toDir, "downloadToFile.txt");

        try {
            // I hope that the port 1 is not used !
            new HttpDownloader().download(new URI("http://localhost:1/unknown"), toFile);
        } catch (SonarException e) {
            assertThat(toFile.exists(), is(false));
        }
    }

    @Test
    public void userAgentIsSonarVersion() throws URISyntaxException, IOException {
        Server server = mock(Server.class);
        when(server.getVersion()).thenReturn("2.2");

        byte[] bytes = new HttpDownloader(server, new PropertiesConfiguration()).download(new URI(baseUrl));
        Properties props = new Properties();
        props.load(IOUtils.toInputStream(new String(bytes)));
        assertThat(props.getProperty("agent"), is("Sonar 2.2"));
    }

    @Test
    public void followRedirect() throws URISyntaxException {
        byte[] bytes = new HttpDownloader().download(new URI(baseUrl + "/redirect/"));
        assertThat(new String(bytes), containsString("count"));
    }

    @Test
    public void shouldGetDirectProxySynthesis() throws URISyntaxException {
        ProxySelector proxySelector = mock(ProxySelector.class);
        when(proxySelector.select((URI) anyObject())).thenReturn(Arrays.asList(Proxy.NO_PROXY));
        assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector), is("no proxy"));
    }

    @Test
    public void shouldGetProxySynthesis() throws URISyntaxException {
        ProxySelector proxySelector = mock(ProxySelector.class);
        when(proxySelector.select((URI) anyObject())).thenReturn(Arrays.asList((Proxy) new FakeProxy()));
        assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector),
                is("proxy: http://proxy_url:4040"));
    }
}

class FakeProxy extends Proxy {
    public FakeProxy() {
        super(Type.HTTP, new InetSocketAddress("http://proxy_url", 4040));
    }
}