]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10345 Add IT's for webhooks management
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 14 Feb 2018 14:54:21 +0000 (15:54 +0100)
committerGuillaume Jambet <guillaume.jambet@gmail.com>
Thu, 1 Mar 2018 14:21:05 +0000 (15:21 +0100)
14 files changed:
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/Tester.java
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/TesterSession.java
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/WebhookTester.java [new file with mode: 0644]
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/WebhooksPage.java
sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/CreateRequest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/DeleteRequest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/ListRequest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/UpdateRequest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/WebhooksService.java
tests/src/test/java/org/sonarqube/tests/project/ProjectBadgesTest.java
tests/src/test/java/org/sonarqube/tests/webhook/ExternalServer.java
tests/src/test/java/org/sonarqube/tests/webhook/WebhooksPageTest.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/webhook/WebhooksSuite.java
tests/src/test/java/org/sonarqube/tests/webhook/WebhooksTest.java

index 9401ef2a9070bba83463adac7b90533c61eb5465..fe1d5d8236e1d73b2fa702f6e457c6c61d329223 100644 (file)
@@ -207,6 +207,11 @@ public class Tester extends ExternalResource implements TesterSession {
     return rootSession.qGates();
   }
 
+  @Override
+  public WebhookTester webhooks() {
+    return rootSession.webhooks();
+  }
+
   private static class TesterSessionImpl implements TesterSession {
     private final WsClient client;
 
@@ -262,5 +267,10 @@ public class Tester extends ExternalResource implements TesterSession {
     public QGateTester qGates() {
       return new QGateTester(this);
     }
+
+    @Override
+    public WebhookTester webhooks() {
+      return new WebhookTester(this);
+    }
   }
 }
index f9e1b05483dccd24edade53fbd89f04bc7ff177f..d0e3afdcbd29355c5e6cbf98512efb4ae9a2606d 100644 (file)
@@ -41,4 +41,6 @@ public interface TesterSession {
 
   QGateTester qGates();
 
+  WebhookTester webhooks();
+
 }
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/WebhookTester.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/WebhookTester.java
new file mode 100644 (file)
index 0000000..5b03820
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.util;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import javax.annotation.Nullable;
+import org.sonarqube.ws.Organizations.Organization;
+import org.sonarqube.ws.Projects.CreateWsResponse.Project;
+import org.sonarqube.ws.Webhooks.CreateWsResponse.Webhook;
+import org.sonarqube.ws.Webhooks.Delivery;
+import org.sonarqube.ws.client.webhooks.CreateRequest;
+import org.sonarqube.ws.client.webhooks.DeleteRequest;
+import org.sonarqube.ws.client.webhooks.DeliveriesRequest;
+import org.sonarqube.ws.client.webhooks.DeliveryRequest;
+import org.sonarqube.ws.client.webhooks.ListRequest;
+import org.sonarqube.ws.client.webhooks.WebhooksService;
+
+import static java.util.Arrays.stream;
+import static java.util.Objects.requireNonNull;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class WebhookTester {
+  private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
+
+  private final TesterSession session;
+
+  WebhookTester(TesterSession session) {
+    this.session = session;
+  }
+
+  public WebhooksService service() {
+    return session.wsClient().webhooks();
+  }
+
+  public Webhook generate(Consumer<CreateRequest>... populators) {
+    return generate(null, null, populators);
+  }
+
+  public Webhook generate(Organization organization, Consumer<CreateRequest>... populators) {
+    return generate(organization, null, populators);
+  }
+
+  public Webhook generate(Project project, Consumer<CreateRequest>... populators) {
+    return generate(null, project, populators);
+  }
+
+  @SafeVarargs
+  public final Webhook generate(
+    @Nullable Organization organization,
+    @Nullable Project project,
+    Consumer<CreateRequest>... populators
+  ) {
+    int id = ID_GENERATOR.getAndIncrement();
+    CreateRequest request = new CreateRequest()
+      .setName("Webhook " + id)
+      .setUrl("https://webhook-" + id)
+      .setProject(project != null ? project.getKey(): null)
+      .setOrganization(organization != null ? organization.getKey() : null);
+    stream(populators).forEach(p -> p.accept(request));
+    return service().create(request).getWebhook();
+  }
+
+  public void deleteAllGlobal() {
+    service().list(new ListRequest()).getWebhooksList().forEach(p ->
+      service().delete(new DeleteRequest().setWebhook(p.getKey()))
+    );
+  }
+
+  public List<Delivery> getPersistedDeliveries(Project project) {
+    DeliveriesRequest deliveriesReq = new DeliveriesRequest().setComponentKey(project.getKey());
+    return service().deliveries(deliveriesReq).getDeliveriesList();
+  }
+
+  public Delivery getPersistedDeliveryByName(Project project, String webhookName) {
+    List<Delivery> deliveries = getPersistedDeliveries(project);
+    Optional<Delivery> delivery = deliveries.stream().filter(d -> d.getName().equals(webhookName)).findFirst();
+    assertThat(delivery).isPresent();
+    return delivery.get();
+  }
+
+  public Delivery getDetailOfPersistedDelivery(Delivery delivery) {
+    Delivery detail = service().delivery(new DeliveryRequest().setDeliveryId(delivery.getId())).getDelivery();
+    return requireNonNull(detail);
+  }
+
+  public void assertThatPersistedDeliveryIsValid(Delivery delivery, @Nullable Project project, @Nullable String url) {
+    assertThat(delivery.getId()).isNotEmpty();
+    assertThat(delivery.getName()).isNotEmpty();
+    assertThat(delivery.hasSuccess()).isTrue();
+    assertThat(delivery.getHttpStatus()).isGreaterThanOrEqualTo(200);
+    assertThat(delivery.getDurationMs()).isGreaterThanOrEqualTo(0);
+    assertThat(delivery.getAt()).isNotEmpty();
+    if (project != null) {
+      assertThat(delivery.getComponentKey()).isEqualTo(project.getKey());
+    }
+    if (url != null) {
+      assertThat(delivery.getUrl()).startsWith(url);
+    }
+  }
+}
index af6c8c6f816c4d9553f1e968ad8d70753946d894..75260c11e119bd5ec6a40611737d2cef2dad9834 100644 (file)
 package org.sonarqube.qa.util.pageobjects;
 
 import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.SelenideElement;
 
+import static com.codeborne.selenide.Condition.cssClass;
+import static com.codeborne.selenide.Condition.enabled;
 import static com.codeborne.selenide.Condition.exist;
 import static com.codeborne.selenide.Condition.text;
+import static com.codeborne.selenide.Condition.visible;
 import static com.codeborne.selenide.Selenide.$;
 import static com.codeborne.selenide.Selenide.$$;
 
@@ -37,12 +41,55 @@ public class WebhooksPage {
     return this;
   }
 
+  public WebhooksPage hasNoWebhooks() {
+    $(".boxed-group").shouldHave(text("No webhook defined"));
+    return this;
+  }
+
   public WebhooksPage countWebhooks(Integer number) {
     getWebhooks().shouldHaveSize(number);
     return this;
   }
 
+  public WebhooksPage createWebhook(String name, String url) {
+    $(".js-webhook-create").shouldBe(visible).shouldBe(enabled).shouldNotHave(cssClass("disabled")).click();
+    modalShouldBeOpen("Create Webhook");
+    $("#webhook-name").shouldBe(visible).sendKeys(name);
+    $("#webhook-url").shouldBe(visible).sendKeys(url);
+    $("button[type='submit']").shouldBe(visible).click();
+    modalShouldBeClosed();
+    return this;
+  }
+
+  public  WebhooksPage createIsDisabled() {
+    $(".js-webhook-create").shouldBe(visible).shouldHave(cssClass("disabled")).click();
+    modalShouldBeClosed();
+    return this;
+  }
+
+  public WebhooksPage deleteWebhook(String webhookName) {
+    SelenideElement webhook = getWebhook(webhookName);
+    webhook.$(".dropdown-toggle").shouldBe(visible).click();
+    webhook.$(".js-webhook-delete").shouldBe(visible).click();
+    modalShouldBeOpen("Delete Webhook");
+    $("button.button-red").shouldBe(visible).click();
+    modalShouldBeClosed();
+    return this;
+  }
+
+  private static SelenideElement getWebhook(String webhookName) {
+    return getWebhooks().find(text(webhookName)).should(exist);
+  }
+
   private static ElementsCollection getWebhooks() {
     return $$(".boxed-group tbody tr");
   }
+
+  private static void modalShouldBeOpen(String title) {
+    $(".modal-head").shouldBe(visible).shouldHave(text(title));
+  }
+
+  private static void modalShouldBeClosed() {
+    $(".modal-head").shouldNot(exist);
+  }
 }
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/CreateRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/CreateRequest.java
new file mode 100644 (file)
index 0000000..2162c20
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.ws.client.webhooks;
+
+import java.util.List;
+import javax.annotation.Generated;
+
+/**
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/create">Further information about this action online (including a response example)</a>
+ * @since 7.1
+ */
+@Generated("sonar-ws-generator")
+public class CreateRequest {
+
+  private String name;
+  private String organization;
+  private String project;
+  private String url;
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "My Webhook"
+   */
+  public CreateRequest setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * This is part of the internal API.
+   * Example value: "my-org"
+   */
+  public CreateRequest setOrganization(String organization) {
+    this.organization = organization;
+    return this;
+  }
+
+  public String getOrganization() {
+    return organization;
+  }
+
+  /**
+   * Example value: "my_project"
+   */
+  public CreateRequest setProject(String project) {
+    this.project = project;
+    return this;
+  }
+
+  public String getProject() {
+    return project;
+  }
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "https://www.my-webhook-listener.com/sonar"
+   */
+  public CreateRequest setUrl(String url) {
+    this.url = url;
+    return this;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/DeleteRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/DeleteRequest.java
new file mode 100644 (file)
index 0000000..aab9cea
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.ws.client.webhooks;
+
+import java.util.List;
+import javax.annotation.Generated;
+
+/**
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/delete">Further information about this action online (including a response example)</a>
+ * @since 7.1
+ */
+@Generated("sonar-ws-generator")
+public class DeleteRequest {
+
+  private String webhook;
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "my_project"
+   */
+  public DeleteRequest setWebhook(String webhook) {
+    this.webhook = webhook;
+    return this;
+  }
+
+  public String getWebhook() {
+    return webhook;
+  }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/ListRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/ListRequest.java
new file mode 100644 (file)
index 0000000..d56a880
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.ws.client.webhooks;
+
+import java.util.List;
+import javax.annotation.Generated;
+
+/**
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/list">Further information about this action online (including a response example)</a>
+ * @since 7.1
+ */
+@Generated("sonar-ws-generator")
+public class ListRequest {
+
+  private String organization;
+  private String project;
+
+  /**
+   * This is part of the internal API.
+   * Example value: "my-org"
+   */
+  public ListRequest setOrganization(String organization) {
+    this.organization = organization;
+    return this;
+  }
+
+  public String getOrganization() {
+    return organization;
+  }
+
+  /**
+   * Example value: "my_project"
+   */
+  public ListRequest setProject(String project) {
+    this.project = project;
+    return this;
+  }
+
+  public String getProject() {
+    return project;
+  }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/UpdateRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/webhooks/UpdateRequest.java
new file mode 100644 (file)
index 0000000..64b8ad6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.ws.client.webhooks;
+
+import java.util.List;
+import javax.annotation.Generated;
+
+/**
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/update">Further information about this action online (including a response example)</a>
+ * @since 7.1
+ */
+@Generated("sonar-ws-generator")
+public class UpdateRequest {
+
+  private String name;
+  private String url;
+  private String webhook;
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "My Webhook"
+   */
+  public UpdateRequest setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "https://www.my-webhook-listener.com/sonar"
+   */
+  public UpdateRequest setUrl(String url) {
+    this.url = url;
+    return this;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "my_project"
+   */
+  public UpdateRequest setWebhook(String webhook) {
+    this.webhook = webhook;
+    return this;
+  }
+
+  public String getWebhook() {
+    return webhook;
+  }
+}
index 9f8b4587accdd4da072e53e803522d840df509a3..7eb3b34a329350e20ae838c742b22c85c7491ec6 100644 (file)
@@ -26,8 +26,10 @@ import org.sonarqube.ws.client.BaseService;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.PostRequest;
 import org.sonarqube.ws.client.WsConnector;
+import org.sonarqube.ws.Webhooks.CreateWsResponse;
 import org.sonarqube.ws.Webhooks.DeliveriesWsResponse;
 import org.sonarqube.ws.Webhooks.DeliveryWsResponse;
+import org.sonarqube.ws.Webhooks.ListWsResponse;
 
 /**
  * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks">Further information about this web service online</a>
@@ -39,6 +41,38 @@ public class WebhooksService extends BaseService {
     super(wsConnector, "api/webhooks");
   }
 
+  /**
+   *
+   * This is part of the internal API.
+   * This is a POST request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/create">Further information about this action online (including a response example)</a>
+   * @since 7.1
+   */
+  public CreateWsResponse create(CreateRequest request) {
+    return call(
+      new PostRequest(path("create"))
+        .setParam("name", request.getName())
+        .setParam("organization", request.getOrganization())
+        .setParam("project", request.getProject())
+        .setParam("url", request.getUrl()),
+      CreateWsResponse.parser());
+  }
+
+  /**
+   *
+   * This is part of the internal API.
+   * This is a POST request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/delete">Further information about this action online (including a response example)</a>
+   * @since 7.1
+   */
+  public void delete(DeleteRequest request) {
+    call(
+      new PostRequest(path("delete"))
+        .setParam("webhook", request.getWebhook())
+        .setMediaType(MediaTypes.JSON)
+      ).content();
+  }
+
   /**
    *
    * This is part of the internal API.
@@ -67,4 +101,36 @@ public class WebhooksService extends BaseService {
         .setParam("deliveryId", request.getDeliveryId()),
       DeliveryWsResponse.parser());
   }
+
+  /**
+   *
+   * This is part of the internal API.
+   * This is a GET request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/list">Further information about this action online (including a response example)</a>
+   * @since 7.1
+   */
+  public ListWsResponse list(ListRequest request) {
+    return call(
+      new GetRequest(path("list"))
+        .setParam("organization", request.getOrganization())
+        .setParam("project", request.getProject()),
+      ListWsResponse.parser());
+  }
+
+  /**
+   *
+   * This is part of the internal API.
+   * This is a POST request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/update">Further information about this action online (including a response example)</a>
+   * @since 7.1
+   */
+  public void update(UpdateRequest request) {
+    call(
+      new PostRequest(path("update"))
+        .setParam("name", request.getName())
+        .setParam("url", request.getUrl())
+        .setParam("webhook", request.getWebhook())
+        .setMediaType(MediaTypes.JSON)
+      ).content();
+  }
 }
index 161861e58b134bf16ea26f0809d9a26152e4e48f..3e9f23f0a60086e3374aa6e0ec2b5748c9b2a3ee 100644 (file)
@@ -115,7 +115,7 @@ public class ProjectBadgesTest {
   }
 
   private void shouldHaveUrl(SelenideElement badgesModal, String url) {
-    badgesModal.$(".badge-snippet pre")
+    badgesModal.$(".code-snippet pre")
       .shouldBe(Condition.visible)
       .shouldHave(Condition.text(url));
   }
index 220dc1f59e5a034b851b9c41a9a74b649c5b995f..66cdb5c24132f7425854d5dfa3b2ce7069b33f69 100644 (file)
@@ -93,7 +93,18 @@ class ExternalServer extends ExternalResource {
     return jetty.getURI().resolve(path).toString();
   }
 
+  void waitUntilAllWebHooksCalled(int expectedNumberOfRequests) throws InterruptedException {
+    // Wait up to 30 seconds max
+    for (int i = 0; i < 60; i++) {
+      if (getPayloadRequests().size() == expectedNumberOfRequests) {
+        break;
+      }
+      Thread.sleep(500);
+    }
+  }
+
   void clear() {
     payloads.clear();
   }
+
 }
diff --git a/tests/src/test/java/org/sonarqube/tests/webhook/WebhooksPageTest.java b/tests/src/test/java/org/sonarqube/tests/webhook/WebhooksPageTest.java
new file mode 100644 (file)
index 0000000..ac3e8ed
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.tests.webhook;
+
+import com.sonar.orchestrator.Orchestrator;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.qa.util.Tester;
+import org.sonarqube.qa.util.pageobjects.WebhooksPage;
+import org.sonarqube.ws.Projects.CreateWsResponse.Project;
+import org.sonarqube.ws.Users.CreateWsResponse.User;
+import org.sonarqube.ws.Webhooks.CreateWsResponse.Webhook;
+
+import static util.ItUtils.runProjectAnalysis;
+
+public class WebhooksPageTest
+{
+  @ClassRule
+  public static Orchestrator orchestrator = WebhooksSuite.ORCHESTRATOR;
+
+  @Rule
+  public Tester tester = new Tester(orchestrator);
+
+  @Before
+  @After
+  public void reset() {
+    tester.webhooks().deleteAllGlobal();
+  }
+
+  @Test
+  public void list_global_webhooks() {
+    tester.webhooks().generate();
+    Webhook webhook = tester.webhooks().generate();
+    tester.wsClient().users().skipOnboardingTutorial();
+    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials("admin").openWebhooks();
+    webhooksPage
+      .countWebhooks(2)
+      .hasWebhook(webhook.getUrl())
+      .hasWebhook(webhook.getName());
+  }
+
+  @Test
+  public void list_project_webhooks() {
+    User user = tester.users().generateAdministratorOnDefaultOrganization();
+    tester.wsClient().users().skipOnboardingTutorial();
+
+    Project project = tester.projects().provision();
+    analyseProject(project);
+
+    Webhook webhook1 = tester.webhooks().generate(project);
+    Webhook webhook2 = tester.webhooks().generate(project);
+
+    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials(user.getLogin()).openProjectWebhooks(project.getKey());
+    webhooksPage
+      .countWebhooks(2)
+      .hasWebhook(webhook1.getUrl())
+      .hasWebhook(webhook2.getUrl());
+  }
+
+  @Test
+  public void create_new_webhook() {
+    User user = tester.users().generateAdministratorOnDefaultOrganization();
+    tester.wsClient().users().skipOnboardingTutorial();
+
+    Project project = tester.projects().provision();
+    analyseProject(project);
+
+    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials(user.getLogin()).openProjectWebhooks(project.getKey());
+    webhooksPage
+      .hasNoWebhooks()
+      .createWebhook("my-webhook", "http://greg:pass@test.com")
+      .countWebhooks(1)
+      .hasWebhook("my-webhook")
+      .hasWebhook("http://greg:pass@test.com");
+  }
+
+  @Test
+  public void prevent_webhook_creation() {
+    tester.wsClient().users().skipOnboardingTutorial();
+
+    Webhook webhook = tester.webhooks().generate();
+    for (int i = 0; i < 9; i++) {
+      tester.webhooks().generate();
+    }
+
+    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials("admin").openWebhooks();
+    webhooksPage
+      .countWebhooks(10)
+      .createIsDisabled()
+      .deleteWebhook(webhook.getName())
+      .countWebhooks(9)
+      .createWebhook("my-new-webhook", "http://my-new-webhook.com");
+  }
+
+  @Test
+  public void delete_webhook() {
+    User user = tester.users().generateAdministratorOnDefaultOrganization();
+    tester.wsClient().users().skipOnboardingTutorial();
+
+    Project project = tester.projects().provision();
+    analyseProject(project);
+
+    tester.webhooks().generate(project);
+    tester.webhooks().generate(project);
+    Webhook webhook = tester.webhooks().generate(project);
+
+    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials(user.getLogin()).openProjectWebhooks(project.getKey());
+    webhooksPage
+      .countWebhooks(3)
+      .deleteWebhook(webhook.getName())
+      .countWebhooks(2);
+  }
+
+  private void analyseProject(Project project) {
+    runProjectAnalysis(orchestrator, "shared/xoo-sample",
+      "sonar.projectKey", project.getKey(),
+      "sonar.projectName", project.getName());
+  }
+}
index 261c88ff139578216ce5a95b1419147ff8651e22..6412ec5c48e115dd8f32e925ee5fc19ffcd0fb23 100644 (file)
@@ -28,6 +28,7 @@ import static util.ItUtils.xooPlugin;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
+  WebhooksPageTest.class,
   WebhooksTest.class
 })
 public class WebhooksSuite {
index 2531d8674b1077d7e70aa335f95f10ef0ce44d59..ad73ced0d2b256f416ac81651330d0923ca7964d 100644 (file)
 package org.sonarqube.tests.webhook;
 
 import com.sonar.orchestrator.Orchestrator;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.apache.commons.lang3.StringUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonarqube.qa.util.Tester;
-import org.sonarqube.qa.util.pageobjects.WebhooksPage;
 import org.sonarqube.ws.Issues.Issue;
 import org.sonarqube.ws.Organizations.Organization;
 import org.sonarqube.ws.Projects.CreateWsResponse.Project;
 import org.sonarqube.ws.Qualitygates;
 import org.sonarqube.ws.Qualityprofiles.CreateWsResponse.QualityProfile;
-import org.sonarqube.ws.Users;
-import org.sonarqube.ws.Users.CreateWsResponse.User;
 import org.sonarqube.ws.Webhooks;
-import org.sonarqube.ws.client.HttpException;
-import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.Webhooks.CreateWsResponse.Webhook;
 import org.sonarqube.ws.client.issues.BulkChangeRequest;
 import org.sonarqube.ws.client.issues.SearchRequest;
-import org.sonarqube.ws.client.projects.DeleteRequest;
 import org.sonarqube.ws.client.qualitygates.CreateConditionRequest;
-import org.sonarqube.ws.client.settings.ResetRequest;
-import org.sonarqube.ws.client.settings.SetRequest;
-import org.sonarqube.ws.client.webhooks.DeliveriesRequest;
-import org.sonarqube.ws.client.webhooks.DeliveryRequest;
-import util.ItUtils;
 
 import static java.util.Collections.singletonList;
-import static java.util.Objects.requireNonNull;
-import static java.util.stream.IntStream.range;
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.jsonToMap;
 import static util.ItUtils.runProjectAnalysis;
 
 public class WebhooksTest {
 
-  private static final String PROJECT_KEY = "my-project";
-  private static final String PROJECT_NAME = "My Project";
-  private static final String GLOBAL_WEBHOOK_PROPERTY = "sonar.webhooks.global";
-  private static final String PROJECT_WEBHOOK_PROPERTY = "sonar.webhooks.project";
-
   @ClassRule
   public static Orchestrator orchestrator = WebhooksSuite.ORCHESTRATOR;
+
   @ClassRule
   public static ExternalServer externalServer = new ExternalServer();
 
   @Rule
   public Tester tester = new Tester(orchestrator);
 
-  private WsClient adminWs = ItUtils.newAdminWsClient(orchestrator);
-
   @Before
   public void setUp() {
     externalServer.clear();
@@ -86,28 +63,20 @@ public class WebhooksTest {
   @Before
   @After
   public void reset() {
-    disableGlobalWebhooks();
-    try {
-      // delete project and related properties/webhook deliveries
-      adminWs.projects().delete(new DeleteRequest().setProject(PROJECT_KEY));
-    } catch (HttpException e) {
-      // ignore because project may not exist
-    }
+    tester.webhooks().deleteAllGlobal();
   }
 
   @Test
   public void call_multiple_global_and_project_webhooks_when_analysis_is_done() throws InterruptedException {
-    orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_NAME);
-    enableGlobalWebhooks(
-      new Webhook("Jenkins", externalServer.urlFor("/jenkins")),
-      new Webhook("HipChat", externalServer.urlFor("/hipchat")));
-    enableProjectWebhooks(PROJECT_KEY,
-      new Webhook("Burgr", externalServer.urlFor("/burgr")));
+    Project project = tester.projects().provision();
+    Webhook jenkins = tester.webhooks().generate(p -> p.setName("Jenkins").setUrl(externalServer.urlFor("/jenkins")));
+    Webhook hipchat = tester.webhooks().generate(p -> p.setName("HipChat").setUrl(externalServer.urlFor("/hipchat")));
+    Webhook burgr = tester.webhooks().generate(project, p -> p.setName("Burgr").setUrl(externalServer.urlFor("/burgr")));
 
-    analyseProject();
+    analyseProject(project);
 
     // the same payload has been sent to three servers
-    waitUntilAllWebHooksCalled(3);
+    externalServer.waitUntilAllWebHooksCalled(3);
     assertThat(externalServer.getPayloadRequests()).hasSize(3);
     PayloadRequest request = externalServer.getPayloadRequests().get(0);
     for (int i = 1; i < 3; i++) {
@@ -116,137 +85,104 @@ public class WebhooksTest {
     }
 
     // verify HTTP headers
-    assertThat(request.getHttpHeaders().get("X-SonarQube-Project")).isEqualTo(PROJECT_KEY);
+    assertThat(request.getHttpHeaders().get("X-SonarQube-Project")).isEqualTo(project.getKey());
 
     // verify content of payload
     Map<String, Object> payload = jsonToMap(request.getJson());
     assertThat(payload.get("status")).isEqualTo("SUCCESS");
     assertThat(payload.get("analysedAt")).isNotNull();
-    Map<String, String> project = (Map<String, String>) payload.get("project");
-    assertThat(project.get("key")).isEqualTo(PROJECT_KEY);
-    assertThat(project.get("name")).isEqualTo(PROJECT_NAME);
-    assertThat(project.get("url")).isEqualTo(orchestrator.getServer().getUrl() + "/dashboard?id=" + PROJECT_KEY);
+    Map<String, String> projectPayload = (Map<String, String>) payload.get("project");
+    assertThat(projectPayload.get("key")).isEqualTo(project.getKey());
+    assertThat(projectPayload.get("name")).isEqualTo(project.getName());
+    assertThat(projectPayload.get("url")).isEqualTo(orchestrator.getServer().getUrl() + "/dashboard?id=" + project.getKey());
     Map<String, Object> gate = (Map<String, Object>) payload.get("qualityGate");
     assertThat(gate.get("name")).isEqualTo("Sonar way");
     assertThat(gate.get("status")).isEqualTo("OK");
     assertThat(gate.get("conditions")).isNotNull();
 
     // verify list of persisted deliveries (api/webhooks/deliveries)
-    List<Webhooks.Delivery> deliveries = getPersistedDeliveries();
+    List<Webhooks.Delivery> deliveries = tester.webhooks().getPersistedDeliveries(project);
     assertThat(deliveries).hasSize(3);
     for (Webhooks.Delivery delivery : deliveries) {
-      assertThatPersistedDeliveryIsValid(delivery);
+      tester.webhooks().assertThatPersistedDeliveryIsValid(delivery, project, externalServer.urlFor("/"));
       assertThat(delivery.getSuccess()).isTrue();
       assertThat(delivery.getHttpStatus()).isEqualTo(200);
-      assertThat(delivery.getName()).isIn("Jenkins", "HipChat", "Burgr");
+      assertThat(delivery.getName()).isIn(jenkins.getName(), hipchat.getName(), burgr.getName());
       assertThat(delivery.hasErrorStacktrace()).isFalse();
       // payload is available only in api/webhooks/delivery to avoid loading multiple DB CLOBs
       assertThat(delivery.hasPayload()).isFalse();
     }
 
     // verify detail of persisted delivery (api/webhooks/delivery)
-    Webhooks.Delivery detail = getDetailOfPersistedDelivery(deliveries.get(0));
-    assertThatPersistedDeliveryIsValid(detail);
+    Webhooks.Delivery detail = tester.webhooks().getDetailOfPersistedDelivery(deliveries.get(0));
+    tester.webhooks().assertThatPersistedDeliveryIsValid(detail, project, externalServer.urlFor("/"));
     assertThat(detail.getPayload()).isEqualTo(request.getJson());
   }
 
   @Test
   public void persist_delivery_as_failed_if_external_server_returns_an_error_code() {
-    enableGlobalWebhooks(
-      new Webhook("Fail", externalServer.urlFor("/fail")),
-      new Webhook("HipChat", externalServer.urlFor("/hipchat")));
+    Project project = tester.projects().provision();
+    Webhook fail = tester.webhooks().generate(p -> p.setName("Fail").setUrl(externalServer.urlFor("/fail")));
+    Webhook hipchat = tester.webhooks().generate(p -> p.setName("HipChat").setUrl(externalServer.urlFor("/hipchat")));
 
-    analyseProject();
+    analyseProject(project);
 
     // all webhooks are called, even if one returns an error code
     assertThat(externalServer.getPayloadRequests()).hasSize(2);
 
     // verify persisted deliveries
-    Webhooks.Delivery failedDelivery = getPersistedDeliveryByName("Fail");
-    assertThatPersistedDeliveryIsValid(failedDelivery);
+    Webhooks.Delivery failedDelivery = tester.webhooks().getPersistedDeliveryByName(project, fail.getName());
+    tester.webhooks().assertThatPersistedDeliveryIsValid(failedDelivery, project, fail.getUrl());
     assertThat(failedDelivery.getSuccess()).isFalse();
     assertThat(failedDelivery.getHttpStatus()).isEqualTo(500);
 
-    Webhooks.Delivery successfulDelivery = getPersistedDeliveryByName("HipChat");
-    assertThatPersistedDeliveryIsValid(successfulDelivery);
+    Webhooks.Delivery successfulDelivery = tester.webhooks().getPersistedDeliveryByName(project, hipchat.getName());
+    tester.webhooks().assertThatPersistedDeliveryIsValid(successfulDelivery, project, hipchat.getUrl());
     assertThat(successfulDelivery.getSuccess()).isTrue();
     assertThat(successfulDelivery.getHttpStatus()).isEqualTo(200);
   }
 
-  /**
-   * Restrict calls to ten webhooks per type (global or project)
-   */
-  @Test
-  public void do_not_become_a_denial_of_service_attacker() throws InterruptedException {
-    orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_NAME);
-
-    List<Webhook> globalWebhooks = range(0, 15).mapToObj(i -> new Webhook("G" + i, externalServer.urlFor("/global"))).collect(Collectors.toList());
-    enableGlobalWebhooks(globalWebhooks.toArray(new Webhook[globalWebhooks.size()]));
-    List<Webhook> projectWebhooks = range(0, 15).mapToObj(i -> new Webhook("P" + i, externalServer.urlFor("/project"))).collect(Collectors.toList());
-    enableProjectWebhooks(PROJECT_KEY, projectWebhooks.toArray(new Webhook[projectWebhooks.size()]));
-
-    analyseProject();
-
-    // only the first ten global webhooks and ten project webhooks are called
-    waitUntilAllWebHooksCalled(10 + 10);
-    assertThat(externalServer.getPayloadRequests()).hasSize(10 + 10);
-    assertThat(externalServer.getPayloadRequestsOnPath("/global")).hasSize(10);
-    assertThat(externalServer.getPayloadRequestsOnPath("/project")).hasSize(10);
-
-    // verify persisted deliveries
-    assertThat(getPersistedDeliveries()).hasSize(10 + 10);
-  }
-
   @Test
-  public void persist_delivery_as_failed_if_webhook_url_is_malformed() {
-    enableGlobalWebhooks(new Webhook("Jenkins", "this_is_not_an_url"));
+  public void persist_delivery_as_failed_if_webhook_is_not_reachable() {
+    Project project = tester.projects().provision();
+    Webhook badUrl = tester.webhooks().generate(p -> p.setUrl("http://does_not_exist"));
 
-    analyseProject();
+    analyseProject(project);
 
     assertThat(externalServer.getPayloadRequests()).isEmpty();
 
     // verify persisted deliveries
-    Webhooks.Delivery delivery = getPersistedDeliveryByName("Jenkins");
-    Webhooks.Delivery detail = getDetailOfPersistedDelivery(delivery);
+    Webhooks.Delivery delivery = tester.webhooks().getPersistedDeliveryByName(project, badUrl.getName());
+    Webhooks.Delivery detail = tester.webhooks().getDetailOfPersistedDelivery(delivery);
 
     assertThat(detail.getSuccess()).isFalse();
     assertThat(detail.hasHttpStatus()).isFalse();
     assertThat(detail.hasDurationMs()).isFalse();
     assertThat(detail.getPayload()).isNotEmpty();
     assertThat(detail.getErrorStacktrace())
-      .contains("java.lang.IllegalArgumentException")
-      .contains("Webhook URL is not valid: this_is_not_an_url");
-  }
-
-  @Test
-  public void ignore_webhook_if_url_is_missing() {
-    // property sets, as used to define webhooks, do
-    // not allow to validate values yet
-    enableGlobalWebhooks(new Webhook("Jenkins", null));
-
-    analyseProject();
-
-    assertThat(externalServer.getPayloadRequests()).isEmpty();
-    assertThat(getPersistedDeliveries()).isEmpty();
+      .contains("java.net.UnknownHostException")
+      .contains("Name or service not known");
   }
 
   @Test
   public void send_webhook_on_issue_change() throws InterruptedException {
     Organization defaultOrganization = tester.organizations().getDefaultOrganization();
-    Project wsProject = tester.projects().provision(r -> r.setProject(PROJECT_KEY).setName(PROJECT_NAME));
-    enableProjectWebhooks(PROJECT_KEY, new Webhook("Burgr", externalServer.urlFor("/burgr")));
+    Project project = tester.projects().provision();
+    Webhook burgr = tester.webhooks().generate(project, p -> p.setName("Burgr").setUrl(externalServer.urlFor("/burgr")));
+
     // quality profile with one issue per line
     QualityProfile qualityProfile = tester.qProfiles().createXooProfile(defaultOrganization);
     tester.qProfiles().activateRule(qualityProfile, "xoo:OneIssuePerLine");
-    tester.qProfiles().assignQProfileToProject(qualityProfile, wsProject);
+    tester.qProfiles().assignQProfileToProject(qualityProfile, project);
     // quality gate definition
     Qualitygates.CreateResponse qGate = tester.qGates().generate();
     tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(String.valueOf(qGate.getId()))
       .setMetric("reliability_rating").setOp("GT").setError("1"));
-    tester.qGates().associateProject(qGate, wsProject);
+    tester.qGates().associateProject(qGate, project);
     // analyze project and clear first webhook
-    analyseProject();
-    waitUntilAllWebHooksCalled(1);
+
+    analyseProject(project);
+    externalServer.waitUntilAllWebHooksCalled(1);
     externalServer.clear();
 
     // change an issue to blocker bug, QG status goes from OK to ERROR, so webhook is called
@@ -255,18 +191,18 @@ public class WebhooksTest {
     tester.wsClient().issues().bulkChange(new BulkChangeRequest().setIssues(singletonList(firstIssue.getKey()))
       .setSetSeverity(singletonList("BLOCKER"))
       .setSetType(singletonList("BUG")));
-    waitUntilAllWebHooksCalled(1);
+    externalServer.waitUntilAllWebHooksCalled(1);
 
     PayloadRequest request = externalServer.getPayloadRequests().get(0);
-    assertThat(request.getHttpHeaders().get("X-SonarQube-Project")).isEqualTo(PROJECT_KEY);
+    assertThat(request.getHttpHeaders().get("X-SonarQube-Project")).isEqualTo(project.getKey());
     // verify content of payload
     Map<String, Object> payload = jsonToMap(request.getJson());
     assertThat(payload.get("status")).isEqualTo("SUCCESS");
     assertThat(payload.get("analysedAt")).isNotNull();
-    Map<String, String> project = (Map<String, String>) payload.get("project");
-    assertThat(project.get("key")).isEqualTo(PROJECT_KEY);
-    assertThat(project.get("name")).isEqualTo(PROJECT_NAME);
-    assertThat(project.get("url")).isEqualTo(orchestrator.getServer().getUrl() + "/dashboard?id=" + PROJECT_KEY);
+    Map<String, String> projectPayload = (Map<String, String>) payload.get("project");
+    assertThat(projectPayload.get("key")).isEqualTo(project.getKey());
+    assertThat(projectPayload.get("name")).isEqualTo(project.getName());
+    assertThat(projectPayload.get("url")).isEqualTo(orchestrator.getServer().getUrl() + "/dashboard?id=" + project.getKey());
     Map<String, Object> gate = (Map<String, Object>) payload.get("qualityGate");
     assertThat(gate.get("name")).isEqualTo(qGate.getName());
     assertThat(gate.get("status")).isEqualTo("ERROR");
@@ -276,127 +212,22 @@ public class WebhooksTest {
     // change severity of issue, won't change the QG status, so no webhook called
     tester.wsClient().issues().bulkChange(new BulkChangeRequest().setIssues(singletonList(firstIssue.getKey()))
       .setSetSeverity(singletonList("MINOR")));
-    waitUntilAllWebHooksCalled(1);
+    externalServer.waitUntilAllWebHooksCalled(1);
     assertThat(externalServer.getPayloadRequests()).isEmpty();
 
     // resolve issue as won't fix, QG status goes to OK, so webhook called
     tester.wsClient().issues().bulkChange(new BulkChangeRequest().setIssues(singletonList(firstIssue.getKey()))
       .setDoTransition("wontfix"));
-    waitUntilAllWebHooksCalled(1);
+    externalServer.waitUntilAllWebHooksCalled(1);
     request = externalServer.getPayloadRequests().get(0);
     payload = jsonToMap(request.getJson());
     gate = (Map<String, Object>) payload.get("qualityGate");
     assertThat(gate.get("status")).isEqualTo("OK");
   }
 
-  @Test
-  public void list_global_webhooks() {
-    enableGlobalWebhooks(new Webhook("foo", "http://foo.bar"), new Webhook("bar", "https://bar.baz/test"));
-    tester.wsClient().users().skipOnboardingTutorial();
-    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials("admin").openWebhooks();
-    webhooksPage
-      .countWebhooks(2)
-      .hasWebhook("http://foo.bar");
-  }
-
-  @Test
-  public void list_project_webhooks() {
-    analyseProject();
-    enableProjectWebhooks(PROJECT_KEY, new Webhook("foo", "http://foo.bar"), new Webhook("bar", "https://bar.baz/test"));
-    User user = tester.users().generateAdministratorOnDefaultOrganization();
-    tester.wsClient().users().skipOnboardingTutorial();
-    WebhooksPage webhooksPage = tester.openBrowser().logIn().submitCredentials(user.getLogin()).openProjectWebhooks(PROJECT_KEY);
-    webhooksPage
-      .countWebhooks(2)
-      .hasWebhook("http://foo.bar");
-  }
-
-  private void analyseProject() {
+  private void analyseProject(Project project) {
     runProjectAnalysis(orchestrator, "shared/xoo-sample",
-      "sonar.projectKey", PROJECT_KEY,
-      "sonar.projectName", PROJECT_NAME);
-  }
-
-  private List<Webhooks.Delivery> getPersistedDeliveries() {
-    DeliveriesRequest deliveriesReq = new DeliveriesRequest().setComponentKey(PROJECT_KEY);
-    return adminWs.webhooks().deliveries(deliveriesReq).getDeliveriesList();
-  }
-
-  private Webhooks.Delivery getPersistedDeliveryByName(String webhookName) {
-    List<Webhooks.Delivery> deliveries = getPersistedDeliveries();
-    return deliveries.stream().filter(d -> d.getName().equals(webhookName)).findFirst().get();
-  }
-
-  private Webhooks.Delivery getDetailOfPersistedDelivery(Webhooks.Delivery delivery) {
-    Webhooks.Delivery detail = adminWs.webhooks().delivery(new DeliveryRequest().setDeliveryId(delivery.getId())).getDelivery();
-    return requireNonNull(detail);
-  }
-
-  private void assertThatPersistedDeliveryIsValid(Webhooks.Delivery delivery) {
-    assertThat(delivery.getId()).isNotEmpty();
-    assertThat(delivery.getName()).isNotEmpty();
-    assertThat(delivery.hasSuccess()).isTrue();
-    assertThat(delivery.getHttpStatus()).isGreaterThanOrEqualTo(200);
-    assertThat(delivery.getDurationMs()).isGreaterThanOrEqualTo(0);
-    assertThat(delivery.getAt()).isNotEmpty();
-    assertThat(delivery.getComponentKey()).isEqualTo(PROJECT_KEY);
-    assertThat(delivery.getUrl()).startsWith(externalServer.urlFor("/"));
-  }
-
-  private void enableGlobalWebhooks(Webhook... webhooks) {
-    enableWebhooks(null, GLOBAL_WEBHOOK_PROPERTY, webhooks);
-  }
-
-  private void enableProjectWebhooks(String projectKey, Webhook... webhooks) {
-    enableWebhooks(projectKey, PROJECT_WEBHOOK_PROPERTY, webhooks);
-  }
-
-  private void enableWebhooks(@Nullable String projectKey, String property, Webhook... webhooks) {
-    List<String> webhookIds = new ArrayList<>();
-    for (int i = 0; i < webhooks.length; i++) {
-      Webhook webhook = webhooks[i];
-      String id = String.valueOf(i + 1);
-      webhookIds.add(id);
-      setProperty(projectKey, property + "." + id + ".name", webhook.name);
-      setProperty(projectKey, property + "." + id + ".url", webhook.url);
-    }
-    setProperty(projectKey, property, StringUtils.join(webhookIds, ","));
+      "sonar.projectKey", project.getKey(),
+      "sonar.projectName", project.getName());
   }
-
-  private void disableGlobalWebhooks() {
-    setProperty(null, GLOBAL_WEBHOOK_PROPERTY, null);
-  }
-
-  private void setProperty(@Nullable String componentKey, String key, @Nullable String value) {
-    if (value == null) {
-      ResetRequest req = new ResetRequest().setKeys(Collections.singletonList(key)).setComponent(componentKey);
-      adminWs.settings().reset(req);
-    } else {
-      SetRequest req = new SetRequest().setKey(key).setValue(value).setComponent(componentKey);
-      adminWs.settings().set(req);
-    }
-  }
-
-  private static class Webhook {
-    private final String name;
-    private final String url;
-
-    Webhook(@Nullable String name, @Nullable String url) {
-      this.name = name;
-      this.url = url;
-    }
-  }
-
-  /**
-   * Wait up to 30 seconds
-   */
-  private static void waitUntilAllWebHooksCalled(int expectedNumberOfRequests) throws InterruptedException {
-    for (int i = 0; i < 60; i++) {
-      if (externalServer.getPayloadRequests().size() == expectedNumberOfRequests) {
-        break;
-      }
-      Thread.sleep(500);
-    }
-  }
-
 }