@@ -121,9 +121,9 @@ public class ComponentTreeAction implements MeasuresWsAction { | |||
.setDescription(format("Navigate through components based on the chosen strategy with specified measures. The %s or the %s parameter must be provided.<br>" + | |||
"Requires one of the following permissions:" + | |||
"<ul>" + | |||
"<li>'Administer System'</li>" + | |||
"<li>'Administer' rights on the specified project</li>" + | |||
"<li>'Browse' on the specified project</li>" + | |||
" <li>'Administer System'</li>" + | |||
" <li>'Administer' rights on the specified project</li>" + | |||
" <li>'Browse' on the specified project</li>" + | |||
"</ul>" + | |||
"When limiting search with the %s parameter, directories are not returned.", | |||
PARAM_BASE_COMPONENT_ID, PARAM_BASE_COMPONENT_KEY, Param.TEXT_QUERY)) |
@@ -148,6 +148,7 @@ import org.sonar.server.plugins.ws.PluginsWs; | |||
import org.sonar.server.plugins.ws.UninstallAction; | |||
import org.sonar.server.plugins.ws.UpdatesAction; | |||
import org.sonar.server.project.ws.ProjectsWsModule; | |||
import org.sonar.server.projectanalysis.ProjectAnalysisModule; | |||
import org.sonar.server.projectlink.ws.ProjectLinksModule; | |||
import org.sonar.server.property.InternalPropertiesImpl; | |||
import org.sonar.server.qualitygate.QualityGateModule; | |||
@@ -490,6 +491,9 @@ public class PlatformLevel4 extends PlatformLevel { | |||
// Project Links | |||
ProjectLinksModule.class, | |||
// Project Analyses | |||
ProjectAnalysisModule.class, | |||
// System | |||
ServerLogging.class, | |||
RestartAction.class, |
@@ -0,0 +1,37 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.projectanalysis; | |||
import org.sonar.core.platform.Module; | |||
import org.sonar.server.projectanalysis.ws.CreateEventAction; | |||
import org.sonar.server.projectanalysis.ws.ProjectAnalysesWs; | |||
public class ProjectAnalysisModule extends Module { | |||
@Override | |||
protected void configureModule() { | |||
add( | |||
ProjectAnalysesWs.class, | |||
// actions | |||
CreateEventAction.class); | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.projectanalysis; | |||
import javax.annotation.ParametersAreNonnullByDefault; | |||
@@ -0,0 +1,214 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.projectanalysis.ws; | |||
import java.util.List; | |||
import java.util.function.Consumer; | |||
import java.util.function.Predicate; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.event.EventDto; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.ProjectAnalyses.CreateEventResponse; | |||
import org.sonarqube.ws.ProjectAnalyses.Event; | |||
import org.sonarqube.ws.client.projectanalysis.CreateEventRequest; | |||
import org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static java.lang.String.format; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.OTHER; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.VERSION; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.fromLabel; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_ANALYSIS; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_CATEGORY; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_DESCRIPTION; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_NAME; | |||
public class CreateEventAction implements ProjectAnalysesWsAction { | |||
private final DbClient dbClient; | |||
private final UuidFactory uuidFactory; | |||
private final System2 system; | |||
private final UserSession userSession; | |||
public CreateEventAction(DbClient dbClient, UuidFactory uuidFactory, System2 system, UserSession userSession) { | |||
this.dbClient = dbClient; | |||
this.uuidFactory = uuidFactory; | |||
this.system = system; | |||
this.userSession = userSession; | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction("create_event") | |||
.setDescription("Add an event to a project analysis.<br>" + | |||
"Requires one of the following permissions:" + | |||
"<ul>" + | |||
" <li>'Administer System'</li>" + | |||
" <li>'Administer' rights on the specified project</li>" + | |||
"</ul>") | |||
.setSince("6.3") | |||
.setPost(true) | |||
.setResponseExample(getClass().getResource("create_event-example.json")) | |||
.setHandler(this); | |||
action.createParam(PARAM_ANALYSIS) | |||
.setDescription("Analysis key") | |||
.setExampleValue(Uuids.UUID_EXAMPLE_01) | |||
.setRequired(true); | |||
action.createParam(PARAM_CATEGORY) | |||
.setDescription("Category") | |||
.setDefaultValue(OTHER) | |||
.setPossibleValues(VERSION, OTHER); | |||
action.createParam(PARAM_NAME) | |||
.setDescription("Name") | |||
.setExampleValue("5.6") | |||
.setRequired(true); | |||
action.createParam(PARAM_DESCRIPTION) | |||
.setDescription("Description") | |||
.setExampleValue("Version released"); | |||
} | |||
@Override | |||
public void handle(Request httpRequest, Response httpResponse) throws Exception { | |||
CreateEventRequest request = toAddEventRequest(httpRequest); | |||
CreateEventResponse response = doHandle(request); | |||
writeProtobuf(response, httpRequest, httpResponse); | |||
} | |||
private CreateEventResponse doHandle(CreateEventRequest request) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
SnapshotDto analysis = getAnalysis(dbSession, request); | |||
checkPermissions(analysis); | |||
checkExistingDbEvents(dbSession, request, analysis); | |||
EventDto dbEvent = insertDbEvent(dbSession, request, analysis); | |||
return toCreateEventResponse(dbEvent); | |||
} | |||
} | |||
private void checkPermissions(SnapshotDto analysis) { | |||
userSession.checkComponentUuidPermission(UserRole.ADMIN, analysis.getComponentUuid()); | |||
} | |||
private EventDto insertDbEvent(DbSession dbSession, CreateEventRequest request, SnapshotDto analysis) { | |||
EventDto dbEvent = dbClient.eventDao().insert(dbSession, toDbEvent(request, analysis)); | |||
if (VERSION.equals(request.getCategory())) { | |||
dbClient.snapshotDao().updateVersion(dbSession, analysis.getUuid(), request.getName()); | |||
} | |||
dbSession.commit(); | |||
return dbEvent; | |||
} | |||
private SnapshotDto getAnalysis(DbSession dbSession, CreateEventRequest request) { | |||
SnapshotDto analysis = dbClient.snapshotDao().selectByUuid(dbSession, request.getAnalysis()) | |||
.orElseThrow(() -> new NotFoundException(format("Analysis '%s' is not found", request.getAnalysis()))); | |||
ComponentDto project = dbClient.componentDao().selectByUuid(dbSession, analysis.getComponentUuid()).orNull(); | |||
checkState(project != null, "Project of analysis '%s' is not found", analysis.getUuid()); | |||
checkArgument(Qualifiers.PROJECT.equals(project.qualifier()) && Scopes.PROJECT.equals(project.scope()), | |||
"An event must be created on a project"); | |||
return analysis; | |||
} | |||
private static CreateEventRequest toAddEventRequest(Request request) { | |||
return CreateEventRequest.builder() | |||
.setAnalysis(request.mandatoryParam(PARAM_ANALYSIS)) | |||
.setName(request.mandatoryParam(PARAM_NAME)) | |||
.setCategory(request.mandatoryParamAsEnum(PARAM_CATEGORY, Category.class)) | |||
.setDescription(request.param(PARAM_DESCRIPTION)) | |||
.build(); | |||
} | |||
private EventDto toDbEvent(CreateEventRequest request, SnapshotDto analysis) { | |||
return new EventDto() | |||
.setUuid(uuidFactory.create()) | |||
.setAnalysisUuid(analysis.getUuid()) | |||
.setComponentUuid(analysis.getComponentUuid()) | |||
.setCategory(request.getCategory().getLabel()) | |||
.setName(request.getName()) | |||
.setDescription(request.getDescription()) | |||
.setCreatedAt(system.now()) | |||
.setDate(analysis.getCreatedAt()); | |||
} | |||
private static CreateEventResponse toCreateEventResponse(EventDto dbEvent) { | |||
Event.Builder wsEvent = Event.newBuilder() | |||
.setKey(dbEvent.getUuid()) | |||
.setCategory(fromLabel(dbEvent.getCategory()).name()) | |||
.setAnalysis(dbEvent.getAnalysisUuid()) | |||
.setName(dbEvent.getName()); | |||
setNullable(dbEvent.getDescription(), wsEvent::setDescription); | |||
return CreateEventResponse.newBuilder().setEvent(wsEvent).build(); | |||
} | |||
private void checkExistingDbEvents(DbSession dbSession, CreateEventRequest request, SnapshotDto analysis) { | |||
List<EventDto> dbEvents = dbClient.eventDao().selectByAnalysisUuid(dbSession, analysis.getUuid()); | |||
Predicate<EventDto> similarEventExisting = filterSimilarEvents(request); | |||
dbEvents.stream() | |||
.filter(similarEventExisting) | |||
.findAny() | |||
.ifPresent(throwException(request)); | |||
} | |||
private static Predicate<EventDto> filterSimilarEvents(CreateEventRequest request) { | |||
switch (request.getCategory()) { | |||
case VERSION: | |||
return dbEvent -> VERSION.getLabel().equals(dbEvent.getCategory()); | |||
case OTHER: | |||
return dbEvent -> OTHER.getLabel().equals(dbEvent.getCategory()) && request.getName().equals(dbEvent.getName()); | |||
default: | |||
throw new IllegalStateException("Event category not handled: " + request.getCategory()); | |||
} | |||
} | |||
private static Consumer<EventDto> throwException(CreateEventRequest request) { | |||
switch (request.getCategory()) { | |||
case VERSION: | |||
return dbEvent -> { | |||
throw new IllegalArgumentException(format("A version event already exists on analysis '%s'", request.getAnalysis())); | |||
}; | |||
case OTHER: | |||
return dbEvent -> { | |||
throw new IllegalArgumentException(format("An 'other' event with the same name already exists on analysis '%s'", request.getAnalysis())); | |||
}; | |||
default: | |||
throw new IllegalStateException("Event category not handled: " + request.getCategory()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.projectanalysis.ws; | |||
import org.sonar.api.server.ws.WebService; | |||
public class ProjectAnalysesWs implements WebService { | |||
private final ProjectAnalysesWsAction[] actions; | |||
public ProjectAnalysesWs(ProjectAnalysesWsAction... actions) { | |||
this.actions = actions; | |||
} | |||
@Override | |||
public void define(Context context) { | |||
NewController controller = context.createController("api/project_analyses") | |||
.setDescription("Manage project analyses.") | |||
.setSince("6.3"); | |||
for (ProjectAnalysesWsAction action : actions) { | |||
action.define(controller); | |||
} | |||
controller.done(); | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.projectanalysis.ws; | |||
import org.sonar.server.ws.WsAction; | |||
public interface ProjectAnalysesWsAction extends WsAction { | |||
// Marker interface | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.projectanalysis.ws; | |||
import javax.annotation.ParametersAreNonnullByDefault; | |||
@@ -0,0 +1,9 @@ | |||
{ | |||
"event": { | |||
"analysis": "A2", | |||
"key": "E1", | |||
"category": "OTHER", | |||
"name": "My Custom Event", | |||
"description": "event description" | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.projectanalysis; | |||
import org.junit.Test; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class ProjectAnalysisModuleTest { | |||
@Test | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new ProjectAnalysisModule().configure(container); | |||
assertThat(container.size()).isEqualTo(2 + 2); | |||
} | |||
} |
@@ -0,0 +1,351 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.projectanalysis.ws; | |||
import com.google.common.base.Throwables; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.permission.GlobalPermissions; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.core.util.UuidFactoryFast; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.component.SnapshotTesting; | |||
import org.sonar.db.event.EventDto; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.ProjectAnalyses; | |||
import org.sonarqube.ws.ProjectAnalyses.CreateEventResponse; | |||
import org.sonarqube.ws.client.projectanalysis.CreateEventRequest; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.component.ComponentTesting.newProjectDto; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
import static org.sonar.db.component.SnapshotTesting.newSnapshot; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.client.WsRequest.Method.POST; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.OTHER; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.VERSION; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_ANALYSIS; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_CATEGORY; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_DESCRIPTION; | |||
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_NAME; | |||
public class CreateEventActionTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private DbClient dbClient = db.getDbClient(); | |||
private DbSession dbSession = db.getSession(); | |||
private UuidFactory uuidFactory = UuidFactoryFast.getInstance(); | |||
private System2 system = mock(System2.class); | |||
private WsActionTester ws = new WsActionTester(new CreateEventAction(dbClient, uuidFactory, system, userSession)); | |||
@Before | |||
public void setUp() { | |||
when(system.now()).thenReturn(42L); | |||
} | |||
@Test | |||
public void json_example() { | |||
ComponentDto project = db.components().insertProject(); | |||
SnapshotDto analysis = dbClient.snapshotDao().insert(dbSession, SnapshotTesting.newAnalysis(project).setUuid("A2")); | |||
db.commit(); | |||
uuidFactory = mock(UuidFactory.class); | |||
when(uuidFactory.create()).thenReturn("E1"); | |||
ws = new WsActionTester(new CreateEventAction(dbClient, uuidFactory, system, userSession)); | |||
String result = ws.newRequest() | |||
.setParam(PARAM_ANALYSIS, analysis.getUuid()) | |||
.setParam(PARAM_CATEGORY, OTHER.name()) | |||
.setParam(PARAM_NAME, "My Custom Event") | |||
.setParam(PARAM_DESCRIPTION, "event description") | |||
.execute().getInput(); | |||
assertJson(result).isSimilarTo(getClass().getResource("create_event-example.json")); | |||
} | |||
@Test | |||
public void create_event_in_db() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3") | |||
.setDescription("LTS version"); | |||
when(system.now()).thenReturn(123_456_789L); | |||
CreateEventResponse result = call(request); | |||
List<EventDto> dbEvents = dbClient.eventDao().selectByComponentUuid(dbSession, analysis.getComponentUuid()); | |||
assertThat(dbEvents).hasSize(1); | |||
EventDto dbEvent = dbEvents.get(0); | |||
assertThat(dbEvent.getName()).isEqualTo("5.6.3"); | |||
assertThat(dbEvent.getCategory()).isEqualTo(VERSION.getLabel()); | |||
assertThat(dbEvent.getDescription()).isEqualTo("LTS version"); | |||
assertThat(dbEvent.getAnalysisUuid()).isEqualTo(analysis.getUuid()); | |||
assertThat(dbEvent.getComponentUuid()).isEqualTo(analysis.getComponentUuid()); | |||
assertThat(dbEvent.getUuid()).isEqualTo(result.getEvent().getKey()); | |||
assertThat(dbEvent.getCreatedAt()).isEqualTo(123_456_789L); | |||
assertThat(dbEvent.getDate()).isEqualTo(analysis.getCreatedAt()); | |||
} | |||
@Test | |||
public void create_event_as_project_admin() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto("P1")); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3") | |||
.setDescription("LTS version"); | |||
userSession.anonymous().addProjectUuidPermissions(UserRole.ADMIN, "P1"); | |||
CreateEventResponse result = call(request); | |||
assertThat(result.getEvent().getKey()).isNotEmpty(); | |||
} | |||
@Test | |||
public void create_version_event() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3") | |||
.setDescription("LTS version"); | |||
call(request); | |||
Optional<SnapshotDto> newAnalysis = dbClient.snapshotDao().selectByUuid(dbSession, analysis.getUuid()); | |||
assertThat(newAnalysis.get().getVersion()).isEqualTo("5.6.3"); | |||
} | |||
@Test | |||
public void create_other_event_with_ws_response() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setName("Project Import") | |||
.setDescription("Import from another instance"); | |||
CreateEventResponse result = call(request); | |||
SnapshotDto newAnalysis = dbClient.snapshotDao().selectByUuid(dbSession, analysis.getUuid()).get(); | |||
assertThat(analysis.getVersion()).isEqualTo(newAnalysis.getVersion()); | |||
ProjectAnalyses.Event event = result.getEvent(); | |||
assertThat(event.getKey()).isNotEmpty(); | |||
assertThat(event.getCategory()).isEqualTo(OTHER.name()); | |||
assertThat(event.getName()).isEqualTo("Project Import"); | |||
assertThat(event.getDescription()).isEqualTo("Import from another instance"); | |||
assertThat(event.getAnalysis()).isEqualTo(analysis.getUuid()); | |||
} | |||
@Test | |||
public void create_event_without_description() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(OTHER) | |||
.setName("Project Import"); | |||
CreateEventResponse result = call(request); | |||
ProjectAnalyses.Event event = result.getEvent(); | |||
assertThat(event.getKey()).isNotEmpty(); | |||
assertThat(event.hasDescription()).isFalse(); | |||
} | |||
@Test | |||
public void create_2_version_events_on_same_project() { | |||
ComponentDto project = newProjectDto(); | |||
SnapshotDto firstAnalysis = db.components().insertProjectAndSnapshot(project); | |||
CreateEventRequest.Builder firstRequest = CreateEventRequest.builder() | |||
.setAnalysis(firstAnalysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3"); | |||
SnapshotDto secondAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)); | |||
db.commit(); | |||
CreateEventRequest.Builder secondRequest = CreateEventRequest.builder() | |||
.setAnalysis(secondAnalysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("6.3"); | |||
call(firstRequest); | |||
call(secondRequest); | |||
List<EventDto> events = dbClient.eventDao().selectByComponentUuid(dbSession, project.uuid()); | |||
assertThat(events).hasSize(2); | |||
} | |||
@Test | |||
public void fail_if_analysis_is_not_found() { | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("Analysis 'A42' is not found"); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis("A42") | |||
.setCategory(OTHER) | |||
.setName("Project Import"); | |||
call(request); | |||
} | |||
@Test | |||
public void fail_if_2_version_events_on_the_same_analysis() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3"); | |||
call(request); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A version event already exists on analysis '" + analysis.getUuid() + "'"); | |||
call(request.setName("6.3")); | |||
} | |||
@Test | |||
public void fail_if_2_other_events_on_same_analysis_with_same_name() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(OTHER) | |||
.setName("Project Import"); | |||
call(request); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("An 'other' event with the same name already exists on analysis '" + analysis.getUuid() + "'"); | |||
call(request.setName("Project Import")); | |||
} | |||
@Test | |||
public void fail_if_category_other_than_authorized() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto()); | |||
ws.newRequest() | |||
.setParam(PARAM_ANALYSIS, analysis.getUuid()) | |||
.setParam(PARAM_NAME, "Project Import") | |||
.setParam(PARAM_CATEGORY, "QP") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_if_create_on_other_than_a_project() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("An event must be created on a project"); | |||
SnapshotDto analysis = db.components().insertViewAndSnapshot(newView()); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3"); | |||
call(request); | |||
} | |||
@Test | |||
public void fail_if_project_is_not_found() { | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Project of analysis 'A1' is not found"); | |||
SnapshotDto analysis = dbClient.snapshotDao().insert(dbSession, newSnapshot().setUuid("A1")); | |||
db.commit(); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3"); | |||
call(request); | |||
} | |||
@Test | |||
public void fail_if_insufficient_permissions() { | |||
SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto("P1")); | |||
CreateEventRequest.Builder request = CreateEventRequest.builder() | |||
.setAnalysis(analysis.getUuid()) | |||
.setCategory(VERSION) | |||
.setName("5.6.3") | |||
.setDescription("LTS version"); | |||
userSession.anonymous(); | |||
expectedException.expect(ForbiddenException.class); | |||
call(request); | |||
} | |||
@Test | |||
public void ws_parameters() { | |||
WebService.Action definition = ws.getDef(); | |||
assertThat(definition.isPost()).isTrue(); | |||
assertThat(definition.key()).isEqualTo("create_event"); | |||
assertThat(definition.responseExampleAsString()).isNotEmpty(); | |||
} | |||
private CreateEventResponse call(CreateEventRequest.Builder requestBuilder) { | |||
CreateEventRequest request = requestBuilder.build(); | |||
TestRequest httpRequest = ws.newRequest() | |||
.setMethod(POST.name()) | |||
.setMediaType(MediaTypes.PROTOBUF); | |||
httpRequest.setParam(PARAM_CATEGORY, request.getCategory().name()) | |||
.setParam(PARAM_NAME, request.getName()) | |||
.setParam(PARAM_ANALYSIS, request.getAnalysis()); | |||
if (request.getDescription() != null) { | |||
httpRequest.setParam(PARAM_DESCRIPTION, request.getDescription()); | |||
} | |||
try { | |||
return CreateEventResponse.parseFrom(httpRequest.execute().getInputStream()); | |||
} catch (IOException e) { | |||
throw Throwables.propagate(e); | |||
} | |||
} | |||
} |
@@ -138,6 +138,10 @@ public class SnapshotDao implements Dao { | |||
insert(session, Lists.asList(item, others)); | |||
} | |||
public void updateVersion(DbSession dbSession, String analysisUuid, String version) { | |||
mapper(dbSession).updateVersion(analysisUuid, version); | |||
} | |||
/** | |||
* Used by Governance | |||
*/ |
@@ -55,4 +55,6 @@ public interface SnapshotMapper { | |||
void unsetIsLastFlagForComponentUuid(@Param("componentUuid") String componentUuid); | |||
void setIsLastFlagForAnalysisUuid(@Param("analysisUuid") String analysisUuid); | |||
void updateVersion(@Param("analysisUuid") String analysisUuid, @Param("version") String version); | |||
} |
@@ -29,12 +29,21 @@ public class EventDao implements Dao { | |||
return session.getMapper(EventMapper.class).selectByComponentUuid(componentUuid); | |||
} | |||
public void insert(DbSession session, EventDto dto) { | |||
public List<EventDto> selectByAnalysisUuid(DbSession dbSession, String uuid) { | |||
return mapper(dbSession).selectByAnalysisUuid(uuid); | |||
} | |||
public EventDto insert(DbSession session, EventDto dto) { | |||
session.getMapper(EventMapper.class).insert(dto); | |||
return dto; | |||
} | |||
public void delete(DbSession session, Long id) { | |||
session.getMapper(EventMapper.class).delete(id); | |||
} | |||
private static EventMapper mapper(DbSession session) { | |||
return session.getMapper(EventMapper.class); | |||
} | |||
} |
@@ -22,6 +22,10 @@ package org.sonar.db.event; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static org.sonar.db.event.EventValidator.checkEventCategory; | |||
import static org.sonar.db.event.EventValidator.checkEventDescription; | |||
import static org.sonar.db.event.EventValidator.checkEventName; | |||
public class EventDto { | |||
public static final String CATEGORY_VERSION = "Version"; | |||
@@ -80,7 +84,7 @@ public class EventDto { | |||
} | |||
public EventDto setName(String name) { | |||
this.name = name; | |||
this.name = checkEventName(name); | |||
return this; | |||
} | |||
@@ -89,7 +93,7 @@ public class EventDto { | |||
} | |||
public EventDto setCategory(String category) { | |||
this.category = category; | |||
this.category = checkEventCategory(category); | |||
return this; | |||
} | |||
@@ -127,7 +131,7 @@ public class EventDto { | |||
} | |||
public EventDto setDescription(@Nullable String description) { | |||
this.description = description; | |||
this.description = checkEventDescription(description); | |||
return this; | |||
} | |||
@@ -23,10 +23,11 @@ import java.util.List; | |||
public interface EventMapper { | |||
List<EventDto> selectByComponentUuid(String uuid); | |||
List<EventDto> selectByComponentUuid(String componentUuid); | |||
List<EventDto> selectByAnalysisUuid(String analysisUuid); | |||
void insert(EventDto dto); | |||
void delete(long id); | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.event; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
public class EventValidator { | |||
private static final int MAX_NAME_LENGTH = 400; | |||
private static final int MAX_CATEGORY_LENGTH = 50; | |||
private static final int MAX_DESCRIPTION_LENGTH = 4000; | |||
private EventValidator() { | |||
// prevent instantiation | |||
} | |||
public static String checkEventName(String name) { | |||
checkArgument(name.length() <= MAX_NAME_LENGTH, "Event name length (%s) is longer than the maximum authorized (%s). '%s' was provided.", | |||
name.length(), MAX_NAME_LENGTH, name); | |||
return name; | |||
} | |||
public static String checkEventCategory(String category) { | |||
checkArgument(category.length() <= MAX_CATEGORY_LENGTH, "Event category length (%s) is longer than the maximum authorized (%s). '%s' was provided.", | |||
category.length(), MAX_CATEGORY_LENGTH, category); | |||
return category; | |||
} | |||
@CheckForNull | |||
public static String checkEventDescription(@Nullable String description) { | |||
if (description == null) { | |||
return null; | |||
} | |||
checkArgument(description.length() <= MAX_DESCRIPTION_LENGTH, "Event description length (%s) is longer than the maximum authorized (%s). '%s' was provided.", | |||
description.length(), MAX_DESCRIPTION_LENGTH, description); | |||
return description; | |||
} | |||
} |
@@ -177,6 +177,12 @@ | |||
where uuid = #{analysisUuid} | |||
</update> | |||
<update id="updateVersion" parameterType="map"> | |||
update snapshots | |||
set version = #{version, jdbcType=VARCHAR} | |||
where uuid = #{analysisUuid} | |||
</update> | |||
<insert id="insert" parameterType="Snapshot" keyColumn="id" useGeneratedKeys="true" keyProperty="id"> | |||
insert into snapshots ( | |||
uuid, | |||
@@ -227,6 +233,5 @@ | |||
#{period4Date, jdbcType=BIGINT}, | |||
#{period5Date, jdbcType=BIGINT}) | |||
</insert> | |||
</mapper> | |||
@@ -24,6 +24,15 @@ | |||
</where> | |||
</select> | |||
<select id="selectByAnalysisUuid" parameterType="String" resultType="Event"> | |||
SELECT | |||
<include refid="eventColumns"/> | |||
FROM events e | |||
<where> | |||
AND e.analysis_uuid=#{analysisUuid} | |||
</where> | |||
</select> | |||
<insert id="insert" parameterType="Event" keyColumn="id" useGeneratedKeys="true" keyProperty="id"> | |||
INSERT INTO events (uuid, analysis_uuid, component_uuid, name, category, description, event_data, event_date, created_at) | |||
VALUES ( |
@@ -65,6 +65,7 @@ import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.util.SequenceUuidFactory; | |||
import org.sonar.db.component.ComponentDbTester; | |||
import org.sonar.db.event.EventDbTester; | |||
import org.sonar.db.organization.OrganizationDbTester; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.organization.OrganizationTesting; | |||
@@ -99,6 +100,7 @@ public class DbTester extends ExternalResource { | |||
private final UserDbTester userTester; | |||
private final ComponentDbTester componentTester; | |||
private final EventDbTester eventTester; | |||
private final OrganizationDbTester organizationTester; | |||
private final PermissionTemplateDbTester permissionTemplateTester; | |||
private final QualityGateDbTester qualityGateDbTester; | |||
@@ -110,6 +112,7 @@ public class DbTester extends ExternalResource { | |||
initDbClient(); | |||
this.userTester = new UserDbTester(this); | |||
this.componentTester = new ComponentDbTester(this); | |||
this.eventTester = new EventDbTester(this); | |||
this.organizationTester = new OrganizationDbTester(this); | |||
this.permissionTemplateTester = new PermissionTemplateDbTester(this); | |||
this.qualityGateDbTester = new QualityGateDbTester(this); | |||
@@ -177,6 +180,10 @@ public class DbTester extends ExternalResource { | |||
return componentTester; | |||
} | |||
public EventDbTester events() { | |||
return eventTester; | |||
} | |||
public OrganizationDbTester organizations() { | |||
return organizationTester; | |||
} |
@@ -35,6 +35,7 @@ import static com.google.common.collect.Lists.newArrayList; | |||
import static java.util.Collections.emptyList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.component.ComponentTesting.newProjectDto; | |||
import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED; | |||
import static org.sonar.db.component.SnapshotQuery.SORT_FIELD.BY_DATE; | |||
import static org.sonar.db.component.SnapshotQuery.SORT_ORDER.ASC; | |||
import static org.sonar.db.component.SnapshotQuery.SORT_ORDER.DESC; | |||
@@ -296,6 +297,18 @@ public class SnapshotDaoTest { | |||
verifyStatusAndIsLastFlag("A3", SnapshotDto.STATUS_PROCESSED, true); | |||
} | |||
@Test | |||
public void updateVersion() { | |||
insertAnalysis("P1", "A1", STATUS_PROCESSED, true); | |||
db.commit(); | |||
underTest.updateVersion(dbSession, "A1", "5.6.3"); | |||
SnapshotDto result = underTest.selectByUuid(dbSession, "A1").get(); | |||
assertThat(result.getVersion()).isEqualTo("5.6.3"); | |||
} | |||
private void insertAnalysis(String projectUuid, String uuid, String status, boolean isLastFlag) { | |||
SnapshotDto snapshot = SnapshotTesting.newAnalysis(ComponentTesting.newProjectDto(projectUuid)) | |||
.setLast(isLastFlag) |
@@ -24,9 +24,16 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.component.ComponentTesting.newProjectDto; | |||
import static org.sonar.db.component.SnapshotTesting.newAnalysis; | |||
import static org.sonar.db.event.EventTesting.newEvent; | |||
public class EventDaoTest { | |||
@@ -34,6 +41,8 @@ public class EventDaoTest { | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private DbSession dbSession = dbTester.getSession(); | |||
EventDao underTest = dbTester.getDbClient().eventDao(); | |||
@@ -60,6 +69,25 @@ public class EventDaoTest { | |||
assertThat(dto.getCreatedAt()).isEqualTo(1225630680000L); | |||
} | |||
@Test | |||
public void select_by_analysis_uuid() { | |||
ComponentDto project = newProjectDto(); | |||
SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); | |||
SnapshotDto otherAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)); | |||
dbTester.commit(); | |||
dbTester.events().insertEvent(newEvent(analysis).setUuid("A1")); | |||
dbTester.events().insertEvent(newEvent(otherAnalysis).setUuid("O1")); | |||
dbTester.events().insertEvent(newEvent(analysis).setUuid("A2")); | |||
dbTester.events().insertEvent(newEvent(otherAnalysis).setUuid("O2")); | |||
dbTester.events().insertEvent(newEvent(analysis).setUuid("A3")); | |||
dbTester.events().insertEvent(newEvent(otherAnalysis).setUuid("O3")); | |||
List<EventDto> result = underTest.selectByAnalysisUuid(dbSession, analysis.getUuid()); | |||
assertThat(result).hasSize(3); | |||
assertThat(result).extracting(EventDto::getUuid).containsOnly("A1", "A2", "A3"); | |||
} | |||
@Test | |||
public void return_different_categories() { | |||
dbTester.prepareDbUnit(getClass(), "shared.xml"); |
@@ -0,0 +1,45 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.event; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
public class EventDbTester { | |||
private final DbTester db; | |||
private final DbClient dbClient; | |||
private final DbSession dbSession; | |||
public EventDbTester(DbTester db) { | |||
this.db = db; | |||
this.dbClient = db.getDbClient(); | |||
this.dbSession = db.getSession(); | |||
} | |||
public EventDto insertEvent(EventDto event) { | |||
dbClient.eventDao().insert(dbSession, event); | |||
db.commit(); | |||
return event; | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.event; | |||
import org.sonar.db.component.SnapshotDto; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
public class EventTesting { | |||
public static EventDto newEvent(SnapshotDto analysis) { | |||
requireNonNull(analysis.getUuid()); | |||
requireNonNull(analysis.getComponentUuid()); | |||
return new EventDto() | |||
.setAnalysisUuid(analysis.getUuid()) | |||
.setComponentUuid(analysis.getComponentUuid()) | |||
.setUuid(randomAlphanumeric(40)) | |||
.setName(randomAlphanumeric(400)) | |||
.setDescription(randomAlphanumeric(400)) | |||
.setCategory(randomAlphanumeric(50)) | |||
.setComponentUuid(analysis.getComponentUuid()) | |||
.setCreatedAt(System.currentTimeMillis()) | |||
.setDate(System.currentTimeMillis()); | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.event; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import static com.google.common.base.Strings.repeat; | |||
public class EventValidatorTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Test | |||
public void valid_cases() { | |||
EventValidator.checkEventName(repeat("a", 400)); | |||
EventValidator.checkEventCategory(repeat("a", 50)); | |||
EventValidator.checkEventDescription(repeat("a", 4000)); | |||
EventValidator.checkEventDescription(null); | |||
} | |||
@Test | |||
public void fail_if_name_longer_than_400() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Event name length (401) is longer than the maximum authorized (400)."); | |||
EventValidator.checkEventName(repeat("a", 400 + 1)); | |||
} | |||
@Test | |||
public void fail_if_category_longer_than_50() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Event category length (51) is longer than the maximum authorized (50). 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' was provided."); | |||
EventValidator.checkEventCategory(repeat("a", 50 + 1)); | |||
} | |||
@Test | |||
public void fail_if_description_longer_than_4000() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Event description length (4001) is longer than the maximum authorized (4000)."); | |||
EventValidator.checkEventDescription(repeat("a", 4000 + 1)); | |||
} | |||
} |
@@ -0,0 +1,124 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.projectanalysis; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
public class CreateEventRequest { | |||
private final String analysis; | |||
private final Category category; | |||
private final String name; | |||
private final String description; | |||
private CreateEventRequest(Builder builder) { | |||
analysis = builder.analysis; | |||
category = builder.category; | |||
name = builder.name; | |||
description = builder.description; | |||
} | |||
public String getAnalysis() { | |||
return analysis; | |||
} | |||
public Category getCategory() { | |||
return category; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
@CheckForNull | |||
public String getDescription() { | |||
return description; | |||
} | |||
public static Builder builder() { | |||
return new Builder(); | |||
} | |||
public static class Builder { | |||
private String analysis; | |||
private Category category = Category.OTHER; | |||
private String name; | |||
private String description; | |||
private Builder() { | |||
// enforce static factory method | |||
} | |||
public Builder setAnalysis(String analysis) { | |||
this.analysis = analysis; | |||
return this; | |||
} | |||
public Builder setCategory(Category category) { | |||
this.category = category; | |||
return this; | |||
} | |||
public Builder setName(String name) { | |||
this.name = name; | |||
return this; | |||
} | |||
public Builder setDescription(@Nullable String description) { | |||
this.description = description; | |||
return this; | |||
} | |||
public CreateEventRequest build() { | |||
checkArgument(analysis != null, "Analysis key is required"); | |||
checkArgument(category != null, "Category is required"); | |||
checkArgument(name != null, "Name is required"); | |||
return new CreateEventRequest(this); | |||
} | |||
} | |||
public enum Category { | |||
VERSION("Version"), OTHER("Other"); | |||
private final String label; | |||
Category(String label) { | |||
this.label = label; | |||
} | |||
public String getLabel() { | |||
return label; | |||
} | |||
public static Category fromLabel(String label) { | |||
for (Category category : values()) { | |||
if (category.getLabel().equals(label)) { | |||
return category; | |||
} | |||
} | |||
throw new IllegalArgumentException("Unknown event category label '" + label + "'"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.projectanalysis; | |||
public class ProjectAnalysesWsParameters { | |||
public static final String PARAM_ANALYSIS = "analysis"; | |||
public static final String PARAM_CATEGORY = "category"; | |||
public static final String PARAM_NAME = "name"; | |||
public static final String PARAM_DESCRIPTION = "description"; | |||
private ProjectAnalysesWsParameters() { | |||
// static access only | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonarqube.ws.client.projectanalysis; | |||
import javax.annotation.ParametersAreNonnullByDefault; | |||
@@ -0,0 +1,38 @@ | |||
// SonarQube, open source software quality management tool. | |||
// Copyright (C) 2008-2016 SonarSource | |||
// mailto:contact AT sonarsource DOT com | |||
// | |||
// SonarQube is free software; you can redistribute it and/or | |||
// modify it under the terms of the GNU Lesser General Public | |||
// License as published by the Free Software Foundation; either | |||
// version 3 of the License, or (at your option) any later version. | |||
// | |||
// SonarQube is distributed in the hope that it will be useful, | |||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
// Lesser General Public License for more details. | |||
// | |||
// You should have received a copy of the GNU Lesser General Public License | |||
// along with this program; if not, write to the Free Software Foundation, | |||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
syntax = "proto2"; | |||
package sonarqube.ws.projectanalysis; | |||
option java_package = "org.sonarqube.ws"; | |||
option java_outer_classname = "ProjectAnalyses"; | |||
option optimize_for = SPEED; | |||
// WS api/project_analyses/create_event | |||
message CreateEventResponse { | |||
optional Event event = 1; | |||
} | |||
message Event { | |||
optional string key = 1; | |||
optional string analysis = 2; | |||
optional string category = 3; | |||
optional string name = 4; | |||
optional string description = 5; | |||
} |
@@ -0,0 +1,78 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.projectanalysis; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.OTHER; | |||
import static org.sonarqube.ws.client.projectanalysis.CreateEventRequest.Category.VERSION; | |||
public class CreateEventRequestTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private CreateEventRequest.Builder underTest = CreateEventRequest.builder(); | |||
@Test | |||
public void build_request() { | |||
CreateEventRequest result = underTest.setAnalysis("P1").setCategory(OTHER).setName("name").setDescription("description").build(); | |||
assertThat(result.getAnalysis()).isEqualTo("P1"); | |||
assertThat(result.getCategory()).isEqualTo(OTHER); | |||
assertThat(result.getName()).isEqualTo("name"); | |||
assertThat(result.getDescription()).isEqualTo("description"); | |||
} | |||
@Test | |||
public void other_category_by_default() { | |||
CreateEventRequest result = underTest.setAnalysis("P1").setName("name").build(); | |||
assertThat(OTHER.equals(result.getCategory())); | |||
} | |||
@Test | |||
public void fail_when_no_category() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Category is required"); | |||
underTest.setAnalysis("P1").setName("name").setCategory(null).build(); | |||
} | |||
@Test | |||
public void fail_when_no_analysis() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Analysis key is required"); | |||
underTest.setCategory(VERSION).setName("name").build(); | |||
} | |||
@Test | |||
public void fail_when_no_name() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Name is required"); | |||
underTest.setAnalysis("P1").setCategory(VERSION).build(); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.projectanalysis; | |||
import org.junit.Test; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.test.TestUtils.hasOnlyPrivateConstructors; | |||
public class ProjectAnalysesWsParametersTest { | |||
@Test | |||
public void private_access_only() { | |||
assertThat(hasOnlyPrivateConstructors(ProjectAnalysesWsParameters.class)).isTrue(); | |||
} | |||
} |