@@ -40,6 +40,8 @@ import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.application.config.TestAppSettings; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
import org.sonar.process.cluster.hz.DistributedAnswer; | |||
import org.sonar.process.cluster.hz.DistributedCall; | |||
import org.sonar.process.cluster.hz.DistributedCallback; | |||
@@ -194,6 +196,16 @@ public class AppNodesClusterHostsConsistencyTest { | |||
callback.onComplete((Map<Member, T>) hostsPerMember); | |||
} | |||
@Override | |||
public void subscribeRuleActivationTopic(RuleActivationListener listener) { | |||
} | |||
@Override | |||
public void publishEvent(RuleSetChangeEvent event) { | |||
} | |||
@Override | |||
public void close() { | |||
@@ -26,6 +26,8 @@ import java.util.Map; | |||
import java.util.Set; | |||
import java.util.UUID; | |||
import java.util.concurrent.locks.Lock; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
import org.sonar.process.ProcessId; | |||
public interface HazelcastMember extends AutoCloseable { | |||
@@ -106,6 +108,10 @@ public interface HazelcastMember extends AutoCloseable { | |||
*/ | |||
<T> void callAsync(DistributedCall<T> callable, MemberSelector memberSelector, DistributedCallback<T> callback); | |||
void subscribeRuleActivationTopic(RuleActivationListener listener); | |||
void publishEvent(RuleSetChangeEvent event); | |||
@Override | |||
void close(); | |||
} |
@@ -27,6 +27,8 @@ import com.hazelcast.core.HazelcastInstanceNotActiveException; | |||
import com.hazelcast.core.IExecutorService; | |||
import com.hazelcast.core.MultiExecutionCallback; | |||
import com.hazelcast.cp.IAtomicReference; | |||
import com.hazelcast.topic.ITopic; | |||
import com.hazelcast.topic.MessageListener; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.UUID; | |||
@@ -37,6 +39,8 @@ import java.util.concurrent.TimeoutException; | |||
import java.util.concurrent.locks.Lock; | |||
import java.util.stream.Collectors; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
class HazelcastMemberImpl implements HazelcastMember { | |||
@@ -125,6 +129,18 @@ class HazelcastMemberImpl implements HazelcastMember { | |||
}); | |||
} | |||
@Override | |||
public void subscribeRuleActivationTopic(RuleActivationListener listener) { | |||
ITopic<RuleSetChangeEvent> topic = hzInstance.getTopic("ruleActivated"); | |||
MessageListener<RuleSetChangeEvent> hzListener = message -> listener.listen(message.getMessageObject()); | |||
topic.addMessageListener(hzListener); | |||
} | |||
@Override | |||
public void publishEvent(RuleSetChangeEvent event) { | |||
hzInstance.getTopic("ruleActivated").publish(event); | |||
} | |||
@Override | |||
public void close() { | |||
try { |
@@ -40,11 +40,14 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { | |||
private final DbClient dbClient; | |||
private final RuleActivator ruleActivator; | |||
private final ActiveRuleIndexer activeRuleIndexer; | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService; | |||
public BuiltInQProfileUpdateImpl(DbClient dbClient, RuleActivator ruleActivator, ActiveRuleIndexer activeRuleIndexer) { | |||
public BuiltInQProfileUpdateImpl(DbClient dbClient, RuleActivator ruleActivator, ActiveRuleIndexer activeRuleIndexer, | |||
QualityProfileChangeEventService qualityProfileChangeEventService) { | |||
this.dbClient = dbClient; | |||
this.ruleActivator = ruleActivator; | |||
this.activeRuleIndexer = activeRuleIndexer; | |||
this.qualityProfileChangeEventService = qualityProfileChangeEventService; | |||
} | |||
public List<ActiveRuleChange> update(DbSession dbSession, BuiltInQProfile builtInDefinition, RulesProfileDto initialRuleProfile) { | |||
@@ -56,8 +59,8 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { | |||
// all rules, including those which are removed from built-in profile | |||
Set<String> ruleUuids = Stream.concat( | |||
deactivatedRuleUuids.stream(), | |||
builtInDefinition.getActiveRules().stream().map(BuiltInQProfile.ActiveRule::getRuleUuid)) | |||
deactivatedRuleUuids.stream(), | |||
builtInDefinition.getActiveRules().stream().map(BuiltInQProfile.ActiveRule::getRuleUuid)) | |||
.collect(toSet()); | |||
Collection<RuleActivation> activations = new ArrayList<>(); | |||
@@ -69,13 +72,16 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { | |||
RuleActivationContext context = ruleActivator.createContextForBuiltInProfile(dbSession, initialRuleProfile, ruleUuids); | |||
List<ActiveRuleChange> changes = new ArrayList<>(); | |||
for (RuleActivation activation : activations) { | |||
changes.addAll(ruleActivator.activate(dbSession, activation, context)); | |||
} | |||
changes.addAll(ruleActivator.activate(dbSession, activations, context)); | |||
// these rules are no longer part of the built-in profile | |||
deactivatedRuleUuids.forEach(ruleUuid -> changes.addAll(ruleActivator.deactivate(dbSession, context, ruleUuid, false))); | |||
if (!changes.isEmpty()) { | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(context.getProfiles(), changes, initialRuleProfile.getLanguage()); | |||
} | |||
activeRuleIndexer.commitAndIndex(dbSession, changes); | |||
return changes; | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
import org.sonar.process.cluster.hz.HazelcastMember; | |||
@ServerSide | |||
public class DistributedRuleActivatorEventsDistributor implements RuleActivatorEventsDistributor { | |||
private HazelcastMember hazelcastMember; | |||
public DistributedRuleActivatorEventsDistributor(HazelcastMember hazelcastMember) { | |||
this.hazelcastMember = hazelcastMember; | |||
} | |||
@Override | |||
public void subscribe(RuleActivationListener listener) { | |||
hazelcastMember.subscribeRuleActivationTopic(listener); | |||
} | |||
@Override | |||
public void pushEvent(RuleSetChangeEvent event) { | |||
hazelcastMember.publishEvent(event); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
public interface QualityProfileChangeEventService { | |||
void publishRuleActivationToSonarLintClients(ProjectDto project, Optional<QProfileDto> activatedProfile, Optional<QProfileDto> deactivatedProfile); | |||
void distributeRuleChangeEvent(Collection<QProfileDto> profiles, List<ActiveRuleChange> activeRuleChanges, String language); | |||
} |
@@ -0,0 +1,206 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import org.jetbrains.annotations.NotNull; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.core.util.ParamChange; | |||
import org.sonar.core.util.RuleChange; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.db.qualityprofile.ActiveRuleParamDto; | |||
import org.sonar.db.qualityprofile.ProjectQprofileAssociationDto; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
import org.sonar.server.rule.index.RuleQuery; | |||
@ServerSide | |||
public class QualityProfileChangeEventServiceImpl implements QualityProfileChangeEventService { | |||
private final DbClient dbClient; | |||
private final RuleIndex ruleIndex; | |||
private final RuleActivatorEventsDistributor eventsDistributor; | |||
public QualityProfileChangeEventServiceImpl(DbClient dbClient, RuleIndex ruleIndex, RuleActivatorEventsDistributor eventsDistributor) { | |||
this.dbClient = dbClient; | |||
this.ruleIndex = ruleIndex; | |||
this.eventsDistributor = eventsDistributor; | |||
} | |||
@Override | |||
public void publishRuleActivationToSonarLintClients(ProjectDto project, Optional<QProfileDto> activatedProfile, Optional<QProfileDto> deactivatedProfile) { | |||
List<RuleChange> activatedRules = new ArrayList<>(); | |||
List<RuleChange> deactivatedRules = new ArrayList<>(); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
if (activatedProfile.isPresent()) { | |||
RuleQuery query = new RuleQuery().setQProfile(activatedProfile.get()).setActivation(true).setIncludeExternal(true); | |||
// .setLanguages() ? | |||
Iterator<String> searchIdResult = ruleIndex.searchAll(query); | |||
List<String> uuids = new ArrayList<>(); | |||
while (searchIdResult.hasNext()) { | |||
uuids.add(searchIdResult.next()); | |||
} | |||
List<RuleDto> ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, uuids); | |||
Map<String, List<ActiveRuleParamDto>> paramsByRuleUuid = dbClient.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, uuids) | |||
.stream().collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid)); | |||
for (RuleDto ruleDto : ruleDtos) { | |||
RuleChange ruleChange = toRuleChange(ruleDto, paramsByRuleUuid); | |||
activatedRules.add(ruleChange); | |||
} | |||
} | |||
if (deactivatedProfile.isPresent()) { | |||
RuleQuery query = new RuleQuery().setQProfile(deactivatedProfile.get()).setActivation(true).setIncludeExternal(true); | |||
// .setLanguages() ? | |||
Iterator<String> searchIdResult = ruleIndex.searchAll(query); | |||
List<String> uuids = new ArrayList<>(); | |||
while (searchIdResult.hasNext()) { | |||
uuids.add(searchIdResult.next()); | |||
} | |||
List<RuleDto> ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, uuids); | |||
Map<String, List<ActiveRuleParamDto>> paramsByRuleUuid = dbClient.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, uuids) | |||
.stream().collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid)); | |||
for (RuleDto ruleDto : ruleDtos) { | |||
RuleChange ruleChange = toRuleChange(ruleDto, paramsByRuleUuid); | |||
deactivatedRules.add(ruleChange); | |||
} | |||
} | |||
} | |||
RuleSetChangeEvent event = new RuleSetChangeEvent(new String[]{project.getKey()}, activatedRules.toArray(new RuleChange[0]), deactivatedRules.toArray(new RuleChange[0])); | |||
eventsDistributor.pushEvent(event); | |||
} | |||
@NotNull | |||
private RuleChange toRuleChange(RuleDto ruleDto, Map<String, List<ActiveRuleParamDto>> paramsByRuleUuid) { | |||
RuleChange ruleChange = new RuleChange(); | |||
ruleChange.setKey(ruleDto.getRuleKey()); | |||
ruleChange.setLanguage(ruleDto.getLanguage()); | |||
ruleChange.setSeverity(ruleDto.getSeverityString()); | |||
List<ParamChange> paramChanges = new ArrayList<>(); | |||
List<ActiveRuleParamDto> activeRuleParamDtos = paramsByRuleUuid.getOrDefault(ruleDto.getUuid(), new ArrayList<>()); | |||
for (ActiveRuleParamDto activeRuleParam : activeRuleParamDtos) { | |||
paramChanges.add(new ParamChange(activeRuleParam.getKey(), activeRuleParam.getValue())); | |||
} | |||
ruleChange.setParams(paramChanges.toArray(new ParamChange[0])); | |||
String templateUuid = ruleDto.getTemplateUuid(); | |||
if (templateUuid != null && !"".equals(templateUuid)) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
RuleDto templateRule = dbClient.ruleDao().selectByUuid(templateUuid, dbSession) | |||
.orElseThrow(() -> new IllegalStateException(String.format("unknow Template Rule '%s'", templateUuid))); | |||
ruleChange.setTemplateKey(templateRule.getRuleKey()); | |||
} | |||
} | |||
return ruleChange; | |||
} | |||
public void distributeRuleChangeEvent(Collection<QProfileDto> profiles, List<ActiveRuleChange> activeRuleChanges, String language) { | |||
if (activeRuleChanges.isEmpty()) { | |||
return; | |||
} | |||
Set<RuleChange> activatedRules = new HashSet<>(); | |||
Set<RuleChange> deactivatedRules = new HashSet<>(); | |||
for (ActiveRuleChange arc : activeRuleChanges) { | |||
RuleChange ruleChange = new RuleChange(); | |||
ruleChange.setKey(arc.getActiveRule().getRuleKey().rule()); | |||
ruleChange.setSeverity(arc.getSeverity()); | |||
ruleChange.setLanguage(language); | |||
Optional<String> templateKey = templateKey(arc); | |||
templateKey.ifPresent(ruleChange::setTemplateKey); | |||
// params | |||
List<ParamChange> paramChanges = new ArrayList<>(); | |||
for (Map.Entry<String, String> entry : arc.getParameters().entrySet()) { | |||
paramChanges.add(new ParamChange(entry.getKey(), entry.getValue())); | |||
} | |||
ruleChange.setParams(paramChanges.toArray(new ParamChange[0])); | |||
switch (arc.getType()) { | |||
case ACTIVATED: | |||
case UPDATED: | |||
activatedRules.add(ruleChange); | |||
break; | |||
case DEACTIVATED: | |||
deactivatedRules.add(ruleChange); | |||
break; | |||
} | |||
} | |||
Set<String> projectKeys = getProjectKeys(profiles); | |||
RuleSetChangeEvent event = new RuleSetChangeEvent(projectKeys.toArray(new String[0]), activatedRules.toArray(new RuleChange[0]), deactivatedRules.toArray(new RuleChange[0])); | |||
eventsDistributor.pushEvent(event); | |||
} | |||
private Optional<String> templateKey(ActiveRuleChange arc) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String ruleUuid = arc.getRuleUuid(); | |||
RuleDto rule = dbClient.ruleDao().selectByUuid(ruleUuid, dbSession).orElseThrow(() -> new IllegalStateException("unknow rule")); | |||
String templateUuid = rule.getTemplateUuid(); | |||
if (templateUuid != null && !"".equals(templateUuid)) { | |||
RuleDto templateRule = dbClient.ruleDao().selectByUuid(templateUuid, dbSession) | |||
.orElseThrow(() -> new IllegalStateException(String.format("unknow Template Rule '%s'", templateUuid))); | |||
return Optional.of(templateRule.getRuleKey()); | |||
} | |||
} | |||
return Optional.empty(); | |||
} | |||
private Set<String> getProjectKeys(Collection<QProfileDto> profiles) { | |||
Set<String> projectKeys = new HashSet<>(); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
for (QProfileDto profileDto : profiles) { | |||
List<ProjectQprofileAssociationDto> associationDtos = dbClient.qualityProfileDao().selectSelectedProjects(dbSession, profileDto, null); | |||
for (ProjectQprofileAssociationDto associationDto : associationDtos) { | |||
projectKeys.add(associationDto.getProjectKey()); | |||
} | |||
} | |||
return projectKeys; | |||
} | |||
} | |||
} |
@@ -52,6 +52,7 @@ import org.sonar.server.user.UserSession; | |||
import org.sonar.server.util.TypeValidations; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.stream.Collectors.toList; | |||
import static org.sonar.server.exceptions.BadRequestException.checkRequest; | |||
/** | |||
@@ -72,9 +73,17 @@ public class RuleActivator { | |||
this.userSession = userSession; | |||
} | |||
public List<ActiveRuleChange> activate(DbSession dbSession, Collection<RuleActivation> activations, RuleActivationContext context) { | |||
return activations.stream().map(a -> activate(dbSession, a, context)) | |||
.flatMap(List::stream) | |||
.collect(toList()); | |||
} | |||
public List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, RuleActivationContext context) { | |||
context.reset(activation.getRuleUuid()); | |||
return doActivate(dbSession, activation, context); | |||
List<ActiveRuleChange> activeRuleChanges = doActivate(dbSession, activation, context); | |||
return activeRuleChanges; | |||
} | |||
private List<ActiveRuleChange> doActivate(DbSession dbSession, RuleActivation activation, RuleActivationContext context) { | |||
@@ -357,7 +366,8 @@ public class RuleActivator { | |||
public List<ActiveRuleChange> deactivate(DbSession dbSession, RuleActivationContext context, String ruleUuid, boolean force) { | |||
context.reset(ruleUuid); | |||
return doDeactivate(dbSession, context, force); | |||
List<ActiveRuleChange> activeRuleChanges = doDeactivate(dbSession, context, force); | |||
return activeRuleChanges; | |||
} | |||
private List<ActiveRuleChange> doDeactivate(DbSession dbSession, RuleActivationContext context, boolean force) { |
@@ -0,0 +1,30 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
public interface RuleActivatorEventsDistributor { | |||
void subscribe(RuleActivationListener listener); | |||
void pushEvent(RuleSetChangeEvent event); | |||
} |
@@ -0,0 +1,42 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
@ServerSide | |||
public class StandaloneRuleActivatorEventsDistributor implements RuleActivatorEventsDistributor { | |||
private List<RuleActivationListener> listeners = new ArrayList<>(); | |||
@Override | |||
public void subscribe(RuleActivationListener listener) { | |||
listeners.add(listener); | |||
} | |||
@Override | |||
public void pushEvent(RuleSetChangeEvent event) { | |||
listeners.forEach(l -> l.listen(event)); | |||
} | |||
} |
@@ -56,7 +56,12 @@ import static java.util.Collections.emptyMap; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.groups.Tuple.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoInteractions; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.sonar.api.rules.RulePriority.BLOCKER; | |||
import static org.sonar.api.rules.RulePriority.CRITICAL; | |||
import static org.sonar.api.rules.RulePriority.MAJOR; | |||
@@ -78,9 +83,11 @@ public class BuiltInQProfileUpdateImplTest { | |||
private System2 system2 = new TestSystem2().setNow(NOW); | |||
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); | |||
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); | |||
private BuiltInQProfileUpdateImpl underTest = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivator, activeRuleIndexer); | |||
private BuiltInQProfileUpdateImpl underTest = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivator, activeRuleIndexer, | |||
qualityProfileChangeEventService); | |||
private RulesProfileDto persistedProfile; | |||
@@ -105,13 +112,14 @@ public class BuiltInQProfileUpdateImplTest { | |||
newQp.done(); | |||
BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThat(activeRules).hasSize(2); | |||
assertThatRuleIsNewlyActivated(activeRules, rule1, CRITICAL); | |||
assertThatRuleIsNewlyActivated(activeRules, rule2, MAJOR); | |||
assertThatProfileIsMarkedAsUpdated(persistedProfile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -125,12 +133,13 @@ public class BuiltInQProfileUpdateImplTest { | |||
activateRuleInDb(persistedProfile, rule, BLOCKER); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThat(activeRules).hasSize(1); | |||
assertThatRuleIsUpdated(activeRules, rule, CRITICAL); | |||
assertThatProfileIsMarkedAsUpdated(persistedProfile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -150,6 +159,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
assertThat(activeRules).hasSize(1); | |||
assertThatRuleIsUntouched(activeRules, rule, CRITICAL); | |||
assertThatProfileIsNotMarkedAsUpdated(persistedProfile); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -166,12 +176,13 @@ public class BuiltInQProfileUpdateImplTest { | |||
// so rule1 must be deactivated | |||
activateRuleInDb(persistedProfile, rule1, CRITICAL); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThat(activeRules).hasSize(1); | |||
assertThatRuleIsDeactivated(activeRules, rule1); | |||
assertThatProfileIsMarkedAsUpdated(persistedProfile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -193,7 +204,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
activateRuleInDb(persistedProfile, rule1, BLOCKER); | |||
activateRuleInDb(persistedProfile, rule3, BLOCKER); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThat(activeRules).hasSize(2); | |||
@@ -201,6 +212,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
assertThatRuleIsNewlyActivated(activeRules, rule2, MAJOR); | |||
assertThatRuleIsDeactivated(activeRules, rule3); | |||
assertThatProfileIsMarkedAsUpdated(persistedProfile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
// SONAR-10473 | |||
@@ -222,9 +234,10 @@ public class BuiltInQProfileUpdateImplTest { | |||
rule.setSeverity(Severity.MINOR); | |||
db.rules().update(rule); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThatRuleIsNewlyActivated(activeRules, rule, MINOR); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -237,20 +250,22 @@ public class BuiltInQProfileUpdateImplTest { | |||
newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()); | |||
newQp.done(); | |||
BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(newQp.language(), newQp.name()), rule); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThat(activeRules).hasSize(1); | |||
assertThatRuleHasParams(db, activeRules.get(0), tuple("min", "10")); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
// emulate an upgrade of analyzer that changes the default value of parameter min | |||
ruleParam.setDefaultValue("20"); | |||
db.getDbClient().ruleDao().updateRuleParam(db.getSession(), rule, ruleParam); | |||
underTest.update(db.getSession(), builtIn, persistedProfile); | |||
changes = underTest.update(db.getSession(), builtIn, persistedProfile); | |||
activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile); | |||
assertThat(activeRules).hasSize(1); | |||
assertThatRuleHasParams(db, activeRules.get(0), tuple("min", "20")); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -272,6 +287,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); | |||
assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); | |||
assertThatRuleIsActivated(grandchildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
// SONAR-14559 | |||
@@ -299,6 +315,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
List<ActiveRuleDto> childActiveRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), RulesProfileDto.from(childProfile)); | |||
assertThatRuleIsUpdated(childActiveRules, rule, RulePriority.BLOCKER, INHERITED); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -327,6 +344,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
assertThatRuleHasParams(db, parentActiveRuleDto, tuple("min", "10")); | |||
assertThatRuleHasParams(db, childActiveRuleDto, tuple("min", "10")); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -345,6 +363,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile)); | |||
assertThat(changes).hasSize(2).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
// second run, without any input changes | |||
RuleActivator ruleActivatorWithoutDescendants = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession) { | |||
@@ -355,8 +374,10 @@ public class BuiltInQProfileUpdateImplTest { | |||
}; | |||
} | |||
}; | |||
changes = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivatorWithoutDescendants, activeRuleIndexer).update(db.getSession(), builtIn, RulesProfileDto.from(profile)); | |||
changes = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivatorWithoutDescendants, activeRuleIndexer, qualityProfileChangeEventService) | |||
.update(db.getSession(), builtIn, RulesProfileDto.from(profile)); | |||
assertThat(changes).isEmpty(); | |||
verifyNoMoreInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -376,6 +397,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule); | |||
List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile)); | |||
assertThat(changes).hasSize(3).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
// second run to deactivate the rule | |||
context = new BuiltInQualityProfilesDefinition.Context(); | |||
@@ -384,6 +406,7 @@ public class BuiltInQProfileUpdateImplTest { | |||
builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule); | |||
changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile)); | |||
assertThat(changes).hasSize(3).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.DEACTIVATED); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage())); | |||
assertThatRuleIsDeactivated(profile, rule); | |||
assertThatRuleIsDeactivated(childProfile, rule); |
@@ -50,6 +50,7 @@ import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.assertThrows; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED; | |||
import static org.sonar.server.qualityprofile.ActiveRuleInheritance.OVERRIDES; | |||
@@ -69,6 +70,7 @@ public class RuleActivatorTest { | |||
private final System2 system2 = new TestSystem2().setNow(NOW); | |||
private final TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private final RuleActivator underTest = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); | |||
@Test |
@@ -8,6 +8,7 @@ dependencies { | |||
compile 'javax.servlet:javax.servlet-api' | |||
compile project(':server:sonar-webserver-auth') | |||
compile project(':server:sonar-webserver-ws') | |||
compile project(':server:sonar-webserver-webapi') | |||
testCompile 'junit:junit' | |||
testCompile 'org.assertj:assertj-core' |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.pushapi; | |||
import java.io.IOException; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.concurrent.ScheduledExecutorService; | |||
import java.util.concurrent.ScheduledFuture; | |||
import java.util.concurrent.TimeUnit; | |||
@@ -34,6 +35,17 @@ public abstract class ServerPushClient { | |||
private static final Logger LOG = Loggers.get(ServerPushClient.class); | |||
private static final int DEFAULT_HEARTBEAT_PERIOD = 60; | |||
private static final byte[] CRLF = new byte[] {'\r', '\n'}; | |||
private static final byte[] DATA_END = new byte[] {'\n', '\n'}; | |||
private static final byte[] DATA_FIELD = "data: ".getBytes(StandardCharsets.UTF_8); | |||
protected final AsyncContext asyncContext; | |||
private final ScheduledExecutorService executorService; | |||
@@ -50,6 +62,11 @@ public abstract class ServerPushClient { | |||
startedHeartbeat = executorService.schedule(heartbeatTask, DEFAULT_HEARTBEAT_PERIOD, TimeUnit.SECONDS); | |||
} | |||
public void writeAndFlush(String payload) throws IOException { | |||
output().write(payload.getBytes(StandardCharsets.UTF_8)); | |||
flush(); | |||
} | |||
public void writeAndFlush(char character) { | |||
write(character); | |||
flush(); |
@@ -39,6 +39,14 @@ public class SonarLintClient extends ServerPushClient { | |||
this.languages = languages; | |||
} | |||
public Set<String> getLanguages() { | |||
return languages; | |||
} | |||
public Set<String> getClientProjectKeys() { | |||
return projectKeys; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { |
@@ -19,25 +19,46 @@ | |||
*/ | |||
package org.sonar.server.pushapi.sonarlint; | |||
import java.io.IOException; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.concurrent.CopyOnWriteArrayList; | |||
import java.util.function.Predicate; | |||
import javax.servlet.AsyncEvent; | |||
import javax.servlet.AsyncListener; | |||
import org.json.JSONArray; | |||
import org.json.JSONObject; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.util.ParamChange; | |||
import org.sonar.core.util.RuleActivationListener; | |||
import org.sonar.core.util.RuleChange; | |||
import org.sonar.core.util.RuleSetChangeEvent; | |||
import org.sonar.server.qualityprofile.RuleActivatorEventsDistributor; | |||
import static java.util.Arrays.asList; | |||
@ServerSide | |||
public class SonarLintClientsRegistry { | |||
public class SonarLintClientsRegistry implements RuleActivationListener { | |||
private static final Logger LOG = Loggers.get(SonarLintClientsRegistry.class); | |||
private final RuleActivatorEventsDistributor ruleActivatorEventsDistributor; | |||
public SonarLintClientsRegistry(RuleActivatorEventsDistributor ruleActivatorEventsDistributor) { | |||
this.ruleActivatorEventsDistributor = ruleActivatorEventsDistributor; | |||
} | |||
private final List<SonarLintClient> clients = new CopyOnWriteArrayList<>(); | |||
public void registerClient(SonarLintClient sonarLintClient) { | |||
clients.add(sonarLintClient); | |||
sonarLintClient.scheduleHeartbeat(); | |||
sonarLintClient.addListener(new SonarLintClientEventsListener(sonarLintClient)); | |||
ruleActivatorEventsDistributor.subscribe(this); | |||
LOG.debug("Registering new SonarLint client"); | |||
} | |||
@@ -50,6 +71,71 @@ public class SonarLintClientsRegistry { | |||
return clients.size(); | |||
} | |||
@Override | |||
public void listen(RuleSetChangeEvent ruleChangeEvent) { | |||
LOG.info("Generating a RuleSetChangeEvent"); | |||
// TODO filter on languages here as well | |||
broadcastMessage(ruleChangeEvent, f -> f.getClientProjectKeys().isEmpty() || !Collections.disjoint(f.getClientProjectKeys(), asList(ruleChangeEvent.getProjects()))); | |||
} | |||
public void broadcastMessage(RuleSetChangeEvent message, Predicate<SonarLintClient> filter) { | |||
String jsonString = getJSONString(message); | |||
clients.stream().filter(filter).forEach(c -> { | |||
try { | |||
c.writeAndFlush(jsonString); | |||
} catch (IOException e) { | |||
LOG.error("Unable to send message to a client: " + e.getMessage()); | |||
} | |||
}); | |||
} | |||
public String getJSONString(RuleSetChangeEvent ruleSetChangeEvent) { | |||
JSONObject result = new JSONObject(); | |||
result.put("event", ruleSetChangeEvent.getEvent()); | |||
JSONObject data = new JSONObject(); | |||
data.put("projects", ruleSetChangeEvent.getProjects()); | |||
JSONArray activatedRulesJson = new JSONArray(); | |||
for (RuleChange rule : ruleSetChangeEvent.getActivatedRules()) { | |||
activatedRulesJson.put(toJson(rule)); | |||
} | |||
data.put("activatedRules", activatedRulesJson); | |||
JSONArray deactivatedRulesJson = new JSONArray(); | |||
for (RuleChange rule : ruleSetChangeEvent.getDeactivatedRules()) { | |||
deactivatedRulesJson.put(toJson(rule)); | |||
} | |||
data.put("deactivatedRules", deactivatedRulesJson); | |||
result.put("data", data); | |||
return result.toString(); | |||
} | |||
private JSONObject toJson(RuleChange rule) { | |||
JSONObject ruleJson = new JSONObject(); | |||
ruleJson.put("key", rule.getKey()); | |||
ruleJson.put("language", rule.getLanguage()); | |||
ruleJson.put("severity", rule.getSeverity()); | |||
ruleJson.put("templateKey", rule.getTemplateKey()); | |||
JSONArray params = new JSONArray(); | |||
for (ParamChange paramChange : rule.getParams()) { | |||
params.put(toJson(paramChange)); | |||
} | |||
ruleJson.put("params", params); | |||
return ruleJson; | |||
} | |||
private JSONObject toJson(ParamChange paramChange) { | |||
JSONObject param = new JSONObject(); | |||
param.put("key", paramChange.getKey()); | |||
param.put("value", paramChange.getValue()); | |||
return param; | |||
} | |||
class SonarLintClientEventsListener implements AsyncListener { | |||
private final SonarLintClient client; | |||
@@ -84,7 +84,7 @@ public class SonarLintPushAction extends ServerPushAction { | |||
if (!isServerSideEventsRequest(servletRequest)) { | |||
servletResponse.stream().setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE); | |||
return; | |||
return; // TODO fixme this is not closing the connexion properly | |||
} | |||
setHeadersForResponse(servletResponse); | |||
@@ -92,7 +92,7 @@ public class SonarLintPushAction extends ServerPushAction { | |||
AsyncContext asyncContext = servletRequest.startAsync(); | |||
asyncContext.setTimeout(0); | |||
var sonarLintClient = new SonarLintClient(asyncContext, params.getProjectKeys(), params.getLanguages()); | |||
SonarLintClient sonarLintClient = new SonarLintClient(asyncContext, params.getProjectKeys(), params.getLanguages()); | |||
clientsRegistry.registerClient(sonarLintClient); | |||
} |
@@ -23,6 +23,7 @@ import java.util.Set; | |||
import javax.servlet.AsyncContext; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.server.qualityprofile.StandaloneRuleActivatorEventsDistributor; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -39,7 +40,7 @@ public class SonarLintClientsRegistryTest { | |||
@Before | |||
public void before() { | |||
underTest = new SonarLintClientsRegistry(); | |||
underTest = new SonarLintClientsRegistry(mock(StandaloneRuleActivatorEventsDistributor.class)); | |||
} | |||
@Test |
@@ -41,11 +41,13 @@ public class QProfileResetImpl implements QProfileReset { | |||
private final DbClient db; | |||
private final RuleActivator activator; | |||
private final ActiveRuleIndexer activeRuleIndexer; | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService; | |||
public QProfileResetImpl(DbClient db, RuleActivator activator, ActiveRuleIndexer activeRuleIndexer) { | |||
public QProfileResetImpl(DbClient db, RuleActivator activator, ActiveRuleIndexer activeRuleIndexer, QualityProfileChangeEventService qualityProfileChangeEventService) { | |||
this.db = db; | |||
this.activator = activator; | |||
this.activeRuleIndexer = activeRuleIndexer; | |||
this.qualityProfileChangeEventService = qualityProfileChangeEventService; | |||
} | |||
@Override | |||
@@ -87,6 +89,7 @@ public class QProfileResetImpl implements QProfileReset { | |||
// ignore, probably a rule inherited from parent that can't be deactivated | |||
} | |||
} | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), changes, profile.getLanguage()); | |||
activeRuleIndexer.commitAndIndex(dbSession, changes); | |||
return result; | |||
} |
@@ -44,12 +44,15 @@ public class QProfileRulesImpl implements QProfileRules { | |||
private final RuleActivator ruleActivator; | |||
private final RuleIndex ruleIndex; | |||
private final ActiveRuleIndexer activeRuleIndexer; | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService; | |||
public QProfileRulesImpl(DbClient db, RuleActivator ruleActivator, RuleIndex ruleIndex, ActiveRuleIndexer activeRuleIndexer) { | |||
public QProfileRulesImpl(DbClient db, RuleActivator ruleActivator, RuleIndex ruleIndex, ActiveRuleIndexer activeRuleIndexer, | |||
QualityProfileChangeEventService qualityProfileChangeEventService) { | |||
this.db = db; | |||
this.ruleActivator = ruleActivator; | |||
this.ruleIndex = ruleIndex; | |||
this.activeRuleIndexer = activeRuleIndexer; | |||
this.qualityProfileChangeEventService = qualityProfileChangeEventService; | |||
} | |||
@Override | |||
@@ -63,6 +66,7 @@ public class QProfileRulesImpl implements QProfileRules { | |||
for (RuleActivation activation : activations) { | |||
changes.addAll(ruleActivator.activate(dbSession, activation, context)); | |||
} | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), changes, profile.getLanguage()); | |||
activeRuleIndexer.commitAndIndex(dbSession, changes); | |||
return changes; | |||
} | |||
@@ -70,10 +74,12 @@ public class QProfileRulesImpl implements QProfileRules { | |||
@Override | |||
public BulkChangeResult bulkActivateAndCommit(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery, @Nullable String severity) { | |||
verifyNotBuiltIn(profile); | |||
return doBulk(dbSession, profile, ruleQuery, (context, ruleDefinition) -> { | |||
BulkChangeResult bulkChangeResult = doBulk(dbSession, profile, ruleQuery, (context, ruleDefinition) -> { | |||
RuleActivation activation = RuleActivation.create(ruleDefinition.getUuid(), severity, null); | |||
return ruleActivator.activate(dbSession, activation, context); | |||
}); | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), bulkChangeResult.getChanges(), profile.getLanguage()); | |||
return bulkChangeResult; | |||
} | |||
@Override | |||
@@ -85,6 +91,9 @@ public class QProfileRulesImpl implements QProfileRules { | |||
for (String ruleUuid : ruleUuids) { | |||
changes.addAll(ruleActivator.deactivate(dbSession, context, ruleUuid, false)); | |||
} | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), changes, profile.getLanguage()); | |||
activeRuleIndexer.commitAndIndex(dbSession, changes); | |||
return changes; | |||
} | |||
@@ -92,7 +101,12 @@ public class QProfileRulesImpl implements QProfileRules { | |||
@Override | |||
public BulkChangeResult bulkDeactivateAndCommit(DbSession dbSession, QProfileDto profile, RuleQuery ruleQuery) { | |||
verifyNotBuiltIn(profile); | |||
return doBulk(dbSession, profile, ruleQuery, (context, ruleDefinition) -> ruleActivator.deactivate(dbSession, context, ruleDefinition.getUuid(), false)); | |||
BulkChangeResult bulkChangeResult = doBulk(dbSession, profile, ruleQuery, (context, ruleDefinition) -> | |||
ruleActivator.deactivate(dbSession, context, ruleDefinition.getUuid(), false)); | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), bulkChangeResult.getChanges(), profile.getLanguage()); | |||
return bulkChangeResult; | |||
} | |||
@Override |
@@ -41,12 +41,14 @@ public class QProfileTreeImpl implements QProfileTree { | |||
private final RuleActivator ruleActivator; | |||
private final System2 system2; | |||
private final ActiveRuleIndexer activeRuleIndexer; | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService; | |||
public QProfileTreeImpl(DbClient db, RuleActivator ruleActivator, System2 system2, ActiveRuleIndexer activeRuleIndexer) { | |||
public QProfileTreeImpl(DbClient db, RuleActivator ruleActivator, System2 system2, ActiveRuleIndexer activeRuleIndexer, QualityProfileChangeEventService qualityProfileChangeEventService) { | |||
this.db = db; | |||
this.ruleActivator = ruleActivator; | |||
this.system2 = system2; | |||
this.activeRuleIndexer = activeRuleIndexer; | |||
this.qualityProfileChangeEventService = qualityProfileChangeEventService; | |||
} | |||
@Override | |||
@@ -92,6 +94,7 @@ public class QProfileTreeImpl implements QProfileTree { | |||
// TODO return errors | |||
} | |||
} | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), changes, profile.getLanguage()); | |||
return changes; | |||
} | |||
@@ -120,6 +123,8 @@ public class QProfileTreeImpl implements QProfileTree { | |||
changes.add(new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRule, context.getRule().get()).setInheritance(null)); | |||
} | |||
} | |||
qualityProfileChangeEventService.distributeRuleChangeEvent(List.of(profile), changes, profile.getLanguage()); | |||
return changes; | |||
} | |||
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile.ws; | |||
import java.util.Optional; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
@@ -30,8 +31,11 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.user.UserSession; | |||
import static java.util.Optional.empty; | |||
import static java.util.Optional.of; | |||
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT; | |||
@@ -44,13 +48,16 @@ public class AddProjectAction implements QProfileWsAction { | |||
private final Languages languages; | |||
private final ComponentFinder componentFinder; | |||
private final QProfileWsSupport wsSupport; | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService; | |||
public AddProjectAction(DbClient dbClient, UserSession userSession, Languages languages, ComponentFinder componentFinder, QProfileWsSupport wsSupport) { | |||
public AddProjectAction(DbClient dbClient, UserSession userSession, Languages languages, ComponentFinder componentFinder, | |||
QProfileWsSupport wsSupport, QualityProfileChangeEventService qualityProfileChangeEventService) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.languages = languages; | |||
this.componentFinder = componentFinder; | |||
this.wsSupport = wsSupport; | |||
this.qualityProfileChangeEventService = qualityProfileChangeEventService; | |||
} | |||
@Override | |||
@@ -80,24 +87,36 @@ public class AddProjectAction implements QProfileWsAction { | |||
userSession.checkLoggedIn(); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ProjectDto project = loadProject(dbSession, request); | |||
QProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromName(request)); | |||
checkPermissions(dbSession, profile, project); | |||
QProfileDto currentProfile = dbClient.qualityProfileDao().selectAssociatedToProjectAndLanguage(dbSession, project, profile.getLanguage()); | |||
Optional<QProfileDto> deactivatedProfile = empty(); | |||
if (currentProfile == null) { | |||
QProfileDto defaultProfile = dbClient.qualityProfileDao().selectDefaultProfile(dbSession, profile.getLanguage()); | |||
if (defaultProfile != null) { | |||
deactivatedProfile = of(defaultProfile); | |||
} | |||
// project uses the default profile | |||
dbClient.qualityProfileDao().insertProjectProfileAssociation(dbSession, project, profile); | |||
dbSession.commit(); | |||
} else if (!profile.getKee().equals(currentProfile.getKee())) { | |||
deactivatedProfile = of(currentProfile); | |||
dbClient.qualityProfileDao().updateProjectProfileAssociation(dbSession, project, profile.getKee(), currentProfile.getKee()); | |||
dbSession.commit(); | |||
} | |||
Optional<QProfileDto> activatedProfile = of(profile); | |||
qualityProfileChangeEventService.publishRuleActivationToSonarLintClients(project, activatedProfile, deactivatedProfile); | |||
} | |||
response.noContent(); | |||
} | |||
private ProjectDto loadProject(DbSession dbSession, Request request) { | |||
String projectKey = request.mandatoryParam(PARAM_PROJECT); | |||
return componentFinder.getProjectByKey(dbSession, projectKey); |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile.ws; | |||
import java.util.Optional; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
@@ -30,8 +31,11 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.user.UserSession; | |||
import static java.util.Optional.empty; | |||
import static java.util.Optional.of; | |||
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT; | |||
@@ -44,13 +48,16 @@ public class RemoveProjectAction implements QProfileWsAction { | |||
private final Languages languages; | |||
private final ComponentFinder componentFinder; | |||
private final QProfileWsSupport wsSupport; | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService; | |||
public RemoveProjectAction(DbClient dbClient, UserSession userSession, Languages languages, ComponentFinder componentFinder, QProfileWsSupport wsSupport) { | |||
public RemoveProjectAction(DbClient dbClient, UserSession userSession, Languages languages, ComponentFinder componentFinder, | |||
QProfileWsSupport wsSupport, QualityProfileChangeEventService qualityProfileChangeEventService) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.languages = languages; | |||
this.componentFinder = componentFinder; | |||
this.wsSupport = wsSupport; | |||
this.qualityProfileChangeEventService = qualityProfileChangeEventService; | |||
} | |||
@Override | |||
@@ -86,6 +93,17 @@ public class RemoveProjectAction implements QProfileWsAction { | |||
dbClient.qualityProfileDao().deleteProjectProfileAssociation(dbSession, project, profile); | |||
dbSession.commit(); | |||
Optional<QProfileDto> deactivatedProfile = of(profile); | |||
Optional<QProfileDto> activatedProfile = empty(); | |||
// publish change for rules in the default quality profile | |||
QProfileDto defaultProfile = dbClient.qualityProfileDao().selectDefaultProfile(dbSession, profile.getLanguage()); | |||
if (defaultProfile != null) { | |||
activatedProfile = of(defaultProfile); | |||
} | |||
qualityProfileChangeEventService.publishRuleActivationToSonarLintClients(project, activatedProfile, deactivatedProfile); | |||
response.noContent(); | |||
} | |||
} |
@@ -49,6 +49,7 @@ import org.sonar.server.util.TypeValidations; | |||
import static java.util.Collections.singleton; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
public class QProfileComparisonTest { | |||
@@ -74,8 +75,9 @@ public class QProfileComparisonTest { | |||
dbSession = db.openSession(false); | |||
RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE); | |||
ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db, es.client()); | |||
QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db, new TypeValidations(singletonList(new IntegerTypeValidation())), userSession); | |||
qProfileRules = new QProfileRulesImpl(db, ruleActivator, ruleIndex, activeRuleIndexer); | |||
qProfileRules = new QProfileRulesImpl(db, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService); | |||
comparison = new QProfileComparison(db); | |||
xooRule1 = RuleTesting.newXooX1().setSeverity("MINOR").getDefinition(); |
@@ -41,7 +41,12 @@ import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoInteractions; | |||
import static org.mockito.internal.verification.VerificationModeFactory.times; | |||
import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; | |||
public class QProfileResetImplTest { | |||
@@ -55,11 +60,12 @@ public class QProfileResetImplTest { | |||
private System2 system2 = new AlwaysIncreasingSystem2(); | |||
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); | |||
private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); | |||
private QProfileTree qProfileTree = new QProfileTreeImpl(db.getDbClient(), ruleActivator, system2, activeRuleIndexer); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer); | |||
private QProfileResetImpl underTest = new QProfileResetImpl(db.getDbClient(), ruleActivator, activeRuleIndexer); | |||
private QProfileTree qProfileTree = new QProfileTreeImpl(db.getDbClient(), ruleActivator, system2, activeRuleIndexer, mock(QualityProfileChangeEventService.class)); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer, qualityProfileChangeEventService); | |||
private QProfileResetImpl underTest = new QProfileResetImpl(db.getDbClient(), ruleActivator, activeRuleIndexer, mock(QualityProfileChangeEventService.class)); | |||
@Test | |||
public void reset() { | |||
@@ -77,6 +83,7 @@ public class QProfileResetImplTest { | |||
assertThat(result.getChanges()) | |||
.extracting(ActiveRuleChange::getKey, ActiveRuleChange::getType) | |||
.containsExactlyInAnyOrder(tuple(ActiveRuleKey.of(profile, newRule.getKey()), ACTIVATED)); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -94,6 +101,7 @@ public class QProfileResetImplTest { | |||
assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), childProfile)) | |||
.extracting(OrgActiveRuleDto::getRuleKey) | |||
.containsExactlyInAnyOrder(newRule.getKey(), existingRule.getKey()); | |||
verify(qualityProfileChangeEventService, times(2)).distributeRuleChangeEvent(any(), any(), eq(childProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -106,6 +114,7 @@ public class QProfileResetImplTest { | |||
}) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage(String.format("Operation forbidden for built-in Quality Profile '%s'", profile.getKee())); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -118,5 +127,7 @@ public class QProfileResetImplTest { | |||
}) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("Quality profile must be persisted"); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
} |
@@ -61,6 +61,11 @@ import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.junit.Assert.fail; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoInteractions; | |||
import static org.sonar.api.rule.Severity.BLOCKER; | |||
import static org.sonar.api.rule.Severity.CRITICAL; | |||
import static org.sonar.api.rule.Severity.MAJOR; | |||
@@ -81,9 +86,10 @@ public class QProfileRuleImplTest { | |||
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); | |||
private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); | |||
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); | |||
private QProfileRules underTest = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer); | |||
private QProfileRules underTest = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService); | |||
@Test | |||
public void system_activates_rule_without_parameters() { | |||
@@ -94,6 +100,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap()); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -106,6 +113,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap()); | |||
assertThatProfileIsUpdatedByUser(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -119,6 +127,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10")); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -132,6 +141,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "15")); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -144,6 +154,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
/** | |||
@@ -160,6 +171,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10")); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
/** | |||
@@ -179,6 +191,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, | |||
of(paramWithoutDefault.getName(), "-10", paramWithDefault.getName(), paramWithDefault.getDefaultValue())); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -192,6 +205,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -202,14 +216,16 @@ public class QProfileRuleImplTest { | |||
// initial activation | |||
RuleActivation activation = RuleActivation.create(rule.getUuid(), MAJOR, null); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// update | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "20")); | |||
List<ActiveRuleChange> changes = activate(profile, updateActivation); | |||
changes = activate(profile, updateActivation); | |||
assertThatRuleIsUpdated(profile, rule, CRITICAL, null, of(param.getName(), "20")); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -221,14 +237,16 @@ public class QProfileRuleImplTest { | |||
// initial activation -> param "max" has a default value | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
// update param "min", which has no default value | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(paramWithoutDefault.getName(), "3")); | |||
List<ActiveRuleChange> changes = activate(profile, updateActivation); | |||
changes = activate(profile, updateActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
assertThatRuleIsUpdated(profile, rule, MAJOR, null, of(paramWithDefault.getName(), "10", paramWithoutDefault.getName(), "3")); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -239,14 +257,16 @@ public class QProfileRuleImplTest { | |||
// initial activation -> param "max" has a default value | |||
RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithDefault.getName(), "20")); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// reset to default_value | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(paramWithDefault.getName(), "")); | |||
List<ActiveRuleChange> changes = activate(profile, updateActivation); | |||
changes = activate(profile, updateActivation); | |||
assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), "10")); | |||
assertThat(changes).hasSize(1); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -258,14 +278,16 @@ public class QProfileRuleImplTest { | |||
// initial activation -> param "max" has a default value | |||
RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), "20")); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// remove parameter | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), "")); | |||
List<ActiveRuleChange> changes = activate(profile, updateActivation); | |||
changes = activate(profile, updateActivation); | |||
assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), paramWithDefault.getDefaultValue())); | |||
assertThat(changes).hasSize(1); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -279,6 +301,7 @@ public class QProfileRuleImplTest { | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
db.getDbClient().activeRuleDao().deleteParametersByRuleProfileUuids(db.getSession(), asList(profile.getRulesProfileUuid())); | |||
assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// contrary to activerule, the param is supposed to be inserted but not updated | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(param.getName(), "")); | |||
@@ -286,6 +309,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); | |||
assertThat(changes).hasSize(1); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -295,13 +319,15 @@ public class QProfileRuleImplTest { | |||
// initial activation | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// update with exactly the same severity and params | |||
activation = RuleActivation.create(rule.getUuid()); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
changes = activate(profile, activation); | |||
assertThat(changes).isEmpty(); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -312,13 +338,16 @@ public class QProfileRuleImplTest { | |||
// initial activation -> param "max" has a default value | |||
RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, of(param.getName(), "20")); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// update without any severity or params => keep | |||
RuleActivation update = RuleActivation.create(rule.getUuid()); | |||
List<ActiveRuleChange> changes = activate(profile, update); | |||
changes = activate(profile, update); | |||
assertThat(changes).isEmpty(); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -328,6 +357,7 @@ public class QProfileRuleImplTest { | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
expectFailure("java rule " + rule.getKey() + " cannot be activated on js profile " + profile.getKee(), () -> activate(profile, activation)); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -337,6 +367,7 @@ public class QProfileRuleImplTest { | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
expectFailure("Rule was removed: " + rule.getKey(), () -> activate(profile, activation)); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -346,6 +377,7 @@ public class QProfileRuleImplTest { | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
expectFailure("Rule template can't be activated on a Quality profile: " + rule.getKey(), () -> activate(profile, activation)); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -356,6 +388,7 @@ public class QProfileRuleImplTest { | |||
RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(param.getName(), "foo")); | |||
expectFailure("Value 'foo' must be an integer.", () -> activate(profile, activation)); | |||
verifyNoInteractions(qualityProfileChangeEventService); | |||
} | |||
@Test | |||
@@ -368,13 +401,15 @@ public class QProfileRuleImplTest { | |||
// initial activation | |||
RuleActivation activation = RuleActivation.create(customRule.getUuid(), MAJOR, emptyMap()); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
assertThatRuleIsActivated(profile, customRule, null, MAJOR, null, of("format", "txt")); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
// update -> parameter is not changed | |||
RuleActivation updateActivation = RuleActivation.create(customRule.getUuid(), BLOCKER, of("format", "xml")); | |||
activate(profile, updateActivation); | |||
changes = activate(profile, updateActivation); | |||
assertThatRuleIsActivated(profile, customRule, null, BLOCKER, null, of("format", "txt")); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -383,13 +418,15 @@ public class QProfileRuleImplTest { | |||
RuleDefinitionDto rule = createRule(); | |||
QProfileDto profile = createProfile(rule); | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
List<ActiveRuleChange> changes = deactivate(profile, rule); | |||
changes = deactivate(profile, rule); | |||
verifyNoActiveRules(); | |||
assertThatProfileIsUpdatedByUser(profile); | |||
assertThat(changes).hasSize(1); | |||
assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -397,12 +434,14 @@ public class QProfileRuleImplTest { | |||
RuleDefinitionDto rule = createRule(); | |||
QProfileDto profile = createProfile(rule); | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
List<ActiveRuleChange> changes = deactivate(profile, rule); | |||
changes = deactivate(profile, rule); | |||
verifyNoActiveRules(); | |||
assertThatProfileIsUpdatedBySystem(profile); | |||
assertThatChangeIsDeactivation(changes, rule); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
private void assertThatChangeIsDeactivation(List<ActiveRuleChange> changes, RuleDefinitionDto rule) { | |||
@@ -420,6 +459,7 @@ public class QProfileRuleImplTest { | |||
List<ActiveRuleChange> changes = deactivate(profile, rule); | |||
verifyNoActiveRules(); | |||
assertThat(changes).isEmpty(); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -427,14 +467,16 @@ public class QProfileRuleImplTest { | |||
RuleDefinitionDto rule = createRule(); | |||
QProfileDto profile = createProfile(rule); | |||
RuleActivation activation = RuleActivation.create(rule.getUuid()); | |||
activate(profile, activation); | |||
List<ActiveRuleChange> changes = activate(profile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
rule.setStatus(RuleStatus.REMOVED); | |||
db.getDbClient().ruleDao().update(db.getSession(), rule); | |||
List<ActiveRuleChange> changes = deactivate(profile, rule); | |||
changes = deactivate(profile, rule); | |||
verifyNoActiveRules(); | |||
assertThatChangeIsDeactivation(changes, rule); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage())); | |||
} | |||
@Test | |||
@@ -448,6 +490,7 @@ public class QProfileRuleImplTest { | |||
assertThatProfileHasNoActiveRules(parentProfile); | |||
assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); | |||
assertThatRuleIsActivated(grandChildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(childProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -460,17 +503,20 @@ public class QProfileRuleImplTest { | |||
System.out.println("ACTIVATE ON " + childProfile.getName()); | |||
RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
activate(childProfile, initialActivation); | |||
List<ActiveRuleChange> changes = activate(childProfile, initialActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
System.out.println("---------------"); | |||
System.out.println("ACTIVATE ON " + childProfile.getName()); | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar")); | |||
List<ActiveRuleChange> changes = activate(childProfile, updateActivation); | |||
changes = activate(childProfile, updateActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
assertThatProfileHasNoActiveRules(parentProfile); | |||
assertThatRuleIsUpdated(childProfile, rule, CRITICAL, null, of(param.getName(), "bar")); | |||
assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, INHERITED, of(param.getName(), "bar")); | |||
assertThat(changes).hasSize(2); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -482,15 +528,17 @@ public class QProfileRuleImplTest { | |||
QProfileDto grandChildProfile = createChildProfile(childProfile); | |||
RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
activate(childProfile, initialActivation); | |||
List<ActiveRuleChange> changes = activate(childProfile, initialActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar")); | |||
List<ActiveRuleChange> changes = activate(grandChildProfile, overrideActivation); | |||
changes = activate(grandChildProfile, overrideActivation); | |||
assertThatProfileHasNoActiveRules(parentProfile); | |||
assertThatRuleIsUpdated(childProfile, rule, MAJOR, null, of(param.getName(), "foo")); | |||
assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar")); | |||
assertThat(changes).hasSize(1); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -502,19 +550,22 @@ public class QProfileRuleImplTest { | |||
QProfileDto grandChildProfile = createChildProfile(childProfile); | |||
RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
activate(childProfile, initialActivation); | |||
List<ActiveRuleChange> changes = activate(childProfile, initialActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar")); | |||
activate(grandChildProfile, overrideActivation); | |||
changes = activate(grandChildProfile, overrideActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(grandChildProfile.getLanguage())); | |||
// update child --> do not touch grandChild | |||
RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), BLOCKER, of(param.getName(), "baz")); | |||
List<ActiveRuleChange> changes = activate(childProfile, updateActivation); | |||
changes = activate(childProfile, updateActivation); | |||
assertThatProfileHasNoActiveRules(parentProfile); | |||
assertThatRuleIsUpdated(childProfile, rule, BLOCKER, null, of(param.getName(), "baz")); | |||
assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar")); | |||
assertThat(changes).hasSize(1); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -526,19 +577,22 @@ public class QProfileRuleImplTest { | |||
QProfileDto grandChildProfile = createChildProfile(childProfile); | |||
RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
activate(parentProfile, initialActivation); | |||
List<ActiveRuleChange> changes = activate(parentProfile, initialActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar")); | |||
activate(grandChildProfile, overrideActivation); | |||
changes = activate(grandChildProfile, overrideActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(grandChildProfile.getLanguage())); | |||
// reset parent --> touch child but not grandChild | |||
RuleActivation updateActivation = RuleActivation.createReset(rule.getUuid()); | |||
List<ActiveRuleChange> changes = activate(parentProfile, updateActivation); | |||
changes = activate(parentProfile, updateActivation); | |||
assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); | |||
assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, of(param.getName(), param.getDefaultValue())); | |||
assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar")); | |||
assertThat(changes).hasSize(2); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -549,14 +603,16 @@ public class QProfileRuleImplTest { | |||
QProfileDto childProfile = createChildProfile(parentProfile); | |||
RuleActivation childActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
activate(childProfile, childActivation); | |||
List<ActiveRuleChange> changes = activate(childProfile, childActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar")); | |||
List<ActiveRuleChange> changes = activate(parentProfile, parentActivation); | |||
changes = activate(parentProfile, parentActivation); | |||
assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, of(param.getName(), "bar")); | |||
assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "foo")); | |||
assertThat(changes).hasSize(2); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -567,13 +623,15 @@ public class QProfileRuleImplTest { | |||
QProfileDto childProfile = createChildProfile(parentProfile); | |||
RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
activate(parentProfile, parentActivation); | |||
List<ActiveRuleChange> changes = activate(parentProfile, parentActivation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo")); | |||
List<ActiveRuleChange> changes = activate(childProfile, overrideActivation); | |||
changes = activate(childProfile, overrideActivation); | |||
assertThatRuleIsUpdated(childProfile, rule, MAJOR, INHERITED, of(param.getName(), "foo")); | |||
assertThat(changes).isEmpty(); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -586,11 +644,13 @@ public class QProfileRuleImplTest { | |||
List<ActiveRuleChange> changes = activate(parentProfile, activation); | |||
assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); | |||
assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
changes = deactivate(parentProfile, rule); | |||
assertThatProfileHasNoActiveRules(parentProfile); | |||
assertThatProfileHasNoActiveRules(childProfile); | |||
assertThat(changes).hasSize(2); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -603,14 +663,17 @@ public class QProfileRuleImplTest { | |||
List<ActiveRuleChange> changes = activate(parentProfile, activation); | |||
assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); | |||
assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap()); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
activation = RuleActivation.create(rule.getUuid(), CRITICAL, null); | |||
activate(childProfile, activation); | |||
changes = activate(childProfile, activation); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage())); | |||
changes = deactivate(parentProfile, rule); | |||
assertThatProfileHasNoActiveRules(parentProfile); | |||
assertThatProfileHasNoActiveRules(childProfile); | |||
assertThat(changes).hasSize(2); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -627,6 +690,7 @@ public class QProfileRuleImplTest { | |||
assertThatThrownBy(() -> deactivate(childProfile, rule)) | |||
.isInstanceOf(BadRequestException.class) | |||
.hasMessageContaining("Cannot deactivate inherited rule"); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(parentProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -651,6 +715,7 @@ public class QProfileRuleImplTest { | |||
assertThatRuleIsUpdated(childProfile, rule, CRITICAL, INHERITED, emptyMap()); | |||
assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, emptyMap()); | |||
assertThat(changes).hasSize(1); | |||
} | |||
@Test |
@@ -43,6 +43,10 @@ import static java.util.Collections.singleton; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
public class QProfileRulesImplTest { | |||
@@ -55,9 +59,11 @@ public class QProfileRulesImplTest { | |||
private RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE); | |||
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); | |||
private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), new TypeValidations(singletonList(new IntegerTypeValidation())), userSession); | |||
private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), new TypeValidations(singletonList(new IntegerTypeValidation())), | |||
userSession); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService); | |||
@Test | |||
public void activate_one_rule() { | |||
@@ -70,6 +76,7 @@ public class QProfileRulesImplTest { | |||
assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), qProfile)) | |||
.extracting(ActiveRuleDto::getRuleKey, ActiveRuleDto::getSeverityString) | |||
.containsExactlyInAnyOrder(tuple(rule.getKey(), Severity.CRITICAL)); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(qProfile.getLanguage())); | |||
} | |||
@Test | |||
@@ -85,5 +92,6 @@ public class QProfileRulesImplTest { | |||
assertThat(db.getDbClient().qProfileChangeDao().selectByQuery(db.getSession(), new QProfileChangeQuery(qProfile.getKee()))) | |||
.extracting(QProfileChangeDto::getUserUuid, QProfileChangeDto::getDataAsMap) | |||
.containsExactlyInAnyOrder(tuple(user.getUuid(), ImmutableMap.of("ruleUuid", rule.getUuid(), "severity", Severity.CRITICAL))); | |||
verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(qProfile.getLanguage())); | |||
} | |||
} |
@@ -47,6 +47,12 @@ import static java.util.Collections.emptyMap; | |||
import static java.util.Collections.singleton; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.anyList; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.times; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.api.rule.Severity.BLOCKER; | |||
import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED; | |||
@@ -61,9 +67,10 @@ public class QProfileTreeImplTest { | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); | |||
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer); | |||
private QProfileTree underTest = new QProfileTreeImpl(db.getDbClient(), ruleActivator, System2.INSTANCE, activeRuleIndexer); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer, qualityProfileChangeEventService); | |||
private QProfileTree underTest = new QProfileTreeImpl(db.getDbClient(), ruleActivator, System2.INSTANCE, activeRuleIndexer, mock(QualityProfileChangeEventService.class)); | |||
@Test | |||
public void set_itself_as_parent_fails() { | |||
@@ -133,11 +140,13 @@ public class QProfileTreeImplTest { | |||
assertThat(changes).hasSize(1); | |||
assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), INHERITED, emptyMap()); | |||
assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); | |||
verify(qualityProfileChangeEventService, times(2)).distributeRuleChangeEvent(any(), any(), eq(profile2.getLanguage())); | |||
changes = underTest.removeParentAndCommit(db.getSession(), profile2); | |||
assertThat(changes).hasSize(1); | |||
assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); | |||
assertThatRuleIsNotPresent(profile2, rule1); | |||
verify(qualityProfileChangeEventService, times(2)).distributeRuleChangeEvent(any(), any(), eq(profile2.getLanguage())); | |||
} | |||
@Test | |||
@@ -156,6 +165,7 @@ public class QProfileTreeImplTest { | |||
assertThat(changes).hasSize(1); | |||
assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), INHERITED, emptyMap()); | |||
assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); | |||
verify(qualityProfileChangeEventService, times(2)).distributeRuleChangeEvent(any(), any(), eq(profile2.getLanguage())); | |||
RuleActivation activation = RuleActivation.create(rule1.getUuid(), BLOCKER, null); | |||
changes = activate(profile2, activation); | |||
@@ -168,6 +178,7 @@ public class QProfileTreeImplTest { | |||
// Not testing changes here since severity is not set in changelog | |||
assertThatRuleIsActivated(profile2, rule1, null, BLOCKER, null, emptyMap()); | |||
assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); | |||
verify(qualityProfileChangeEventService, times(3)).distributeRuleChangeEvent(anyList(), any(), eq(profile2.getLanguage())); | |||
} | |||
@Test | |||
@@ -183,6 +194,7 @@ public class QProfileTreeImplTest { | |||
QProfileDto childProfile = createProfile(rule1); | |||
List<ActiveRuleChange> changes = underTest.setParentAndCommit(db.getSession(), childProfile, parentProfile); | |||
verify(qualityProfileChangeEventService, times(2)).distributeRuleChangeEvent(any(), any(), eq(childProfile.getLanguage())); | |||
assertThatRuleIsNotPresent(childProfile, rule1); | |||
assertThatRuleIsActivated(childProfile, rule2, changes, rule2.getSeverityString(), INHERITED, emptyMap()); |
@@ -90,12 +90,13 @@ public class RegisterQualityProfilesNotificationTest { | |||
private DbClient dbClient = db.getDbClient(); | |||
private TypeValidations typeValidations = mock(TypeValidations.class); | |||
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private ServerRuleFinder ruleFinder = new DefaultRuleFinder(dbClient); | |||
private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, ruleFinder, system2, UuidFactoryFast.getInstance(), | |||
typeValidations, activeRuleIndexer); | |||
private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, typeValidations, userSessionRule); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, mock(RuleIndex.class), activeRuleIndexer); | |||
private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, mock(RuleIndex.class), activeRuleIndexer, qualityProfileChangeEventService); | |||
private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer, qualityProfileChangeEventService); | |||
private BuiltInQualityProfilesUpdateListener builtInQualityProfilesNotification = mock(BuiltInQualityProfilesUpdateListener.class); | |||
private RegisterQualityProfiles underTest = new RegisterQualityProfiles(builtInQProfileRepositoryRule, dbClient, | |||
builtInQProfileInsert, builtInQProfileUpdate, builtInQualityProfilesNotification, system2); |
@@ -36,14 +36,19 @@ import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.language.LanguageTesting; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static java.lang.String.format; | |||
import static java.util.Optional.empty; | |||
import static java.util.Optional.of; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES; | |||
public class AddProjectActionTest { | |||
@@ -59,7 +64,8 @@ public class AddProjectActionTest { | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final Languages languages = LanguageTesting.newLanguages(LANGUAGE_1, LANGUAGE_2); | |||
private final QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession); | |||
private final AddProjectAction underTest = new AddProjectAction(dbClient, userSession, languages, TestComponentFinder.from(db), wsSupport); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private final AddProjectAction underTest = new AddProjectAction(dbClient, userSession, languages, TestComponentFinder.from(db), wsSupport, qualityProfileChangeEventService); | |||
private final WsActionTester tester = new WsActionTester(underTest); | |||
@Test | |||
@@ -88,6 +94,7 @@ public class AddProjectActionTest { | |||
assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); | |||
assertProjectIsAssociatedToProfile(project, profile); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, of(profile), empty()); | |||
} | |||
@Test | |||
@@ -101,6 +108,7 @@ public class AddProjectActionTest { | |||
call(project, qualityProfile); | |||
assertProjectIsAssociatedToProfile(project, qualityProfile); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, of(qualityProfile), empty()); | |||
} | |||
@Test | |||
@@ -117,6 +125,7 @@ public class AddProjectActionTest { | |||
assertProjectIsNotAssociatedToProfile(project, profile1); | |||
assertProjectIsAssociatedToProfile(project, profile2); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, of(profile2), of(profile1)); | |||
} | |||
@Test | |||
@@ -132,6 +141,7 @@ public class AddProjectActionTest { | |||
assertProjectIsAssociatedToProfile(project, profile3Language1); | |||
assertProjectIsAssociatedToProfile(project, profile2Language2); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, of(profile3Language1), of(profile1Language1)); | |||
} | |||
@Test | |||
@@ -143,6 +153,7 @@ public class AddProjectActionTest { | |||
call(project, profile); | |||
assertProjectIsAssociatedToProfile(project, profile); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, of(profile), empty()); | |||
} | |||
@Test |
@@ -49,6 +49,7 @@ import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.language.LanguageTesting; | |||
import org.sonar.server.qualityprofile.QProfileTreeImpl; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
@@ -64,6 +65,7 @@ import static java.util.Arrays.asList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES; | |||
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; | |||
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE; | |||
@@ -98,7 +100,7 @@ public class ChangeParentActionTest { | |||
activeRuleIndexer = new ActiveRuleIndexer(dbClient, esClient); | |||
TypeValidations typeValidations = new TypeValidations(Collections.emptyList()); | |||
RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSession); | |||
qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer); | |||
qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer, mock(QualityProfileChangeEventService.class)); | |||
ChangeParentAction underTest = new ChangeParentAction( | |||
dbClient, | |||
qProfileTree, |
@@ -46,6 +46,7 @@ import org.sonar.server.qualityprofile.QProfileExporters; | |||
import org.sonar.server.qualityprofile.QProfileFactoryImpl; | |||
import org.sonar.server.qualityprofile.QProfileRules; | |||
import org.sonar.server.qualityprofile.QProfileRulesImpl; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
@@ -62,6 +63,7 @@ import org.sonarqube.ws.Qualityprofiles.CreateWsResponse.QualityProfile; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES; | |||
import static org.sonar.db.permission.GlobalPermission.SCAN; | |||
import static org.sonar.server.language.LanguageTesting.newLanguages; | |||
@@ -87,8 +89,9 @@ public class CreateActionTest { | |||
private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), dbClient); | |||
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client()); | |||
private ProfileImporter[] profileImporters = createImporters(); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, null, userSession); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService); | |||
private QProfileExporters qProfileExporters = new QProfileExporters(dbClient, null, qProfileRules, profileImporters); | |||
private CreateAction underTest = new CreateAction(dbClient, new QProfileFactoryImpl(dbClient, UuidFactoryFast.getInstance(), System2.INSTANCE, activeRuleIndexer), |
@@ -45,6 +45,7 @@ import org.sonar.server.qualityprofile.QProfileRules; | |||
import org.sonar.server.qualityprofile.QProfileRulesImpl; | |||
import org.sonar.server.qualityprofile.QProfileTree; | |||
import org.sonar.server.qualityprofile.QProfileTreeImpl; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.qualityprofile.RuleActivation; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
@@ -59,6 +60,7 @@ import static java.util.Arrays.asList; | |||
import static java.util.Collections.singleton; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.MediaTypes.PROTOBUF; | |||
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; | |||
@@ -80,9 +82,10 @@ public class InheritanceActionTest { | |||
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(dbClient, esClient); | |||
private RuleIndex ruleIndex = new RuleIndex(esClient, System2.INSTANCE); | |||
private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, new TypeValidations(new ArrayList<>()), userSession); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer); | |||
private QProfileTree qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService); | |||
private QProfileTree qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer, mock(QualityProfileChangeEventService.class)); | |||
private WsActionTester ws = new WsActionTester(new InheritanceAction( | |||
dbClient, |
@@ -43,6 +43,7 @@ import org.sonar.server.es.SearchOptions; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.qualityprofile.QProfileRules; | |||
import org.sonar.server.qualityprofile.QProfileRulesImpl; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
@@ -56,6 +57,7 @@ import org.sonar.server.ws.WsActionTester; | |||
import static java.util.Collections.emptyList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.fail; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_LANGUAGES; | |||
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_QPROFILE; | |||
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY; | |||
@@ -81,8 +83,9 @@ public class QProfilesWsMediumTest { | |||
private final RuleIndexer ruleIndexer = new RuleIndexer(es.client(), dbClient); | |||
private final ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client()); | |||
private final TypeValidations typeValidations = new TypeValidations(emptyList()); | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private final RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSessionRule); | |||
private final QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer); | |||
private final QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService); | |||
private final QProfileWsSupport qProfileWsSupport = new QProfileWsSupport(dbClient, userSessionRule); | |||
private final RuleQueryFactory ruleQueryFactory = new RuleQueryFactory(dbClient); | |||
@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile.ws; | |||
import java.net.HttpURLConnection; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.server.ws.WebService; | |||
@@ -38,14 +39,18 @@ import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.language.LanguageTesting; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static java.lang.String.format; | |||
import static java.util.Optional.empty; | |||
import static java.util.Optional.of; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES; | |||
public class RemoveProjectActionTest { | |||
@@ -61,8 +66,9 @@ public class RemoveProjectActionTest { | |||
private final Languages languages = LanguageTesting.newLanguages(LANGUAGE_1, LANGUAGE_2); | |||
private final QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession); | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService = Mockito.mock(QualityProfileChangeEventService.class); | |||
private final RemoveProjectAction underTest = new RemoveProjectAction(dbClient, userSession, languages, | |||
new ComponentFinder(dbClient, new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT)), wsSupport); | |||
new ComponentFinder(dbClient, new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT)), wsSupport, qualityProfileChangeEventService); | |||
private final WsActionTester ws = new WsActionTester(underTest); | |||
@Test | |||
@@ -97,6 +103,7 @@ public class RemoveProjectActionTest { | |||
assertProjectIsNotAssociatedToProfile(project, profileLang1); | |||
assertProjectIsAssociatedToProfile(project, profileLang2); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, empty(), of(profileLang1)); | |||
} | |||
@Test | |||
@@ -110,6 +117,7 @@ public class RemoveProjectActionTest { | |||
assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); | |||
assertProjectIsNotAssociatedToProfile(project, profile); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, empty(), of(profile)); | |||
} | |||
@Test | |||
@@ -122,6 +130,7 @@ public class RemoveProjectActionTest { | |||
call(project, profile); | |||
assertProjectIsNotAssociatedToProfile(project, profile); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, empty(), of(profile)); | |||
} | |||
@Test | |||
@@ -136,6 +145,7 @@ public class RemoveProjectActionTest { | |||
call(project, profile); | |||
assertProjectIsNotAssociatedToProfile(project, profile); | |||
verify(qualityProfileChangeEventService).publishRuleActivationToSonarLintClients(project, empty(), of(profile)); | |||
} | |||
@Test |
@@ -48,6 +48,7 @@ import org.sonar.server.language.LanguageTesting; | |||
import org.sonar.server.qualityprofile.ActiveRuleChange; | |||
import org.sonar.server.qualityprofile.QProfileRules; | |||
import org.sonar.server.qualityprofile.QProfileRulesImpl; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventService; | |||
import org.sonar.server.qualityprofile.RuleActivation; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
@@ -105,12 +106,14 @@ public class SearchActionTest { | |||
private final ActiveRuleCompleter activeRuleCompleter = new ActiveRuleCompleter(db.getDbClient(), languages); | |||
private final RuleQueryFactory ruleQueryFactory = new RuleQueryFactory(db.getDbClient()); | |||
private final MacroInterpreter macroInterpreter = mock(MacroInterpreter.class); | |||
private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class); | |||
private final RuleMapper ruleMapper = new RuleMapper(languages, macroInterpreter); | |||
private final SearchAction underTest = new SearchAction(ruleIndex, activeRuleCompleter, ruleQueryFactory, db.getDbClient(), ruleMapper, | |||
new RuleWsSupport(db.getDbClient(), userSession)); | |||
private final TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); | |||
private final RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, db.getDbClient(), typeValidations, userSession); | |||
private final QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer); | |||
private final QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer, | |||
qualityProfileChangeEventService); | |||
private final WsActionTester ws = new WsActionTester(underTest); | |||
@Before |
@@ -69,6 +69,10 @@ public class ServletRequest extends ValidatingRequest { | |||
MediaTypes.DEFAULT)); | |||
} | |||
public HttpServletRequest getHttpRequest() { | |||
return source; | |||
} | |||
@Override | |||
public BufferedReader getReader() { | |||
try { |
@@ -189,6 +189,7 @@ import org.sonar.server.qualitygate.ws.QualityGateWsModule; | |||
import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationHandler; | |||
import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationTemplate; | |||
import org.sonar.server.qualityprofile.BuiltInQProfileRepositoryImpl; | |||
import org.sonar.server.qualityprofile.DistributedRuleActivatorEventsDistributor; | |||
import org.sonar.server.qualityprofile.QProfileBackuperImpl; | |||
import org.sonar.server.qualityprofile.QProfileComparison; | |||
import org.sonar.server.qualityprofile.QProfileCopier; | |||
@@ -198,7 +199,9 @@ import org.sonar.server.qualityprofile.QProfileParser; | |||
import org.sonar.server.qualityprofile.QProfileResetImpl; | |||
import org.sonar.server.qualityprofile.QProfileRulesImpl; | |||
import org.sonar.server.qualityprofile.QProfileTreeImpl; | |||
import org.sonar.server.qualityprofile.QualityProfileChangeEventServiceImpl; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.StandaloneRuleActivatorEventsDistributor; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.qualityprofile.ws.QProfilesWsModule; | |||
import org.sonar.server.root.ws.RootWsModule; | |||
@@ -274,6 +277,9 @@ public class PlatformLevel4 extends PlatformLevel { | |||
addIfCluster(NodeHealthModule.class); | |||
addIfCluster(DistributedRuleActivatorEventsDistributor.class); | |||
addIfStandalone(StandaloneRuleActivatorEventsDistributor.class); | |||
add( | |||
ClusterVerification.class, | |||
LogServerId.class, | |||
@@ -304,6 +310,7 @@ public class PlatformLevel4 extends PlatformLevel { | |||
QProfileTreeImpl.class, | |||
QProfileRulesImpl.class, | |||
RuleActivator.class, | |||
QualityProfileChangeEventServiceImpl.class, | |||
QProfileExporters.class, | |||
QProfileFactoryImpl.class, | |||
QProfileCopier.class, |
@@ -0,0 +1,38 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.core.util; | |||
public class ParamChange { | |||
String key; | |||
String value; | |||
public ParamChange(String key, String value) { | |||
this.key = key; | |||
this.value = value; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getValue() { | |||
return value; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.core.util; | |||
public interface RuleActivationListener { | |||
void listen(RuleSetChangeEvent event); | |||
} |
@@ -0,0 +1,68 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.core.util; | |||
public class RuleChange { | |||
String key; | |||
String language; | |||
String templateKey; | |||
String severity; | |||
ParamChange[] params = new ParamChange[0]; | |||
public String getKey() { | |||
return key; | |||
} | |||
public void setKey(String key) { | |||
this.key = key; | |||
} | |||
public String getLanguage() { | |||
return language; | |||
} | |||
public void setLanguage(String language) { | |||
this.language = language; | |||
} | |||
public String getTemplateKey() { | |||
return templateKey; | |||
} | |||
public void setTemplateKey(String templateKey) { | |||
this.templateKey = templateKey; | |||
} | |||
public String getSeverity() { | |||
return severity; | |||
} | |||
public void setSeverity(String severity) { | |||
this.severity = severity; | |||
} | |||
public ParamChange[] getParams() { | |||
return params; | |||
} | |||
public void setParams(ParamChange[] params) { | |||
this.params = params; | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.core.util; | |||
import java.io.Serializable; | |||
public class RuleSetChangeEvent implements Serializable { | |||
private final String event = "RuleSetChange"; | |||
private String[] projects; | |||
private RuleChange[] activatedRules; | |||
private RuleChange[] deactivatedRules; | |||
public RuleSetChangeEvent(String[] projects, RuleChange[] activatedRules, RuleChange[] deactivatedRules) { | |||
this.projects = projects; | |||
this.activatedRules = activatedRules; | |||
this.deactivatedRules = deactivatedRules; | |||
} | |||
public void setProjects(String[] projects) { | |||
this.projects = projects; | |||
} | |||
public void setActivatedRules(RuleChange[] activatedRules) { | |||
this.activatedRules = activatedRules; | |||
} | |||
public void setDeactivatedRules(RuleChange[] deactivatedRules) { | |||
this.deactivatedRules = deactivatedRules; | |||
} | |||
public String getEvent() { | |||
return event; | |||
} | |||
public String[] getProjects() { | |||
return projects; | |||
} | |||
public RuleChange[] getActivatedRules() { | |||
return activatedRules; | |||
} | |||
public RuleChange[] getDeactivatedRules() { | |||
return deactivatedRules; | |||
} | |||
} |