]> source.dussan.org Git - sonarqube.git/commitdiff
use testFixtures instead of test configuration of webserver-ws
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Wed, 28 Aug 2019 14:52:53 +0000 (16:52 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 2 Sep 2019 18:21:04 +0000 (20:21 +0200)
12 files changed:
build.gradle
server/sonar-webserver-core/build.gradle
server/sonar-webserver-webapi/build.gradle
server/sonar-webserver-ws/build.gradle
server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/DumbResponse.java [deleted file]
server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/TestRequest.java [deleted file]
server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/TestResponse.java [deleted file]
server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsActionTester.java [deleted file]
server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java [new file with mode: 0644]
server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java [new file with mode: 0644]
server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java [new file with mode: 0644]
server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java [new file with mode: 0644]

index a967d1a626702ab3bc9d62fba63172eb59503064..1cb2102ad0f442a53c6d298ec96d8c4feed77289 100644 (file)
@@ -95,6 +95,7 @@ subprojects {
   apply plugin: 'io.spring.dependency-management'
   apply plugin: 'jacoco'
   apply plugin: 'java'
+  apply plugin: 'java-test-fixtures'
   apply plugin: 'idea'
   apply plugin: 'org.owasp.dependencycheck'
 
index 9e1d57fa1d78d3b4fb64c6d005643eb50e4716cd..ea21d81838d7b87cf97454075490ecf5690a0149 100644 (file)
@@ -75,7 +75,7 @@ dependencies {
   testCompile project(path: ":server:sonar-server-common", configuration: "tests")
   testCompile project(path: ":server:sonar-webserver-auth", configuration: "tests")
   testCompile project(path: ":server:sonar-webserver-es", configuration: "tests")
-  testCompile project(path: ":server:sonar-webserver-ws", configuration: "tests")
+  testCompile testFixtures(project(':server:sonar-webserver-ws'))
   testCompile project(':sonar-testing-harness')
 
   runtime 'io.jsonwebtoken:jjwt-jackson'
index b1428c97c94c0e3dcd196120e5184bf00622299e..58b5f8e7064ac4112508f52f59ca0f556e127ea4 100644 (file)
@@ -37,7 +37,7 @@ dependencies {
   testCompile project(path: ":server:sonar-server-common", configuration: "tests")
   testCompile project(path: ":server:sonar-webserver-auth", configuration: "tests")
   testCompile project(path: ":server:sonar-webserver-es", configuration: "tests")
-  testCompile project(path: ":server:sonar-webserver-ws", configuration: "tests")
+  testCompile testFixtures(project(':server:sonar-webserver-ws'))
   testCompile project(':sonar-testing-harness')
 }
 
index 7fa56ae5c0b718ec4f62366884aef2ba4d8eb31c..33d0249b7f1eef1440733d23e6d59ff1104b5332 100644 (file)
@@ -6,12 +6,6 @@ sonarqube {
   }
 }
 
-configurations {
-  tests
-
-  testCompile.extendsFrom tests
-}
-
 dependencies {
   // please keep the list grouped by configuration and ordered by name
 
@@ -30,14 +24,8 @@ dependencies {
   testCompile 'javax.servlet:javax.servlet-api'
   testCompile 'org.apache.tomcat.embed:tomcat-embed-core'
   testCompile 'org.mockito:mockito-core'
-  testCompile project(':sonar-testing-harness')
-}
 
-task testJar(type: Jar) {
-  classifier = 'tests'
-  from sourceSets.test.output
-}
+  testFixturesApi project(':sonar-testing-harness')
 
-artifacts {
-  tests testJar
+  testFixturesCompileOnly 'com.google.code.findbugs:jsr305'
 }
diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/DumbResponse.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/DumbResponse.java
deleted file mode 100644 (file)
index f7d2aee..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.server.ws;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.Maps;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.net.HttpURLConnection;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.utils.text.XmlWriter;
-
-public class DumbResponse implements Response {
-  private InMemoryStream stream;
-
-  private final ByteArrayOutputStream output = new ByteArrayOutputStream();
-
-  private Map<String, String> headers = Maps.newHashMap();
-
-  public class InMemoryStream implements Response.Stream {
-    private String mediaType;
-
-    private int status = 200;
-
-    @CheckForNull
-    public String mediaType() {
-      return mediaType;
-    }
-
-    public int status() {
-      return status;
-    }
-
-    @Override
-    public Response.Stream setMediaType(String s) {
-      this.mediaType = s;
-      return this;
-    }
-
-    @Override
-    public Response.Stream setStatus(int i) {
-      this.status = i;
-      return this;
-    }
-
-    @Override
-    public OutputStream output() {
-      return output;
-    }
-
-    public String outputAsString() {
-      return new String(output.toByteArray(), StandardCharsets.UTF_8);
-    }
-  }
-
-  @Override
-  public JsonWriter newJsonWriter() {
-    return JsonWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8));
-  }
-
-  @Override
-  public XmlWriter newXmlWriter() {
-    return XmlWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8));
-  }
-
-  @Override
-  public InMemoryStream stream() {
-    if (stream == null) {
-      stream = new InMemoryStream();
-    }
-    return stream;
-  }
-
-  @Override
-  public Response noContent() {
-    stream().setStatus(HttpURLConnection.HTTP_NO_CONTENT);
-    IOUtils.closeQuietly(output);
-    return this;
-  }
-
-  public String outputAsString() {
-    return new String(output.toByteArray(), StandardCharsets.UTF_8);
-  }
-
-  @Override
-  public Response setHeader(String name, String value) {
-    headers.put(name, value);
-    return this;
-  }
-
-  public Collection<String> getHeaderNames() {
-    return headers.keySet();
-  }
-
-  @CheckForNull
-  public String getHeader(String name){
-    return headers.get(name);
-  }
-
-  public byte[] getFlushedOutput() {
-    try {
-      output.flush();
-      return output.toByteArray();
-    } catch (IOException e) {
-      throw Throwables.propagate(e);
-    }
-  }
-}
diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/TestRequest.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/TestRequest.java
deleted file mode 100644 (file)
index aea0e0d..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.server.ws;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Maps;
-import com.google.protobuf.GeneratedMessageV3;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.impl.ws.PartImpl;
-import org.sonar.api.impl.ws.ValidatingRequest;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-import static org.sonarqube.ws.MediaTypes.PROTOBUF;
-
-public class TestRequest extends ValidatingRequest {
-
-  private final ListMultimap<String, String> multiParams = ArrayListMultimap.create();
-  private final Map<String, String> params = new HashMap<>();
-  private final Map<String, String> headers = new HashMap<>();
-  private final Map<String, Part> parts = Maps.newHashMap();
-  private String payload = "";
-  private boolean payloadConsumed = false;
-  private String method = "GET";
-  private String mimeType = "application/octet-stream";
-  private String path;
-
-  @Override
-  public BufferedReader getReader() {
-    checkState(!payloadConsumed, "Payload already consumed");
-    if (payload == null) {
-      return super.getReader();
-    }
-
-    BufferedReader res = new BufferedReader(new StringReader(payload));
-    payloadConsumed = true;
-    return res;
-  }
-
-  public TestRequest setPayload(String payload) {
-    checkState(!payloadConsumed, "Payload already consumed");
-
-    this.payload = payload;
-    return this;
-  }
-
-  @Override
-  protected String readParam(String key) {
-    return params.get(key);
-  }
-
-  @Override
-  protected List<String> readMultiParam(String key) {
-    return multiParams.get(key);
-  }
-
-  @Override
-  protected InputStream readInputStreamParam(String key) {
-    String value = readParam(key);
-    if (value == null) {
-      return null;
-    }
-    return IOUtils.toInputStream(value);
-  }
-
-  @Override
-  protected Part readPart(String key) {
-    return parts.get(key);
-  }
-
-  public TestRequest setPart(String key, InputStream input, String fileName) {
-    parts.put(key, new PartImpl(input, fileName));
-    return this;
-  }
-
-  @Override
-  public String method() {
-    return method;
-  }
-
-  @Override
-  public boolean hasParam(String key) {
-    return params.containsKey(key) || multiParams.containsKey(key);
-  }
-
-  @Override
-  public String getPath() {
-    return path;
-  }
-
-  @Override
-  public Map<String, String[]> getParams() {
-    ArrayListMultimap<String, String> result = ArrayListMultimap.create(multiParams);
-    params.forEach(result::put);
-    return result.asMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toArray(new String[0])));
-  }
-
-  public TestRequest setPath(String path) {
-    this.path = path;
-    return this;
-  }
-
-  public TestRequest setMethod(String method) {
-    checkNotNull(method);
-    this.method = method;
-    return this;
-  }
-
-  @Override
-  public String getMediaType() {
-    return mimeType;
-  }
-
-  public TestRequest setMediaType(String type) {
-    checkNotNull(type);
-    this.mimeType = type;
-    return this;
-  }
-
-  public TestRequest setParam(String key, String value) {
-    checkNotNull(key);
-    checkNotNull(value);
-    this.params.put(key, value);
-    return this;
-  }
-
-  public TestRequest setMultiParam(String key, List<String> values) {
-    requireNonNull(key);
-    requireNonNull(values);
-
-    multiParams.putAll(key, values);
-
-    return this;
-  }
-
-  @Override
-  public Map<String, String> getHeaders() {
-    return ImmutableMap.copyOf(headers);
-  }
-
-  @Override
-  public Optional<String> header(String name) {
-    return Optional.ofNullable(headers.get(name));
-  }
-
-  public TestRequest setHeader(String name, String value) {
-    headers.put(requireNonNull(name), requireNonNull(value));
-    return this;
-  }
-
-  public TestResponse execute() {
-    try {
-      DumbResponse response = new DumbResponse();
-      action().handler().handle(this, response);
-      return new TestResponse(response);
-    } catch (Exception e) {
-      throw Throwables.propagate(e);
-    }
-  }
-
-  public <T extends GeneratedMessageV3> T executeProtobuf(Class<T> protobufClass) {
-    return setMediaType(PROTOBUF).execute().getInputObject(protobufClass);
-  }
-
-  @Override
-  public String toString() {
-    return path;
-  }
-}
diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/TestResponse.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/TestResponse.java
deleted file mode 100644 (file)
index 352d0bb..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.server.ws;
-
-import com.google.protobuf.GeneratedMessageV3;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.lang.reflect.Method;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import javax.annotation.CheckForNull;
-import org.sonar.test.JsonAssert;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class TestResponse {
-
-  private final DumbResponse dumbResponse;
-
-  public TestResponse(DumbResponse dumbResponse) {
-    this.dumbResponse = dumbResponse;
-  }
-
-  public InputStream getInputStream() {
-    return new ByteArrayInputStream(dumbResponse.getFlushedOutput());
-  }
-
-  public <T extends GeneratedMessageV3> T getInputObject(Class<T> protobufClass) {
-    try (InputStream input = getInputStream()) {
-      Method parseFromMethod = protobufClass.getMethod("parseFrom", InputStream.class);
-      @SuppressWarnings("unchecked")
-      T result = (T) parseFromMethod.invoke(null, input);
-      return result;
-    } catch (Exception e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  public String getInput() {
-    return new String(dumbResponse.getFlushedOutput(), StandardCharsets.UTF_8);
-  }
-
-  public String getMediaType() {
-    return dumbResponse.stream().mediaType();
-  }
-
-  public int getStatus() {
-    return dumbResponse.stream().status();
-  }
-
-  @CheckForNull
-  public String getHeader(String headerKey) {
-    return dumbResponse.getHeader(headerKey);
-  }
-
-  public void assertJson(String expectedJson) {
-    JsonAssert.assertJson(getInput()).isSimilarTo(expectedJson);
-  }
-
-  /**
-   * Compares JSON response with JSON file available in classpath. For example if class
-   * is org.foo.BarTest and filename is index.json, then file must be located
-   * at src/test/resources/org/foo/BarTest/index.json.
-   *
-   * @param clazz                the test class
-   * @param expectedJsonFilename name of the file containing the expected JSON
-   */
-  public void assertJson(Class clazz, String expectedJsonFilename) {
-    String path = clazz.getSimpleName() + "/" + expectedJsonFilename;
-    URL url = clazz.getResource(path);
-    if (url == null) {
-      throw new IllegalStateException("Cannot find " + path);
-    }
-    JsonAssert.assertJson(getInput()).isSimilarTo(url);
-  }
-
-  public void assertNoContent() {
-    assertThat(getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT);
-  }
-}
diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsActionTester.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsActionTester.java
deleted file mode 100644 (file)
index fede932..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.server.ws;
-
-import com.google.common.collect.Iterables;
-import org.sonar.api.server.ws.WebService;
-
-public class WsActionTester {
-
-  public static final String CONTROLLER_KEY = "test";
-  private final WebService.Action action;
-
-  public WsActionTester(WsAction wsAction) {
-    WebService.Context context = new WebService.Context();
-    WebService.NewController newController = context.createController(CONTROLLER_KEY);
-    wsAction.define(newController);
-    newController.done();
-    action = Iterables.get(context.controller(CONTROLLER_KEY).actions(), 0);
-  }
-
-  public WebService.Action getDef() {
-    return action;
-  }
-
-  public TestRequest newRequest() {
-    TestRequest request = new TestRequest();
-    request.setAction(action);
-    return request;
-  }
-}
diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java
new file mode 100644 (file)
index 0000000..f7d2aee
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.ws;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Maps;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.utils.text.XmlWriter;
+
+public class DumbResponse implements Response {
+  private InMemoryStream stream;
+
+  private final ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+  private Map<String, String> headers = Maps.newHashMap();
+
+  public class InMemoryStream implements Response.Stream {
+    private String mediaType;
+
+    private int status = 200;
+
+    @CheckForNull
+    public String mediaType() {
+      return mediaType;
+    }
+
+    public int status() {
+      return status;
+    }
+
+    @Override
+    public Response.Stream setMediaType(String s) {
+      this.mediaType = s;
+      return this;
+    }
+
+    @Override
+    public Response.Stream setStatus(int i) {
+      this.status = i;
+      return this;
+    }
+
+    @Override
+    public OutputStream output() {
+      return output;
+    }
+
+    public String outputAsString() {
+      return new String(output.toByteArray(), StandardCharsets.UTF_8);
+    }
+  }
+
+  @Override
+  public JsonWriter newJsonWriter() {
+    return JsonWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8));
+  }
+
+  @Override
+  public XmlWriter newXmlWriter() {
+    return XmlWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8));
+  }
+
+  @Override
+  public InMemoryStream stream() {
+    if (stream == null) {
+      stream = new InMemoryStream();
+    }
+    return stream;
+  }
+
+  @Override
+  public Response noContent() {
+    stream().setStatus(HttpURLConnection.HTTP_NO_CONTENT);
+    IOUtils.closeQuietly(output);
+    return this;
+  }
+
+  public String outputAsString() {
+    return new String(output.toByteArray(), StandardCharsets.UTF_8);
+  }
+
+  @Override
+  public Response setHeader(String name, String value) {
+    headers.put(name, value);
+    return this;
+  }
+
+  public Collection<String> getHeaderNames() {
+    return headers.keySet();
+  }
+
+  @CheckForNull
+  public String getHeader(String name){
+    return headers.get(name);
+  }
+
+  public byte[] getFlushedOutput() {
+    try {
+      output.flush();
+      return output.toByteArray();
+    } catch (IOException e) {
+      throw Throwables.propagate(e);
+    }
+  }
+}
diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java
new file mode 100644 (file)
index 0000000..aea0e0d
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.ws;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import com.google.protobuf.GeneratedMessageV3;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.impl.ws.PartImpl;
+import org.sonar.api.impl.ws.ValidatingRequest;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+import static org.sonarqube.ws.MediaTypes.PROTOBUF;
+
+public class TestRequest extends ValidatingRequest {
+
+  private final ListMultimap<String, String> multiParams = ArrayListMultimap.create();
+  private final Map<String, String> params = new HashMap<>();
+  private final Map<String, String> headers = new HashMap<>();
+  private final Map<String, Part> parts = Maps.newHashMap();
+  private String payload = "";
+  private boolean payloadConsumed = false;
+  private String method = "GET";
+  private String mimeType = "application/octet-stream";
+  private String path;
+
+  @Override
+  public BufferedReader getReader() {
+    checkState(!payloadConsumed, "Payload already consumed");
+    if (payload == null) {
+      return super.getReader();
+    }
+
+    BufferedReader res = new BufferedReader(new StringReader(payload));
+    payloadConsumed = true;
+    return res;
+  }
+
+  public TestRequest setPayload(String payload) {
+    checkState(!payloadConsumed, "Payload already consumed");
+
+    this.payload = payload;
+    return this;
+  }
+
+  @Override
+  protected String readParam(String key) {
+    return params.get(key);
+  }
+
+  @Override
+  protected List<String> readMultiParam(String key) {
+    return multiParams.get(key);
+  }
+
+  @Override
+  protected InputStream readInputStreamParam(String key) {
+    String value = readParam(key);
+    if (value == null) {
+      return null;
+    }
+    return IOUtils.toInputStream(value);
+  }
+
+  @Override
+  protected Part readPart(String key) {
+    return parts.get(key);
+  }
+
+  public TestRequest setPart(String key, InputStream input, String fileName) {
+    parts.put(key, new PartImpl(input, fileName));
+    return this;
+  }
+
+  @Override
+  public String method() {
+    return method;
+  }
+
+  @Override
+  public boolean hasParam(String key) {
+    return params.containsKey(key) || multiParams.containsKey(key);
+  }
+
+  @Override
+  public String getPath() {
+    return path;
+  }
+
+  @Override
+  public Map<String, String[]> getParams() {
+    ArrayListMultimap<String, String> result = ArrayListMultimap.create(multiParams);
+    params.forEach(result::put);
+    return result.asMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toArray(new String[0])));
+  }
+
+  public TestRequest setPath(String path) {
+    this.path = path;
+    return this;
+  }
+
+  public TestRequest setMethod(String method) {
+    checkNotNull(method);
+    this.method = method;
+    return this;
+  }
+
+  @Override
+  public String getMediaType() {
+    return mimeType;
+  }
+
+  public TestRequest setMediaType(String type) {
+    checkNotNull(type);
+    this.mimeType = type;
+    return this;
+  }
+
+  public TestRequest setParam(String key, String value) {
+    checkNotNull(key);
+    checkNotNull(value);
+    this.params.put(key, value);
+    return this;
+  }
+
+  public TestRequest setMultiParam(String key, List<String> values) {
+    requireNonNull(key);
+    requireNonNull(values);
+
+    multiParams.putAll(key, values);
+
+    return this;
+  }
+
+  @Override
+  public Map<String, String> getHeaders() {
+    return ImmutableMap.copyOf(headers);
+  }
+
+  @Override
+  public Optional<String> header(String name) {
+    return Optional.ofNullable(headers.get(name));
+  }
+
+  public TestRequest setHeader(String name, String value) {
+    headers.put(requireNonNull(name), requireNonNull(value));
+    return this;
+  }
+
+  public TestResponse execute() {
+    try {
+      DumbResponse response = new DumbResponse();
+      action().handler().handle(this, response);
+      return new TestResponse(response);
+    } catch (Exception e) {
+      throw Throwables.propagate(e);
+    }
+  }
+
+  public <T extends GeneratedMessageV3> T executeProtobuf(Class<T> protobufClass) {
+    return setMediaType(PROTOBUF).execute().getInputObject(protobufClass);
+  }
+
+  @Override
+  public String toString() {
+    return path;
+  }
+}
diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java
new file mode 100644 (file)
index 0000000..352d0bb
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.ws;
+
+import com.google.protobuf.GeneratedMessageV3;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import javax.annotation.CheckForNull;
+import org.sonar.test.JsonAssert;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestResponse {
+
+  private final DumbResponse dumbResponse;
+
+  public TestResponse(DumbResponse dumbResponse) {
+    this.dumbResponse = dumbResponse;
+  }
+
+  public InputStream getInputStream() {
+    return new ByteArrayInputStream(dumbResponse.getFlushedOutput());
+  }
+
+  public <T extends GeneratedMessageV3> T getInputObject(Class<T> protobufClass) {
+    try (InputStream input = getInputStream()) {
+      Method parseFromMethod = protobufClass.getMethod("parseFrom", InputStream.class);
+      @SuppressWarnings("unchecked")
+      T result = (T) parseFromMethod.invoke(null, input);
+      return result;
+    } catch (Exception e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  public String getInput() {
+    return new String(dumbResponse.getFlushedOutput(), StandardCharsets.UTF_8);
+  }
+
+  public String getMediaType() {
+    return dumbResponse.stream().mediaType();
+  }
+
+  public int getStatus() {
+    return dumbResponse.stream().status();
+  }
+
+  @CheckForNull
+  public String getHeader(String headerKey) {
+    return dumbResponse.getHeader(headerKey);
+  }
+
+  public void assertJson(String expectedJson) {
+    JsonAssert.assertJson(getInput()).isSimilarTo(expectedJson);
+  }
+
+  /**
+   * Compares JSON response with JSON file available in classpath. For example if class
+   * is org.foo.BarTest and filename is index.json, then file must be located
+   * at src/test/resources/org/foo/BarTest/index.json.
+   *
+   * @param clazz                the test class
+   * @param expectedJsonFilename name of the file containing the expected JSON
+   */
+  public void assertJson(Class clazz, String expectedJsonFilename) {
+    String path = clazz.getSimpleName() + "/" + expectedJsonFilename;
+    URL url = clazz.getResource(path);
+    if (url == null) {
+      throw new IllegalStateException("Cannot find " + path);
+    }
+    JsonAssert.assertJson(getInput()).isSimilarTo(url);
+  }
+
+  public void assertNoContent() {
+    assertThat(getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT);
+  }
+}
diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java
new file mode 100644 (file)
index 0000000..fede932
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.ws;
+
+import com.google.common.collect.Iterables;
+import org.sonar.api.server.ws.WebService;
+
+public class WsActionTester {
+
+  public static final String CONTROLLER_KEY = "test";
+  private final WebService.Action action;
+
+  public WsActionTester(WsAction wsAction) {
+    WebService.Context context = new WebService.Context();
+    WebService.NewController newController = context.createController(CONTROLLER_KEY);
+    wsAction.define(newController);
+    newController.done();
+    action = Iterables.get(context.controller(CONTROLLER_KEY).actions(), 0);
+  }
+
+  public WebService.Action getDef() {
+    return action;
+  }
+
+  public TestRequest newRequest() {
+    TestRequest request = new TestRequest();
+    request.setAction(action);
+    return request;
+  }
+}