all return warnings count, warnings list is only available from api/ce/task on demandtags/7.5
@@ -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 + | |||
'}'; | |||
} | |||
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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 |
@@ -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 | |||
( |
@@ -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); |
@@ -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[][] { |
@@ -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; | |||
} | |||
} |
@@ -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) { |
@@ -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); | |||
} |
@@ -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; | |||
@@ -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(); | |||
} | |||
@@ -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(); |
@@ -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 |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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 { |