/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.httpd;
import fi.iki.elonen.NanoHTTPD;
import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.util.Arrays;
import java.util.Properties;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.process.DefaultProcessCommands;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX;
import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
public class CeHttpServerTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Rule
public ExpectedException expectedException = ExpectedException.none();
private static final RuntimeException FAILING_ACTION = new IllegalStateException("Simulating the action failed");
private CeHttpServer underTest;
private File sharedDir;
@Before
public void setUp() throws Exception {
this.sharedDir = temp.newFolder();
Properties properties = new Properties();
properties.setProperty(PROPERTY_PROCESS_INDEX, "1");
properties.setProperty(PROPERTY_SHARED_PATH, sharedDir.getAbsolutePath());
underTest = new CeHttpServer(properties, Arrays.asList(new PomPomAction(), new FailingAction()));
underTest.start();
}
@After
public void tearDown() {
underTest.stop();
}
@Test
public void start_publishes_URL_in_IPC() throws Exception {
try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(this.sharedDir, 1)) {
assertThat(commands.getHttpUrl()).startsWith("http://127.0.0.1:");
}
}
@Test
public void return_http_response_with_code_404_and_exception_message_as_body_when_url_has_no_matching_action() throws IOException {
String action = "/dfdsfdsfsdsd";
Response response = call(underTest.getUrl() + action);
assertThat(response.code()).isEqualTo(404);
assertThat(response.body().string()).isEqualTo("Error 404, '" + action + "' not found.");
}
@Test
public void action_is_matched_on_exact_URL() throws IOException {
Response response = call(underTest.getUrl() + "/pompom");
assertIsPomPomResponse(response);
}
@Test
public void action_is_matched_on_URL_ignoring_case() throws IOException {
Response response = call(underTest.getUrl() + "/pOMpoM");
assertIsPomPomResponse(response);
}
@Test
public void action_is_matched_on_URL_with_parameters() throws IOException {
Response response = call(underTest.getUrl() + "/pompom?toto=2");
assertIsPomPomResponse(response);
}
@Test
public void start_starts_http_server_and_publishes_URL_in_IPC() throws Exception {
Response response = call(underTest.getUrl() + "/pompom?toto=2");
assertIsPomPomResponse(response);
}
@Test
public void stop_stops_http_server() throws Exception {
underTest.stop();
expectedException.expect(ConnectException.class);
call(underTest.getUrl());
}
@Test
public void return_http_response_with_code_500_and_exception_message_as_body_when_action_throws_exception() throws IOException {
Response response = call(underTest.getUrl() + "/failing");
assertThat(response.code()).isEqualTo(500);
assertThat(response.body().string()).isEqualTo(FAILING_ACTION.getMessage());
}
private void assertIsPomPomResponse(Response response) throws IOException {
assertThat(response.code()).isEqualTo(200);
assertThat(IOUtils.toString(response.body().byteStream())).isEqualTo("ok");
}
private static Response call(String url) throws IOException {
Request request = new Request.Builder().get().url(url).build();
return new OkHttpClient().newCall(request).execute();
}
private static class PomPomAction implements HttpAction {
@Override
public void register(ActionRegistry registry) {
registry.register("pompom", this);
}
@Override
public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "ok");
}
}
private static class FailingAction implements HttpAction {
@Override
public void register(ActionRegistry registry) {
registry.register("failing", this);
}
@Override
public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
throw FAILING_ACTION;
}
}
}