]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9708 Return 'incremental' field on tasks in queue
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 16 Aug 2017 10:27:40 +0000 (12:27 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 16 Aug 2017 13:08:17 +0000 (15:08 +0200)
16 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeTaskCharacteristicMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeTaskCharacteristicDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/queue/ReportSubmitterTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java
sonar-ws/src/test/java/org/sonarqube/ws/client/ce/CeServiceTest.java

index ceebc8134d07f39dccc4b3456e021c789807d142..7c417ef114857811b079030359031e4bdd2fd360 100644 (file)
 package org.sonar.db.ce;
 
 import java.util.Collection;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
 
+import static org.sonar.db.DatabaseUtils.executeLargeInputs;
+
 public class CeTaskCharacteristicDao implements Dao {
+
   public void insert(DbSession dbSession, Collection<CeTaskCharacteristicDto> characteristics) {
     for (CeTaskCharacteristicDto dto : characteristics) {
       mapper(dbSession).insert(dto);
     }
   }
 
-  public Map<String, String> getTaskCharacteristics(DbSession dbSession, String taskUuid) {
-    Map<String, String> map = new LinkedHashMap<>();
-    List<CeTaskCharacteristicDto> characteristics = mapper(dbSession).selectTaskCharacteristics(taskUuid);
-    characteristics.stream().forEach(dto -> map.put(dto.getKey(), dto.getValue()));
-    return map;
+  public List<CeTaskCharacteristicDto> selectByTaskUuid(DbSession dbSession, String taskUuid) {
+    return mapper(dbSession).selectByTaskUuid(taskUuid);
+  }
+
+  public List<CeTaskCharacteristicDto> selectByTaskUuids(DbSession dbSession, List<String> taskUuids) {
+    return executeLargeInputs(taskUuids, uuid -> mapper(dbSession).selectByTaskUuids(uuid));
   }
 
   private static CeTaskCharacteristicMapper mapper(DbSession session) {
index 993049aa93d340553fb64f7c79e49efe8332f21d..06fbcfac5c8c3a8e3a9214ee6173d87dfaecbb89 100644 (file)
@@ -20,6 +20,9 @@
 package org.sonar.db.ce;
 
 public class CeTaskCharacteristicDto {
+
+  public static final String INCREMENTAL_KEY = "incremental";
+
   private String uuid;
   private String taskUuid;
   private String key;
@@ -29,31 +32,35 @@ public class CeTaskCharacteristicDto {
     return uuid;
   }
 
-  public void setUuid(String uuid) {
+  public CeTaskCharacteristicDto setUuid(String uuid) {
     this.uuid = uuid;
+    return this;
   }
 
   public String getTaskUuid() {
     return taskUuid;
   }
 
-  public void setTaskUuid(String taskUuid) {
+  public CeTaskCharacteristicDto setTaskUuid(String taskUuid) {
     this.taskUuid = taskUuid;
+    return this;
   }
 
   public String getKey() {
     return key;
   }
 
-  public void setKey(String key) {
+  public CeTaskCharacteristicDto setKey(String key) {
     this.key = key;
+    return this;
   }
 
   public String getValue() {
     return value;
   }
 
-  public void setValue(String value) {
+  public CeTaskCharacteristicDto setValue(String value) {
     this.value = value;
+    return this;
   }
 }
index 492b88505e8c795aa543a13c85d1bd3001444cb6..fe9fa7994b1e7e083dcdda2c23ca03f5b412a9a0 100644 (file)
 package org.sonar.db.ce;
 
 import java.util.List;
-
 import org.apache.ibatis.annotations.Param;
 
 public interface CeTaskCharacteristicMapper {
-  List<CeTaskCharacteristicDto> selectTaskCharacteristics(@Param("taskUuid") String taskUuid);
+
+  List<CeTaskCharacteristicDto> selectByTaskUuid(@Param("taskUuid") String taskUuid);
+
+  List<CeTaskCharacteristicDto> selectByTaskUuids(@Param("taskUuids") List<String> taskUuids);
 
   void insert(CeTaskCharacteristicDto taskCharacteristic);
 
index 002219c4b7146387440abf32053fe2df6db971ea..2e65de2cce97d7dba9a77940170414b1e49e04c0 100644 (file)
@@ -2,30 +2,45 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
 
 <mapper namespace="org.sonar.db.ce.CeTaskCharacteristicMapper">
-  <insert id="insert" parameterType="CeTaskCharacteristic" useGeneratedKeys="false">
-    insert into ce_task_characteristics (
-      uuid,
-      task_uuid,
-      kee,
-      text_value
-    )
-    values (
-      #{uuid,jdbcType=VARCHAR},
-      #{taskUuid,jdbcType=VARCHAR},
-      #{key,jdbcType=VARCHAR},
-      #{value,jdbcType=VARCHAR}
-    )
-  </insert>
-  
-  <select id="selectTaskCharacteristics" parameterType="map" resultType="CeTaskCharacteristic">
+
+  <sql id="columns">
+    c.uuid as "uuid",
+    c.task_uuid as "taskUuid",
+    c.kee as "key",
+    c.text_value as "value"
+  </sql>
+
+  <select id="selectByTaskUuid" parameterType="map" resultType="CeTaskCharacteristic">
     SELECT
-      c.uuid as "uuid",
-      c.task_uuid as "taskUuid",
-      c.kee as "key",
-      c.text_value as "value"
+      <include refid="columns"/>
     FROM 
       ce_task_characteristics c 
     WHERE
       c.task_uuid = #{taskUuid,jdbcType=VARCHAR}
   </select>
+
+  <select id="selectByTaskUuids" parameterType="map" resultType="CeTaskCharacteristic">
+    SELECT
+      <include refid="columns"/>
+    FROM
+      ce_task_characteristics c
+    WHERE
+      c.task_uuid in <foreach collection="taskUuids" open="(" close=")" item="taskUuid" separator=",">#{taskUuid,jdbcType=VARCHAR}</foreach>
+  </select>
+
+  <insert id="insert" parameterType="CeTaskCharacteristic" useGeneratedKeys="false">
+    insert into ce_task_characteristics (
+    uuid,
+    task_uuid,
+    kee,
+    text_value
+    )
+    values (
+    #{uuid,jdbcType=VARCHAR},
+    #{taskUuid,jdbcType=VARCHAR},
+    #{key,jdbcType=VARCHAR},
+    #{value,jdbcType=VARCHAR}
+    )
+  </insert>
+
 </mapper>
index e4d3d3b9f9a6487f3458a87c8020c4fca992ea7b..aa3eca59a9af969695ea8d89e15440e2620f2137 100644 (file)
  */
 package org.sonar.db.ce;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-
-import java.util.Collections;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
 public class CeTaskCharacteristicDaoTest {
   @Rule
   public DbTester dbTester = DbTester.create(System2.INSTANCE);
@@ -39,21 +39,49 @@ public class CeTaskCharacteristicDaoTest {
   private CeTaskCharacteristicDao underTest = new CeTaskCharacteristicDao();
 
   @Test
-  public void test_insert() {
-    CeTaskCharacteristicDto dto = new CeTaskCharacteristicDto();
-    dto.setKey("key");
-    dto.setValue("value");
-    dto.setUuid("uuid");
-    dto.setTaskUuid("task");
-    underTest.insert(dbTester.getSession(), Collections.singletonList(dto));
+  public void selectByTaskUuid() {
+    CeTaskCharacteristicDto dto1 = new CeTaskCharacteristicDto()
+      .setKey("key1")
+      .setValue("value1")
+      .setUuid("uuid1")
+      .setTaskUuid("task");
+    CeTaskCharacteristicDto dto2 = new CeTaskCharacteristicDto()
+      .setKey("key2")
+      .setValue("value2")
+      .setUuid("uuid2")
+      .setTaskUuid("task");
+    underTest.insert(dbTester.getSession(), asList(dto1, dto2));
     dbTester.getSession().commit();
 
-    assertThat(underTest.getTaskCharacteristics(dbTester.getSession(), "task")).containsOnly(entry("key", "value"));
+    assertThat(underTest.selectByTaskUuid(dbTester.getSession(), "task"))
+      .extracting(CeTaskCharacteristicDto::getTaskUuid, CeTaskCharacteristicDto::getUuid, CeTaskCharacteristicDto::getKey, CeTaskCharacteristicDto::getValue)
+      .containsOnly(
+        tuple("task", "uuid1", "key1", "value1"),
+        tuple("task", "uuid2", "key2", "value2"));
+    assertThat(underTest.selectByTaskUuid(dbTester.getSession(), "unknown")).isEmpty();
   }
 
   @Test
-  public void test_no_result() {
-    assertThat(underTest.getTaskCharacteristics(dbTester.getSession(), "task")).isEmpty();
+  public void selectByTaskUuids() {
+    CeTaskCharacteristicDto dto1 = new CeTaskCharacteristicDto()
+      .setKey("key1")
+      .setValue("value1")
+      .setUuid("uuid1")
+      .setTaskUuid("task1");
+    CeTaskCharacteristicDto dto2 = new CeTaskCharacteristicDto()
+      .setKey("key2")
+      .setValue("value2")
+      .setUuid("uuid2")
+      .setTaskUuid("task2");
+    underTest.insert(dbTester.getSession(), asList(dto1, dto2));
+    dbTester.getSession().commit();
 
+    assertThat(underTest.selectByTaskUuids(dbTester.getSession(), asList("task1", "task2")))
+      .extracting(CeTaskCharacteristicDto::getTaskUuid, CeTaskCharacteristicDto::getUuid, CeTaskCharacteristicDto::getKey, CeTaskCharacteristicDto::getValue)
+      .containsOnly(
+        tuple("task1", "uuid1", "key1", "value1"),
+        tuple("task2", "uuid2", "key2", "value2"));
+    assertThat(underTest.selectByTaskUuids(dbTester.getSession(), singletonList("unknown"))).isEmpty();
   }
+
 }
index b1ac6073762e0481c6fe688e26f1a6c7507b7b40..bf3c7923f67c1e19a2829d4f15af672804a246f3 100644 (file)
@@ -217,8 +217,7 @@ public class ActivityAction implements CeWsAction {
     }
 
     java.util.Optional<CeActivityDto> activity = dbClient.ceActivityDao().selectByUuid(dbSession, textQuery);
-    return activity.map(ceActivityDto -> Optional.of(formatter.formatActivity(dbSession, ceActivityDto))).orElseGet(Optional::absent);
-
+    return activity.map(ceActivityDto -> Optional.of(formatter.formatActivity(dbSession, ceActivityDto, null))).orElseGet(Optional::absent);
   }
 
   private CeTaskQuery buildQuery(DbSession dbSession, ActivityWsRequest request, @Nullable ComponentDto component) {
index 013516ad9839a3d9b3992312e9b7c673b93bd0f6..ae371a6b37ce04e06722d67b383025ce5e3ea625 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.ce.ws;
 
 import java.util.List;
+import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
@@ -62,11 +63,13 @@ public class ComponentAction implements CeWsAction {
     WebService.NewAction action = controller.createAction("component")
       .setDescription("Get the pending tasks, in-progress tasks and the last executed task of a given component (usually a project).<br>" +
         "Requires the following permission: 'Browse' on the specified component.<br>" +
-        "Either '%s' or '%s' must be provided, not both.<br>" +
-        "Since 6.1, field \"logs\" is deprecated and its value is always false.",
+        "Either '%s' or '%s' must be provided, not both.",
         PARAM_COMPONENT_ID, PARAM_COMPONENT_KEY)
       .setSince("5.2")
       .setResponseExample(getClass().getResource("component-example.json"))
+      .setChangelog(
+        new Change("6.1", "field \"logs\" is deprecated and its value is always false"),
+        new Change("6.6", "field \"incremental\" is added"))
       .setHandler(this);
 
     action.createParam(PARAM_COMPONENT_ID)
@@ -92,7 +95,7 @@ public class ComponentAction implements CeWsAction {
       ProjectResponse.Builder wsResponseBuilder = ProjectResponse.newBuilder();
       wsResponseBuilder.addAllQueue(formatter.formatQueue(dbSession, queueDtos));
       if (activityDtos.size() == 1) {
-        wsResponseBuilder.setCurrent(formatter.formatActivity(dbSession, activityDtos.get(0)));
+        wsResponseBuilder.setCurrent(formatter.formatActivity(dbSession, activityDtos.get(0), null));
       }
       writeProtobuf(wsResponseBuilder.build(), wsRequest, wsResponse);
     }
index a39958add89d93c7418aa21106c84eb4e26800c4..ed0868698390b032076e450154d39f14d05cd9aa 100644 (file)
@@ -28,6 +28,7 @@ import java.util.Optional;
 import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
@@ -72,6 +73,7 @@ public class TaskAction implements CeWsAction {
         "Since 6.1, field \"logs\" is deprecated and its value is always false.")
       .setResponseExample(getClass().getResource("task-example.json"))
       .setSince("5.2")
+      .setChangelog(new Change("6.6", "field \"incremental\" is added"))
       .setHandler(this);
 
     action
@@ -94,7 +96,7 @@ public class TaskAction implements CeWsAction {
       if (queueDto.isPresent()) {
         com.google.common.base.Optional<ComponentDto> component = loadComponent(dbSession, queueDto.get().getComponentUuid());
         checkPermission(component);
-        wsTaskResponse.setTask(wsTaskFormatter.formatQueue(dbSession, queueDto.get(), component));
+        wsTaskResponse.setTask(wsTaskFormatter.formatQueue(dbSession, queueDto.get()));
       } else {
         CeActivityDto ceActivityDto = WsUtils.checkFoundWithOptional(dbClient.ceActivityDao().selectByUuid(dbSession, taskUuid), "No activity found for task '%s'", taskUuid);
         com.google.common.base.Optional<ComponentDto> component = loadComponent(dbSession, ceActivityDto.getComponentUuid());
@@ -102,7 +104,7 @@ public class TaskAction implements CeWsAction {
         Set<AdditionalField> additionalFields = AdditionalField.getFromRequest(wsRequest);
         maskErrorStacktrace(ceActivityDto, additionalFields);
         wsTaskResponse.setTask(
-          wsTaskFormatter.formatActivity(dbSession, ceActivityDto, component, extractScannerContext(dbSession, ceActivityDto, additionalFields)));
+          wsTaskFormatter.formatActivity(dbSession, ceActivityDto, extractScannerContext(dbSession, ceActivityDto, additionalFields)));
       }
       writeProtobuf(wsTaskResponse.build(), wsRequest, wsResponse);
     }
index 16aead9298a75c772d346498e6bac10209583db1..a148896ab159477b0bca7cf9df058624954be055 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.server.ce.ws;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -28,6 +28,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.utils.DateUtils;
@@ -37,14 +38,13 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.SnapshotDto;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonarqube.ws.WsCe;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
-import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonList;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
 import static org.sonar.core.util.Protobuf.setNullable;
@@ -64,20 +64,15 @@ public class TaskFormatter {
   }
 
   public List<WsCe.Task> formatQueue(DbSession dbSession, List<CeQueueDto> dtos) {
-    ComponentDtoCache cache = ComponentDtoCache.forQueueDtos(dbClient, dbSession, dtos);
+    DtoCache cache = DtoCache.forQueueDtos(dbClient, dbSession, dtos);
     return dtos.stream().map(input -> formatQueue(input, cache)).collect(MoreCollectors.toList(dtos.size()));
   }
 
   public WsCe.Task formatQueue(DbSession dbSession, CeQueueDto queue) {
-    return formatQueue(queue, ComponentDtoCache.forQueueDtos(dbClient, dbSession, singletonList(queue)));
+    return formatQueue(queue, DtoCache.forQueueDtos(dbClient, dbSession, singletonList(queue)));
   }
 
-  public WsCe.Task formatQueue(DbSession dbSession, CeQueueDto dto, Optional<ComponentDto> component) {
-    checkArgument(Objects.equals(dto.getComponentUuid(), component.transform(ComponentDto::uuid).orNull()));
-    return formatQueue(dto, ComponentDtoCache.forComponentDto(dbClient, dbSession, component));
-  }
-
-  private WsCe.Task formatQueue(CeQueueDto dto, ComponentDtoCache componentDtoCache) {
+  private WsCe.Task formatQueue(CeQueueDto dto, DtoCache componentDtoCache) {
     WsCe.Task.Builder builder = WsCe.Task.newBuilder();
     String organizationKey = componentDtoCache.getOrganizationKey(dto.getComponentUuid());
     // FIXME organization field should be set from the CeQueueDto rather than from the ComponentDto
@@ -94,26 +89,22 @@ public class TaskFormatter {
     builder.setSubmittedAt(formatDateTime(new Date(dto.getCreatedAt())));
     setNullable(dto.getStartedAt(), builder::setStartedAt, DateUtils::formatDateTime);
     setNullable(computeExecutionTimeMs(dto), builder::setExecutionTimeMs);
+    builder.setIncremental(componentDtoCache.hasIncrementalCharacteristic(dto.getUuid()));
     return builder.build();
   }
 
-  public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto activity) {
-    return formatActivity(activity, ComponentDtoCache.forActivityDtos(dbClient, dbSession, singletonList(activity)), null);
-  }
-
-  public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto dto, Optional<ComponentDto> component,
-    @Nullable String scannerContext) {
-    return formatActivity(dto, ComponentDtoCache.forComponentDto(dbClient, dbSession, component), scannerContext);
+  public WsCe.Task formatActivity(DbSession dbSession, CeActivityDto dto, @Nullable String scannerContext) {
+    return formatActivity(dto, DtoCache.forActivityDtos(dbClient, dbSession, singletonList(dto)), scannerContext);
   }
 
   public List<WsCe.Task> formatActivity(DbSession dbSession, List<CeActivityDto> dtos) {
-    ComponentDtoCache cache = ComponentDtoCache.forActivityDtos(dbClient, dbSession, dtos);
+    DtoCache cache = DtoCache.forActivityDtos(dbClient, dbSession, dtos);
     return dtos.stream()
       .map(input -> formatActivity(input, cache, null))
       .collect(MoreCollectors.toList(dtos.size()));
   }
 
-  private static WsCe.Task formatActivity(CeActivityDto dto, ComponentDtoCache componentDtoCache, @Nullable String scannerContext) {
+  private static WsCe.Task formatActivity(CeActivityDto dto, DtoCache componentDtoCache, @Nullable String scannerContext) {
     WsCe.Task.Builder builder = WsCe.Task.newBuilder();
     String organizationKey = componentDtoCache.getOrganizationKey(dto.getComponentUuid());
     // FIXME organization field should be set from the CeActivityDto rather than from the ComponentDto
@@ -126,8 +117,9 @@ public class TaskFormatter {
     String analysisUuid = dto.getAnalysisUuid();
     if (analysisUuid != null) {
       builder.setAnalysisId(analysisUuid);
-      setNullable(componentDtoCache.getAnalysis(analysisUuid), analysis -> builder.setIncremental(analysis.getIncremental()));
     }
+    SnapshotDto analysis = analysisUuid == null ? null : componentDtoCache.getAnalysis(analysisUuid);
+    builder.setIncremental(analysis != null && analysis.getIncremental());
     setNullable(analysisUuid, builder::setAnalysisId);
     setNullable(dto.getSubmitterLogin(), builder::setSubmitterLogin);
     builder.setSubmittedAt(formatDateTime(new Date(dto.getSubmittedAt())));
@@ -150,22 +142,28 @@ public class TaskFormatter {
     return builder;
   }
 
-  private static class ComponentDtoCache {
+  private static class DtoCache {
     private final Map<String, ComponentDto> componentsByUuid;
     private final Map<String, OrganizationDto> organizationsByUuid;
     private final Map<String, SnapshotDto> analysisByUuid;
+    private final Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid;
 
-    private ComponentDtoCache(Map<String, ComponentDto> componentsByUuid, Map<String, OrganizationDto> organizationsByUuid, Map<String, SnapshotDto> analysisByUuid) {
+    private DtoCache(Map<String, ComponentDto> componentsByUuid, Map<String, OrganizationDto> organizationsByUuid, Map<String, SnapshotDto> analysisByUuid,
+      Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid) {
       this.componentsByUuid = componentsByUuid;
       this.organizationsByUuid = organizationsByUuid;
       this.analysisByUuid = analysisByUuid;
+      this.characteristicsByTaskUuid = characteristicsByTaskUuid;
     }
 
-    static ComponentDtoCache forQueueDtos(DbClient dbClient, DbSession dbSession, Collection<CeQueueDto> ceQueueDtos) {
+    static DtoCache forQueueDtos(DbClient dbClient, DbSession dbSession, Collection<CeQueueDto> ceQueueDtos) {
       Map<String, ComponentDto> componentsByUuid = dbClient.componentDao().selectByUuids(dbSession, uuidOfCeQueueDtos(ceQueueDtos))
         .stream()
         .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid));
-      return new ComponentDtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), Collections.emptyMap());
+      Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid = dbClient.ceTaskCharacteristicsDao()
+        .selectByTaskUuids(dbSession, ceQueueDtos.stream().map(CeQueueDto::getUuid).collect(Collectors.toList()))
+        .stream().collect(MoreCollectors.index(CeTaskCharacteristicDto::getTaskUuid));
+      return new DtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), Collections.emptyMap(), characteristicsByTaskUuid);
     }
 
     private static Set<String> uuidOfCeQueueDtos(Collection<CeQueueDto> ceQueueDtos) {
@@ -176,7 +174,7 @@ public class TaskFormatter {
         .collect(MoreCollectors.toSet(ceQueueDtos.size()));
     }
 
-    static ComponentDtoCache forActivityDtos(DbClient dbClient, DbSession dbSession, Collection<CeActivityDto> ceActivityDtos) {
+    static DtoCache forActivityDtos(DbClient dbClient, DbSession dbSession, Collection<CeActivityDto> ceActivityDtos) {
       Map<String, ComponentDto> componentsByUuid = dbClient.componentDao().selectByUuids(
         dbSession,
         uuidOfCeActivityDtos(ceActivityDtos))
@@ -184,7 +182,8 @@ public class TaskFormatter {
         .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid));
       Set<String> analysisUuids = ceActivityDtos.stream().map(CeActivityDto::getAnalysisUuid).filter(Objects::nonNull).collect(MoreCollectors.toSet());
       Map<String, SnapshotDto> analysisByUuid = dbClient.snapshotDao().selectByUuids(dbSession, analysisUuids).stream().collect(MoreCollectors.uniqueIndex(SnapshotDto::getUuid));
-      return new ComponentDtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), analysisByUuid);
+      return new DtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), analysisByUuid,
+        ImmutableMultimap.<String, CeTaskCharacteristicDto>builder().build());
     }
 
     private static Set<String> uuidOfCeActivityDtos(Collection<CeActivityDto> ceActivityDtos) {
@@ -195,11 +194,6 @@ public class TaskFormatter {
         .collect(MoreCollectors.toSet(ceActivityDtos.size()));
     }
 
-    static ComponentDtoCache forComponentDto(DbClient dbClient, DbSession dbSession, Optional<ComponentDto> component) {
-      Map<String, ComponentDto> componentsByUuid = component.isPresent() ? ImmutableMap.of(component.get().uuid(), component.get()) : emptyMap();
-      return new ComponentDtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), Collections.emptyMap());
-    }
-
     private static Map<String, OrganizationDto> buildOrganizationsByUuid(DbClient dbClient, DbSession dbSession, Map<String, ComponentDto> componentsByUuid) {
       return dbClient.organizationDao().selectByUuids(
         dbSession,
@@ -237,6 +231,12 @@ public class TaskFormatter {
     SnapshotDto getAnalysis(String analysisUuid) {
       return analysisByUuid.get(analysisUuid);
     }
+
+    boolean hasIncrementalCharacteristic(String taskUuid) {
+      return characteristicsByTaskUuid.get(taskUuid).stream()
+        .filter(c -> c.getKey().equals(CeTaskCharacteristicDto.INCREMENTAL_KEY))
+        .anyMatch(c -> c.getValue().equals("true"));
+    }
   }
 
   /**
index c6f20d7bc1ea6af32cf75e5e524fea34599bacac..d3a37c0d0ad2daab92aa1c0e449558e432fa5807 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.ce.ws;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import javax.annotation.Nullable;
@@ -30,10 +31,12 @@ import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.ce.taskprocessor.CeTaskProcessor;
+import org.sonar.core.util.Uuids;
 import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeActivityDto.Status;
 import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.SnapshotDto;
@@ -60,6 +63,9 @@ import static org.sonar.api.utils.DateUtils.formatDate;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
 import static org.sonar.db.ce.CeActivityDto.Status.FAILED;
 import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
+import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS;
+import static org.sonar.db.ce.CeQueueDto.Status.PENDING;
+import static org.sonar.db.ce.CeTaskCharacteristicDto.INCREMENTAL_KEY;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MAX_EXECUTED_AT;
@@ -124,7 +130,7 @@ public class ActivityActionTest {
     ComponentDto project2 = db.components().insertPrivateProject();
     insertActivity("T1", project1, SUCCESS);
     insertActivity("T2", project2, FAILED);
-    insertQueue("T3", project1, CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T3", project1, IN_PROGRESS);
 
     ActivityResponse activityResponse = call(ws.newRequest()
       .setParam("status", "FAILED,IN_PROGRESS"));
@@ -141,7 +147,7 @@ public class ActivityActionTest {
     ComponentDto project2 = db.components().insertPrivateProject();
     insertActivity("T1", project1, SUCCESS);
     insertActivity("T2", project2, FAILED);
-    insertQueue("T3", project1, CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T3", project1, IN_PROGRESS);
 
     ActivityResponse activityResponse = call(ws.newRequest()
       .setParam("status", "FAILED,IN_PROGRESS,SUCCESS")
@@ -171,7 +177,7 @@ public class ActivityActionTest {
     // T2 is the current activity (the most recent one)
     insertActivity("T1", project, SUCCESS);
     insertActivity("T2", project, FAILED);
-    insertQueue("T3", project, CeQueueDto.Status.PENDING);
+    insertQueue("T3", project, PENDING);
 
     ActivityResponse activityResponse = call(
       ws.newRequest()
@@ -188,7 +194,7 @@ public class ActivityActionTest {
     ComponentDto project2 = db.components().insertPrivateProject();
     insertActivity("T1", project1, SUCCESS);
     insertActivity("T2", project2, FAILED);
-    insertQueue("T3", project1, CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T3", project1, IN_PROGRESS);
 
     assertPage(1, asList("T3"));
     assertPage(2, asList("T3", "T2"));
@@ -269,12 +275,12 @@ public class ActivityActionTest {
   public void search_task_id_in_queue_ignoring_other_parameters() throws IOException {
     logInAsSystemAdministrator();
     ComponentDto project = db.components().insertPrivateProject();
-    insertQueue("T1", project, CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T1", project, IN_PROGRESS);
 
     ActivityResponse result = call(
       ws.newRequest()
         .setParam(Param.TEXT_QUERY, "T1")
-        .setParam(PARAM_STATUS, CeQueueDto.Status.PENDING.name()));
+        .setParam(PARAM_STATUS, PENDING.name()));
 
     assertThat(result.getTasksCount()).isEqualTo(1);
     assertThat(result.getTasks(0).getId()).isEqualTo("T1");
@@ -310,7 +316,7 @@ public class ActivityActionTest {
   @Test
   public void search_task_by_component_id() {
     ComponentDto project = db.components().insertPrivateProject();
-    insertQueue("T1", project, CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T1", project, IN_PROGRESS);
     insertActivity("T1", project, SUCCESS);
     userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
 
@@ -334,7 +340,7 @@ public class ActivityActionTest {
 
     assertThat(activityResponse.getTasksList())
       .extracting(Task::getId, Task::getIncremental)
-    .containsExactlyInAnyOrder(tuple("T1", true));
+      .containsExactlyInAnyOrder(tuple("T1", true));
   }
 
   @Test
@@ -371,6 +377,27 @@ public class ActivityActionTest {
       .containsExactlyInAnyOrder(tuple("T1", true));
   }
 
+  @Test
+  public void incremental_on_in_queue_analysis() {
+    ComponentDto project = db.components().insertPrivateProject();
+    CeQueueDto queue1 = insertQueue("T1", project, PENDING);
+    insertCharacteristic(queue1, INCREMENTAL_KEY, "true");
+    CeQueueDto queue2 = insertQueue("T2", project, IN_PROGRESS);
+    insertCharacteristic(queue2, INCREMENTAL_KEY, "true");
+    userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
+
+    ActivityResponse activityResponse = call(ws.newRequest()
+      .setParam(PARAM_COMPONENT_ID, project.uuid())
+      .setParam("status", "PENDING,FAILED,IN_PROGRESS"));
+
+    assertThat(activityResponse.getTasksList())
+      .extracting(Task::getId, Task::getIncremental)
+      .containsExactlyInAnyOrder(
+        tuple("T1", true),
+        tuple("T2", true)
+      );
+  }
+
   @Test
   public void fail_if_both_filters_on_component_id_and_name() {
     expectedException.expect(BadRequestException.class);
@@ -480,11 +507,22 @@ public class ActivityActionTest {
     activityDto.setExecutionTimeMs(500L);
     activityDto.setExecutedAt(EXECUTED_AT);
     activityDto.setAnalysisUuid(analysis == null ? null : analysis.getUuid());
-    db.getDbClient().ceActivityDao(). insert(db.getSession(), activityDto);
+    db.getDbClient().ceActivityDao().insert(db.getSession(), activityDto);
     db.commit();
     return activityDto;
   }
 
+  private CeTaskCharacteristicDto insertCharacteristic(CeQueueDto queueDto, String key, String value) {
+    CeTaskCharacteristicDto dto = new CeTaskCharacteristicDto()
+      .setUuid(Uuids.createFast())
+      .setTaskUuid(queueDto.getUuid())
+      .setKey(key)
+      .setValue(value);
+    db.getDbClient().ceTaskCharacteristicsDao().insert(db.getSession(), Collections.singletonList(dto));
+    db.commit();
+    return dto;
+  }
+
   private static ActivityResponse call(TestRequest request) {
     return request.executeProtobuf(ActivityResponse.class);
   }
index d153fa0f9d4a10712645becb9e120562a4b630a7..afecd31d24a456e8ed67f747b154208e5b83c8bd 100644 (file)
  */
 package org.sonar.server.ce.ws;
 
+import java.util.Collections;
 import javax.annotation.Nullable;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Uuids;
 import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.SnapshotDto;
@@ -41,7 +44,9 @@ import org.sonarqube.ws.MediaTypes;
 import org.sonarqube.ws.WsCe;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Java6Assertions.tuple;
 import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
+import static org.sonar.db.ce.CeTaskCharacteristicDto.INCREMENTAL_KEY;
 import static org.sonar.server.ce.ws.ComponentAction.PARAM_COMPONENT_ID;
 import static org.sonar.server.ce.ws.ComponentAction.PARAM_COMPONENT_KEY;
 
@@ -78,11 +83,11 @@ public class ComponentActionTest {
     SnapshotDto analysisProject1 = db.components().insertSnapshot(project1);
     ComponentDto project2 = db.components().insertPrivateProject(organization);
     userSession.addProjectPermission(UserRole.USER, project1);
-    insertActivity("T1", project1,CeActivityDto.Status.SUCCESS, analysisProject1);
+    insertActivity("T1", project1, CeActivityDto.Status.SUCCESS, analysisProject1);
     insertActivity("T2", project2, CeActivityDto.Status.FAILED, null);
-    insertActivity("T3", project1,CeActivityDto.Status.FAILED, null);
-    insertQueue("T4", project1,CeQueueDto.Status.IN_PROGRESS);
-    insertQueue("T5", project1,CeQueueDto.Status.PENDING);
+    insertActivity("T3", project1, CeActivityDto.Status.FAILED, null);
+    insertQueue("T4", project1, CeQueueDto.Status.IN_PROGRESS);
+    insertQueue("T5", project1, CeQueueDto.Status.PENDING);
 
     WsCe.ProjectResponse response = ws.newRequest()
       .setParam("componentId", project1.uuid())
@@ -98,6 +103,7 @@ public class ComponentActionTest {
       .extracting(WsCe.Task::getOrganization)
       .containsOnly(organization.getKey());
     assertThat(response.getCurrent().getOrganization()).isEqualTo(organization.getKey());
+    assertThat(response.getCurrent().getIncremental()).isFalse();
   }
 
   @Test
@@ -166,6 +172,28 @@ public class ComponentActionTest {
       .containsExactlyInAnyOrder("T1", true);
   }
 
+  @Test
+  public void incremental_on_in_queue_analysis() {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPrivateProject(organization);
+    userSession.addProjectPermission(UserRole.USER, project);
+    CeQueueDto queue1 = insertQueue("T1", project, CeQueueDto.Status.IN_PROGRESS);
+    insertCharacteristic(queue1, INCREMENTAL_KEY, "true");
+    CeQueueDto queue2 = insertQueue("T2", project, CeQueueDto.Status.PENDING);
+    insertCharacteristic(queue2, INCREMENTAL_KEY, "true");
+
+    WsCe.ProjectResponse response = ws.newRequest()
+      .setParam("componentId", project.uuid())
+      .executeProtobuf(WsCe.ProjectResponse.class);
+
+    assertThat(response.getQueueList())
+      .extracting(WsCe.Task::getId, WsCe.Task::getIncremental)
+      .containsOnly(
+        tuple("T1", true),
+        tuple("T2", true)
+      );
+  }
+
   @Test
   public void fail_with_404_when_component_does_not_exist() throws Exception {
     expectedException.expect(NotFoundException.class);
@@ -228,4 +256,15 @@ public class ComponentActionTest {
     db.getSession().commit();
     return activityDto;
   }
+
+  private CeTaskCharacteristicDto insertCharacteristic(CeQueueDto queueDto, String key, String value) {
+    CeTaskCharacteristicDto dto = new CeTaskCharacteristicDto()
+      .setUuid(Uuids.createFast())
+      .setTaskUuid(queueDto.getUuid())
+      .setKey(key)
+      .setValue(value);
+    db.getDbClient().ceTaskCharacteristicsDao().insert(db.getSession(), Collections.singletonList(dto));
+    db.commit();
+    return dto;
+  }
 }
index 6415597b482fd3d664b76c65c90ecbbad2d78e61..038f227104ba9b3a258a60b3e465da00166c348f 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.ce.ws;
 
+import java.util.Collections;
 import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
@@ -27,11 +28,14 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.System2;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.util.CloseableIterator;
+import org.sonar.core.util.Uuids;
 import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
@@ -54,18 +58,18 @@ public class TaskActionTest {
   public ExpectedException expectedException = ExpectedException.none();
 
   @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+  public DbTester db = DbTester.create(System2.INSTANCE);
 
   private OrganizationDto organizationDto;
   private ComponentDto project;
-  private TaskFormatter formatter = new TaskFormatter(dbTester.getDbClient(), System2.INSTANCE);
-  private TaskAction underTest = new TaskAction(dbTester.getDbClient(), formatter, userSession);
+  private TaskFormatter formatter = new TaskFormatter(db.getDbClient(), System2.INSTANCE);
+  private TaskAction underTest = new TaskAction(db.getDbClient(), formatter, userSession);
   private WsActionTester ws = new WsActionTester(underTest);
 
   @Before
   public void setUp() {
-    organizationDto = dbTester.organizations().insert();
-    project = dbTester.components().insertPrivateProject(organizationDto);
+    organizationDto = db.organizations().insert();
+    project = db.components().insertPrivateProject(organizationDto);
   }
 
   @Test
@@ -92,6 +96,7 @@ public class TaskActionTest {
     assertThat(taskResponse.getTask().getComponentName()).isEqualTo(project.name());
     assertThat(taskResponse.getTask().hasExecutionTimeMs()).isFalse();
     assertThat(taskResponse.getTask().getLogs()).isFalse();
+    assertThat(taskResponse.getTask().getIncremental()).isFalse();
   }
 
   @Test
@@ -116,6 +121,44 @@ public class TaskActionTest {
     assertThat(task.getLogs()).isFalse();
   }
 
+  @Test
+  public void incremental_on_queued_task() {
+    logInAsRoot();
+
+    ComponentDto project = db.components().insertPrivateProject();
+    CeQueueDto queueDto = createAndPersistQueueTask(project);
+    insertCharacteristic(queueDto, "incremental", "true");
+
+    WsCe.TaskResponse taskResponse = ws.newRequest()
+      .setParam("id", SOME_TASK_UUID)
+      .executeProtobuf(WsCe.TaskResponse.class);
+
+    assertThat(taskResponse.getTask().getIncremental()).isTrue();
+  }
+
+  @Test
+  public void incremental_on_archived_task() {
+    logInAsRoot();
+
+    ComponentDto project = db.components().insertPrivateProject();
+    SnapshotDto analysis = db.components().insertSnapshot(project, s -> s.setIncremental(true));
+    CeQueueDto queueDto = new CeQueueDto()
+      .setTaskType(CeTaskTypes.REPORT)
+      .setUuid(SOME_TASK_UUID)
+      .setComponentUuid(project.uuid());
+    CeActivityDto activityDto = new CeActivityDto(queueDto)
+      .setStatus(CeActivityDto.Status.FAILED)
+      .setExecutionTimeMs(500L)
+      .setAnalysisUuid(analysis.getUuid());
+    persist(activityDto);
+
+    WsCe.TaskResponse taskResponse = ws.newRequest()
+      .setParam("id", SOME_TASK_UUID)
+      .executeProtobuf(WsCe.TaskResponse.class);
+
+    assertThat(taskResponse.getTask().getIncremental()).isTrue();
+  }
+
   @Test
   public void return_stacktrace_of_failed_activity_with_stacktrace_when_additionalField_is_set() {
     logInAsRoot();
@@ -344,20 +387,31 @@ public class TaskActionTest {
     return dto;
   }
 
+  private CeTaskCharacteristicDto insertCharacteristic(CeQueueDto queueDto, String key, String value) {
+    CeTaskCharacteristicDto dto = new CeTaskCharacteristicDto()
+      .setUuid(Uuids.createFast())
+      .setTaskUuid(queueDto.getUuid())
+      .setKey(key)
+      .setValue(value);
+    db.getDbClient().ceTaskCharacteristicsDao().insert(db.getSession(), Collections.singletonList(dto));
+    db.commit();
+    return dto;
+  }
+
   private void persist(CeQueueDto queueDto) {
-    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
-    dbTester.commit();
+    db.getDbClient().ceQueueDao().insert(db.getSession(), queueDto);
+    db.commit();
   }
 
   private CeActivityDto persist(CeActivityDto activityDto) {
-    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
-    dbTester.commit();
+    db.getDbClient().ceActivityDao().insert(db.getSession(), activityDto);
+    db.commit();
     return activityDto;
   }
 
   private void persistScannerContext(String taskUuid, String scannerContext) {
-    dbTester.getDbClient().ceScannerContextDao().insert(dbTester.getSession(), taskUuid, CloseableIterator.from(singleton(scannerContext).iterator()));
-    dbTester.commit();
+    db.getDbClient().ceScannerContextDao().insert(db.getSession(), taskUuid, CloseableIterator.from(singleton(scannerContext).iterator()));
+    db.commit();
   }
 
   private void logInAsSystemAdministrator() {
index 3e99deaa3939865a01f879d92236d7b6aa29b08b..44cc1612ab5f21fc00bf2cbbaa8d47b4e337a475 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.ce.ws;
 
-import com.google.common.base.Optional;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Date;
@@ -160,7 +159,7 @@ public class TaskFormatterTest {
   public void formatActivity() {
     CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
 
-    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto);
+    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto, null);
 
     assertThat(wsTask.getType()).isEqualTo(CeTaskTypes.REPORT);
     assertThat(wsTask.getId()).isEqualTo("UUID");
@@ -177,7 +176,7 @@ public class TaskFormatterTest {
     CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED);
 
     String expected = "scanner context baby!";
-    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto, Optional.absent(), expected);
+    WsCe.Task wsTask = underTest.formatActivity(db.getSession(), dto, expected);
 
     assertThat(wsTask.hasScannerContext()).isTrue();
     assertThat(wsTask.getScannerContext()).isEqualTo(expected);
index 7b08a477f8b783e22ef569a942ddc69e198b5b98..931a979096811b3bfdd2c6b4533b67f6a6efc3a2 100644 (file)
  */
 package org.sonar.server.computation.queue;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
-import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
-import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
-import static org.sonar.db.permission.OrganizationPermission.SCAN;
-
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
-
 import org.apache.commons.io.IOUtils;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
@@ -56,6 +40,7 @@ import org.sonar.core.util.SequenceUuidFactory;
 import org.sonar.core.util.UuidFactory;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
@@ -69,6 +54,22 @@ import org.sonar.server.favorite.FavoriteUpdater;
 import org.sonar.server.permission.PermissionTemplateService;
 import org.sonar.server.tester.UserSessionRule;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
+import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
+import static org.sonar.db.permission.OrganizationPermission.SCAN;
+
 public class ReportSubmitterTest {
 
   private static final String PROJECT_KEY = "MY_PROJECT";
@@ -140,8 +141,10 @@ public class ReportSubmitterTest {
     verify(queue).submit(submittedTask.capture());
     String taskUuid = submittedTask.getValue().getUuid();
 
-    Map<String, String> insertedCharacteristics = db.getDbClient().ceTaskCharacteristicsDao().getTaskCharacteristics(db.getSession(), taskUuid);
-    assertThat(insertedCharacteristics).containsOnly(entry("incremental", "true"), entry("pr", "mypr"));
+    List<CeTaskCharacteristicDto> insertedCharacteristics = db.getDbClient().ceTaskCharacteristicsDao().selectByTaskUuid(db.getSession(), taskUuid);
+    assertThat(insertedCharacteristics)
+      .extracting(CeTaskCharacteristicDto::getKey, CeTaskCharacteristicDto::getValue)
+      .containsOnly(tuple("incremental", "true"), tuple("pr", "mypr"));
   }
 
   @Test
index ad610ee4a04ade75ee4b6274bce5ceee7d1d6b5c..c223da8dd3af63797816e85dd300dbf99d695d01 100644 (file)
@@ -21,6 +21,7 @@ package org.sonarqube.ws.client.ce;
 
 import org.sonarqube.ws.WsCe;
 import org.sonarqube.ws.WsCe.ActivityResponse;
+import org.sonarqube.ws.WsCe.ProjectResponse;
 import org.sonarqube.ws.WsCe.TaskTypesWsResponse;
 import org.sonarqube.ws.WsCe.WorkerCountResponse;
 import org.sonarqube.ws.client.BaseService;
@@ -95,4 +96,11 @@ public class CeService extends BaseService {
     return call(new GetRequest(path(ACTION_WORKER_COUNT)), WorkerCountResponse.parser());
   }
 
+  public ProjectResponse component(String componentKey) {
+    return call(
+      new GetRequest(path("component"))
+        .setParam(PARAM_COMPONENT_KEY, componentKey),
+      ProjectResponse.parser());
+  }
+
 }
index 16d443a7276abca4c05f4f7c21e9e3b2b16c72a1..5e65034cd41dae4380cac1ed2593a8d84987da25 100644 (file)
@@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.data.MapEntry.entry;
 import static org.mockito.Mockito.mock;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MAX_EXECUTED_AT;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MIN_SUBMITTED_AT;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_ONLY_CURRENTS;
@@ -141,4 +142,16 @@ public class CeServiceTest {
     assertThat(serviceTester.getGetRequest().getPath()).isEqualTo("api/ce/worker_count");
     assertThat(serviceTester.getGetParser()).isSameAs(WsCe.WorkerCountResponse.parser());
   }
+
+  @Test
+  public void component() {
+    underTest.component("my_component");
+    GetRequest result = serviceTester.getGetRequest();
+
+    assertThat(serviceTester.getGetParser()).isSameAs(WsCe.ProjectResponse.parser());
+    serviceTester.assertThat(result)
+      .hasPath("component")
+      .hasParam(PARAM_COMPONENT_KEY, "my_component")
+      .andNoOtherParam();
+  }
 }