assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 25 // level 1
- + 46 // content of DaoModule
+ + 47 // content of DaoModule
+ 2 // content of EsSearchModule
+ 62 // content of CorePropertyDefinitions
+ 1 // content of CePropertyDefinitions
import org.sonar.db.user.UserDao;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserTokenDao;
+import org.sonar.db.webhook.WebhookDeliveryDao;
public class DaoModule extends Module {
private static final List<Class<? extends Dao>> classes = ImmutableList.<Class<? extends Dao>>builder().add(
UserDao.class,
UserGroupDao.class,
UserPermissionDao.class,
- UserTokenDao.class).build();
+ UserTokenDao.class,
+ WebhookDeliveryDao.class).build();
@Override
protected void configureModule() {
import org.sonar.db.user.UserDao;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserTokenDao;
+import org.sonar.db.webhook.WebhookDeliveryDao;
public class DbClient {
private final ActiveRuleDao activeRuleDao;
private final QProfileChangeDao qProfileChangeDao;
private final UserPermissionDao userPermissionDao;
+ private final WebhookDeliveryDao webhookDeliveryDao;
public DbClient(Database database, MyBatis myBatis, Dao... daos) {
this.database = database;
activeRuleDao = getDao(map, ActiveRuleDao.class);
qProfileChangeDao = getDao(map, QProfileChangeDao.class);
userPermissionDao = getDao(map, UserPermissionDao.class);
+ webhookDeliveryDao = getDao(map, WebhookDeliveryDao.class);
}
public DbSession openSession(boolean batch) {
return userPermissionDao;
}
+ public WebhookDeliveryDao webhookDeliveryDao() {
+ return webhookDeliveryDao;
+ }
+
protected <K extends Dao> K getDao(Map<Class, Dao> map, Class<K> clazz) {
return (K) map.get(clazz);
}
import org.sonar.db.version.v45.Migration45Mapper;
import org.sonar.db.version.v50.Migration50Mapper;
import org.sonar.db.version.v53.Migration53Mapper;
+import org.sonar.db.webhook.WebhookDeliveryMapper;
public class MyBatis {
UserGroupMapper.class,
UserMapper.class,
UserPermissionMapper.class,
- UserTokenMapper.class
+ UserTokenMapper.class,
+ WebhookDeliveryMapper.class
};
confBuilder.loadMappers(mappers);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 java.util.Optional;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+public class WebhookDeliveryDao implements Dao {
+
+ public Optional<WebhookDeliveryDto> selectByUuid(DbSession dbSession, String uuid) {
+ return Optional.ofNullable(mapper(dbSession).selectByUuid(uuid));
+ }
+ public void insert(DbSession dbSession, WebhookDeliveryDto dto) {
+ mapper(dbSession).insert(dto);
+ }
+
+ public void deleteComponentBeforeDate(DbSession dbSession, String componentUuid, long beforeDate) {
+ mapper(dbSession).deleteComponentBeforeDate(componentUuid, beforeDate);
+ }
+
+ private static WebhookDeliveryMapper mapper(DbSession dbSession) {
+ return dbSession.getMapper(WebhookDeliveryMapper.class);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class WebhookDeliveryDto extends WebhookDeliveryLiteDto<WebhookDeliveryDto> {
+ /** Error message if HTTP request cannot be sent, else null */
+ private String errorStacktrace;
+ /** The payload that has been sent, cannot be null */
+ private String payload;
+
+ @CheckForNull
+ public String getErrorStacktrace() {
+ return errorStacktrace;
+ }
+
+ public WebhookDeliveryDto setErrorStacktrace(@Nullable String s) {
+ this.errorStacktrace = s;
+ return this;
+ }
+
+ @CheckForNull
+ public String getPayload() {
+ return payload;
+ }
+
+ public WebhookDeliveryDto setPayload(@Nullable String s) {
+ this.payload = s;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("uuid", uuid)
+ .append("componentUuid", componentUuid)
+ .append("name", name)
+ .append("success", success)
+ .append("httpStatus", httpStatus)
+ .append("durationMs", durationMs)
+ .append("url", url)
+ .append("createdAt", createdAt)
+ .append("errorStacktrace", errorStacktrace)
+ .toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class WebhookDeliveryLiteDto<T extends WebhookDeliveryLiteDto> {
+ /** Technical unique identifier, can't be null */
+ protected String uuid;
+ /** Component UUID, can't be null */
+ protected String componentUuid;
+ /** Compute Engine task UUID, can't be null */
+ protected String ceTaskUuid;
+ /** Name, can't be null */
+ protected String name;
+ protected boolean success;
+ /** HTTP response status. Null if HTTP request cannot be sent */
+ protected Integer httpStatus;
+ /** Duration in ms. Null if HTTP request cannot be sent */
+ protected Integer durationMs;
+ /** URL, cannot be null */
+ protected String url;
+ /** Time of delivery */
+ protected long createdAt;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public T setUuid(String s) {
+ this.uuid = s;
+ return (T)this;
+ }
+
+ public String getComponentUuid() {
+ return componentUuid;
+ }
+
+ public T setComponentUuid(String s) {
+ this.componentUuid = s;
+ return (T)this;
+ }
+
+ public String getCeTaskUuid() {
+ return ceTaskUuid;
+ }
+
+ public T setCeTaskUuid(String s) {
+ this.ceTaskUuid = s;
+ return (T)this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public T setName(String s) {
+ this.name = s;
+ return (T)this;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public T setSuccess(boolean b) {
+ this.success = b;
+ return (T)this;
+ }
+
+ @CheckForNull
+ public Integer getHttpStatus() {
+ return httpStatus;
+ }
+
+ public T setHttpStatus(@Nullable Integer i) {
+ this.httpStatus = i;
+ return (T)this;
+ }
+
+ @CheckForNull
+ public Integer getDurationMs() {
+ return durationMs;
+ }
+
+ public T setDurationMs(@Nullable Integer i) {
+ this.durationMs = i;
+ return (T)this;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public T setUrl(String s) {
+ this.url = s;
+ return (T)this;
+ }
+
+ public long getCreatedAt() {
+ return createdAt;
+ }
+
+ public T setCreatedAt(long l) {
+ this.createdAt = l;
+ return (T)this;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("uuid", uuid)
+ .append("componentUuid", componentUuid)
+ .append("ceTaskUuid", ceTaskUuid)
+ .append("name", name)
+ .append("success", success)
+ .append("httpStatus", httpStatus)
+ .append("durationMs", durationMs)
+ .append("url", url)
+ .append("createdAt", createdAt)
+ .toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 javax.annotation.CheckForNull;
+import org.apache.ibatis.annotations.Param;
+
+public interface WebhookDeliveryMapper {
+
+ @CheckForNull
+ WebhookDeliveryDto selectByUuid(@Param("uuid") String uuid);
+
+ void insert(WebhookDeliveryDto dto);
+
+ void deleteComponentBeforeDate(@Param("componentUuid") String componentUuid, @Param("beforeDate") long beforeDate);
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.db.webhook;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.db.webhook.WebhookDeliveryMapper">
+
+ <select id="selectByUuid" parameterType="String" resultType="org.sonar.db.webhook.WebhookDeliveryDto">
+ select
+ uuid,
+ component_uuid as componentUuid,
+ ce_task_uuid as ceTaskUuid,
+ name,
+ url,
+ success,
+ http_status as httpStatus,
+ duration_ms as durationMs,
+ payload,
+ error_stacktrace as errorStacktrace,
+ created_at as createdAt
+ from webhook_deliveries
+ where uuid = #{uuid,jdbcType=VARCHAR}
+ </select>
+
+ <insert id="insert" parameterType="org.sonar.db.webhook.WebhookDeliveryDto" useGeneratedKeys="false">
+ insert into webhook_deliveries (
+ uuid,
+ component_uuid,
+ ce_task_uuid,
+ name,
+ url,
+ success,
+ http_status,
+ duration_ms,
+ payload,
+ error_stacktrace,
+ created_at
+ ) values (
+ #{uuid,jdbcType=VARCHAR},
+ #{componentUuid,jdbcType=VARCHAR},
+ #{ceTaskUuid,jdbcType=VARCHAR},
+ #{name,jdbcType=VARCHAR},
+ #{url,jdbcType=VARCHAR},
+ #{success,jdbcType=BOOLEAN},
+ #{httpStatus,jdbcType=INTEGER},
+ #{durationMs,jdbcType=INTEGER},
+ #{payload,jdbcType=VARCHAR},
+ #{errorStacktrace,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=TIMESTAMP}
+ )
+ </insert>
+
+ <delete id="deleteComponentBeforeDate" parameterType="map">
+ delete from webhook_deliveries
+ where
+ component_uuid = #{componentUuid,jdbcType=VARCHAR} and
+ created_at < #{beforeDate,jdbcType=BIGINT}
+ </delete>
+</mapper>
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(2 + 44);
+ assertThat(container.size()).isEqualTo(2 + 45);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+public class WebhookDeliveryDaoTest {
+
+ private static final long DATE_1 = 1_999_000L;
+
+ @Rule
+ public final DbTester dbTester = DbTester.create(System2.INSTANCE).setDisableDefaultOrganization(true);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private final DbClient dbClient = dbTester.getDbClient();
+ private final DbSession dbSession = dbTester.getSession();
+ private final WebhookDeliveryDao underTest = dbClient.webhookDeliveryDao();
+
+ @Test
+ public void insert_row_with_only_mandatory_columns() {
+ WebhookDeliveryDto dto = newDto("DELIVERY_1", "COMPONENT_1", "TASK_1");
+
+ underTest.insert(dbSession, dto);
+
+ WebhookDeliveryDto stored = selectByUuid(dto.getUuid());
+ verifyMandatoryFields(dto, stored);
+
+ // optional fields are null
+ assertThat(stored.getHttpStatus()).isNull();
+ assertThat(stored.getDurationMs()).isNull();
+ assertThat(stored.getErrorStacktrace()).isNull();
+ }
+
+ @Test
+ public void insert_row_with_all_columns() {
+ WebhookDeliveryDto dto = newDto("DELIVERY_1", "COMPONENT_1", "TASK_1")
+ .setDurationMs(10000)
+ .setHttpStatus(200)
+ .setErrorStacktrace("timeout")
+ .setPayload("{json}");
+
+ underTest.insert(dbSession, dto);
+
+ WebhookDeliveryDto stored = selectByUuid(dto.getUuid());
+ verifyMandatoryFields(dto, stored);
+ assertThat(stored.getHttpStatus()).isEqualTo(dto.getHttpStatus());
+ assertThat(stored.getDurationMs()).isEqualTo(dto.getDurationMs());
+ assertThat(stored.getErrorStacktrace()).isEqualTo(dto.getErrorStacktrace());
+ }
+
+ @Test
+ public void delete_rows_before_date() {
+ underTest.insert(dbSession, newDto("DELIVERY_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L));
+ underTest.insert(dbSession, newDto("DELIVERY_2", "COMPONENT_1", "TASK_2").setCreatedAt(2_000_000L));
+ underTest.insert(dbSession, newDto("DELIVERY_3", "COMPONENT_2", "TASK_3").setCreatedAt(1_000_000L));
+
+ // should delete the old delivery on COMPONENT_1 and keep the one of COMPONENT_2
+ underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_1", 1_500_000L);
+
+ List<Object> uuids = dbTester.select(dbSession, "select uuid as \"uuid\" from webhook_deliveries")
+ .stream()
+ .map(columns -> columns.get("uuid"))
+ .collect(Collectors.toList());
+ assertThat(uuids).containsOnly("DELIVERY_2", "DELIVERY_3");
+
+ }
+
+ private void verifyMandatoryFields(WebhookDeliveryDto expected, WebhookDeliveryDto actual) {
+ assertThat(actual.getUuid()).isEqualTo(expected.getUuid());
+ assertThat(actual.getComponentUuid()).isEqualTo(expected.getComponentUuid());
+ assertThat(actual.getCeTaskUuid()).isEqualTo(expected.getCeTaskUuid());
+ assertThat(actual.getName()).isEqualTo(expected.getName());
+ assertThat(actual.getUrl()).isEqualTo(expected.getUrl());
+ assertThat(actual.isSuccess()).isEqualTo(expected.isSuccess());
+ assertThat(actual.getPayload()).isEqualTo(expected.getPayload());
+ 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 componentUuid, String ceTaskUuid) {
+ return new WebhookDeliveryDto()
+ .setUuid(uuid)
+ .setComponentUuid(componentUuid)
+ .setCeTaskUuid(ceTaskUuid)
+ .setName("Jenkins")
+ .setUrl("http://jenkins")
+ .setSuccess(true)
+ .setPayload("{json}")
+ .setCreatedAt(DATE_1);
+ }
+
+ private WebhookDeliveryDto selectByUuid(String uuid) {
+ Optional<WebhookDeliveryDto> dto = underTest.selectByUuid(dbSession, uuid);
+ assertThat(dto).isPresent();
+ return dto.get();
+ }
+}