Browse Source

SONAR-11238 api/ce/[task|activity|component] return task warnings

all return warnings count, warnings list is only available from api/ce/task on demand
tags/7.5
Sébastien Lesaint 5 years ago
parent
commit
e4364789b5

+ 19
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeActivityDto.java View File

@@ -96,9 +96,14 @@ public class CeActivityDto {
* Flag indicating whether the analysis of the current activity has a scanner context or not.
* <p>
* This property can not be populated when inserting but <strong>is populated when reading</strong>.
* </p>
*/
private boolean hasScannerContext;
/**
* Count of warnings attached to the current activity.
* <p>
* This property can not be populated when inserting but <strong>is populated when retrieving the activity by UUID</strong>.
*/
private int warningCount = 0;

CeActivityDto() {
// required for MyBatis
@@ -311,8 +316,19 @@ public class CeActivityDto {
return hasScannerContext;
}

protected void setHasScannerContext(boolean hasScannerContext) {
protected CeActivityDto setHasScannerContext(boolean hasScannerContext) {
this.hasScannerContext = hasScannerContext;
return this;
}

public int getWarningCount() {
return warningCount;
}

protected CeActivityDto setWarningCount(int warningCount) {
checkArgument(warningCount >= 0);
this.warningCount = warningCount;
return this;
}

@Override
@@ -339,6 +355,7 @@ public class CeActivityDto {
", errorMessage='" + errorMessage + '\'' +
", errorStacktrace='" + errorStacktrace + '\'' +
", hasScannerContext=" + hasScannerContext +
", warningCount=" + warningCount +
'}';
}


+ 8
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageDao.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.db.ce;

import java.util.List;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;

@@ -27,6 +28,13 @@ public class CeTaskMessageDao implements Dao {
getMapper(dbSession).insert(dto);
}

/**
* @return the messages for the specific task, if any, in ascending order of column {@code CREATED_AT}.
*/
public List<CeTaskMessageDto> selectByTask(DbSession dbSession, String taskUuid) {
return getMapper(dbSession).selectByTask(taskUuid);
}

private static CeTaskMessageMapper getMapper(DbSession dbSession) {
return dbSession.getMapper(CeTaskMessageMapper.class);
}

+ 3
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageMapper.java View File

@@ -19,9 +19,12 @@
*/
package org.sonar.db.ce;

import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface CeTaskMessageMapper {
void insert(@Param("dto") CeTaskMessageDto dto);

List<CeTaskMessageDto> selectByTask(@Param("taskUuid") String taskUuid);

}

+ 19
- 8
server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml View File

@@ -15,6 +15,10 @@
csc.task_uuid is not null as hasScannerContext
</sql>

<sql id="countWarnings">
(select count(1) from ce_task_message ctm where ctm.task_uuid = ca.uuid) as warningCount
</sql>

<sql id="columns">
ca.id,
ca.uuid,
@@ -42,25 +46,31 @@

<select id="selectByUuid" parameterType="String" resultType="org.sonar.db.ce.CeActivityDto">
select
<include refid="columns"/>,
ca.error_stacktrace as errorStacktrace
<include refid="columns"/>,
ca.error_stacktrace as errorStacktrace,
<include refid="countWarnings"/>
from ce_activity ca
left outer join ce_scanner_context csc on ca.uuid = csc.task_uuid
where ca.uuid=#{uuid,jdbcType=VARCHAR}
left outer join ce_scanner_context csc on
ca.uuid = csc.task_uuid
where
ca.uuid=#{uuid,jdbcType=VARCHAR}
</select>

<select id="selectByQuery" parameterType="map" resultType="org.sonar.db.ce.CeActivityDto">
select
<include refid="columns"/>
<include refid="columns"/>,
<include refid="countWarnings"/>
<include refid="sqlSelectByQuery" />
order by ca.id desc
order by
ca.id desc
limit #{pagination.pageSize,jdbcType=INTEGER} offset #{pagination.offset,jdbcType=INTEGER}
</select>

<select id="selectByQuery" parameterType="map" resultType="org.sonar.db.ce.CeActivityDto" databaseId="mssql">
select * from (
select row_number() over(order by id desc) as number,
<include refid="columns"/>
<include refid="columns"/>,
<include refid="countWarnings"/>
<include refid="sqlSelectByQuery" />
) as query
where
@@ -72,7 +82,8 @@
select * from (
select rownum as rn, t.* from (
select
<include refid="columns"/>
<include refid="columns"/>,
<include refid="countWarnings"/>
<include refid="sqlSelectByQuery" />
order by ca.id desc
) t

+ 18
- 0
server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeTaskMessageMapper.xml View File

@@ -3,6 +3,24 @@

<mapper namespace="org.sonar.db.ce.CeTaskMessageMapper">

<sql id="columns">
ctm.uuid,
ctm.task_uuid as taskUuid,
ctm.message as message,
ctm.created_at as createdAt
</sql>

<select id="selectByTask" resultType="org.sonar.db.ce.CeTaskMessageDto">
select
<include refid="columns"/>
from
ce_task_message ctm
where
ctm.task_uuid=#{taskUuid,jdbcType=VARCHAR}
order by
ctm.created_at asc
</select>

<insert id="insert" parameterType="org.sonar.db.ce.CeTaskMessageDto" useGeneratedKeys="false">
insert into ce_task_message
(

+ 124
- 29
server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java View File

@@ -29,6 +29,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.IntStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractListAssert;
@@ -75,7 +77,7 @@ public class CeActivityDaoTest {

@Test
public void test_insert() {
CeActivityDto inserted = insert("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
CeActivityDto inserted = insert("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, SUCCESS);

Optional<CeActivityDto> saved = underTest.selectByUuid(db.getSession(), "TASK_1");
assertThat(saved).isPresent();
@@ -83,7 +85,7 @@ public class CeActivityDaoTest {
assertThat(dto.getUuid()).isEqualTo("TASK_1");
assertThat(dto.getMainComponentUuid()).isEqualTo(MAINCOMPONENT_1);
assertThat(dto.getComponentUuid()).isEqualTo(COMPONENT_1);
assertThat(dto.getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
assertThat(dto.getStatus()).isEqualTo(SUCCESS);
assertThat(dto.getSubmitterUuid()).isEqualTo("submitter uuid");
assertThat(dto.getSubmittedAt()).isEqualTo(1_450_000_000_000L);
assertThat(dto.getWorkerUuid()).isEqualTo("worker uuid");
@@ -101,6 +103,34 @@ public class CeActivityDaoTest {
assertThat(dto.getErrorStacktrace()).isNull();
assertThat(dto.getErrorType()).isNull();
assertThat(dto.isHasScannerContext()).isFalse();
assertThat(dto.getWarningCount()).isZero();
}

@Test
public void selectByUuid_populates_warning_count() {
CeActivityDto[] tasks = {
insert("TASK_1", REPORT, "PROJECT_1", SUCCESS),
insert("TASK_2", REPORT, "PROJECT_1", SUCCESS),
insert("TASK_3", REPORT, "PROJECT_1", SUCCESS)
};
int moreThan1 = 2 + new Random().nextInt(5);
insertWarnings(tasks[0], moreThan1);
insertWarnings(tasks[1], 0);
insertWarnings(tasks[2], 1);

assertThat(underTest.selectByUuid(dbSession, tasks[0].getUuid()).get().getWarningCount()).isEqualTo(moreThan1);
assertThat(underTest.selectByUuid(dbSession, tasks[1].getUuid()).get().getWarningCount()).isEqualTo(0);
assertThat(underTest.selectByUuid(dbSession, tasks[2].getUuid()).get().getWarningCount()).isEqualTo(1);
}

private void insertWarnings(CeActivityDto task, int warningCount) {
IntStream.range(0, warningCount).forEach(i -> db.getDbClient().ceTaskMessageDao().insert(dbSession,
new CeTaskMessageDto()
.setUuid(UuidFactoryFast.getInstance().create())
.setTaskUuid(task.getUuid())
.setMessage("message_" + task.getUuid() + "_" + i)
.setCreatedAt(task.getUuid().hashCode() + i)));
db.commit();
}

@Test
@@ -296,7 +326,7 @@ public class CeActivityDaoTest {

@Test
public void test_insert_of_errorMessage_of_1_000_chars() {
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED)
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, FAILED)
.setErrorMessage(Strings.repeat("x", 1_000));
underTest.insert(db.getSession(), dto);

@@ -307,7 +337,7 @@ public class CeActivityDaoTest {
@Test
public void test_insert_of_errorMessage_of_1_001_chars_is_truncated_to_1000() {
String expected = Strings.repeat("x", 1_000);
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED)
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, FAILED)
.setErrorMessage(expected + "y");
underTest.insert(db.getSession(), dto);

@@ -317,7 +347,7 @@ public class CeActivityDaoTest {

@Test
public void test_insert_error_message_and_stacktrace() {
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED)
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, FAILED)
.setErrorStacktrace("error stack");
underTest.insert(db.getSession(), dto);

@@ -330,7 +360,7 @@ public class CeActivityDaoTest {

@Test
public void test_insert_error_message_only() {
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED);
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, FAILED);
underTest.insert(db.getSession(), dto);

Optional<CeActivityDto> saved = underTest.selectByUuid(db.getSession(), "TASK_1");
@@ -342,11 +372,11 @@ public class CeActivityDaoTest {
@Test
public void insert_must_set_relevant_is_last_field() {
// only a single task on MAINCOMPONENT_1 -> is_last=true
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_1", REPORT, MAINCOMPONENT_1, SUCCESS);
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isTrue();

// only a single task on MAINCOMPONENT_2 -> is_last=true
insert("TASK_2", REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS);
insert("TASK_2", REPORT, MAINCOMPONENT_2, SUCCESS);
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue();

// two tasks on MAINCOMPONENT_1, the most recent one is TASK_3
@@ -356,7 +386,7 @@ public class CeActivityDaoTest {
assertThat(underTest.selectByUuid(db.getSession(), "TASK_3").get().getIsLast()).isTrue();

// inserting a cancelled task does not change the last task
insert("TASK_4", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.CANCELED);
insert("TASK_4", REPORT, MAINCOMPONENT_1, CANCELED);
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isFalse();
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue();
assertThat(underTest.selectByUuid(db.getSession(), "TASK_3").get().getIsLast()).isTrue();
@@ -365,10 +395,10 @@ public class CeActivityDaoTest {

@Test
public void test_selectByQuery() {
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_1", REPORT, MAINCOMPONENT_1, SUCCESS);
insert("TASK_2", REPORT, MAINCOMPONENT_1, FAILED);
insert("TASK_3", REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS);
insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS);
insert("TASK_3", REPORT, MAINCOMPONENT_2, SUCCESS);
insert("TASK_4", "views", null, SUCCESS);

// no filters
CeTaskQuery query = new CeTaskQuery().setStatuses(Collections.emptyList());
@@ -381,7 +411,7 @@ public class CeActivityDaoTest {
assertThat(dtos).extracting("uuid").containsExactly("TASK_2", "TASK_1");

// select by status
query = new CeTaskQuery().setStatuses(singletonList(CeActivityDto.Status.SUCCESS.name()));
query = new CeTaskQuery().setStatuses(singletonList(SUCCESS.name()));
dtos = underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100));
assertThat(dtos).extracting("uuid").containsExactly("TASK_4", "TASK_3", "TASK_1");

@@ -423,12 +453,62 @@ public class CeActivityDaoTest {
assertThat(dto.isHasScannerContext()).isTrue();
}

@Test
public void selectByQuery_populates_warningCount() {
CeActivityDto[] tasks = {
insert("TASK_1", REPORT, "PROJECT_1", SUCCESS),
insert("TASK_2", REPORT, "PROJECT_1", FAILED),
insert("TASK_3", REPORT, "PROJECT_2", SUCCESS),
insert("TASK_4", "views", null, SUCCESS)
};
int moreThan1 = 2 + new Random().nextInt(5);
insertWarnings(tasks[0], moreThan1);
insertWarnings(tasks[1], 3);
insertWarnings(tasks[2], 1);
insertWarnings(tasks[3], 6);

// no filters
CeTaskQuery query = new CeTaskQuery().setStatuses(Collections.emptyList());
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(10)))
.extracting(CeActivityDto::getUuid, CeActivityDto::getWarningCount)
.containsExactly(tuple("TASK_4", 6), tuple("TASK_3", 1), tuple("TASK_2", 3), tuple("TASK_1", moreThan1));

// select by component uuid
query = new CeTaskQuery().setMainComponentUuid("PROJECT_1");
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)))
.extracting(CeActivityDto::getUuid, CeActivityDto::getWarningCount)
.containsExactly(tuple("TASK_2", 3), tuple("TASK_1", moreThan1));

// select by status
query = new CeTaskQuery().setStatuses(singletonList(SUCCESS.name()));
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)))
.extracting(CeActivityDto::getUuid, CeActivityDto::getWarningCount)
.containsExactly(tuple("TASK_4", 6), tuple("TASK_3", 1), tuple("TASK_1", moreThan1));

// select by type
query = new CeTaskQuery().setType(REPORT);
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)))
.extracting(CeActivityDto::getUuid, CeActivityDto::getWarningCount)
.containsExactly(tuple("TASK_3", 1), tuple("TASK_2", 3), tuple("TASK_1", moreThan1));
query = new CeTaskQuery().setType("views");
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)))
.extracting(CeActivityDto::getUuid, CeActivityDto::getWarningCount)
.containsExactly(tuple("TASK_4", 6));

// select by multiple conditions
query = new CeTaskQuery().setType(REPORT).setOnlyCurrents(true).setMainComponentUuid("PROJECT_1");
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)))
.extracting(CeActivityDto::getUuid, CeActivityDto::getWarningCount)
.containsExactly(tuple("TASK_2", 3));

}

@Test
public void selectByQuery_is_paginated_and_return_results_sorted_from_last_to_first() {
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_2", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.FAILED);
insert("TASK_3", REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS);
insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS);
insert("TASK_1", REPORT, MAINCOMPONENT_1, SUCCESS);
insert("TASK_2", REPORT, MAINCOMPONENT_1, FAILED);
insert("TASK_3", REPORT, MAINCOMPONENT_2, SUCCESS);
insert("TASK_4", "views", null, SUCCESS);

assertThat(selectPageOfUuids(forPage(1).andSize(1))).containsExactly("TASK_4");
assertThat(selectPageOfUuids(forPage(2).andSize(1))).containsExactly("TASK_3");
@@ -441,7 +521,7 @@ public class CeActivityDaoTest {

@Test
public void selectByQuery_no_results_if_shortcircuited_by_component_uuids() {
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_1", REPORT, MAINCOMPONENT_1, SUCCESS);

CeTaskQuery query = new CeTaskQuery();
query.setMainComponentUuids(Collections.emptyList());
@@ -474,7 +554,7 @@ public class CeActivityDaoTest {
queueDto.setUuid(uuid);
queueDto.setTaskType("fake");
CeActivityDto dto = new CeActivityDto(queueDto);
dto.setStatus(CeActivityDto.Status.SUCCESS);
dto.setStatus(SUCCESS);
dto.setSubmittedAt(submittedAt);
dto.setExecutedAt(executedAt);
underTest.insert(db.getSession(), dto);
@@ -513,11 +593,26 @@ public class CeActivityDaoTest {
.extracting("errorStacktrace").containsOnly((String) null);
}

@Test
public void selectOlderThan_does_not_populate_warningCount() {
CeActivityDto activity1 = insert("TASK_1", REPORT, "PROJECT_1", FAILED);
insertWarnings(activity1, 10);
CeActivityDto activity2 = insert("TASK_2", REPORT, "PROJECT_1", SUCCESS);
insertWarnings(activity2, 1);

List<CeActivityDto> dtos = underTest.selectOlderThan(db.getSession(), system2.now() + 1_000_000L);

assertThat(dtos)
.hasSize(2)
.extracting(CeActivityDto::getWarningCount)
.containsOnly(0);
}

@Test
public void deleteByUuids() {
insert("TASK_1", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_2", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_3", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_1", "REPORT", MAINCOMPONENT_1, SUCCESS);
insert("TASK_2", "REPORT", MAINCOMPONENT_1, SUCCESS);
insert("TASK_3", "REPORT", MAINCOMPONENT_1, SUCCESS);

underTest.deleteByUuids(db.getSession(), ImmutableSet.of("TASK_1", "TASK_3"));
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").isPresent()).isFalse();
@@ -527,7 +622,7 @@ public class CeActivityDaoTest {

@Test
public void deleteByUuids_does_nothing_if_uuid_does_not_exist() {
insert("TASK_1", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_1", "REPORT", MAINCOMPONENT_1, SUCCESS);

// must not fail
underTest.deleteByUuids(db.getSession(), singleton("TASK_2"));
@@ -537,14 +632,14 @@ public class CeActivityDaoTest {

@Test
public void count_last_by_status_and_main_component_uuid() {
insert("TASK_1", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_1", CeTaskTypes.REPORT, MAINCOMPONENT_1, SUCCESS);
// component 2
insert("TASK_2", CeTaskTypes.REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS);
insert("TASK_2", CeTaskTypes.REPORT, MAINCOMPONENT_2, SUCCESS);
// status failed
insert("TASK_3", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.FAILED);
insert("TASK_3", CeTaskTypes.REPORT, MAINCOMPONENT_1, FAILED);
// status canceled
insert("TASK_4", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.CANCELED);
insert("TASK_5", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS);
insert("TASK_4", CeTaskTypes.REPORT, MAINCOMPONENT_1, CANCELED);
insert("TASK_5", CeTaskTypes.REPORT, MAINCOMPONENT_1, SUCCESS);
db.commit();

assertThat(underTest.countLastByStatusAndMainComponentUuid(dbSession, SUCCESS, MAINCOMPONENT_1)).isEqualTo(1);
@@ -601,7 +696,7 @@ public class CeActivityDaoTest {
queueDto.setTaskType("fake");

CeActivityDto dto = new CeActivityDto(queueDto);
dto.setStatus(CeActivityDto.Status.SUCCESS);
dto.setStatus(SUCCESS);
dto.setAnalysisUuid(uuid + "_AA");
system2.setNow(date);
underTest.insert(db.getSession(), dto);

+ 10
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDtoTest.java View File

@@ -132,6 +132,16 @@ public class CeActivityDtoTest {
assertThat(underTest.getErrorMessage()).isEqualTo(before + after);
}

@Test
public void setWarningCount_throws_IAE_if_less_than_0() {
underTest.setWarningCount(0);
underTest.setWarningCount(1 + new Random().nextInt(10));

expectedException.expect(IllegalArgumentException.class);

underTest.setWarningCount(-1 - new Random().nextInt(10));
}

@DataProvider
public static Object[][] stringsWithChar0() {
return new Object[][] {

+ 48
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeTaskMessageDaoTest.java View File

@@ -19,13 +19,16 @@
*/
package org.sonar.db.ce;

import java.util.List;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;

import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;

public class CeTaskMessageDaoTest {
@@ -49,6 +52,51 @@ public class CeTaskMessageDaoTest {
.hasSize(1)
.extracting(t -> t.get("UUID"), t -> t.get("TASK_UUID"), t -> t.get("MESSAGE"), t -> t.get("CREATED_AT"))
.containsOnly(Tuple.tuple("uuid_1", "task_uuid_1", "message_1", 1_222_333L));
}

@Test
public void selectByTask_returns_empty_on_empty_table() {
String taskUuid = randomAlphabetic(10);

List<CeTaskMessageDto> dto = underTest.selectByTask(dbTester.getSession(), taskUuid);

assertThat(dto).isEmpty();
}

@Test
public void selectByTask_returns_message_of_task_ordered_by_CREATED_AT_asc() {
String task1 = "task1";
String task2 = "task2";
CeTaskMessageDto[] messages = {
insertMessage(task1, 0, 1_222_333L),
insertMessage(task2, 1, 2_222_333L),
insertMessage(task2, 2, 1_111_333L),
insertMessage(task1, 3, 1_222_111L),
insertMessage(task1, 4, 222_111L),
insertMessage(task1, 5, 3_222_111L)
};

assertThat(underTest.selectByTask(dbTester.getSession(), task1))
.extracting(CeTaskMessageDto::getUuid)
.containsExactly(messages[4].getUuid(), messages[3].getUuid(), messages[0].getUuid(), messages[5].getUuid());

assertThat(underTest.selectByTask(dbTester.getSession(), task2))
.extracting(CeTaskMessageDto::getUuid)
.containsExactly(messages[2].getUuid(), messages[1].getUuid());

assertThat(underTest.selectByTask(dbTester.getSession(), randomAlphabetic(5)))
.isEmpty();
}

private CeTaskMessageDto insertMessage(String taskUuid, int i, long createdAt) {
CeTaskMessageDto res = new CeTaskMessageDto()
.setUuid("message_" + i)
.setTaskUuid(taskUuid)
.setMessage("test_" + i)
.setCreatedAt(createdAt);
DbSession dbSession = dbTester.getSession();
underTest.insert(dbSession, res);
dbSession.commit();
return res;
}
}

+ 6
- 5
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java View File

@@ -20,12 +20,12 @@
package org.sonar.server.ce.ws;

import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -53,6 +53,7 @@ import static java.lang.Boolean.parseBoolean;
import static java.lang.Integer.parseInt;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.apache.commons.lang.StringUtils.defaultString;
import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime;
@@ -209,16 +210,16 @@ public class ActivityAction implements CeWsAction {
private Optional<Ce.Task> searchTaskByUuid(DbSession dbSession, Request request) {
String textQuery = request.getQ();
if (textQuery == null) {
return Optional.absent();
return Optional.empty();
}

java.util.Optional<CeQueueDto> queue = dbClient.ceQueueDao().selectByUuid(dbSession, textQuery);
Optional<CeQueueDto> queue = dbClient.ceQueueDao().selectByUuid(dbSession, textQuery);
if (queue.isPresent()) {
return Optional.of(formatter.formatQueue(dbSession, queue.get()));
}

java.util.Optional<CeActivityDto> activity = dbClient.ceActivityDao().selectByUuid(dbSession, textQuery);
return activity.map(ceActivityDto -> Optional.of(formatter.formatActivity(dbSession, ceActivityDto, null))).orElseGet(Optional::absent);
Optional<CeActivityDto> activity = dbClient.ceActivityDao().selectByUuid(dbSession, textQuery);
return activity.map(ceActivityDto -> formatter.formatActivity(dbSession, ceActivityDto, null, emptyList()));
}

private CeTaskQuery buildQuery(DbSession dbSession, Request request, @Nullable ComponentDto component) {

+ 4
- 3
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java View File

@@ -38,11 +38,12 @@ import org.sonar.server.ws.KeyExamples;
import org.sonarqube.ws.Ce;
import org.sonarqube.ws.Ce.ComponentResponse;

import static java.util.Collections.emptyList;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT;
import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT_ID;
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class ComponentAction implements CeWsAction {

@@ -97,7 +98,7 @@ public class ComponentAction implements CeWsAction {
Ce.ComponentResponse.Builder wsResponseBuilder = ComponentResponse.newBuilder();
wsResponseBuilder.addAllQueue(formatter.formatQueue(dbSession, queueDtos));
if (activityDtos.size() == 1) {
wsResponseBuilder.setCurrent(formatter.formatActivity(dbSession, activityDtos.get(0), null));
wsResponseBuilder.setCurrent(formatter.formatActivity(dbSession, activityDtos.get(0), null, emptyList()));
}
writeProtobuf(wsResponseBuilder.build(), wsRequest, wsResponse);
}

+ 16
- 2
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java View File

@@ -38,6 +38,7 @@ 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.CeTaskMessageDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.server.user.UserSession;
@@ -105,7 +106,9 @@ public class TaskAction implements CeWsAction {
Set<AdditionalField> additionalFields = AdditionalField.getFromRequest(wsRequest);
maskErrorStacktrace(ceActivityDto, additionalFields);
wsTaskResponse.setTask(
wsTaskFormatter.formatActivity(dbSession, ceActivityDto, extractScannerContext(dbSession, ceActivityDto, additionalFields)));
wsTaskFormatter.formatActivity(dbSession, ceActivityDto,
extractScannerContext(dbSession, ceActivityDto, additionalFields),
extractWarnings(dbSession, ceActivityDto, additionalFields)));
}
writeProtobuf(wsTaskResponse.build(), wsRequest, wsResponse);
}
@@ -147,9 +150,20 @@ public class TaskAction implements CeWsAction {
return null;
}

private List<String> extractWarnings(DbSession dbSession, CeActivityDto activityDto, Set<AdditionalField> additionalFields) {
if (additionalFields.contains(AdditionalField.WARNINGS)) {
List<CeTaskMessageDto> dtos = dbClient.ceTaskMessageDao().selectByTask(dbSession, activityDto.getUuid());
return dtos.stream()
.map(CeTaskMessageDto::getMessage)
.collect(MoreCollectors.toList(dtos.size()));
}
return Collections.emptyList();
}

private enum AdditionalField {
STACKTRACE("stacktrace"),
SCANNER_CONTEXT("scannerContext");
SCANNER_CONTEXT("scannerContext"),
WARNINGS("warnings");

private final String label;


+ 8
- 4
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java View File

@@ -46,6 +46,7 @@ import org.sonarqube.ws.Common;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.util.Protobuf.setNullable;
@@ -95,18 +96,18 @@ public class TaskFormatter {
return builder.build();
}

public Ce.Task formatActivity(DbSession dbSession, CeActivityDto dto, @Nullable String scannerContext) {
return formatActivity(dto, DtoCache.forActivityDtos(dbClient, dbSession, singletonList(dto)), scannerContext);
public Ce.Task formatActivity(DbSession dbSession, CeActivityDto dto, @Nullable String scannerContext, List<String> warnings) {
return formatActivity(dto, DtoCache.forActivityDtos(dbClient, dbSession, singletonList(dto)), scannerContext, warnings);
}

public List<Ce.Task> formatActivity(DbSession dbSession, List<CeActivityDto> dtos) {
DtoCache cache = DtoCache.forActivityDtos(dbClient, dbSession, dtos);
return dtos.stream()
.map(input -> formatActivity(input, cache, null))
.map(input -> formatActivity(input, cache, null, emptyList()))
.collect(MoreCollectors.toList(dtos.size()));
}

private static Ce.Task formatActivity(CeActivityDto dto, DtoCache cache, @Nullable String scannerContext) {
private static Ce.Task formatActivity(CeActivityDto dto, DtoCache cache, @Nullable String scannerContext, List<String> warnings) {
Ce.Task.Builder builder = Ce.Task.newBuilder();
String organizationKey = cache.getOrganizationKey(dto.getComponentUuid());
setNullable(organizationKey, builder::setOrganization);
@@ -129,6 +130,9 @@ public class TaskFormatter {
setNullable(dto.getErrorType(), builder::setErrorType);
setNullable(scannerContext, builder::setScannerContext);
builder.setHasScannerContext(dto.isHasScannerContext());
builder.setWarningCount(dto.getWarningCount());
warnings.forEach(builder::addWarnings);

return builder.build();
}


+ 35
- 0
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java View File

@@ -22,6 +22,7 @@ package org.sonar.server.ce.ws;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.IntStream;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
@@ -36,6 +37,7 @@ 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.CeTaskMessageDto;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
@@ -57,6 +59,7 @@ import org.sonarqube.ws.Common;
import org.sonarqube.ws.MediaTypes;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
@@ -116,6 +119,7 @@ public class ActivityActionTest {
assertThat(task.hasAnalysisId()).isFalse();
assertThat(task.getExecutionTimeMs()).isEqualTo(500L);
assertThat(task.getLogs()).isFalse();
assertThat(task.getWarningCount()).isZero();

task = activityResponse.getTasks(1);
assertThat(task.getId()).isEqualTo("T1");
@@ -123,6 +127,7 @@ public class ActivityActionTest {
assertThat(task.getComponentId()).isEqualTo(project1.uuid());
assertThat(task.getLogs()).isFalse();
assertThat(task.getOrganization()).isEqualTo(org1.getKey());
assertThat(task.getWarningCount()).isZero();
}

@Test
@@ -214,6 +219,36 @@ public class ActivityActionTest {
assertPage(10, asList("T3", "T2", "T1"));
}

@Test
public void return_warnings_count_on_queue_and_activity_but_no_warnings_list() {
logInAsSystemAdministrator();
ComponentDto project1 = db.components().insertPrivateProject();
ComponentDto project2 = db.components().insertPrivateProject();
insertActivity("T1", project1, SUCCESS);
insertActivity("T2", project2, FAILED);
insertQueue("T3", project1, IN_PROGRESS);
insertMessages("T1", 2);
insertMessages("T2", 0);
insertMessages("T3", 5);

ActivityResponse activityResponse = call(ws.newRequest()
.setParam(Param.PAGE_SIZE, Integer.toString(10))
.setParam(PARAM_STATUS, "SUCCESS,FAILED,CANCELED,IN_PROGRESS,PENDING"));
assertThat(activityResponse.getTasksList())
.extracting(Task::getId, Task::getWarningCount, Task::getWarningsList)
.containsOnly(tuple("T1", 2, emptyList()), tuple("T2", 0, emptyList()), tuple("T3", 0, emptyList()));
}

private void insertMessages(String taskUuid, int messageCount) {
IntStream.range(0, messageCount)
.forEach(i -> db.getDbClient().ceTaskMessageDao().insert(db.getSession(), new CeTaskMessageDto()
.setUuid("uuid_" + taskUuid + "_" + i)
.setTaskUuid(taskUuid)
.setMessage("m_" + taskUuid + "_" + i)
.setCreatedAt(taskUuid.hashCode() + i)));
db.commit();
}

@Test
public void project_administrator_can_access_his_project_activity() {
ComponentDto project1 = db.components().insertPrivateProject();

+ 56
- 17
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java View File

@@ -20,6 +20,8 @@
package org.sonar.server.ce.ws;

import java.util.Collections;
import java.util.Random;
import java.util.stream.IntStream;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
@@ -31,6 +33,7 @@ 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.CeTaskMessageDto;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
@@ -44,6 +47,7 @@ import org.sonarqube.ws.Ce;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.MediaTypes;

import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
@@ -103,12 +107,15 @@ public class ComponentActionTest {
assertThat(response.getQueue(1).getId()).isEqualTo("T5");
// T3 is the latest task executed on PROJECT_1
assertThat(response.hasCurrent()).isTrue();
assertThat(response.getCurrent().getId()).isEqualTo("T3");
assertThat(response.getCurrent().hasAnalysisId()).isFalse();
Ce.Task current = response.getCurrent();
assertThat(current.getId()).isEqualTo("T3");
assertThat(current.hasAnalysisId()).isFalse();
assertThat(current.getWarningCount()).isZero();
assertThat(current.getWarningsList()).isEmpty();
assertThat(response.getQueueList())
.extracting(Ce.Task::getOrganization)
.containsOnly(organization.getKey());
assertThat(response.getCurrent().getOrganization()).isEqualTo(organization.getKey());
assertThat(current.getOrganization()).isEqualTo(organization.getKey());
}

@Test
@@ -122,8 +129,11 @@ public class ComponentActionTest {
.setParam(PARAM_COMPONENT, project.getDbKey())
.executeProtobuf(Ce.ComponentResponse.class);
assertThat(response.hasCurrent()).isTrue();
assertThat(response.getCurrent().getId()).isEqualTo("T1");
assertThat(response.getCurrent().getAnalysisId()).isEqualTo(analysis.getUuid());
Ce.Task current = response.getCurrent();
assertThat(current.getId()).isEqualTo("T1");
assertThat(current.getAnalysisId()).isEqualTo(analysis.getUuid());
assertThat(current.getWarningCount()).isZero();
assertThat(current.getWarningsList()).isEmpty();
}

@Test
@@ -137,8 +147,11 @@ public class ComponentActionTest {
.setParam(PARAM_COMPONENT_ID, project.uuid())
.executeProtobuf(Ce.ComponentResponse.class);
assertThat(response.hasCurrent()).isTrue();
assertThat(response.getCurrent().getId()).isEqualTo("T1");
assertThat(response.getCurrent().getAnalysisId()).isEqualTo(analysis.getUuid());
Ce.Task current = response.getCurrent();
assertThat(current.getId()).isEqualTo("T1");
assertThat(current.getAnalysisId()).isEqualTo(analysis.getUuid());
assertThat(current.getWarningCount()).isZero();
assertThat(current.getWarningsList()).isEmpty();
}

@Test
@@ -157,7 +170,10 @@ public class ComponentActionTest {
assertThat(response.getQueueCount()).isEqualTo(0);
// T3 is the latest task executed on PROJECT_1 ignoring Canceled ones
assertThat(response.hasCurrent()).isTrue();
assertThat(response.getCurrent().getId()).isEqualTo("T3");
Ce.Task current = response.getCurrent();
assertThat(current.getId()).isEqualTo("T3");
assertThat(current.getWarningCount()).isZero();
assertThat(current.getWarningsList()).isEmpty();
}

@Test
@@ -175,9 +191,9 @@ public class ComponentActionTest {
.executeProtobuf(Ce.ComponentResponse.class);

assertThat(response.getCurrent())
.extracting(Ce.Task::getId, Ce.Task::getBranch, Ce.Task::getBranchType, Ce.Task::getStatus, Ce.Task::getComponentKey)
.extracting(Ce.Task::getId, Ce.Task::getBranch, Ce.Task::getBranchType, Ce.Task::getStatus, Ce.Task::getComponentKey, Ce.Task::getWarningCount, Ce.Task::getWarningsList)
.containsOnly(
"T1", longLivingBranch.getBranch(), Common.BranchType.LONG, Ce.TaskStatus.SUCCESS, project.getKey());
"T1", longLivingBranch.getBranch(), Common.BranchType.LONG, Ce.TaskStatus.SUCCESS, project.getKey(), 0, emptyList());
}

@Test
@@ -197,10 +213,10 @@ public class ComponentActionTest {
.executeProtobuf(Ce.ComponentResponse.class);

assertThat(response.getQueueList())
.extracting(Ce.Task::getId, Ce.Task::getBranch, Ce.Task::getBranchType, Ce.Task::getStatus, Ce.Task::getComponentKey)
.extracting(Ce.Task::getId, Ce.Task::getBranch, Ce.Task::getBranchType, Ce.Task::getStatus, Ce.Task::getComponentKey, Ce.Task::getWarningCount, Ce.Task::getWarningsList)
.containsOnly(
tuple("T1", longLivingBranch.getBranch(), Common.BranchType.LONG, Ce.TaskStatus.IN_PROGRESS, project.getKey()),
tuple("T2", longLivingBranch.getBranch(), Common.BranchType.LONG, Ce.TaskStatus.PENDING, project.getKey()));
tuple("T1", longLivingBranch.getBranch(), Common.BranchType.LONG, Ce.TaskStatus.IN_PROGRESS, project.getKey(), 0, emptyList()),
tuple("T2", longLivingBranch.getBranch(), Common.BranchType.LONG, Ce.TaskStatus.PENDING, project.getKey(), 0, emptyList()));
}

@Test
@@ -222,11 +238,34 @@ public class ComponentActionTest {
.executeProtobuf(Ce.ComponentResponse.class);

assertThat(response.getQueueList())
.extracting(Ce.Task::getId, Ce.Task::getComponentKey, Ce.Task::getBranch, Ce.Task::getBranchType)
.extracting(Ce.Task::getId, Ce.Task::getComponentKey, Ce.Task::getBranch, Ce.Task::getBranchType, Ce.Task::getWarningCount, Ce.Task::getWarningsList)
.containsOnly(
tuple("Main", project.getKey(), "", Common.BranchType.UNKNOWN_BRANCH_TYPE),
tuple("Long", longLivingBranch.getKey(), longLivingBranch.getBranch(), Common.BranchType.LONG),
tuple("Short", shortLivingBranch.getKey(), shortLivingBranch.getBranch(), Common.BranchType.SHORT));
tuple("Main", project.getKey(), "", Common.BranchType.UNKNOWN_BRANCH_TYPE, 0, emptyList()),
tuple("Long", longLivingBranch.getKey(), longLivingBranch.getBranch(), Common.BranchType.LONG, 0, emptyList()),
tuple("Short", shortLivingBranch.getKey(), shortLivingBranch.getBranch(), Common.BranchType.SHORT, 0, emptyList()));
}

@Test
public void populates_warning_count_of_activities_but_not_warnings() {
ComponentDto privateProject = db.components().insertPrivateProject();
userSession.addProjectPermission(UserRole.USER, privateProject);
SnapshotDto analysis = db.components().insertSnapshot(privateProject);
CeActivityDto activity = insertActivity("Short", privateProject, SUCCESS, analysis);
int messageCount = 1 + new Random().nextInt(10);
IntStream.range(0, messageCount).forEach(i -> db.getDbClient().ceTaskMessageDao().insert(db.getSession(), new CeTaskMessageDto()
.setUuid("uuid_" + i)
.setTaskUuid(activity.getUuid())
.setMessage("m_" + i)
.setCreatedAt(i)));
db.commit();

Ce.ComponentResponse response = ws.newRequest()
.setParam(PARAM_COMPONENT, privateProject.getKey())
.executeProtobuf(Ce.ComponentResponse.class);
assertThat(response.hasCurrent()).isTrue();
assertThat(response.getCurrent())
.extracting(Ce.Task::getWarningCount, Ce.Task::getWarningsList)
.containsOnly(messageCount, emptyList());
}

@Test

+ 178
- 27
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java View File

@@ -20,6 +20,8 @@
package org.sonar.server.ce.ws;

import java.util.Collections;
import java.util.Random;
import java.util.stream.IntStream;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Rule;
@@ -29,14 +31,17 @@ import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.util.CloseableIterator;
import org.sonar.core.util.UuidFactoryFast;
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.CeTaskMessageDto;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
@@ -47,6 +52,7 @@ import org.sonarqube.ws.Common;

import static java.util.Collections.singleton;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY;
import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
import static org.sonar.db.component.BranchType.LONG;
@@ -65,16 +71,18 @@ public class TaskActionTest {
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

private OrganizationDto organizationDto;
private ComponentDto project;
private OrganizationDto organization;
private ComponentDto privateProject;
private ComponentDto publicProject;
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 = db.organizations().insert();
project = db.components().insertPrivateProject(organizationDto);
organization = db.organizations().insert();
privateProject = db.components().insertPrivateProject(organization);
publicProject = db.components().insertPublicProject(organization);
}

@Test
@@ -85,7 +93,7 @@ public class TaskActionTest {
CeQueueDto queueDto = new CeQueueDto();
queueDto.setTaskType(CeTaskTypes.REPORT);
queueDto.setUuid(SOME_TASK_UUID);
queueDto.setComponentUuid(project.uuid());
queueDto.setComponentUuid(privateProject.uuid());
queueDto.setStatus(CeQueueDto.Status.PENDING);
queueDto.setSubmitterUuid(user.getUuid());
persist(queueDto);
@@ -93,15 +101,39 @@ public class TaskActionTest {
Ce.TaskResponse taskResponse = ws.newRequest()
.setParam("id", SOME_TASK_UUID)
.executeProtobuf(Ce.TaskResponse.class);
assertThat(taskResponse.getTask().getOrganization()).isEqualTo(organizationDto.getKey());
assertThat(taskResponse.getTask().getOrganization()).isEqualTo(organization.getKey());
assertThat(taskResponse.getTask().getId()).isEqualTo(SOME_TASK_UUID);
assertThat(taskResponse.getTask().getStatus()).isEqualTo(Ce.TaskStatus.PENDING);
assertThat(taskResponse.getTask().getSubmitterLogin()).isEqualTo(user.getLogin());
assertThat(taskResponse.getTask().getComponentId()).isEqualTo(project.uuid());
assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(project.getDbKey());
assertThat(taskResponse.getTask().getComponentName()).isEqualTo(project.name());
assertThat(taskResponse.getTask().getComponentId()).isEqualTo(privateProject.uuid());
assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(privateProject.getDbKey());
assertThat(taskResponse.getTask().getComponentName()).isEqualTo(privateProject.name());
assertThat(taskResponse.getTask().hasExecutionTimeMs()).isFalse();
assertThat(taskResponse.getTask().getLogs()).isFalse();
assertThat(taskResponse.getTask().getWarningCount()).isZero();
assertThat(taskResponse.getTask().getWarningsList()).isEmpty();
}

@Test
public void no_warning_detail_on_task_in_queue() {
UserDto user = db.users().insertUser();
userSession.logIn(user).setRoot();
CeQueueDto queueDto = createAndPersistQueueTask(null, user);
IntStream.range(0, 1 + new Random().nextInt(5))
.forEach(i -> db.getDbClient().ceTaskMessageDao().insert(db.getSession(),
new CeTaskMessageDto()
.setUuid("u_" + i)
.setTaskUuid(queueDto.getUuid())
.setMessage("m_" + i)
.setCreatedAt(queueDto.getUuid().hashCode() + i)));
db.commit();

Ce.TaskResponse taskResponse = ws.newRequest()
.setParam("id", SOME_TASK_UUID)
.executeProtobuf(Ce.TaskResponse.class);
Ce.Task task = taskResponse.getTask();
assertThat(task.getWarningCount()).isZero();
assertThat(task.getWarningsList()).isEmpty();
}

@Test
@@ -116,15 +148,17 @@ public class TaskActionTest {
.setParam("id", SOME_TASK_UUID)
.executeProtobuf(Ce.TaskResponse.class);
Ce.Task task = taskResponse.getTask();
assertThat(task.getOrganization()).isEqualTo(organizationDto.getKey());
assertThat(task.getOrganization()).isEqualTo(organization.getKey());
assertThat(task.getId()).isEqualTo(SOME_TASK_UUID);
assertThat(task.getStatus()).isEqualTo(Ce.TaskStatus.FAILED);
assertThat(task.getComponentId()).isEqualTo(project.uuid());
assertThat(task.getComponentKey()).isEqualTo(project.getDbKey());
assertThat(task.getComponentName()).isEqualTo(project.name());
assertThat(task.getComponentId()).isEqualTo(privateProject.uuid());
assertThat(task.getComponentKey()).isEqualTo(privateProject.getDbKey());
assertThat(task.getComponentName()).isEqualTo(privateProject.name());
assertThat(task.getAnalysisId()).isEqualTo(activityDto.getAnalysisUuid());
assertThat(task.getExecutionTimeMs()).isEqualTo(500L);
assertThat(task.getLogs()).isFalse();
assertThat(task.getWarningCount()).isZero();
assertThat(task.getWarningsList()).isEmpty();
}

@Test
@@ -268,8 +302,39 @@ public class TaskActionTest {
@Test
public void get_project_queue_task_with_scan_permission_on_project() {
UserDto user = db.users().insertUser();
userSession.logIn(user).addProjectPermission(GlobalPermissions.SCAN_EXECUTION, project);
CeQueueDto task = createAndPersistQueueTask(project, user);
userSession.logIn(user).addProjectPermission(GlobalPermissions.SCAN_EXECUTION, privateProject);
CeQueueDto task = createAndPersistQueueTask(privateProject, user);

call(task.getUuid());
}

@Test
public void getting_project_queue_task_of_public_project_fails_with_ForbiddenException() {
UserDto user = db.users().insertUser();
userSession.logIn().registerComponents(publicProject);
CeQueueDto task = createAndPersistQueueTask(publicProject, user);

expectedException.expect(ForbiddenException.class);

call(task.getUuid());
}

@Test
public void get_project_queue_task_of_private_project_with_user_permission_fails_with_ForbiddenException() {
UserDto user = db.users().insertUser();
userSession.logIn().addProjectPermission(UserRole.USER, privateProject);
CeQueueDto task = createAndPersistQueueTask(privateProject, user);

expectedException.expect(ForbiddenException.class);

call(task.getUuid());
}

@Test
public void get_project_queue_task_on_public_project() {
UserDto user = db.users().insertUser();
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, privateProject);
CeQueueDto task = createAndPersistQueueTask(privateProject, user);

call(task.getUuid());
}
@@ -277,8 +342,8 @@ public class TaskActionTest {
@Test
public void get_project_queue_task_with_scan_permission_on_organization_but_not_on_project() {
UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(SCAN, project.getOrganizationUuid());
CeQueueDto task = createAndPersistQueueTask(project, user);
userSession.logIn(user).addPermission(SCAN, privateProject.getOrganizationUuid());
CeQueueDto task = createAndPersistQueueTask(privateProject, user);

call(task.getUuid());
}
@@ -287,7 +352,7 @@ public class TaskActionTest {
public void getting_project_queue_task_throws_ForbiddenException_if_no_admin_nor_scan_permissions() {
UserDto user = db.users().insertUser();
userSession.logIn(user);
CeQueueDto task = createAndPersistQueueTask(project, user);
CeQueueDto task = createAndPersistQueueTask(privateProject, user);

expectedException.expect(ForbiddenException.class);

@@ -316,16 +381,26 @@ public class TaskActionTest {

@Test
public void get_project_archived_task_with_scan_permission_on_project() {
userSession.logIn().addProjectPermission(GlobalPermissions.SCAN_EXECUTION, project);
CeActivityDto task = createAndPersistArchivedTask(project);
userSession.logIn().addProjectPermission(GlobalPermissions.SCAN_EXECUTION, privateProject);
CeActivityDto task = createAndPersistArchivedTask(privateProject);

call(task.getUuid());
}

@Test
public void getting_archived_task_of_public_project_fails_with_ForbiddenException() {
userSession.logIn().registerComponents(publicProject);
CeActivityDto task = createAndPersistArchivedTask(publicProject);

expectedException.expect(ForbiddenException.class);
call(task.getUuid());
}

@Test
public void get_project_archived_task_with_scan_permission_on_organization_but_not_on_project() {
userSession.logIn().addPermission(SCAN, project.getOrganizationUuid());
CeActivityDto task = createAndPersistArchivedTask(project);
userSession.logIn().addPermission(SCAN, privateProject.getOrganizationUuid());
CeActivityDto task = createAndPersistArchivedTask(privateProject);

call(task.getUuid());
}
@@ -333,7 +408,7 @@ public class TaskActionTest {
@Test
public void getting_project_archived_task_throws_ForbiddenException_if_no_admin_nor_scan_permissions() {
userSession.logIn();
CeActivityDto task = createAndPersistArchivedTask(project);
CeActivityDto task = createAndPersistArchivedTask(privateProject);

expectedException.expect(ForbiddenException.class);

@@ -358,6 +433,67 @@ public class TaskActionTest {
call(task.getUuid());
}

@Test
public void get_warnings_on_global_archived_task_requires_to_be_system_administrator() {
logInAsSystemAdministrator();

getWarningsImpl(createAndPersistArchivedTask(null));
}

@Test
public void get_warnings_on_public_project_archived_task_if_not_admin_fails_with_ForbiddenException() {
userSession.logIn().registerComponents(publicProject);

expectedException.expect(ForbiddenException.class);

getWarningsImpl(createAndPersistArchivedTask(publicProject));
}

@Test
public void get_warnings_on_private_project_archived_task_if_user_fails_with_ForbiddenException() {
userSession.logIn().addProjectPermission(UserRole.USER, privateProject);

expectedException.expect(ForbiddenException.class);

getWarningsImpl(createAndPersistArchivedTask(privateProject));
}

@Test
public void get_warnings_on_private_project_archived_task_if_scan() {
userSession.logIn().addProjectPermission(SCAN_EXECUTION, privateProject);

getWarningsImpl(createAndPersistArchivedTask(privateProject));
}

@Test
public void get_warnings_on_private_project_archived_task_if_scan_on_organization() {
userSession.logIn().addPermission(OrganizationPermission.SCAN, organization);

getWarningsImpl(createAndPersistArchivedTask(privateProject));
}

private void getWarningsImpl(CeActivityDto task) {
String[] warnings = IntStream.range(0, 1 + new Random().nextInt(10))
.mapToObj(i -> insertWarning(task, i))
.map(CeTaskMessageDto::getMessage)
.toArray(String[]::new);

Ce.Task taskWithWarnings = callWithWarnings(task.getUuid());
assertThat(taskWithWarnings.getWarningCount()).isEqualTo(warnings.length);
assertThat(taskWithWarnings.getWarningsList()).containsExactly(warnings);
}

private CeTaskMessageDto insertWarning(CeActivityDto task, int i) {
CeTaskMessageDto res = new CeTaskMessageDto()
.setUuid(UuidFactoryFast.getInstance().create())
.setTaskUuid(task.getUuid())
.setMessage("msg_" + task.getUuid() + "_" + i)
.setCreatedAt(task.getUuid().hashCode() + i);
db.getDbClient().ceTaskMessageDao().insert(db.getSession(), res);
db.getSession().commit();
return res;
}

private CeActivityDto createAndPersistArchivedTask(@Nullable ComponentDto component) {
CeQueueDto queueDto = new CeQueueDto();
queueDto.setTaskType(CeTaskTypes.REPORT);
@@ -374,10 +510,7 @@ public class TaskActionTest {
}

private CeActivityDto createActivityDto(String uuid) {
CeQueueDto queueDto = new CeQueueDto();
queueDto.setTaskType(CeTaskTypes.REPORT);
queueDto.setUuid(uuid);
queueDto.setComponentUuid(project.uuid());
CeQueueDto queueDto = createQueueDto(uuid);
CeActivityDto activityDto = new CeActivityDto(queueDto);
activityDto.setStatus(CeActivityDto.Status.FAILED);
activityDto.setExecutionTimeMs(500L);
@@ -385,6 +518,14 @@ public class TaskActionTest {
return activityDto;
}

private CeQueueDto createQueueDto(String uuid) {
CeQueueDto queueDto = new CeQueueDto();
queueDto.setTaskType(CeTaskTypes.REPORT);
queueDto.setUuid(uuid);
queueDto.setComponentUuid(privateProject.uuid());
return queueDto;
}

private CeQueueDto createAndPersistQueueTask(@Nullable ComponentDto component, UserDto user) {
CeQueueDto dto = new CeQueueDto();
dto.setTaskType(CeTaskTypes.REPORT);
@@ -449,4 +590,14 @@ public class TaskActionTest {
assertThat(task.getId()).isEqualTo(taskUuid);
}

private Ce.Task callWithWarnings(String taskUuid) {
Ce.TaskResponse taskResponse = ws.newRequest()
.setParam("id", taskUuid)
.setParam("additionalFields", "warnings")
.executeProtobuf(Ce.TaskResponse.class);
Ce.Task task = taskResponse.getTask();
assertThat(task.getId()).isEqualTo(taskUuid);
return task;
}

}

+ 55
- 3
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java View File

@@ -19,11 +19,15 @@
*/
package org.sonar.server.ce.ws;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Random;
import java.util.stream.IntStream;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
@@ -35,6 +39,8 @@ import org.sonar.db.user.UserDto;
import org.sonarqube.ws.Ce;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
@@ -45,6 +51,10 @@ public class TaskFormatterTest {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();

private int warningCount = new Random().nextInt(10);

private System2 system2 = mock(System2.class);
private TaskFormatter underTest = new TaskFormatter(db.getDbClient(), system2);
@@ -163,12 +173,22 @@ public class TaskFormatterTest {
assertThat(wsTasks).extracting("id").containsExactly("UUID1", "UUID2");
}

@Test
public void formatActivity_throws_NPE_if_warnings_parameter_is_null() {
UserDto user = db.users().insertUser();
CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED, user);

expectedException.expect(NullPointerException.class);

underTest.formatActivity(db.getSession(), dto, "foo", null);
}

@Test
public void formatActivity() {
UserDto user = db.users().insertUser();
CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED, user);

Ce.Task wsTask = underTest.formatActivity(db.getSession(), dto, null);
Ce.Task wsTask = underTest.formatActivity(db.getSession(), dto, null, emptyList());

assertThat(wsTask.getType()).isEqualTo(CeTaskTypes.REPORT);
assertThat(wsTask.getId()).isEqualTo("UUID");
@@ -179,6 +199,8 @@ public class TaskFormatterTest {
assertThat(wsTask.getAnalysisId()).isEqualTo("U1");
assertThat(wsTask.getLogs()).isFalse();
assertThat(wsTask.hasScannerContext()).isFalse();
assertThat(wsTask.getWarningCount()).isEqualTo(warningCount);
assertThat(wsTask.getWarningsList()).isEmpty();
}

@Test
@@ -186,12 +208,23 @@ public class TaskFormatterTest {
CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED, null);

String expected = "scanner context baby!";
Ce.Task wsTask = underTest.formatActivity(db.getSession(), dto, expected);
Ce.Task wsTask = underTest.formatActivity(db.getSession(), dto, expected, emptyList());

assertThat(wsTask.hasScannerContext()).isTrue();
assertThat(wsTask.getScannerContext()).isEqualTo(expected);
}

@Test
public void formatActivity_set_warnings_list_if_argument_is_non_empty_not_checking_consistency_with_warning_count() {
CeActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED, null);
String[] warnings = IntStream.range(0, warningCount + 1 + new Random().nextInt(5)).mapToObj(i -> "warning_" + i).toArray(String[]::new);

Ce.Task wsTask = underTest.formatActivity(db.getSession(), dto, null, Arrays.stream(warnings).collect(toList()));

assertThat(wsTask.getWarningCount()).isEqualTo(warningCount);
assertThat(wsTask.getWarningsList()).containsExactly(warnings);
}

@Test
public void formatActivities() {
UserDto user1 = db.users().insertUser();
@@ -251,9 +284,28 @@ public class TaskFormatterTest {
.setComponentUuid(componentUuid)
.setSubmitterUuid(user == null ? null : user.getUuid())
.setUuid(taskUuid);
return new CeActivityDto(queueDto)
TestActivityDto testActivityDto = new TestActivityDto(queueDto);
testActivityDto.setWarningCount(warningCount);
return testActivityDto
.setStatus(status)
.setExecutionTimeMs(500L)
.setAnalysisUuid("U1");
}

private class TestActivityDto extends CeActivityDto {

public TestActivityDto(CeQueueDto queueDto) {
super(queueDto);
}

@Override
public CeActivityDto setHasScannerContext(boolean hasScannerContext) {
return super.setHasScannerContext(hasScannerContext);
}

@Override
public CeActivityDto setWarningCount(int warningCount) {
return super.setWarningCount(warningCount);
}
}
}

+ 2
- 0
sonar-ws/src/main/protobuf/ws-ce.proto View File

@@ -105,6 +105,8 @@ message Task {
optional string errorType = 23;
optional string pullRequest = 24;
optional string pullRequestTitle = 25;
optional int32 warningCount = 26;
repeated string warnings = 27;
}

enum TaskStatus {

Loading…
Cancel
Save