package org.sonar.db.webhook; | package org.sonar.db.webhook; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.Optional; | import java.util.Optional; | ||||
import org.apache.ibatis.session.RowBounds; | import org.apache.ibatis.session.RowBounds; | ||||
import org.sonar.db.Dao; | import org.sonar.db.Dao; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import static java.util.function.Function.identity; | |||||
import static java.util.stream.Collectors.toMap; | |||||
public class WebhookDeliveryDao implements Dao { | public class WebhookDeliveryDao implements Dao { | ||||
public Optional<WebhookDeliveryDto> selectByUuid(DbSession dbSession, String uuid) { | public Optional<WebhookDeliveryDto> selectByUuid(DbSession dbSession, String uuid) { | ||||
mapper(dbSession).deleteComponentBeforeDate(componentUuid, beforeDate); | mapper(dbSession).deleteComponentBeforeDate(componentUuid, beforeDate); | ||||
} | } | ||||
public Map<String, WebhookDeliveryLiteDto> selectLatestDeliveries(DbSession dbSession, List<WebhookDto> webhooks) { | |||||
return webhooks.stream() | |||||
.flatMap(webhook -> selectByWebhookUuid(dbSession, webhook.getUuid(),0,1).stream()) | |||||
.collect(toMap(WebhookDeliveryLiteDto::getWebhookUuid, identity())); | |||||
} | |||||
private static WebhookDeliveryMapper mapper(DbSession dbSession) { | private static WebhookDeliveryMapper mapper(DbSession dbSession) { | ||||
return dbSession.getMapper(WebhookDeliveryMapper.class); | return dbSession.getMapper(WebhookDeliveryMapper.class); | ||||
} | } |
import org.sonar.db.user.RootFlagAssertions; | import org.sonar.db.user.RootFlagAssertions; | ||||
import org.sonar.db.user.UserDbTester; | import org.sonar.db.user.UserDbTester; | ||||
import org.sonar.db.webhook.WebhookDbTester; | import org.sonar.db.webhook.WebhookDbTester; | ||||
import org.sonar.db.webhook.WebhookDeliveryDbTester; | |||||
import static com.google.common.base.Preconditions.checkState; | import static com.google.common.base.Preconditions.checkState; | ||||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | ||||
private final FileSourceTester fileSourceTester; | private final FileSourceTester fileSourceTester; | ||||
private final PluginDbTester pluginDbTester; | private final PluginDbTester pluginDbTester; | ||||
private final WebhookDbTester webhookDbTester; | private final WebhookDbTester webhookDbTester; | ||||
private final WebhookDeliveryDbTester webhookDeliveryDbTester; | |||||
public DbTester(System2 system2, @Nullable String schemaPath) { | public DbTester(System2 system2, @Nullable String schemaPath) { | ||||
super(TestDb.create(schemaPath)); | super(TestDb.create(schemaPath)); | ||||
this.fileSourceTester = new FileSourceTester(this); | this.fileSourceTester = new FileSourceTester(this); | ||||
this.pluginDbTester = new PluginDbTester(this); | this.pluginDbTester = new PluginDbTester(this); | ||||
this.webhookDbTester = new WebhookDbTester(this); | this.webhookDbTester = new WebhookDbTester(this); | ||||
this.webhookDeliveryDbTester = new WebhookDeliveryDbTester(this); | |||||
} | } | ||||
public static DbTester create() { | public static DbTester create() { | ||||
return webhookDbTester; | return webhookDbTester; | ||||
} | } | ||||
public WebhookDeliveryDbTester webhookDelivery() { | |||||
return webhookDeliveryDbTester; | |||||
} | |||||
@Override | @Override | ||||
protected void after() { | protected void after() { | ||||
if (session != null) { | if (session != null) { |
import static org.sonar.db.component.ComponentTesting.newFileDto; | import static org.sonar.db.component.ComponentTesting.newFileDto; | ||||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | import static org.sonar.db.component.ComponentTesting.newModuleDto; | ||||
import static org.sonar.db.component.ComponentTesting.newProjectCopy; | import static org.sonar.db.component.ComponentTesting.newProjectCopy; | ||||
import static org.sonar.db.webhook.WebhookDbTesting.newWebhookDeliveryDto; | |||||
import static org.sonar.db.webhook.WebhookDbTesting.newDto; | |||||
import static org.sonar.db.webhook.WebhookDbTesting.selectAllDeliveryUuids; | import static org.sonar.db.webhook.WebhookDbTesting.selectAllDeliveryUuids; | ||||
public class PurgeDaoTest { | public class PurgeDaoTest { | ||||
@Test | @Test | ||||
public void deleteProject_deletes_webhook_deliveries() { | public void deleteProject_deletes_webhook_deliveries() { | ||||
ComponentDto project = dbTester.components().insertPublicProject(); | ComponentDto project = dbTester.components().insertPublicProject(); | ||||
dbClient.webhookDeliveryDao().insert(dbSession, newWebhookDeliveryDto().setComponentUuid(project.uuid()).setUuid("D1")); | |||||
dbClient.webhookDeliveryDao().insert(dbSession, newWebhookDeliveryDto().setComponentUuid("P2").setUuid("D2")); | |||||
dbClient.webhookDeliveryDao().insert(dbSession, newDto().setComponentUuid(project.uuid()).setUuid("D1")); | |||||
dbClient.webhookDeliveryDao().insert(dbSession, newDto().setComponentUuid("P2").setUuid("D2")); | |||||
underTest.deleteProject(dbSession, project.uuid()); | underTest.deleteProject(dbSession, project.uuid()); | ||||
// only statics | // only statics | ||||
} | } | ||||
public static WebhookDeliveryDto newWebhookDeliveryDto() { | |||||
/** | |||||
* Build a {@link WebhookDeliveryDto} with all mandatory fields. | |||||
* Optional fields are kept null. | |||||
*/ | |||||
public static WebhookDeliveryDto newDto(String uuid, String webhookUuid, String componentUuid, String ceTaskUuid) { | |||||
return newDto() | |||||
.setUuid(uuid) | |||||
.setWebhookUuid(webhookUuid) | |||||
.setComponentUuid(componentUuid) | |||||
.setCeTaskUuid(ceTaskUuid); | |||||
} | |||||
public static WebhookDeliveryDto newDto() { | |||||
return new WebhookDeliveryDto() | return new WebhookDeliveryDto() | ||||
.setUuid(randomAlphanumeric(40)) | .setUuid(randomAlphanumeric(40)) | ||||
.setComponentUuid(randomAlphanumeric(40)) | .setComponentUuid(randomAlphanumeric(40)) |
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.DbTester; | import org.sonar.db.DbTester; | ||||
import static com.google.common.collect.ImmutableList.of; | |||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.sonar.db.webhook.WebhookDbTesting.newWebhookDeliveryDto; | |||||
import static org.sonar.db.webhook.WebhookTesting.newProjectWebhook; | |||||
public class WebhookDeliveryDaoTest { | public class WebhookDeliveryDaoTest { | ||||
@Test | @Test | ||||
public void selectOrderedByComponentUuid_returns_empty_if_no_records() { | public void selectOrderedByComponentUuid_returns_empty_if_no_records() { | ||||
underTest.insert(dbSession, newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")); | |||||
List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByComponentUuid(dbSession, "ANOTHER_COMPONENT", 0, 10); | List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByComponentUuid(dbSession, "ANOTHER_COMPONENT", 0, 10); | ||||
@Test | @Test | ||||
public void selectOrderedByComponentUuid_returns_records_ordered_by_date() { | public void selectOrderedByComponentUuid_returns_records_ordered_by_date() { | ||||
WebhookDeliveryDto dto1 = newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
WebhookDeliveryDto dto2 = newDto("D2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto3 = newDto("D3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_1").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto1 = WebhookDbTesting.newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
WebhookDeliveryDto dto2 = WebhookDbTesting.newDto("D2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto3 = WebhookDbTesting.newDto("D3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_1").setCreatedAt(NOW); | |||||
underTest.insert(dbSession, dto3); | underTest.insert(dbSession, dto3); | ||||
underTest.insert(dbSession, dto2); | underTest.insert(dbSession, dto2); | ||||
underTest.insert(dbSession, dto1); | underTest.insert(dbSession, dto1); | ||||
@Test | @Test | ||||
public void selectOrderedByCeTaskUuid_returns_empty_if_no_records() { | public void selectOrderedByCeTaskUuid_returns_empty_if_no_records() { | ||||
underTest.insert(dbSession, newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")); | |||||
List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "ANOTHER_TASK", 0, 10); | List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "ANOTHER_TASK", 0, 10); | ||||
@Test | @Test | ||||
public void selectOrderedByCeTaskUuid_returns_records_ordered_by_date() { | public void selectOrderedByCeTaskUuid_returns_records_ordered_by_date() { | ||||
WebhookDeliveryDto dto1 = newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
WebhookDeliveryDto dto2 = newDto("D2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto3 = newDto("D3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_2").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto1 = WebhookDbTesting.newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
WebhookDeliveryDto dto2 = WebhookDbTesting.newDto("D2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto3 = WebhookDbTesting.newDto("D3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_2").setCreatedAt(NOW); | |||||
underTest.insert(dbSession, dto3); | underTest.insert(dbSession, dto3); | ||||
underTest.insert(dbSession, dto2); | underTest.insert(dbSession, dto2); | ||||
underTest.insert(dbSession, dto1); | underTest.insert(dbSession, dto1); | ||||
@Test | @Test | ||||
public void selectByWebhookUuid_returns_empty_if_no_records() { | public void selectByWebhookUuid_returns_empty_if_no_records() { | ||||
underTest.insert(dbSession, newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")); | |||||
List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, "a-webhook-uuid", 0, 10); | List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, "a-webhook-uuid", 0, 10); | ||||
@Test | @Test | ||||
public void selectByWebhookUuid_returns_records_ordered_by_date() { | public void selectByWebhookUuid_returns_records_ordered_by_date() { | ||||
WebhookDto webhookDto = dbWebhooks.insert(WebhookTesting.newProjectWebhook("COMPONENT_1")); | WebhookDto webhookDto = dbWebhooks.insert(WebhookTesting.newProjectWebhook("COMPONENT_1")); | ||||
WebhookDeliveryDto dto1 = newDto("D1", webhookDto.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
WebhookDeliveryDto dto2 = newDto("D2", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto3 = newDto("D3", "fake-webhook-uuid", "COMPONENT_2", "TASK_1").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto1 = WebhookDbTesting.newDto("D1", webhookDto.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
WebhookDeliveryDto dto2 = WebhookDbTesting.newDto("D2", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW); | |||||
WebhookDeliveryDto dto3 = WebhookDbTesting.newDto("D3", "fake-webhook-uuid", "COMPONENT_2", "TASK_1").setCreatedAt(NOW); | |||||
underTest.insert(dbSession, dto3); | underTest.insert(dbSession, dto3); | ||||
underTest.insert(dbSession, dto2); | underTest.insert(dbSession, dto2); | ||||
underTest.insert(dbSession, dto1); | underTest.insert(dbSession, dto1); | ||||
@Test | @Test | ||||
public void selectByWebhookUuid_returns_records_according_to_pagination() { | public void selectByWebhookUuid_returns_records_according_to_pagination() { | ||||
WebhookDto webhookDto = dbWebhooks.insert(WebhookTesting.newProjectWebhook("COMPONENT_1")); | WebhookDto webhookDto = dbWebhooks.insert(WebhookTesting.newProjectWebhook("COMPONENT_1")); | ||||
WebhookDeliveryDto dto1 = newDto("D1", webhookDto.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE); | |||||
underTest.insert(dbSession, dto1); | |||||
WebhookDeliveryDto dto2 = newDto("D2", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW); | |||||
underTest.insert(dbSession, dto2); | |||||
underTest.insert(dbSession, newDto("D3", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
underTest.insert(dbSession, newDto("D4", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
underTest.insert(dbSession, newDto("D5", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
underTest.insert(dbSession, newDto("D6", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D1", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW - 5_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D2", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW - 4_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D3", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW - 3_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D4", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW - 2_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D5", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW - 1_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("D6", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, webhookDto.getUuid(), 1, 3); | |||||
List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, webhookDto.getUuid(), 2, 2); | |||||
assertThat(deliveries).extracting(WebhookDeliveryLiteDto::getUuid).containsExactlyInAnyOrder("D3", "D4", "D5"); | |||||
assertThat(deliveries).extracting(WebhookDeliveryLiteDto::getUuid).containsExactly("D4", "D3"); | |||||
} | } | ||||
@Test | |||||
public void selectLatestDelivery_of_a_webhook() { | |||||
WebhookDto webhook1 = dbWebhooks.insert(newProjectWebhook("COMPONENT_1")); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("WH1-DELIVERY-1-UUID", webhook1.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("WH1-DELIVERY-2-UUID", webhook1.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
WebhookDto webhook2 = dbWebhooks.insert(newProjectWebhook("COMPONENT_1")); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("WH2-DELIVERY-1-UUID", webhook2.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("WH2-DELIVERY-2-UUID", webhook2.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
Map<String, WebhookDeliveryLiteDto> map = underTest.selectLatestDeliveries(dbSession, of(webhook1, webhook2)); | |||||
assertThat(map).containsKeys(webhook1.getUuid()); | |||||
assertThat(map.get(webhook1.getUuid())).extracting(WebhookDeliveryLiteDto::getUuid).contains("WH1-DELIVERY-2-UUID"); | |||||
assertThat(map).containsKeys(webhook2.getUuid()); | |||||
assertThat(map.get(webhook2.getUuid())).extracting(WebhookDeliveryLiteDto::getUuid).contains("WH2-DELIVERY-2-UUID"); | |||||
} | |||||
@Test | @Test | ||||
public void insert_row_with_only_mandatory_columns() { | public void insert_row_with_only_mandatory_columns() { | ||||
WebhookDeliveryDto dto = newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1") | |||||
WebhookDeliveryDto dto = WebhookDbTesting.newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1") | |||||
.setHttpStatus(null) | .setHttpStatus(null) | ||||
.setDurationMs(null) | .setDurationMs(null) | ||||
.setErrorStacktrace(null); | .setErrorStacktrace(null); | ||||
@Test | @Test | ||||
public void insert_row_with_all_columns() { | public void insert_row_with_all_columns() { | ||||
WebhookDeliveryDto dto = newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1"); | |||||
WebhookDeliveryDto dto = WebhookDbTesting.newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1"); | |||||
underTest.insert(dbSession, dto); | underTest.insert(dbSession, dto); | ||||
@Test | @Test | ||||
public void deleteComponentBeforeDate_deletes_rows_before_date() { | public void deleteComponentBeforeDate_deletes_rows_before_date() { | ||||
underTest.insert(dbSession, newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L)); | |||||
underTest.insert(dbSession, newDto("DELIVERY_2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_2").setCreatedAt(2_000_000L)); | |||||
underTest.insert(dbSession, newDto("DELIVERY_3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_3").setCreatedAt(1_000_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("DELIVERY_2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_2").setCreatedAt(2_000_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("DELIVERY_3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_3").setCreatedAt(1_000_000L)); | |||||
// should delete the old delivery on COMPONENT_1 and keep the one of COMPONENT_2 | // should delete the old delivery on COMPONENT_1 and keep the one of COMPONENT_2 | ||||
underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_1", 1_500_000L); | underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_1", 1_500_000L); | ||||
@Test | @Test | ||||
public void deleteComponentBeforeDate_does_nothing_on_invalid_uuid() { | public void deleteComponentBeforeDate_does_nothing_on_invalid_uuid() { | ||||
underTest.insert(dbSession, newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L)); | |||||
underTest.insert(dbSession, WebhookDbTesting.newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L)); | |||||
underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_2", 1_500_000L); | underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_2", 1_500_000L); | ||||
assertThat(actual.getCreatedAt()).isEqualTo(expected.getCreatedAt()); | assertThat(actual.getCreatedAt()).isEqualTo(expected.getCreatedAt()); | ||||
} | } | ||||
/** | |||||
* Build a {@link WebhookDeliveryDto} with all mandatory fields. | |||||
* Optional fields are kept null. | |||||
*/ | |||||
private static WebhookDeliveryDto newDto(String uuid, String webhookUuid, String componentUuid, String ceTaskUuid) { | |||||
return newWebhookDeliveryDto() | |||||
.setUuid(uuid) | |||||
.setWebhookUuid(webhookUuid) | |||||
.setComponentUuid(componentUuid) | |||||
.setCeTaskUuid(ceTaskUuid); | |||||
} | |||||
private WebhookDeliveryDto selectByUuid(String uuid) { | private WebhookDeliveryDto selectByUuid(String uuid) { | ||||
Optional<WebhookDeliveryDto> dto = underTest.selectByUuid(dbSession, uuid); | Optional<WebhookDeliveryDto> dto = underTest.selectByUuid(dbSession, uuid); | ||||
assertThat(dto).isPresent(); | assertThat(dto).isPresent(); |
/* | |||||
* 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.sonar.db.webhook; | |||||
import org.sonar.db.DbSession; | |||||
import org.sonar.db.DbTester; | |||||
public class WebhookDeliveryDbTester { | |||||
private final DbTester dbTester; | |||||
public WebhookDeliveryDbTester(DbTester dbTester) { | |||||
this.dbTester = dbTester; | |||||
} | |||||
public WebhookDeliveryLiteDto insert(WebhookDeliveryDto dto) { | |||||
DbSession dbSession = dbTester.getSession(); | |||||
dbTester.getDbClient().webhookDeliveryDao().insert(dbSession, dto); | |||||
dbSession.commit(); | |||||
return dto; | |||||
} | |||||
} |
*/ | */ | ||||
package org.sonar.db.webhook; | package org.sonar.db.webhook; | ||||
import java.util.Calendar; | |||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.organization.OrganizationDto; | import org.sonar.db.organization.OrganizationDto; | ||||
import java.util.Calendar; | |||||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | ||||
public class WebhookTesting { | public class WebhookTesting { | ||||
.setOrganizationUuid(organizationDto.getUuid()); | .setOrganizationUuid(organizationDto.getUuid()); | ||||
} | } | ||||
public static WebhookDto newOrganizationWebhook(String name, String organizationUuid) { | |||||
return getWebhookDto() | |||||
.setName(name) | |||||
.setOrganizationUuid(organizationUuid); | |||||
} | |||||
private static WebhookDto getWebhookDto() { | private static WebhookDto getWebhookDto() { | ||||
return new WebhookDto() | return new WebhookDto() | ||||
.setUuid(randomAlphanumeric(40)) | .setUuid(randomAlphanumeric(40)) |
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.function.Function; | import java.util.function.Function; | ||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.server.platform.db.migration.step.DataChange; | import org.sonar.server.platform.db.migration.step.DataChange; | ||||
import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProvider; | import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProvider; | ||||
import static com.google.common.base.Preconditions.checkNotNull; | |||||
import static java.util.stream.Collectors.toList; | import static java.util.stream.Collectors.toList; | ||||
import static java.util.stream.Collectors.toMap; | import static java.util.stream.Collectors.toMap; | ||||
for (String value : values) { | for (String value : values) { | ||||
PropertyRow name = properties.get("sonar.webhooks.project." + value + ".name"); | PropertyRow name = properties.get("sonar.webhooks.project." + value + ".name"); | ||||
PropertyRow url = properties.get("sonar.webhooks.project." + value + ".url"); | PropertyRow url = properties.get("sonar.webhooks.project." + value + ".url"); | ||||
webhooks.add(new Webhook(name, url, null, projectUuidOf(context, name))); | |||||
String projectUuid = checkNotNull(projectUuidOf(context, name), "Project was not found for property : sonar.webhooks.project.%s", value); | |||||
webhooks.add(new Webhook(name, url, null, projectUuid)); | |||||
} | } | ||||
return webhooks; | return webhooks; | ||||
} | } | ||||
@CheckForNull | |||||
private static String projectUuidOf(Context context, PropertyRow row) throws SQLException { | private static String projectUuidOf(Context context, PropertyRow row) throws SQLException { | ||||
return context | return context | ||||
.prepareSelect("select uuid from projects where id = ?") | .prepareSelect("select uuid from projects where id = ?") |
Request request = buildHttpRequest(webhook, payload); | Request request = buildHttpRequest(webhook, payload); | ||||
try (Response response = execute(request)) { | try (Response response = execute(request)) { | ||||
builder.setHttpStatus(response.code()); | builder.setHttpStatus(response.code()); | ||||
builder.setDurationInMs((int) (system.now() - startedAt)); | |||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
builder.setError(e); | builder.setError(e); | ||||
} | } | ||||
return builder.build(); | |||||
return builder | |||||
.setDurationInMs((int) (system.now() - startedAt)) | |||||
.build(); | |||||
} | } | ||||
private static Request buildHttpRequest(Webhook webhook, WebhookPayload payload) { | private static Request buildHttpRequest(Webhook webhook, WebhookPayload payload) { |
import com.google.common.io.Resources; | import com.google.common.io.Resources; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.Optional; | import java.util.Optional; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.api.server.ws.Request; | import org.sonar.api.server.ws.Request; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.organization.OrganizationDto; | import org.sonar.db.organization.OrganizationDto; | ||||
import org.sonar.db.webhook.WebhookDeliveryLiteDto; | |||||
import org.sonar.db.webhook.WebhookDto; | import org.sonar.db.webhook.WebhookDto; | ||||
import org.sonar.server.organization.DefaultOrganizationProvider; | import org.sonar.server.organization.DefaultOrganizationProvider; | ||||
import org.sonar.server.user.UserSession; | import org.sonar.server.user.UserSession; | ||||
import org.sonarqube.ws.Webhooks.ListWsResponse.Builder; | |||||
import org.sonarqube.ws.Webhooks; | |||||
import org.sonarqube.ws.Webhooks.ListResponse; | |||||
import org.sonarqube.ws.Webhooks.ListResponseElement; | |||||
import static java.util.Optional.ofNullable; | import static java.util.Optional.ofNullable; | ||||
import static org.apache.commons.lang.StringUtils.isNotBlank; | import static org.apache.commons.lang.StringUtils.isNotBlank; | ||||
import static org.sonar.api.utils.DateUtils.formatDateTime; | |||||
import static org.sonar.server.webhook.ws.WebhooksWsParameters.LIST_ACTION; | import static org.sonar.server.webhook.ws.WebhooksWsParameters.LIST_ACTION; | ||||
import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM; | import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM; | ||||
import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM; | import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM; | ||||
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; | import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; | ||||
import static org.sonar.server.ws.WsUtils.checkStateWithOptional; | import static org.sonar.server.ws.WsUtils.checkStateWithOptional; | ||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | import static org.sonar.server.ws.WsUtils.writeProtobuf; | ||||
import static org.sonarqube.ws.Webhooks.ListWsResponse.newBuilder; | |||||
public class ListAction implements WebhooksWsAction { | public class ListAction implements WebhooksWsAction { | ||||
userSession.checkLoggedIn(); | userSession.checkLoggedIn(); | ||||
writeResponse(request, response, doHandle(organizationKey, projectKey)); | |||||
try (DbSession dbSession = dbClient.openSession(true)) { | |||||
List<WebhookDto> webhookDtos = doHandle(dbSession, organizationKey, projectKey); | |||||
Map<String, WebhookDeliveryLiteDto> lastDeliveries = loadLastDeliveriesOf(dbSession, webhookDtos); | |||||
writeResponse(request, response, webhookDtos, lastDeliveries); | |||||
} | |||||
} | } | ||||
private List<WebhookDto> doHandle(@Nullable String organizationKey, @Nullable String projectKey) { | |||||
try (DbSession dbSession = dbClient.openSession(true)) { | |||||
private Map<String, WebhookDeliveryLiteDto> loadLastDeliveriesOf(DbSession dbSession, List<WebhookDto> webhookDtos) { | |||||
return dbClient.webhookDeliveryDao().selectLatestDeliveries(dbSession, webhookDtos); | |||||
} | |||||
OrganizationDto organizationDto; | |||||
if (isNotBlank(organizationKey)) { | |||||
Optional<OrganizationDto> dtoOptional = dbClient.organizationDao().selectByKey(dbSession, organizationKey); | |||||
organizationDto = checkFoundWithOptional(dtoOptional, "No organization with key '%s'", organizationKey); | |||||
} else { | |||||
organizationDto = defaultOrganizationDto(dbSession); | |||||
} | |||||
private List<WebhookDto> doHandle(DbSession dbSession, @Nullable String organizationKey, @Nullable String projectKey) { | |||||
if (isNotBlank(projectKey)) { | |||||
OrganizationDto organizationDto; | |||||
if (isNotBlank(organizationKey)) { | |||||
Optional<OrganizationDto> dtoOptional = dbClient.organizationDao().selectByKey(dbSession, organizationKey); | |||||
organizationDto = checkFoundWithOptional(dtoOptional, "No organization with key '%s'", organizationKey); | |||||
} else { | |||||
organizationDto = defaultOrganizationDto(dbSession); | |||||
} | |||||
Optional<ComponentDto> optional = ofNullable(dbClient.componentDao().selectByKey(dbSession, projectKey).orNull()); | |||||
ComponentDto componentDto = checkFoundWithOptional(optional, "project %s does not exist", projectKey); | |||||
webhookSupport.checkPermission(componentDto); | |||||
webhookSupport.checkThatProjectBelongsToOrganization(componentDto, organizationDto, "Project '%s' does not belong to organisation '%s'", projectKey, organizationKey); | |||||
webhookSupport.checkPermission(componentDto); | |||||
return dbClient.webhookDao().selectByProject(dbSession, componentDto); | |||||
if (isNotBlank(projectKey)) { | |||||
} else { | |||||
Optional<ComponentDto> optional = ofNullable(dbClient.componentDao().selectByKey(dbSession, projectKey).orNull()); | |||||
ComponentDto componentDto = checkFoundWithOptional(optional, "project %s does not exist", projectKey); | |||||
webhookSupport.checkPermission(componentDto); | |||||
webhookSupport.checkThatProjectBelongsToOrganization(componentDto, organizationDto, "Project '%s' does not belong to organisation '%s'", projectKey, organizationKey); | |||||
webhookSupport.checkPermission(componentDto); | |||||
return dbClient.webhookDao().selectByProject(dbSession, componentDto); | |||||
webhookSupport.checkPermission(organizationDto); | |||||
return dbClient.webhookDao().selectByOrganization(dbSession, organizationDto); | |||||
} else { | |||||
} | |||||
webhookSupport.checkPermission(organizationDto); | |||||
return dbClient.webhookDao().selectByOrganization(dbSession, organizationDto); | |||||
} | } | ||||
} | |||||
private static void writeResponse(Request request, Response response, List<WebhookDto> webhookDtos) { | |||||
Builder responseBuilder = newBuilder(); | |||||
} | |||||
private static void writeResponse(Request request, Response response, List<WebhookDto> webhookDtos, Map<String, WebhookDeliveryLiteDto> lastDeliveries) { | |||||
ListResponse.Builder responseBuilder = ListResponse.newBuilder(); | |||||
webhookDtos | webhookDtos | ||||
.stream() | .stream() | ||||
.forEach(webhook -> responseBuilder.addWebhooksBuilder() | |||||
.setKey(webhook.getUuid()) | |||||
.setName(webhook.getName()) | |||||
.setUrl(webhook.getUrl())); | |||||
.forEach(webhook -> { | |||||
ListResponseElement.Builder responseElementBuilder = responseBuilder.addWebhooksBuilder(); | |||||
responseElementBuilder | |||||
.setKey(webhook.getUuid()) | |||||
.setName(webhook.getName()) | |||||
.setUrl(webhook.getUrl()); | |||||
addLastDelivery(responseElementBuilder, webhook, lastDeliveries); | |||||
}); | |||||
writeProtobuf(responseBuilder.build(), request, response); | writeProtobuf(responseBuilder.build(), request, response); | ||||
} | } | ||||
private static void addLastDelivery(ListResponseElement.Builder responseElementBuilder, WebhookDto webhook, Map<String, WebhookDeliveryLiteDto> lastDeliveries) { | |||||
if (lastDeliveries.containsKey(webhook.getUuid())) { | |||||
WebhookDeliveryLiteDto delivery = lastDeliveries.get(webhook.getUuid()); | |||||
Webhooks.LatestDelivery.Builder builder = responseElementBuilder.getLatestDeliveryBuilder() | |||||
.setId(delivery.getUuid()) | |||||
.setAt(formatDateTime(delivery.getCreatedAt())) | |||||
.setSuccess(delivery.isSuccess()); | |||||
if (delivery.getHttpStatus() != null) { | |||||
builder.setHttpStatus(delivery.getHttpStatus()); | |||||
} | |||||
if (delivery.getDurationMs() != null) { | |||||
builder.setDurationMs(delivery.getDurationMs()); | |||||
} | |||||
builder.build(); | |||||
} | |||||
} | |||||
private OrganizationDto defaultOrganizationDto(DbSession dbSession) { | private OrganizationDto defaultOrganizationDto(DbSession dbSession) { | ||||
String uuid = defaultOrganizationProvider.get().getUuid(); | String uuid = defaultOrganizationProvider.get().getUuid(); | ||||
Optional<OrganizationDto> organizationDto = dbClient.organizationDao().selectByUuid(dbSession, uuid); | Optional<OrganizationDto> organizationDto = dbClient.organizationDao().selectByUuid(dbSession, uuid); |
import static org.apache.commons.lang.StringUtils.isNotBlank; | import static org.apache.commons.lang.StringUtils.isNotBlank; | ||||
import static org.sonar.api.server.ws.WebService.Param.PAGE; | import static org.sonar.api.server.ws.WebService.Param.PAGE; | ||||
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; | import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; | ||||
import static org.sonar.api.utils.Paging.offset; | |||||
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02; | import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02; | ||||
import static org.sonar.server.es.SearchOptions.MAX_LIMIT; | import static org.sonar.server.es.SearchOptions.MAX_LIMIT; | ||||
import static org.sonar.server.webhook.ws.WebhookWsSupport.copyDtoToProtobuf; | import static org.sonar.server.webhook.ws.WebhookWsSupport.copyDtoToProtobuf; | ||||
int totalElements; | int totalElements; | ||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
if (isNotBlank(webhookUuid)) { | if (isNotBlank(webhookUuid)) { | ||||
deliveries = dbClient.webhookDeliveryDao().selectByWebhookUuid(dbSession, webhookUuid, page - 1, pageSize); | |||||
component = getComponentDto(dbSession, deliveries); | |||||
totalElements = dbClient.webhookDeliveryDao().countDeliveriesByWebhookUuid(dbSession, webhookUuid); | totalElements = dbClient.webhookDeliveryDao().countDeliveriesByWebhookUuid(dbSession, webhookUuid); | ||||
deliveries = dbClient.webhookDeliveryDao().selectByWebhookUuid(dbSession, webhookUuid, offset(page, pageSize), pageSize); | |||||
component = getComponentDto(dbSession, deliveries); | |||||
} else if (componentKey != null) { | } else if (componentKey != null) { | ||||
component = componentFinder.getByKey(dbSession, componentKey); | component = componentFinder.getByKey(dbSession, componentKey); | ||||
deliveries = dbClient.webhookDeliveryDao().selectOrderedByComponentUuid(dbSession, component.uuid(), page - 1, pageSize); | |||||
totalElements = dbClient.webhookDeliveryDao().countDeliveriesByComponentUuid(dbSession, component.uuid()); | totalElements = dbClient.webhookDeliveryDao().countDeliveriesByComponentUuid(dbSession, component.uuid()); | ||||
deliveries = dbClient.webhookDeliveryDao().selectOrderedByComponentUuid(dbSession, component.uuid(), offset(page, pageSize), pageSize); | |||||
} else { | } else { | ||||
deliveries = dbClient.webhookDeliveryDao().selectOrderedByCeTaskUuid(dbSession, ceTaskId, page - 1, pageSize); | |||||
component = getComponentDto(dbSession, deliveries); | |||||
totalElements = dbClient.webhookDeliveryDao().countDeliveriesByCeTaskUuid(dbSession, ceTaskId); | totalElements = dbClient.webhookDeliveryDao().countDeliveriesByCeTaskUuid(dbSession, ceTaskId); | ||||
deliveries = dbClient.webhookDeliveryDao().selectOrderedByCeTaskUuid(dbSession, ceTaskId, offset(page, pageSize), pageSize); | |||||
component = getComponentDto(dbSession, deliveries); | |||||
} | } | ||||
} | } | ||||
return new Data(component, deliveries).withPagingInfo(page, pageSize, totalElements); | return new Data(component, deliveries).withPagingInfo(page, pageSize, totalElements); |
{ | { | ||||
"paging": { | |||||
"pageIndex": 1, | |||||
"pageSize": 10, | |||||
"total": 1 | |||||
}, | |||||
"deliveries": [ | "deliveries": [ | ||||
{ | { | ||||
"id": "d1", | "id": "d1", | ||||
"durationMs": 10 | "durationMs": 10 | ||||
} | } | ||||
] | ] | ||||
} | |||||
} |
{ | { | ||||
"paging": { | |||||
"pageIndex": 1, | |||||
"pageSize": 10, | |||||
"total": 1 | |||||
}, | |||||
"deliveries": [ | |||||
{ | |||||
"id": "d1", | |||||
"componentKey": "my-project", | |||||
"ceTaskId": "task-1", | |||||
"name": "Jenkins", | |||||
"url": "http://jenkins", | |||||
"at": "2017-07-14T04:40:00+0200", | |||||
"success": true, | |||||
"httpStatus": 200, | |||||
"durationMs": 10 | |||||
} | |||||
] | |||||
} | |||||
"delivery": { | |||||
"id": "d1", | |||||
"componentKey": "my-project", | |||||
"ceTaskId": "task-1", | |||||
"name": "Jenkins", | |||||
"url": "http://jenkins", | |||||
"at": "2017-07-14T04:40:00+0200", | |||||
"success": true, | |||||
"httpStatus": 200, | |||||
"durationMs": 10, | |||||
"payload": "{\"status\"=\"SUCCESS\"}" | |||||
} | |||||
} |
WebhookDelivery delivery = newSender().call(webhook, PAYLOAD); | WebhookDelivery delivery = newSender().call(webhook, PAYLOAD); | ||||
assertThat(delivery.getHttpStatus()).isEmpty(); | assertThat(delivery.getHttpStatus()).isEmpty(); | ||||
assertThat(delivery.getDurationInMs()).isEmpty(); | |||||
assertThat(delivery.getDurationInMs().get()).isGreaterThanOrEqualTo(0); | |||||
// message can be "Connection refused" or "connect timed out" | // message can be "Connection refused" or "connect timed out" | ||||
assertThat(delivery.getErrorMessage().get()).matches("(.*Connection refused.*)|(.*connect timed out.*)"); | assertThat(delivery.getErrorMessage().get()).matches("(.*Connection refused.*)|(.*connect timed out.*)"); | ||||
assertThat(delivery.getAt()).isEqualTo(NOW); | assertThat(delivery.getAt()).isEqualTo(NOW); | ||||
WebhookDelivery delivery = newSender().call(webhook, PAYLOAD); | WebhookDelivery delivery = newSender().call(webhook, PAYLOAD); | ||||
assertThat(delivery.getHttpStatus()).isEmpty(); | assertThat(delivery.getHttpStatus()).isEmpty(); | ||||
assertThat(delivery.getDurationInMs()).isEmpty(); | |||||
assertThat(delivery.getDurationInMs().get()).isGreaterThanOrEqualTo(0); | |||||
assertThat(delivery.getError().get()).isInstanceOf(IllegalArgumentException.class); | assertThat(delivery.getError().get()).isInstanceOf(IllegalArgumentException.class); | ||||
assertThat(delivery.getErrorMessage().get()).isEqualTo("Webhook URL is not valid: this_is_not_an_url"); | assertThat(delivery.getErrorMessage().get()).isEqualTo("Webhook URL is not valid: this_is_not_an_url"); | ||||
assertThat(delivery.getAt()).isEqualTo(NOW); | assertThat(delivery.getAt()).isEqualTo(NOW); |
import org.sonar.db.DbClient; | import org.sonar.db.DbClient; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.DbTester; | import org.sonar.db.DbTester; | ||||
import org.sonar.db.webhook.WebhookDbTesting; | |||||
import org.sonar.db.webhook.WebhookDeliveryDto; | import org.sonar.db.webhook.WebhookDeliveryDto; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||
import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||
import static org.sonar.db.webhook.WebhookDbTesting.newWebhookDeliveryDto; | |||||
import static org.sonar.db.webhook.WebhookDbTesting.newDto; | |||||
import static org.sonar.db.webhook.WebhookDbTesting.selectAllDeliveryUuids; | import static org.sonar.db.webhook.WebhookDbTesting.selectAllDeliveryUuids; | ||||
public class WebhookDeliveryStorageTest { | public class WebhookDeliveryStorageTest { | ||||
} | } | ||||
private static WebhookDeliveryDto newDto(String uuid, String componentUuid, long at) { | private static WebhookDeliveryDto newDto(String uuid, String componentUuid, long at) { | ||||
return newWebhookDeliveryDto() | |||||
return WebhookDbTesting.newDto() | |||||
.setUuid(uuid) | .setUuid(uuid) | ||||
.setComponentUuid(componentUuid) | .setComponentUuid(componentUuid) | ||||
.setCreatedAt(at); | .setCreatedAt(at); |
*/ | */ | ||||
package org.sonar.server.webhook.ws; | package org.sonar.server.webhook.ws; | ||||
import java.util.List; | |||||
import org.junit.Rule; | import org.junit.Rule; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.junit.rules.ExpectedException; | import org.junit.rules.ExpectedException; | ||||
import org.sonar.db.organization.OrganizationDbTester; | import org.sonar.db.organization.OrganizationDbTester; | ||||
import org.sonar.db.organization.OrganizationDto; | import org.sonar.db.organization.OrganizationDto; | ||||
import org.sonar.db.webhook.WebhookDbTester; | import org.sonar.db.webhook.WebhookDbTester; | ||||
import org.sonar.db.webhook.WebhookDeliveryDbTester; | |||||
import org.sonar.db.webhook.WebhookDto; | import org.sonar.db.webhook.WebhookDto; | ||||
import org.sonar.server.exceptions.ForbiddenException; | import org.sonar.server.exceptions.ForbiddenException; | ||||
import org.sonar.server.exceptions.NotFoundException; | import org.sonar.server.exceptions.NotFoundException; | ||||
import org.sonar.server.organization.DefaultOrganizationProvider; | import org.sonar.server.organization.DefaultOrganizationProvider; | ||||
import org.sonar.server.tester.UserSessionRule; | import org.sonar.server.tester.UserSessionRule; | ||||
import org.sonar.server.ws.WsActionTester; | import org.sonar.server.ws.WsActionTester; | ||||
import org.sonarqube.ws.Webhooks.ListWsResponse; | |||||
import org.sonarqube.ws.Webhooks.ListWsResponse.List; | |||||
import org.sonarqube.ws.Webhooks; | |||||
import org.sonarqube.ws.Webhooks.ListResponse; | |||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.sonar.api.web.UserRole.ADMIN; | import static org.sonar.api.web.UserRole.ADMIN; | ||||
import static org.sonar.db.DbTester.create; | import static org.sonar.db.DbTester.create; | ||||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | ||||
import static org.sonar.db.webhook.WebhookDbTesting.newDto; | |||||
import static org.sonar.db.webhook.WebhookTesting.newOrganizationWebhook; | |||||
import static org.sonar.server.organization.TestDefaultOrganizationProvider.from; | import static org.sonar.server.organization.TestDefaultOrganizationProvider.from; | ||||
import static org.sonar.server.tester.UserSessionRule.standalone; | import static org.sonar.server.tester.UserSessionRule.standalone; | ||||
import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM; | import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM; | ||||
public class ListActionTest { | public class ListActionTest { | ||||
@Rule | |||||
public ExpectedException expectedException = none(); | |||||
private static final long NOW = 1_500_000_000L; | |||||
private static final long BEFORE = NOW - 1_000L; | |||||
@Rule | |||||
public UserSessionRule userSession = standalone(); | |||||
@Rule | |||||
public ExpectedException expectedException = none(); | |||||
@Rule | |||||
public DbTester db = create(); | |||||
@Rule | |||||
public UserSessionRule userSession = standalone(); | |||||
private DbClient dbClient = db.getDbClient(); | |||||
private DefaultOrganizationProvider defaultOrganizationProvider = from(db); | |||||
private WebhookSupport webhookSupport = new WebhookSupport(userSession); | |||||
private ListAction underTest = new ListAction(dbClient, userSession, defaultOrganizationProvider, webhookSupport); | |||||
@Rule | |||||
public DbTester db = create(); | |||||
private ComponentDbTester componentDbTester = db.components(); | |||||
private WebhookDbTester webhookDbTester = db.webhooks(); | |||||
private OrganizationDbTester organizationDbTester = db.organizations(); | |||||
private WsActionTester wsActionTester = new WsActionTester(underTest); | |||||
private DbClient dbClient = db.getDbClient(); | |||||
private DefaultOrganizationProvider defaultOrganizationProvider = from(db); | |||||
private WebhookSupport webhookSupport = new WebhookSupport(userSession); | |||||
private ListAction underTest = new ListAction(dbClient, userSession, defaultOrganizationProvider, webhookSupport); | |||||
@Test | |||||
public void definition() { | |||||
private ComponentDbTester componentDbTester = db.components(); | |||||
private WebhookDbTester webhookDbTester = db.webhooks(); | |||||
private WebhookDeliveryDbTester webhookDeliveryDbTester = db.webhookDelivery(); | |||||
private OrganizationDbTester organizationDbTester = db.organizations(); | |||||
private WsActionTester wsActionTester = new WsActionTester(underTest); | |||||
WebService.Action action = wsActionTester.getDef(); | |||||
@Test | |||||
public void definition() { | |||||
assertThat(action).isNotNull(); | |||||
assertThat(action.isInternal()).isFalse(); | |||||
assertThat(action.isPost()).isFalse(); | |||||
assertThat(action.responseExampleAsString()).isNotEmpty(); | |||||
assertThat(action.params()) | |||||
.extracting(Param::key, Param::isRequired) | |||||
.containsExactlyInAnyOrder( | |||||
tuple("organization", false), | |||||
tuple("project", false)); | |||||
WebService.Action action = wsActionTester.getDef(); | |||||
} | |||||
assertThat(action).isNotNull(); | |||||
assertThat(action.isInternal()).isFalse(); | |||||
assertThat(action.isPost()).isFalse(); | |||||
assertThat(action.responseExampleAsString()).isNotEmpty(); | |||||
assertThat(action.params()) | |||||
.extracting(Param::key, Param::isRequired) | |||||
.containsExactlyInAnyOrder( | |||||
tuple("organization", false), | |||||
tuple("project", false)); | |||||
@Test | |||||
public void List_global_webhooks() { | |||||
} | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(db.getDefaultOrganization()); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(db.getDefaultOrganization()); | |||||
userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization().getUuid()); | |||||
@Test | |||||
public void list_webhooks_and_their_latest_delivery() { | |||||
WebhookDto webhook1 = webhookDbTester.insert(newOrganizationWebhook("aaa", defaultOrganizationProvider.get().getUuid())); | |||||
webhookDeliveryDbTester.insert(newDto("WH1-DELIVERY-1-UUID", webhook1.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE)); | |||||
webhookDeliveryDbTester.insert(newDto("WH1-DELIVERY-2-UUID", webhook1.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
ListWsResponse response = wsActionTester.newRequest() | |||||
.executeProtobuf(ListWsResponse.class); | |||||
WebhookDto webhook2 = webhookDbTester.insert(newOrganizationWebhook("bbb", defaultOrganizationProvider.get().getUuid())); | |||||
webhookDeliveryDbTester.insert(newDto("WH2-DELIVERY-1-UUID", webhook2.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE)); | |||||
webhookDeliveryDbTester.insert(newDto("WH2-DELIVERY-2-UUID", webhook2.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW)); | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(List::getName, List::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization().getUuid()); | |||||
} | |||||
ListResponse response = wsActionTester.newRequest().executeProtobuf(ListResponse.class); | |||||
@Test | |||||
public void List_project_webhooks_when_no_organization_is_provided() { | |||||
List<Webhooks.ListResponseElement> elements = response.getWebhooksList(); | |||||
assertThat(elements.size()).isEqualTo(2); | |||||
ComponentDto project1 = componentDbTester.insertPrivateProject(); | |||||
userSession.logIn().addProjectPermission(ADMIN, project1); | |||||
assertThat(elements.get(0)).extracting(Webhooks.ListResponseElement::getKey).containsExactly(webhook1.getUuid()); | |||||
assertThat(elements.get(0)).extracting(Webhooks.ListResponseElement::getName).containsExactly("aaa"); | |||||
assertThat(elements.get(0).getLatestDelivery()).isNotNull(); | |||||
assertThat(elements.get(0).getLatestDelivery()).extracting(Webhooks.LatestDelivery::getId).containsExactly("WH1-DELIVERY-2-UUID"); | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(project1); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(project1); | |||||
assertThat(elements.get(1)).extracting(Webhooks.ListResponseElement::getKey).containsExactly(webhook2.getUuid()); | |||||
assertThat(elements.get(1)).extracting(Webhooks.ListResponseElement::getName).containsExactly("bbb"); | |||||
assertThat(elements.get(1).getLatestDelivery()).isNotNull(); | |||||
assertThat(elements.get(1).getLatestDelivery()).extracting(Webhooks.LatestDelivery::getId).containsExactly("WH2-DELIVERY-2-UUID"); | |||||
} | |||||
ListWsResponse response = wsActionTester.newRequest() | |||||
.setParam(PROJECT_KEY_PARAM, project1.getKey()) | |||||
.executeProtobuf(ListWsResponse.class); | |||||
@Test | |||||
public void list_webhooks_when_no_delivery() { | |||||
WebhookDto webhook1 = webhookDbTester.insert(newOrganizationWebhook("aaa", defaultOrganizationProvider.get().getUuid())); | |||||
WebhookDto webhook2 = webhookDbTester.insert(newOrganizationWebhook("bbb", defaultOrganizationProvider.get().getUuid())); | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(List::getName, List::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization().getUuid()); | |||||
} | |||||
ListResponse response = wsActionTester.newRequest().executeProtobuf(ListResponse.class); | |||||
@Test | |||||
public void List_organization_webhooks() { | |||||
List<Webhooks.ListResponseElement> elements = response.getWebhooksList(); | |||||
assertThat(elements.size()).isEqualTo(2); | |||||
OrganizationDto organizationDto = organizationDbTester.insert(); | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(organizationDto); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(organizationDto); | |||||
userSession.logIn().addPermission(ADMINISTER, organizationDto.getUuid()); | |||||
assertThat(elements.get(0)).extracting(Webhooks.ListResponseElement::getKey).containsExactly(webhook1.getUuid()); | |||||
assertThat(elements.get(0)).extracting(Webhooks.ListResponseElement::getName).containsExactly("aaa"); | |||||
assertThat(elements.get(0).hasLatestDelivery()).isFalse(); | |||||
ListWsResponse response = wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, organizationDto.getKey()) | |||||
.executeProtobuf(ListWsResponse.class); | |||||
assertThat(elements.get(1)).extracting(Webhooks.ListResponseElement::getKey).containsExactly(webhook2.getUuid()); | |||||
assertThat(elements.get(1)).extracting(Webhooks.ListResponseElement::getName).containsExactly("bbb"); | |||||
assertThat(elements.get(1).hasLatestDelivery()).isFalse(); | |||||
} | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(List::getName, List::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
@Test | |||||
public void list_global_webhooks() { | |||||
} | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(db.getDefaultOrganization()); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(db.getDefaultOrganization()); | |||||
userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization().getUuid()); | |||||
@Test | |||||
public void List_project_webhooks_when_organization_is_provided() { | |||||
ListResponse response = wsActionTester.newRequest() | |||||
.executeProtobuf(ListResponse.class); | |||||
OrganizationDto organization = organizationDbTester.insert(); | |||||
ComponentDto project = componentDbTester.insertPrivateProject(organization); | |||||
userSession.logIn().addProjectPermission(ADMIN, project); | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(Webhooks.ListResponseElement::getName, Webhooks.ListResponseElement::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(project); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(project); | |||||
} | |||||
ListWsResponse response = wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, organization.getKey()) | |||||
.setParam(PROJECT_KEY_PARAM, project.getKey()) | |||||
.executeProtobuf(ListWsResponse.class); | |||||
@Test | |||||
public void list_project_webhooks_when_no_organization_is_provided() { | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(List::getName, List::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
ComponentDto project1 = componentDbTester.insertPrivateProject(); | |||||
userSession.logIn().addProjectPermission(ADMIN, project1); | |||||
} | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(project1); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(project1); | |||||
@Test | |||||
public void return_NotFoundException_if_requested_project_is_not_found() throws Exception { | |||||
ListResponse response = wsActionTester.newRequest() | |||||
.setParam(PROJECT_KEY_PARAM, project1.getKey()) | |||||
.executeProtobuf(ListResponse.class); | |||||
userSession.logIn().setSystemAdministrator(); | |||||
expectedException.expect(NotFoundException.class); | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(Webhooks.ListResponseElement::getName, Webhooks.ListResponseElement::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
wsActionTester.newRequest() | |||||
.setParam(PROJECT_KEY_PARAM, "pipo") | |||||
.executeProtobuf(ListWsResponse.class); | |||||
} | |||||
} | |||||
@Test | |||||
public void list_organization_webhooks() { | |||||
@Test | |||||
public void return_NotFoundException_if_requested_organization_is_not_found() throws Exception { | |||||
OrganizationDto organizationDto = organizationDbTester.insert(); | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(organizationDto); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(organizationDto); | |||||
userSession.logIn().addPermission(ADMINISTER, organizationDto.getUuid()); | |||||
userSession.logIn().setSystemAdministrator(); | |||||
expectedException.expect(NotFoundException.class); | |||||
ListResponse response = wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, organizationDto.getKey()) | |||||
.executeProtobuf(ListResponse.class); | |||||
wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, "pipo") | |||||
.executeProtobuf(ListWsResponse.class); | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(Webhooks.ListResponseElement::getName, Webhooks.ListResponseElement::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
} | |||||
} | |||||
@Test | |||||
public void fail_if_project_exists_but_does_not_belong_to_requested_organization() { | |||||
@Test | |||||
public void list_project_webhooks_when_organization_is_provided() { | |||||
OrganizationDto organization = organizationDbTester.insert(); | |||||
ComponentDto project = componentDbTester.insertPrivateProject(); | |||||
OrganizationDto organization = organizationDbTester.insert(); | |||||
ComponentDto project = componentDbTester.insertPrivateProject(organization); | |||||
userSession.logIn().addProjectPermission(ADMIN, project); | |||||
expectedException.expect(NotFoundException.class); | |||||
expectedException.expectMessage(format("Project '%s' does not belong to organisation '%s'", project.getKey(), organization.getKey())); | |||||
WebhookDto dto1 = webhookDbTester.insertWebhook(project); | |||||
WebhookDto dto2 = webhookDbTester.insertWebhook(project); | |||||
userSession.logIn().addProjectPermission(ADMIN, project); | |||||
ListResponse response = wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, organization.getKey()) | |||||
.setParam(PROJECT_KEY_PARAM, project.getKey()) | |||||
.executeProtobuf(ListResponse.class); | |||||
wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, organization.getKey()) | |||||
.setParam(PROJECT_KEY_PARAM, project.getKey()) | |||||
.execute(); | |||||
assertThat(response.getWebhooksList()) | |||||
.extracting(Webhooks.ListResponseElement::getName, Webhooks.ListResponseElement::getUrl) | |||||
.contains(tuple(dto1.getName(), dto1.getUrl()), | |||||
tuple(dto2.getName(), dto2.getUrl())); | |||||
} | |||||
} | |||||
@Test | |||||
public void return_UnauthorizedException_if_not_logged_in() throws Exception { | |||||
@Test | |||||
public void return_NotFoundException_if_requested_project_is_not_found() throws Exception { | |||||
userSession.anonymous(); | |||||
expectedException.expect(UnauthorizedException.class); | |||||
userSession.logIn().setSystemAdministrator(); | |||||
expectedException.expect(NotFoundException.class); | |||||
wsActionTester.newRequest() | |||||
.executeProtobuf(ListWsResponse.class); | |||||
wsActionTester.newRequest() | |||||
.setParam(PROJECT_KEY_PARAM, "pipo") | |||||
.executeProtobuf(ListResponse.class); | |||||
} | |||||
} | |||||
@Test | |||||
public void throw_ForbiddenException_if_not_organization_administrator() { | |||||
@Test | |||||
public void return_NotFoundException_if_requested_organization_is_not_found() throws Exception { | |||||
userSession.logIn(); | |||||
userSession.logIn().setSystemAdministrator(); | |||||
expectedException.expect(NotFoundException.class); | |||||
expectedException.expect(ForbiddenException.class); | |||||
expectedException.expectMessage("Insufficient privileges"); | |||||
wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, "pipo") | |||||
.executeProtobuf(ListResponse.class); | |||||
wsActionTester.newRequest() | |||||
.executeProtobuf(ListWsResponse.class); | |||||
} | |||||
} | |||||
@Test | |||||
public void throw_ForbiddenException_if_not_project_administrator() { | |||||
@Test | |||||
public void fail_if_project_exists_but_does_not_belong_to_requested_organization() { | |||||
ComponentDto project = componentDbTester.insertPrivateProject(); | |||||
OrganizationDto organization = organizationDbTester.insert(); | |||||
ComponentDto project = componentDbTester.insertPrivateProject(); | |||||
userSession.logIn(); | |||||
expectedException.expect(NotFoundException.class); | |||||
expectedException.expectMessage(format("Project '%s' does not belong to organisation '%s'", project.getKey(), organization.getKey())); | |||||
expectedException.expect(ForbiddenException.class); | |||||
expectedException.expectMessage("Insufficient privileges"); | |||||
userSession.logIn().addProjectPermission(ADMIN, project); | |||||
wsActionTester.newRequest() | |||||
.setParam(PROJECT_KEY_PARAM, project.getKey()) | |||||
.executeProtobuf(ListWsResponse.class); | |||||
wsActionTester.newRequest() | |||||
.setParam(ORGANIZATION_KEY_PARAM, organization.getKey()) | |||||
.setParam(PROJECT_KEY_PARAM, project.getKey()) | |||||
.execute(); | |||||
} | |||||
} | |||||
@Test | |||||
public void return_UnauthorizedException_if_not_logged_in() throws Exception { | |||||
userSession.anonymous(); | |||||
expectedException.expect(UnauthorizedException.class); | |||||
wsActionTester.newRequest() | |||||
.executeProtobuf(ListResponse.class); | |||||
} | |||||
@Test | |||||
public void throw_ForbiddenException_if_not_organization_administrator() { | |||||
userSession.logIn(); | |||||
expectedException.expect(ForbiddenException.class); | |||||
expectedException.expectMessage("Insufficient privileges"); | |||||
wsActionTester.newRequest() | |||||
.executeProtobuf(ListResponse.class); | |||||
} | |||||
@Test | |||||
public void throw_ForbiddenException_if_not_project_administrator() { | |||||
ComponentDto project = componentDbTester.insertPrivateProject(); | |||||
userSession.logIn(); | |||||
expectedException.expect(ForbiddenException.class); | |||||
expectedException.expectMessage("Insufficient privileges"); | |||||
wsActionTester.newRequest() | |||||
.setParam(PROJECT_KEY_PARAM, project.getKey()) | |||||
.executeProtobuf(ListResponse.class); | |||||
} | |||||
} | } |
import org.sonar.db.DbClient; | import org.sonar.db.DbClient; | ||||
import org.sonar.db.DbTester; | import org.sonar.db.DbTester; | ||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.component.ComponentTesting; | |||||
import org.sonar.db.webhook.WebhookDeliveryDbTester; | |||||
import org.sonar.db.webhook.WebhookDeliveryDto; | import org.sonar.db.webhook.WebhookDeliveryDto; | ||||
import org.sonar.server.component.ComponentFinder; | import org.sonar.server.component.ComponentFinder; | ||||
import org.sonar.server.component.TestComponentFinder; | import org.sonar.server.component.TestComponentFinder; | ||||
import org.sonarqube.ws.Webhooks; | import org.sonarqube.ws.Webhooks; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.sonar.db.webhook.WebhookDbTesting.newWebhookDeliveryDto; | |||||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||||
import static org.sonar.db.webhook.WebhookDbTesting.newDto; | |||||
import static org.sonar.test.JsonAssert.assertJson; | import static org.sonar.test.JsonAssert.assertJson; | ||||
public class WebhookDeliveriesActionTest { | public class WebhookDeliveriesActionTest { | ||||
public DbTester db = DbTester.create(System2.INSTANCE); | public DbTester db = DbTester.create(System2.INSTANCE); | ||||
private DbClient dbClient = db.getDbClient(); | private DbClient dbClient = db.getDbClient(); | ||||
private WebhookDeliveryDbTester webhookDeliveryDbTester = db.webhookDelivery(); | |||||
private WsActionTester ws; | private WsActionTester ws; | ||||
private ComponentDto project; | private ComponentDto project; | ||||
ComponentFinder componentFinder = TestComponentFinder.from(db); | ComponentFinder componentFinder = TestComponentFinder.from(db); | ||||
WebhookDeliveriesAction underTest = new WebhookDeliveriesAction(dbClient, userSession, componentFinder); | WebhookDeliveriesAction underTest = new WebhookDeliveriesAction(dbClient, userSession, componentFinder); | ||||
ws = new WsActionTester(underTest); | ws = new WsActionTester(underTest); | ||||
project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("my-project")); | |||||
project = db.components().insertComponent(newPrivateProjectDto(db.organizations().insert()).setDbKey("my-project")); | |||||
} | } | ||||
@Test | @Test | ||||
@Test | @Test | ||||
public void search_by_component_and_return_records_of_example() { | public void search_by_component_and_return_records_of_example() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setUuid("d1") | .setUuid("d1") | ||||
.setComponentUuid(project.uuid()) | .setComponentUuid(project.uuid()) | ||||
.setCeTaskUuid("task-1") | .setCeTaskUuid("task-1") | ||||
@Test | @Test | ||||
public void search_by_task_and_return_records() { | public void search_by_task_and_return_records() { | ||||
WebhookDeliveryDto dto1 = newWebhookDeliveryDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1"); | |||||
WebhookDeliveryDto dto2 = newWebhookDeliveryDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1"); | |||||
WebhookDeliveryDto dto3 = newWebhookDeliveryDto().setComponentUuid(project.uuid()).setCeTaskUuid("t2"); | |||||
WebhookDeliveryDto dto1 = newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1"); | |||||
WebhookDeliveryDto dto2 = newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1"); | |||||
WebhookDeliveryDto dto3 = newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t2"); | |||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto1); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto1); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto2); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto2); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto3); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto3); | ||||
@Test | @Test | ||||
public void search_by_webhook_and_return_records() { | public void search_by_webhook_and_return_records() { | ||||
WebhookDeliveryDto dto1 = newWebhookDeliveryDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid"); | |||||
WebhookDeliveryDto dto2 = newWebhookDeliveryDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid"); | |||||
WebhookDeliveryDto dto3 = newWebhookDeliveryDto().setComponentUuid(project.uuid()).setCeTaskUuid("t2").setWebhookUuid("wh-2-uuid"); | |||||
WebhookDeliveryDto dto1 = newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid"); | |||||
WebhookDeliveryDto dto2 = newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid"); | |||||
WebhookDeliveryDto dto3 = newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t2").setWebhookUuid("wh-2-uuid"); | |||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto1); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto1); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto2); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto2); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto3); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto3); | ||||
userSession.logIn().addProjectPermission(UserRole.ADMIN, project); | userSession.logIn().addProjectPermission(UserRole.ADMIN, project); | ||||
Webhooks.DeliveriesWsResponse response = ws.newRequest() | Webhooks.DeliveriesWsResponse response = ws.newRequest() | ||||
.setParam("ceTaskId", "t1") | |||||
.setParam("webhook", "wh-1-uuid") | |||||
.executeProtobuf(Webhooks.DeliveriesWsResponse.class); | .executeProtobuf(Webhooks.DeliveriesWsResponse.class); | ||||
assertThat(response.getDeliveriesCount()).isEqualTo(2); | assertThat(response.getDeliveriesCount()).isEqualTo(2); | ||||
assertThat(response.getDeliveriesList()).extracting(Webhooks.Delivery::getId).containsOnly(dto1.getUuid(), dto2.getUuid()); | assertThat(response.getDeliveriesList()).extracting(Webhooks.Delivery::getId).containsOnly(dto1.getUuid(), dto2.getUuid()); | ||||
} | } | ||||
@Test | |||||
public void validate_default_pagination() { | |||||
for (int i = 0; i < 15; i++) { | |||||
webhookDeliveryDbTester.insert(newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid")); | |||||
} | |||||
userSession.logIn().addProjectPermission(UserRole.ADMIN, project); | |||||
Webhooks.DeliveriesWsResponse response = ws.newRequest() | |||||
.setParam("webhook", "wh-1-uuid") | |||||
.executeProtobuf(Webhooks.DeliveriesWsResponse.class); | |||||
assertThat(response.getDeliveriesCount()).isEqualTo(10); | |||||
} | |||||
@Test | |||||
public void validate_pagination_first_page() { | |||||
for (int i = 0; i < 12; i++) { | |||||
webhookDeliveryDbTester.insert(newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid")); | |||||
} | |||||
userSession.logIn().addProjectPermission(UserRole.ADMIN, project); | |||||
Webhooks.DeliveriesWsResponse response = ws.newRequest() | |||||
.setParam("webhook", "wh-1-uuid") | |||||
.setParam("p", "1") | |||||
.setParam("ps", "10") | |||||
.executeProtobuf(Webhooks.DeliveriesWsResponse.class); | |||||
assertThat(response.getDeliveriesCount()).isEqualTo(10); | |||||
assertThat(response.getPaging().getTotal()).isEqualTo(12); | |||||
assertThat(response.getPaging().getPageIndex()).isEqualTo(1); | |||||
} | |||||
@Test | |||||
public void validate_pagination_last_page() { | |||||
for (int i = 0; i < 12; i++) { | |||||
webhookDeliveryDbTester.insert(newDto().setComponentUuid(project.uuid()).setCeTaskUuid("t1").setWebhookUuid("wh-1-uuid")); | |||||
} | |||||
userSession.logIn().addProjectPermission(UserRole.ADMIN, project); | |||||
Webhooks.DeliveriesWsResponse response = ws.newRequest() | |||||
.setParam("webhook", "wh-1-uuid") | |||||
.setParam("p", "2") | |||||
.setParam("ps", "10") | |||||
.executeProtobuf(Webhooks.DeliveriesWsResponse.class); | |||||
assertThat(response.getDeliveriesCount()).isEqualTo(2); | |||||
assertThat(response.getPaging().getTotal()).isEqualTo(12); | |||||
assertThat(response.getPaging().getPageIndex()).isEqualTo(2); | |||||
} | |||||
@Test | @Test | ||||
public void search_by_component_and_throw_ForbiddenException_if_not_admin_of_project() { | public void search_by_component_and_throw_ForbiddenException_if_not_admin_of_project() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setComponentUuid(project.uuid()); | .setComponentUuid(project.uuid()); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto); | ||||
db.commit(); | db.commit(); | ||||
@Test | @Test | ||||
public void search_by_task_and_throw_ForbiddenException_if_not_admin_of_project() { | public void search_by_task_and_throw_ForbiddenException_if_not_admin_of_project() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setComponentUuid(project.uuid()); | .setComponentUuid(project.uuid()); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto); | ||||
db.commit(); | db.commit(); |
import org.sonarqube.ws.Webhooks; | import org.sonarqube.ws.Webhooks; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.sonar.db.webhook.WebhookDbTesting.newWebhookDeliveryDto; | |||||
import static org.sonar.db.webhook.WebhookDbTesting.newDto; | |||||
import static org.sonar.test.JsonAssert.assertJson; | import static org.sonar.test.JsonAssert.assertJson; | ||||
public class WebhookDeliveryActionTest { | public class WebhookDeliveryActionTest { | ||||
@Test | @Test | ||||
public void load_the_delivery_of_example() { | public void load_the_delivery_of_example() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setUuid("d1") | .setUuid("d1") | ||||
.setComponentUuid(project.uuid()) | .setComponentUuid(project.uuid()) | ||||
.setCeTaskUuid("task-1") | .setCeTaskUuid("task-1") | ||||
@Test | @Test | ||||
public void return_delivery_that_failed_to_be_sent() { | public void return_delivery_that_failed_to_be_sent() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setComponentUuid(project.uuid()) | .setComponentUuid(project.uuid()) | ||||
.setSuccess(false) | .setSuccess(false) | ||||
.setHttpStatus(null) | .setHttpStatus(null) | ||||
@Test | @Test | ||||
public void return_delivery_with_none_of_optional_fields() { | public void return_delivery_with_none_of_optional_fields() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setComponentUuid(project.uuid()) | .setComponentUuid(project.uuid()) | ||||
.setCeTaskUuid(null) | .setCeTaskUuid(null) | ||||
.setHttpStatus(null) | .setHttpStatus(null) | ||||
@Test | @Test | ||||
public void throw_ForbiddenException_if_not_admin_of_project() { | public void throw_ForbiddenException_if_not_admin_of_project() { | ||||
WebhookDeliveryDto dto = newWebhookDeliveryDto() | |||||
WebhookDeliveryDto dto = newDto() | |||||
.setComponentUuid(project.uuid()); | .setComponentUuid(project.uuid()); | ||||
dbClient.webhookDeliveryDao().insert(db.getSession(), dto); | dbClient.webhookDeliveryDao().insert(db.getSession(), dto); | ||||
db.commit(); | db.commit(); |
webhooks.delivery.payload=Payload: | webhooks.delivery.payload=Payload: | ||||
webhooks.delivery.response_x=Response: {0} | webhooks.delivery.response_x=Response: {0} | ||||
webhooks.documentation_link=Webhooks documentation | webhooks.documentation_link=Webhooks documentation | ||||
webhooks.last_execution=Last execution | |||||
webhooks.last_execution=Last delivery | |||||
webhooks.last_execution.none=Never | webhooks.last_execution.none=Never | ||||
webhooks.maximum_reached=You reached your maximum number of {0} webhooks. You can still update or delete an existing one. | webhooks.maximum_reached=You reached your maximum number of {0} webhooks. You can still update or delete an existing one. | ||||
webhooks.name=Name | webhooks.name=Name |
class NewAction { | class NewAction { | ||||
private final String key; | private final String key; | ||||
private static final String PAGE_PARAM_DESCRIPTION = "1-based page number"; | |||||
private String deprecatedKey; | private String deprecatedKey; | ||||
private String description; | private String description; | ||||
private String since; | private String since; | ||||
*/ | */ | ||||
public NewAction addPagingParams(int defaultPageSize) { | public NewAction addPagingParams(int defaultPageSize) { | ||||
createParam(Param.PAGE) | createParam(Param.PAGE) | ||||
.setDescription("1-based page number") | |||||
.setDescription(PAGE_PARAM_DESCRIPTION) | |||||
.setExampleValue("42") | .setExampleValue("42") | ||||
.setDeprecatedKey("pageIndex", "5.2") | .setDeprecatedKey("pageIndex", "5.2") | ||||
.setDefaultValue("1"); | .setDefaultValue("1"); | ||||
public NewParam createPageParam() { | public NewParam createPageParam() { | ||||
return createParam(Param.PAGE) | return createParam(Param.PAGE) | ||||
.setDescription("1-based page number") | |||||
.setDescription(PAGE_PARAM_DESCRIPTION) | |||||
.setExampleValue("42") | .setExampleValue("42") | ||||
.setDeprecatedKey("pageIndex", "5.2") | .setDeprecatedKey("pageIndex", "5.2") | ||||
.setDefaultValue("1"); | .setDefaultValue("1"); | ||||
/** | /** | ||||
* Add predefined parameters related to pagination of results with a maximum page size. | * Add predefined parameters related to pagination of results with a maximum page size. | ||||
* Note the maximum is a documentation only feature. It does not check anything. | |||||
* @since 7.1 | |||||
*/ | */ | ||||
public NewAction addPagingParamsSince(int defaultPageSize, int maxPageSize, String version) { | public NewAction addPagingParamsSince(int defaultPageSize, int maxPageSize, String version) { | ||||
createParam(Param.PAGE) | createParam(Param.PAGE) | ||||
.setDescription("1-based page number") | |||||
.setDescription(PAGE_PARAM_DESCRIPTION) | |||||
.setExampleValue("42") | .setExampleValue("42") | ||||
.setDefaultValue("1") | .setDefaultValue("1") | ||||
.setSince(version); | .setSince(version); |
*/ | */ | ||||
package org.sonarqube.ws.client.webhooks; | package org.sonarqube.ws.client.webhooks; | ||||
import java.util.List; | |||||
import javax.annotation.Generated; | import javax.annotation.Generated; | ||||
/** | /** | ||||
private String ceTaskId; | private String ceTaskId; | ||||
private String componentKey; | private String componentKey; | ||||
private String p; | |||||
private String ps; | |||||
private String webhook; | |||||
/** | /** | ||||
* Example value: "AU-Tpxb--iU5OvuD2FLy" | * Example value: "AU-Tpxb--iU5OvuD2FLy" | ||||
public String getComponentKey() { | public String getComponentKey() { | ||||
return componentKey; | return componentKey; | ||||
} | } | ||||
/** | |||||
* Example value: "42" | |||||
*/ | |||||
public DeliveriesRequest setP(String p) { | |||||
this.p = p; | |||||
return this; | |||||
} | |||||
public String getP() { | |||||
return p; | |||||
} | |||||
/** | |||||
* Example value: "20" | |||||
*/ | |||||
public DeliveriesRequest setPs(String ps) { | |||||
this.ps = ps; | |||||
return this; | |||||
} | |||||
public String getPs() { | |||||
return ps; | |||||
} | |||||
/** | |||||
* Example value: "AU-TpxcA-iU5OvuD2FLz" | |||||
*/ | |||||
public DeliveriesRequest setWebhook(String webhook) { | |||||
this.webhook = webhook; | |||||
return this; | |||||
} | |||||
public String getWebhook() { | |||||
return webhook; | |||||
} | |||||
} | } |
*/ | */ | ||||
package org.sonarqube.ws.client.webhooks; | package org.sonarqube.ws.client.webhooks; | ||||
import java.util.stream.Collectors; | |||||
import javax.annotation.Generated; | import javax.annotation.Generated; | ||||
import org.sonarqube.ws.MediaTypes; | import org.sonarqube.ws.MediaTypes; | ||||
import org.sonarqube.ws.Webhooks.CreateWsResponse; | |||||
import org.sonarqube.ws.Webhooks.DeliveriesWsResponse; | |||||
import org.sonarqube.ws.Webhooks.DeliveryWsResponse; | |||||
import org.sonarqube.ws.Webhooks.ListResponse; | |||||
import org.sonarqube.ws.client.BaseService; | import org.sonarqube.ws.client.BaseService; | ||||
import org.sonarqube.ws.client.GetRequest; | import org.sonarqube.ws.client.GetRequest; | ||||
import org.sonarqube.ws.client.PostRequest; | import org.sonarqube.ws.client.PostRequest; | ||||
import org.sonarqube.ws.client.WsConnector; | 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> | * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks">Further information about this web service online</a> | ||||
return call( | return call( | ||||
new GetRequest(path("deliveries")) | new GetRequest(path("deliveries")) | ||||
.setParam("ceTaskId", request.getCeTaskId()) | .setParam("ceTaskId", request.getCeTaskId()) | ||||
.setParam("componentKey", request.getComponentKey()), | |||||
.setParam("componentKey", request.getComponentKey()) | |||||
.setParam("p", request.getP()) | |||||
.setParam("ps", request.getPs()) | |||||
.setParam("webhook", request.getWebhook()), | |||||
DeliveriesWsResponse.parser()); | DeliveriesWsResponse.parser()); | ||||
} | } | ||||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/webhooks/list">Further information about this action online (including a response example)</a> | * @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 | * @since 7.1 | ||||
*/ | */ | ||||
public ListWsResponse list(ListRequest request) { | |||||
public ListResponse list(ListRequest request) { | |||||
return call( | return call( | ||||
new GetRequest(path("list")) | new GetRequest(path("list")) | ||||
.setParam("organization", request.getOrganization()) | .setParam("organization", request.getOrganization()) | ||||
.setParam("project", request.getProject()), | .setParam("project", request.getProject()), | ||||
ListWsResponse.parser()); | |||||
ListResponse.parser()); | |||||
} | } | ||||
/** | /** |
option java_outer_classname = "Webhooks"; | option java_outer_classname = "Webhooks"; | ||||
option optimize_for = SPEED; | option optimize_for = SPEED; | ||||
// GET api/webhooks/list | |||||
message ListWsResponse { | |||||
repeated List webhooks = 1; | |||||
message LatestDelivery { | |||||
optional string id = 1; | |||||
optional string at = 2; | |||||
optional bool success = 3; | |||||
optional int32 httpStatus = 4; | |||||
optional int32 durationMs = 5; | |||||
} | |||||
message List { | |||||
optional string key = 1; | |||||
optional string name = 2; | |||||
optional string url = 3; | |||||
optional LatestDelivery latestDelivery = 4; | |||||
message ListResponseElement { | |||||
optional string key = 1; | |||||
optional string name = 2; | |||||
optional string url = 3; | |||||
optional LatestDelivery latestDelivery = 4; | |||||
} | |||||
message LatestDelivery { | |||||
optional string id = 1; | |||||
optional string at = 2; | |||||
optional string success = 3; | |||||
optional string httpStatus = 4; | |||||
optional string durationMs = 5; | |||||
} | |||||
} | |||||
// GET api/webhooks/list | |||||
message ListResponse { | |||||
repeated ListResponseElement webhooks = 1; | |||||
} | } | ||||
// POST api/webhooks/create | // POST api/webhooks/create |
assertThat(detail.getSuccess()).isFalse(); | assertThat(detail.getSuccess()).isFalse(); | ||||
assertThat(detail.hasHttpStatus()).isFalse(); | assertThat(detail.hasHttpStatus()).isFalse(); | ||||
assertThat(detail.hasDurationMs()).isFalse(); | |||||
assertThat(detail.hasDurationMs()).isTrue(); | |||||
assertThat(detail.getPayload()).isNotEmpty(); | assertThat(detail.getPayload()).isNotEmpty(); | ||||
assertThat(detail.getErrorStacktrace()) | assertThat(detail.getErrorStacktrace()) | ||||
.contains("java.net.UnknownHostException") | .contains("java.net.UnknownHostException") |