diff options
author | Daniel Schwarz <daniel.schwarz@sonarsource.com> | 2017-10-02 16:38:15 +0200 |
---|---|---|
committer | Daniel Schwarz <bartfastiel@users.noreply.github.com> | 2017-10-04 13:32:03 +0200 |
commit | ec5005ad979eb7bc47f277b42992851d8a4fbebc (patch) | |
tree | 71440f6b2894deb38a29b3da785358167ce7d3aa /server | |
parent | d70e1e972bc561b94d00af08b5835219aec48482 (diff) | |
download | sonarqube-ec5005ad979eb7bc47f277b42992851d8a4fbebc.tar.gz sonarqube-ec5005ad979eb7bc47f277b42992851d8a4fbebc.zip |
SONAR-9498 merge ChangelogAction and ChangelogLoader
Diffstat (limited to 'server')
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java | 157 | ||||
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogLoader.java | 196 | ||||
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java | 1 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionMockTest.java | 127 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java (renamed from server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionDatabaseTest.java) | 139 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogLoaderTest.java | 159 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java | 2 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java | 2 |
8 files changed, 282 insertions, 501 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java index 0b8c0d81f89..d53298df16f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java @@ -19,9 +19,17 @@ */ package org.sonar.server.qualityprofile.ws; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.api.resources.Languages; +import org.sonar.api.rule.RuleKey; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService.NewAction; @@ -29,10 +37,14 @@ import org.sonar.api.server.ws.WebService.NewController; import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.text.JsonWriter; +import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.qualityprofile.QProfileChangeDto; import org.sonar.db.qualityprofile.QProfileChangeQuery; import org.sonar.db.qualityprofile.QProfileDto; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.user.UserDto; import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime; import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime; @@ -42,13 +54,11 @@ import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters. public class ChangelogAction implements QProfileWsAction { - private final ChangelogLoader changelogLoader; private final QProfileWsSupport wsSupport; private final Languages languages; private DbClient dbClient; - public ChangelogAction(ChangelogLoader changelogLoader, QProfileWsSupport wsSupport, Languages languages, DbClient dbClient) { - this.changelogLoader = changelogLoader; + public ChangelogAction(QProfileWsSupport wsSupport, Languages languages, DbClient dbClient) { this.wsSupport = wsSupport; this.languages = languages; this.dbClient = dbClient; @@ -98,18 +108,20 @@ public class ChangelogAction implements QProfileWsAction { int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE); query.setPage(page, pageSize); - ChangelogLoader.Changelog changelog = changelogLoader.load(dbSession, query); - writeResponse(response.newJsonWriter(), page, pageSize, changelog); + int total = dbClient.qProfileChangeDao().countForQProfileUuid(dbSession, query.getProfileUuid()); + + List<Change> changelogs = load(dbSession, query); + writeResponse(response.newJsonWriter(), total, page, pageSize, changelogs); } } - private static void writeResponse(JsonWriter json, int page, int pageSize, ChangelogLoader.Changelog changelog) { + private static void writeResponse(JsonWriter json, int total, int page, int pageSize, List<Change> changelogs) { json.beginObject(); - json.prop("total", changelog.getTotal()); + json.prop("total", total); json.prop(Param.PAGE, page); json.prop(Param.PAGE_SIZE, pageSize); json.name("events").beginArray(); - for (ChangelogLoader.Change change : changelog.getChanges()) { + for (Change change : changelogs) { json.beginObject() .prop("date", DateUtils.formatDateTime(change.getCreatedAt())) .prop("authorLogin", change.getUserLogin()) @@ -124,7 +136,7 @@ public class ChangelogAction implements QProfileWsAction { json.endObject().close(); } - private static void writeParameters(JsonWriter json, ChangelogLoader.Change change) { + private static void writeParameters(JsonWriter json, Change change) { json.name("params").beginObject() .prop("severity", change.getSeverity()); for (Map.Entry<String, String> param : change.getParams().entrySet()) { @@ -133,4 +145,131 @@ public class ChangelogAction implements QProfileWsAction { json.endObject(); } + + /** + * @return non-null list of changes, by descending order of date + */ + public List<Change> load(DbSession dbSession, QProfileChangeQuery query) { + List<QProfileChangeDto> dtos = dbClient.qProfileChangeDao().selectByQuery(dbSession, query); + List<Change> changes = dtos.stream() + .map(Change::from) + .collect(MoreCollectors.toList(dtos.size())); + completeUserAndRuleNames(dbSession, changes); + return changes; + } + + private void completeUserAndRuleNames(DbSession dbSession, List<Change> changes) { + Set<String> logins = changes.stream().filter(c -> c.userLogin != null).map(c -> c.userLogin).collect(MoreCollectors.toSet()); + Map<String, String> userNamesByLogins = dbClient.userDao() + .selectByLogins(dbSession, logins) + .stream() + .collect(java.util.stream.Collectors.toMap(UserDto::getLogin, UserDto::getName)); + + Set<RuleKey> ruleKeys = changes.stream().filter(c -> c.ruleKey != null).map(c -> c.ruleKey).collect(MoreCollectors.toSet()); + Map<RuleKey, String> ruleNamesByKeys = dbClient.ruleDao() + .selectDefinitionByKeys(dbSession, Lists.newArrayList(ruleKeys)) + .stream() + .collect(java.util.stream.Collectors.toMap(RuleDefinitionDto::getKey, RuleDefinitionDto::getName)); + + changes.forEach(c -> { + c.userName = userNamesByLogins.get(c.userLogin); + c.ruleName = ruleNamesByKeys.get(c.ruleKey); + }); + } + + + static class Change { + private String key; + private String type; + private long at; + private String severity; + private String userLogin; + private String userName; + private String inheritance; + private RuleKey ruleKey; + private String ruleName; + private final Map<String, String> params = new HashMap<>(); + + private Change() { + } + + @VisibleForTesting + Change(String key, String type, long at, @Nullable String severity, @Nullable String userLogin, + @Nullable String userName, @Nullable String inheritance, @Nullable RuleKey ruleKey, @Nullable String ruleName) { + this.key = key; + this.type = type; + this.at = at; + this.severity = severity; + this.userLogin = userLogin; + this.userName = userName; + this.inheritance = inheritance; + this.ruleKey = ruleKey; + this.ruleName = ruleName; + } + + public String getKey() { + return key; + } + + @CheckForNull + public String getSeverity() { + return severity; + } + + @CheckForNull + public String getUserLogin() { + return userLogin; + } + + @CheckForNull + public String getUserName() { + return userName; + } + + public String getType() { + return type; + } + + @CheckForNull + public String getInheritance() { + return inheritance; + } + + public RuleKey getRuleKey() { + return ruleKey; + } + + @CheckForNull + public String getRuleName() { + return ruleName; + } + + public long getCreatedAt() { + return at; + } + + public Map<String, String> getParams() { + return params; + } + + private static Change from(QProfileChangeDto dto) { + Map<String, String> data = dto.getDataAsMap(); + Change change = new Change(); + change.key = dto.getUuid(); + change.userLogin = dto.getLogin(); + change.type = dto.getChangeType(); + change.at = dto.getCreatedAt(); + // see content of data in class org.sonar.server.qualityprofile.ActiveRuleChange + change.severity = data.get("severity"); + String ruleKey = data.get("ruleKey"); + if (ruleKey != null) { + change.ruleKey = RuleKey.parse(ruleKey); + } + change.inheritance = data.get("inheritance"); + data.entrySet().stream() + .filter(entry -> entry.getKey().startsWith("param_")) + .forEach(entry -> change.params.put(entry.getKey().replace("param_", ""), entry.getValue())); + return change; + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogLoader.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogLoader.java deleted file mode 100644 index 2146563002e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogLoader.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info 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.qualityprofile.ws; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.server.ServerSide; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.QProfileChangeDto; -import org.sonar.db.qualityprofile.QProfileChangeQuery; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.user.UserDto; - -import static java.util.Objects.requireNonNull; - -@ServerSide -public class ChangelogLoader { - - private final DbClient dbClient; - - public ChangelogLoader(DbClient dbClient) { - this.dbClient = dbClient; - } - - /** - * @return non-null list of changes, by descending order of date - */ - public Changelog load(DbSession dbSession, QProfileChangeQuery query) { - List<QProfileChangeDto> dtos = dbClient.qProfileChangeDao().selectByQuery(dbSession, query); - List<Change> changes = dtos.stream() - .map(Change::from) - .collect(MoreCollectors.toList(dtos.size())); - completeUserAndRuleNames(dbSession, changes); - - int total = dbClient.qProfileChangeDao().countForQProfileUuid(dbSession, query.getProfileUuid()); - return new Changelog(total, changes); - } - - private void completeUserAndRuleNames(DbSession dbSession, List<Change> changes) { - Set<String> logins = changes.stream().filter(c -> c.userLogin != null).map(c -> c.userLogin).collect(MoreCollectors.toSet()); - Map<String, String> userNamesByLogins = dbClient.userDao() - .selectByLogins(dbSession, logins) - .stream() - .collect(java.util.stream.Collectors.toMap(UserDto::getLogin, UserDto::getName)); - - Set<RuleKey> ruleKeys = changes.stream().filter(c -> c.ruleKey != null).map(c -> c.ruleKey).collect(MoreCollectors.toSet()); - Map<RuleKey, String> ruleNamesByKeys = dbClient.ruleDao() - .selectDefinitionByKeys(dbSession, Lists.newArrayList(ruleKeys)) - .stream() - .collect(java.util.stream.Collectors.toMap(RuleDefinitionDto::getKey, RuleDefinitionDto::getName)); - - changes.forEach(c -> { - c.userName = userNamesByLogins.get(c.userLogin); - c.ruleName = ruleNamesByKeys.get(c.ruleKey); - }); - } - - static class Change { - private String key; - private String type; - private long at; - private String severity; - private String userLogin; - private String userName; - private String inheritance; - private RuleKey ruleKey; - private String ruleName; - private final Map<String, String> params = new HashMap<>(); - - private Change() { - } - - @VisibleForTesting - Change(String key, String type, long at, @Nullable String severity, @Nullable String userLogin, - @Nullable String userName, @Nullable String inheritance, @Nullable RuleKey ruleKey, @Nullable String ruleName) { - this.key = key; - this.type = type; - this.at = at; - this.severity = severity; - this.userLogin = userLogin; - this.userName = userName; - this.inheritance = inheritance; - this.ruleKey = ruleKey; - this.ruleName = ruleName; - } - - public String getKey() { - return key; - } - - @CheckForNull - public String getSeverity() { - return severity; - } - - @CheckForNull - public String getUserLogin() { - return userLogin; - } - - @CheckForNull - public String getUserName() { - return userName; - } - - public String getType() { - return type; - } - - @CheckForNull - public String getInheritance() { - return inheritance; - } - - public RuleKey getRuleKey() { - return ruleKey; - } - - @CheckForNull - public String getRuleName() { - return ruleName; - } - - public long getCreatedAt() { - return at; - } - - public Map<String, String> getParams() { - return params; - } - - private static Change from(QProfileChangeDto dto) { - Map<String, String> data = dto.getDataAsMap(); - Change change = new Change(); - change.key = dto.getUuid(); - change.userLogin = dto.getLogin(); - change.type = dto.getChangeType(); - change.at = dto.getCreatedAt(); - // see content of data in class org.sonar.server.qualityprofile.ActiveRuleChange - change.severity = data.get("severity"); - String ruleKey = data.get("ruleKey"); - if (ruleKey != null) { - change.ruleKey = RuleKey.parse(ruleKey); - } - change.inheritance = data.get("inheritance"); - data.entrySet().stream() - .filter(entry -> entry.getKey().startsWith("param_")) - .forEach(entry -> change.params.put(entry.getKey().replace("param_", ""), entry.getValue())); - return change; - } - } - - static class Changelog { - private final int total; - private final List<Change> changes; - - Changelog(int total, List<Change> changes) { - this.total = total; - this.changes = requireNonNull(changes); - } - - public int getTotal() { - return total; - } - - public List<Change> getChanges() { - return changes; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java index 6f5aa204f81..ae82298bb81 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java @@ -34,7 +34,6 @@ public class QProfilesWsModule extends Module { CompareAction.class, CopyAction.class, ChangelogAction.class, - ChangelogLoader.class, ChangeParentAction.class, CreateAction.class, DeleteAction.class, diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionMockTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionMockTest.java deleted file mode 100644 index 736b0b76e09..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionMockTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info 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.qualityprofile.ws; - -import java.util.Collections; -import java.util.List; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.sonar.api.resources.Languages; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.QProfileChangeQuery; -import org.sonar.db.rule.RuleTesting; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.qualityprofile.QProfileTesting; -import org.sonar.server.ws.WsTester; - -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.api.utils.DateUtils.parseDate; -import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P1_KEY; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_SINCE; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_TO; - -public class ChangelogActionMockTest { - - private static final long A_DATE = 1_500_000_000_000L; - - @Rule - public DbTester db = DbTester.create(); - - private WsTester ws; - private ChangelogLoader changelogLoader = mock(ChangelogLoader.class); - private QProfileWsSupport wsSupport = mock(QProfileWsSupport.class); - private OrganizationDto organization; - - @Before - public void before() { - ws = new WsTester(new QProfilesWs(mock(ActivateRulesAction.class), - new ChangelogAction(changelogLoader, wsSupport, new Languages(), db.getDbClient()))); - organization = db.organizations().insert(); - } - - @Test - public void changelog_empty() throws Exception { - when(wsSupport.getProfile(any(DbSession.class), eq(QProfileReference.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1(organization)); - when(changelogLoader.load(any(DbSession.class), any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(0, Collections.emptyList())); - - ws.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_KEY, XOO_P1_KEY) - .execute().assertJson(getClass(), "changelog_empty.json"); - } - - @Test - public void changelog_nominal() throws Exception { - when(wsSupport.getProfile(any(DbSession.class), eq(QProfileReference.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1(organization)); - ChangelogLoader.Change change1 = new ChangelogLoader.Change("C1", "ACTIVATED", A_DATE, null, null, null, null, null, null); - ChangelogLoader.Change change2 = new ChangelogLoader.Change("C2", "ACTIVATED", A_DATE + 10, null, null, null, null, null, null); - List<ChangelogLoader.Change> changes = asList(change1, change2); - when(changelogLoader.load(any(DbSession.class), any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(10, changes)); - - ws.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_KEY, XOO_P1_KEY) - .execute().assertJson(getClass(), "changelog_nominal.json"); - } - - @Test - public void changelog_with_all_fields() throws Exception { - when(wsSupport.getProfile(any(DbSession.class), eq(QProfileReference.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1(organization)); - ChangelogLoader.Change change1 = new ChangelogLoader.Change("C1", "ACTIVATED", A_DATE, "MAJOR", "marcel", "Marcel", "INHERITED", RuleTesting.XOO_X1, "X One"); - change1.getParams().put("foo", "foo_value"); - change1.getParams().put("bar", "bar_value"); - List<ChangelogLoader.Change> changes = asList(change1); - when(changelogLoader.load(any(DbSession.class), any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(10, changes)); - - ws.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_KEY, XOO_P1_KEY) - .execute().assertJson(getClass(), "changelog_full.json"); - } - - @Test - public void changelog_inclusive_for_dates() throws Exception { - when(wsSupport.getProfile(any(DbSession.class), eq(QProfileReference.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1(organization)); - when(changelogLoader.load(any(DbSession.class), any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(0, Collections.emptyList())); - - ws.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog") - .setParam(PARAM_KEY, XOO_P1_KEY) - .setParam(PARAM_SINCE, "2016-09-01") - .setParam(PARAM_TO, "2016-09-01") - .execute(); - - ArgumentCaptor<QProfileChangeQuery> argumentCaptor = ArgumentCaptor.forClass(QProfileChangeQuery.class); - verify(changelogLoader).load(any(DbSession.class), argumentCaptor.capture()); - assertThat(argumentCaptor.getValue().getFromIncluded()).isEqualTo(parseDate("2016-09-01").getTime()); - assertThat(argumentCaptor.getValue().getToExcluded()).isEqualTo(parseDate("2016-09-02").getTime()); - } - - @Test(expected = NotFoundException.class) - public void fail_on_unknown_profile() throws Exception { - when(wsSupport.getProfile(any(DbSession.class), eq(QProfileReference.fromKey(XOO_P1_KEY)))).thenThrow(new NotFoundException("Profile not found")); - - ws.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_KEY, XOO_P1_KEY).execute(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionDatabaseTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java index 8f6d7166b66..77c6b0da904 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionDatabaseTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java @@ -19,54 +19,68 @@ */ package org.sonar.server.qualityprofile.ws; +import com.google.common.collect.ImmutableMap; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Consumer; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.resources.Languages; +import org.sonar.api.rule.RuleKey; import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.System2; +import org.sonar.api.utils.DateUtils; +import org.sonar.api.utils.internal.TestSystem2; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QProfileChangeDto; import org.sonar.db.qualityprofile.QProfileDto; import org.sonar.db.qualityprofile.QualityProfileTesting; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; +import org.sonar.server.qualityprofile.ActiveRule; +import org.sonar.server.qualityprofile.ActiveRuleChange; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; +import org.sonar.test.JsonAssert; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.test.JsonAssert.assertJson; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE; -public class ChangelogActionDatabaseTest { +public class ChangelogActionTest { + + private TestSystem2 system2 = new TestSystem2().setNow(1_500_000_000_000L); @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); + public DbTester dbTester = DbTester.create(system2); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @Rule public ExpectedException thrown = ExpectedException.none(); private WsActionTester ws; - private ChangelogLoader changelogLoader; private QProfileWsSupport wsSupport; private OrganizationDto organization; private DefaultOrganizationProvider defaultOrganizationProvider; @Before public void before() { + system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime()); defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); wsSupport = new QProfileWsSupport(dbTester.getDbClient(), userSession, defaultOrganizationProvider); - changelogLoader = new ChangelogLoader(dbTester.getDbClient()); ws = new WsActionTester( - new ChangelogAction(changelogLoader, wsSupport, new Languages(), dbTester.getDbClient())); + new ChangelogAction(wsSupport, new Languages(), dbTester.getDbClient())); organization = dbTester.organizations().insert(); } @@ -84,6 +98,47 @@ public class ChangelogActionDatabaseTest { } @Test + public void example() { + QProfileDto profile = dbTester.qualityProfiles().insert(organization); + String profileUuid = profile.getRulesProfileUuid(); + + system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:39+0100").getTime()); + RuleDefinitionDto rule1 = dbTester.rules().insert(RuleKey.of("squid", "S2438"), r -> r.setName("\"Threads\" should not be used where \"Runnables\" are expected")); + UserDto user1 = dbTester.users().insertUser(u -> u.setLogin("anakin.skywalker").setName("Anakin Skywalker")); + insertChange(profile, c -> c.setRulesProfileUuid(profileUuid) + .setLogin(user1.getLogin()) + .setChangeType(ActiveRuleChange.Type.ACTIVATED.name()) + .setData(ImmutableMap.of("severity", "CRITICAL", "ruleKey", rule1.getKey().toString()))); + + system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:18+0100").getTime()); + RuleDefinitionDto rule2 = dbTester.rules().insert(RuleKey.of("squid", "S2162"), r -> r.setName("\"equals\" methods should be symmetric and work for subclasses")); + UserDto user2 = dbTester.users().insertUser(u -> u.setLogin("padme.amidala").setName("Padme Amidala")); + QProfileChangeDto change2 = insertChange(profile, c -> c.setRulesProfileUuid(profileUuid) + .setLogin(user2.getLogin()) + .setChangeType(ActiveRuleChange.Type.DEACTIVATED.name()) + .setData(ImmutableMap.of("ruleKey", rule2.getKey().toString()))); + + system2.setNow(DateUtils.parseDateTime("2014-09-12T15:20:46+0200").getTime()); + RuleDefinitionDto rule3 = dbTester.rules().insert(RuleKey.of("squid", "S00101"), r -> r.setName("Class names should comply with a naming convention")); + UserDto user3 = dbTester.users().insertUser(u -> u.setLogin("obiwan.kenobi").setName("Obiwan Kenobi")); + QProfileChangeDto change3 = insertChange(profile, c -> c.setRulesProfileUuid(profileUuid) + .setLogin(user3.getLogin()) + .setChangeType(ActiveRuleChange.Type.ACTIVATED.name()) + .setData(ImmutableMap.of("severity", "MAJOR", "param_format", "^[A-Z][a-zA-Z0-9]*$", "ruleKey", rule3.getKey().toString()))); + + dbTester.commit(); + + String response = ws.newRequest() + .setMethod("GET") + .setParam(PARAM_KEY, profile.getKee()) + .setParam("ps", "10") + .execute() + .getInput(); + + assertJson(response).isSimilarTo(getClass().getResource("changelog-example.json")); + } + + @Test public void find_changelog_by_profile_key() throws Exception { QProfileDto profile = dbTester.qualityProfiles().insert(organization); @@ -176,4 +231,74 @@ public class ChangelogActionDatabaseTest { assertThat(response).contains("\"total\":1"); } + + @Test + public void sort_changelog_events_in_reverse_chronological_order() { + QProfileDto profile = dbTester.qualityProfiles().insert(organization); + system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime()); + QProfileChangeDto change1 = insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null, null); + system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:43+0100").getTime()); + QProfileChangeDto change2 = insertChange(profile, ActiveRuleChange.Type.DEACTIVATED, "mazout", null); + dbTester.commit(); + + String response = ws.newRequest() + .setMethod("GET") + .setParam(PARAM_KEY, profile.getKee()) + .execute() + .getInput(); + + assertThat(response).containsSequence("15:43", "15:42"); + } + + @Test + public void return_change_with_all_fields() { + QProfileDto profile = dbTester.qualityProfiles().insert(organization); + Map<String, Object> data = ImmutableMap.of( + "ruleKey", "java:S001", + "severity", "MINOR", + "inheritance", ActiveRule.Inheritance.INHERITED.name(), + "param_foo", "foo_value", + "param_bar", "bar_value"); + QProfileChangeDto change = insertChange(profile, ActiveRuleChange.Type.ACTIVATED, "theLogin", data); + dbTester.commit(); + + String response = ws.newRequest() + .setMethod("GET") + .setParam(PARAM_KEY, profile.getKee()) + .execute() + .getInput(); + + JsonAssert.assertJson(response).isSimilarTo("{\n" + + " \"total\": 1,\n" + + " \"p\": 1,\n" + + " \"ps\": 50,\n" + + " \"events\": [\n" + + " {\n" + + " \"date\": \"2011-04-25T02:15:42+0200\",\n" + + " \"authorLogin\": \"theLogin\",\n" + + " \"action\": \"ACTIVATED\",\n" + + " \"ruleKey\": \"java:S001\",\n" + + " \"params\": {\n" + + " \"severity\": \"MINOR\",\n" + + " \"bar\": \"bar_value\",\n" + + " \"foo\": \"foo_value\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"); + } + + private QProfileChangeDto insertChange(QProfileDto profile, ActiveRuleChange.Type type, @Nullable String login, @Nullable Map<String, Object> data) { + return insertChange(profile, c -> c.setRulesProfileUuid(profile.getRulesProfileUuid()) + .setLogin(login) + .setChangeType(type.name()) + .setData(data)); + } + + private QProfileChangeDto insertChange(QProfileDto profile, Consumer<QProfileChangeDto>... consumers) { + QProfileChangeDto dto = new QProfileChangeDto(); + Arrays.stream(consumers).forEach(c -> c.accept(dto)); + dbTester.getDbClient().qProfileChangeDao().insert(dbTester.getSession(), dto); + return dto; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogLoaderTest.java deleted file mode 100644 index 2fbe940d5ec..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogLoaderTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info 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.qualityprofile.ws; - -import com.google.common.collect.ImmutableMap; -import java.util.Map; -import javax.annotation.Nullable; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.qualityprofile.QProfileChangeDto; -import org.sonar.db.qualityprofile.QProfileChangeQuery; -import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.qualityprofile.ActiveRule; -import org.sonar.server.qualityprofile.ActiveRuleChange; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.data.MapEntry.entry; - -public class ChangelogLoaderTest { - - private System2 system2 = new AlwaysIncreasingSystem2(); - @Rule - public DbTester db = DbTester.create(system2); - private DbSession dbSession = db.getSession(); - - private ChangelogLoader underTest = new ChangelogLoader(db.getDbClient()); - - @Test - public void return_changes_in_reverse_chronological_order() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); - QProfileChangeDto change1 = insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null, null); - QProfileChangeDto change2 = insertChange(profile, ActiveRuleChange.Type.DEACTIVATED, "mazout", null); - - QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee()); - ChangelogLoader.Changelog changes = underTest.load(dbSession, query); - - assertThat(changes.getChanges()) - .extracting(ChangelogLoader.Change::getKey) - .containsExactly(change2.getUuid(), change1.getUuid()); - } - - @Test - public void return_change_with_only_required_fields() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); - QProfileChangeDto inserted = insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null, null); - - QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee()); - ChangelogLoader.Change change = underTest.load(dbSession, query).getChanges().get(0); - - assertThat(change.getKey()).isEqualTo(inserted.getUuid()); - assertThat(change.getCreatedAt()).isEqualTo(inserted.getCreatedAt()); - assertThat(change.getType()).isEqualTo(inserted.getChangeType()); - // optional fields are null or empty - assertThat(change.getInheritance()).isNull(); - assertThat(change.getRuleKey()).isNull(); - assertThat(change.getRuleName()).isNull(); - assertThat(change.getSeverity()).isNull(); - assertThat(change.getUserLogin()).isNull(); - assertThat(change.getUserName()).isNull(); - assertThat(change.getParams()).isEmpty(); - } - - @Test - public void return_change_with_all_fields() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); - Map<String, Object> data = ImmutableMap.of( - "ruleKey", "java:S001", - "severity", "MINOR", - "inheritance", ActiveRule.Inheritance.INHERITED.name(), - "param_foo", "foo_value", - "param_bar", "bar_value"); - QProfileChangeDto inserted = insertChange(profile, ActiveRuleChange.Type.ACTIVATED, "theLogin", data); - - QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee()); - ChangelogLoader.Change change = underTest.load(dbSession, query).getChanges().get(0); - - assertThat(change.getKey()).isEqualTo(inserted.getUuid()); - assertThat(change.getCreatedAt()).isEqualTo(inserted.getCreatedAt()); - assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED.name()); - assertThat(change.getInheritance()).isEqualTo(ActiveRule.Inheritance.INHERITED.name()); - assertThat(change.getRuleKey().toString()).isEqualTo("java:S001"); - assertThat(change.getRuleName()).isNull(); - assertThat(change.getSeverity()).isEqualTo("MINOR"); - assertThat(change.getUserLogin()).isEqualTo("theLogin"); - assertThat(change.getUserName()).isNull(); - assertThat(change.getParams()).containsOnly(entry("foo", "foo_value"), entry("bar", "bar_value")); - } - - @Test - public void return_name_of_rule() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); - RuleDefinitionDto rule = db.rules().insert(); - Map<String, Object> data = ImmutableMap.of("ruleKey", rule.getKey().toString()); - insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null, data); - - QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee()); - ChangelogLoader.Change change = underTest.load(dbSession, query).getChanges().get(0); - - assertThat(change.getRuleKey()).isEqualTo(rule.getKey()); - assertThat(change.getRuleName()).isEqualTo(rule.getName()); - } - - @Test - public void return_name_of_user() { - QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); - UserDto user = db.users().insertUser(); - insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user.getLogin(), null); - - QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee()); - ChangelogLoader.Change change = underTest.load(dbSession, query).getChanges().get(0); - - assertThat(change.getUserLogin()).isEqualTo(user.getLogin()); - assertThat(change.getUserName()).isEqualTo(user.getName()); - } - - @Test - public void return_empty_changelog() { - QProfileChangeQuery query = new QProfileChangeQuery("P1"); - - ChangelogLoader.Changelog changelog = underTest.load(dbSession, query); - - assertThat(changelog.getTotal()).isEqualTo(0); - assertThat(changelog.getChanges()).isEmpty(); - } - - private QProfileChangeDto insertChange(QProfileDto profile, ActiveRuleChange.Type type, @Nullable String login, @Nullable Map<String, Object> data) { - QProfileChangeDto dto = new QProfileChangeDto() - .setRulesProfileUuid(profile.getRulesProfileUuid()) - .setLogin(login) - .setChangeType(type.name()) - .setData(data); - db.getDbClient().qProfileChangeDao().insert(dbSession, dto); - return dto; - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java index d16a500bae3..fb239e4392e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java @@ -29,6 +29,6 @@ public class QProfilesWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new QProfilesWsModule().configure(container); - assertThat(container.size()).isEqualTo(33 + 2); + assertThat(container.size()).isEqualTo(32 + 2); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java index 0ffe1990556..978c940b864 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java @@ -64,7 +64,7 @@ public class QProfilesWsTest { new SearchAction(userSession, languages, dbClient, wsSupport, null), new SetDefaultAction(languages, null, null, wsSupport), new ProjectsAction(null, userSession, wsSupport), - new ChangelogAction(null, wsSupport, languages, dbClient), + new ChangelogAction(wsSupport, languages, dbClient), new ChangeParentAction(dbClient, null, languages, wsSupport, userSession), new CompareAction(null, null, languages), new DeleteAction(languages, null, null, userSession, wsSupport), |