From 0c7ac68a3bf2af1734f08f3dbd1b346f24885ad8 Mon Sep 17 00:00:00 2001 From: Stephane Gamard Date: Mon, 19 May 2014 14:38:36 +0200 Subject: [PATCH] SONAR-5007 - Implemented activation and qprofile params for WS --- .../qualityprofile/db/QualityProfileKey.java | 7 +- .../qualityprofile/index/ActiveRuleIndex.java | 34 ++++++---- .../org/sonar/server/rule2/RuleService.java | 33 +++++++-- .../sonar/server/rule2/index/RuleIndex.java | 1 + .../sonar/server/rule2/index/RuleQuery.java | 25 +++++++ .../sonar/server/rule2/ws/SearchAction.java | 8 ++- .../server/rule2/RuleServiceMediumTest.java | 66 +++++++++++++++++- .../server/rule2/ws/RulesWebServiceTest.java | 68 +++++++++++++++++-- .../search_no_active_rules.json | 20 ++++++ .../search_profile_active_rules.json | 32 +++++++++ 10 files changed, 264 insertions(+), 30 deletions(-) create mode 100644 sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json create mode 100644 sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json diff --git a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileKey.java b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileKey.java index f6677a43d51..7f59ecf5e6d 100644 --- a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileKey.java +++ b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileKey.java @@ -25,7 +25,6 @@ import com.google.common.base.Strings; import java.io.Serializable; /** - * Created by gamars on 05/05/14. * * @since 4.4 */ @@ -51,8 +50,8 @@ public class QualityProfileKey implements Serializable{ * if the format is not valid. */ public static QualityProfileKey parse(String s) { - String[] split = s.split(":"); - Preconditions.checkArgument(split.length == 3, "Bad format of activeRule key: " + s); + String[] split = s.trim().split(":"); + Preconditions.checkArgument(split.length == 2, "Bad format of QualityProfileKey: " + s); return QualityProfileKey.of(split[0], split[1]); } @@ -97,7 +96,7 @@ public class QualityProfileKey implements Serializable{ } /** - * Format is "qProfile:lang", for example "Java:javascript" + * Format is "profile:lang", for example "Java:javascript" */ @Override public String toString() { diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex.java index 6b4a3148818..b0296d50226 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex.java @@ -103,15 +103,15 @@ public class ActiveRuleIndex extends BaseIndex findByRule(RuleKey key){ + /** + * finder methods + */ + public List findByRule(RuleKey key) { SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName()) .setQuery(QueryBuilders .hasParentQuery(this.getParentType(), QueryBuilders.idsQuery(this.getParentType()) - .addIds(key.toString()))) + .addIds(key.toString()) + )) .setRouting(key.toString()); SearchResponse response = request.get(); List activeRules = new ArrayList(); - for(SearchHit hit:response.getHits()){ + for (SearchHit hit : response.getHits()) { activeRules.add(new ActiveRuleDoc(hit.getSource())); } @@ -147,7 +150,12 @@ public class ActiveRuleIndex extends BaseIndex activeRules = activeRuleIndex.findByRule(rule.key()); + for (ActiveRule activeRule : activeRules) { + result.getActiveRules().put(rule.key().toString(), activeRule); + } + } } } + return result; } @@ -102,7 +122,8 @@ public class RuleService implements ServerComponent { /** * Extend rule description by adding a note. - * @param ruleKey the required key + * + * @param ruleKey the required key * @param markdownNote markdown text. null to remove current note. */ public void setNote(RuleKey ruleKey, @Nullable String markdownNote) { diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleIndex.java b/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleIndex.java index c8a31b78294..5210808909c 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleIndex.java +++ b/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleIndex.java @@ -190,6 +190,7 @@ public class RuleIndex extends BaseIndex { protected SearchRequestBuilder buildRequest(RuleQuery query, QueryOptions options) { SearchRequestBuilder esSearch = getClient() .prepareSearch(this.getIndexName()) + .setTypes(this.getIndexType()) .setIndices(this.getIndexName()); /* Integrate Facets */ diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleQuery.java b/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleQuery.java index 0d3aac13d9d..5f8e189ee64 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleQuery.java +++ b/sonar-server/src/main/java/org/sonar/server/rule2/index/RuleQuery.java @@ -29,6 +29,8 @@ import java.util.Collection; public class RuleQuery { + + public static enum SortField { KEY(RuleNormalizer.RuleField.KEY), REPOSITORY(RuleNormalizer.RuleField.REPOSITORY), @@ -74,6 +76,9 @@ public class RuleQuery { private Boolean hasDebtCharacteristic; private SortField sortField; private boolean ascendingSort = true; + private String activation; + private String qProfileKey; + /** * @see org.sonar.server.rule2.RuleService#newRuleQuery() @@ -81,6 +86,26 @@ public class RuleQuery { public RuleQuery() { } + @CheckForNull + public String getqProfileKey() { + return qProfileKey; + } + + public RuleQuery setqProfileKey(String qProfileKey) { + this.qProfileKey = qProfileKey; + return this; + } + + public RuleQuery setActivation(String activation) { + this.activation = activation; + return this; + } + + @CheckForNull + public String getActivation(){ + return this.activation; + } + @CheckForNull public String getKey() { return key; diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java b/sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java index 9374bfce3ba..f69a612fab5 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java +++ b/sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java @@ -52,6 +52,8 @@ public class SearchAction implements RequestHandler { private static final String PARAM_TEXT_QUERY = "q"; private static final String PARAM_REPOSITORIES = "repositories"; + private static final String PARAM_ACTIVATION = "activation"; + private static final String PARAM_QPROFILE = "qprofile"; private static final String PARAM_SEVERITIES = "severities"; private static final String PARAM_STATUSES = "statuses"; private static final String PARAM_LANGUAGES = "languages"; @@ -163,12 +165,12 @@ public class SearchAction implements RequestHandler { .setExampleValue("security,java8"); action - .createParam("qprofile") + .createParam(PARAM_QPROFILE) .setDescription("Key of Quality profile") .setExampleValue("java:Sonar way"); action - .createParam("activation") + .createParam(PARAM_ACTIVATION) .setDescription("Used only if 'qprofile' is set") .setExampleValue("java:Sonar way") .setPossibleValues("false", "true", "all"); @@ -184,6 +186,8 @@ public class SearchAction implements RequestHandler { query.setLanguages(request.paramAsStrings(PARAM_LANGUAGES)); query.setDebtCharacteristics(request.paramAsStrings(PARAM_DEBT_CHARACTERISTICS)); query.setHasDebtCharacteristic(request.paramAsBoolean(PARAM_HAS_DEBT_CHARACTERISTIC)); + query.setActivation(request.param(PARAM_ACTIVATION)); + query.setqProfileKey(request.param(PARAM_QPROFILE)); // TODO move to QueryOptions ? query.setSortField(RuleQuery.SortField.valueOfOrNull(request.param(PARAM_SORT))); diff --git a/sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java index 42f05f555b0..ecc17fba96d 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java @@ -32,11 +32,18 @@ import org.sonar.check.Cardinality; import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.persistence.DbSession; import org.sonar.core.persistence.MyBatis; +import org.sonar.core.qualityprofile.db.ActiveRuleDto; +import org.sonar.core.qualityprofile.db.QualityProfileDao; +import org.sonar.core.qualityprofile.db.QualityProfileDto; import org.sonar.core.rule.RuleDto; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.qualityprofile.persistence.ActiveRuleDao; import org.sonar.server.rule2.index.RuleIndex; +import org.sonar.server.rule2.index.RuleQuery; +import org.sonar.server.rule2.index.RuleResult; import org.sonar.server.rule2.persistence.RuleDao; +import org.sonar.server.search.QueryOptions; import org.sonar.server.tester.ServerTester; import org.sonar.server.user.MockUserSession; @@ -49,7 +56,8 @@ import static org.fest.assertions.Fail.fail; public class RuleServiceMediumTest { @ClassRule - public static ServerTester tester = new ServerTester(); + public static ServerTester tester = new ServerTester() + .setProperty("sonar.es.http.port","9200"); RuleDao dao = tester.get(RuleDao.class); RuleIndex index = tester.get(RuleIndex.class); @@ -158,6 +166,62 @@ public class RuleServiceMediumTest { // assertThat(rule.getNoteUpdatedAt()).isNull(); // assertThat(rule.getNoteUserLogin()).isNull(); + } + + @Test + public void test_search_activation_on_rules() throws InterruptedException { + + // 1. Create in DB + QualityProfileDto qprofile1 = QualityProfileDto.createFor("profile1","java"); + QualityProfileDto qprofile2 = QualityProfileDto.createFor("profile2","java"); + tester.get(QualityProfileDao.class).insert(qprofile1, dbSession); + tester.get(QualityProfileDao.class).insert(qprofile2, dbSession); + + RuleDto rule1 = newRuleDto(RuleKey.of("test", "rule1")); + RuleDto rule2 = newRuleDto(RuleKey.of("test", "rule2")); + tester.get(RuleDao.class).insert(rule1, dbSession); + tester.get(RuleDao.class).insert(rule2, dbSession); + + ActiveRuleDto activeRule1 = ActiveRuleDto.createFor(qprofile1, rule1) + .setSeverity(Severity.BLOCKER); + ActiveRuleDto activeRule2 = ActiveRuleDto.createFor(qprofile1, rule2) + .setSeverity(Severity.BLOCKER); + ActiveRuleDto activeRule3 = ActiveRuleDto.createFor(qprofile2, rule2) + .setSeverity(Severity.BLOCKER); + tester.get(ActiveRuleDao.class).insert(activeRule1, dbSession); + tester.get(ActiveRuleDao.class).insert(activeRule2, dbSession); + tester.get(ActiveRuleDao.class).insert(activeRule3, dbSession); + + dbSession.commit(); + service.refresh(); + + + // 2. test in DB + assertThat(tester.get(RuleDao.class).findAll(dbSession)).hasSize(2); + assertThat(tester.get(ActiveRuleDao.class).findByRule(rule1, dbSession)).hasSize(1); + assertThat(tester.get(ActiveRuleDao.class).findByRule(rule2, dbSession)).hasSize(2); + + + // 3. Test for ALL activations + RuleQuery query = new RuleQuery() + .setActivation("all"); + RuleResult result = service.search(query, new QueryOptions()); + assertThat(result.getActiveRules().values()).hasSize(3); + + // 4. Test for NO active rules + query = new RuleQuery() + .setActivation("false"); + result = service.search(query, new QueryOptions()); + assertThat(result.getActiveRules().values()).hasSize(0); + + // 4. Test for active rules of QProfile + query = new RuleQuery() + .setActivation("true") + .setqProfileKey(qprofile1.getKey().toString()); + result = service.search(query, new QueryOptions()); + assertThat(result.getActiveRules().values()).hasSize(2); + + } private RuleDto newRuleDto(RuleKey ruleKey) { diff --git a/sonar-server/src/test/java/org/sonar/server/rule2/ws/RulesWebServiceTest.java b/sonar-server/src/test/java/org/sonar/server/rule2/ws/RulesWebServiceTest.java index d456a9bd443..7cb40dca157 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule2/ws/RulesWebServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule2/ws/RulesWebServiceTest.java @@ -145,7 +145,7 @@ public class RulesWebServiceTest { @Test - public void search_active_rules() throws Exception { + public void search_all_active_rules() throws Exception { QualityProfileDto profile = newQualityProfile(); tester.get(QualityProfileDao.class).insert(profile, session); @@ -163,21 +163,78 @@ public class RulesWebServiceTest { MockUserSession.set(); WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "search"); request.setParam("q","S001"); + request.setParam("activation","all"); WsTester.Result result = request.execute(); result.assertJson(this.getClass(),"search_active_rules.json"); } @Test - public void search_active_rules_params() throws Exception { + public void search_no_active_rules() throws Exception { QualityProfileDto profile = newQualityProfile(); tester.get(QualityProfileDao.class).insert(profile, session); RuleDto rule = newRuleDto(RuleKey.of(profile.getLanguage(), "S001")); - ruleDao.insert(rule, session); + ruleDao.insert(rule, session); + + ActiveRuleDto activeRule = newActiveRule(profile, rule); + tester.get(ActiveRuleDao.class).insert(activeRule, session); session.commit(); + tester.get(RuleService.class).refresh(); + + + MockUserSession.set(); + WsTester.TestRequest request = wsTester.newGetRequest("api/rules2", "search"); + request.setParam("q","S001"); + request.setParam("activation","false"); + WsTester.Result result = request.execute(); + + result.assertJson(this.getClass(),"search_no_active_rules.json"); + } + + @Test + public void search_profile_active_rules() throws Exception { + QualityProfileDto profile = newQualityProfile().setName("p1"); + tester.get(QualityProfileDao.class).insert(profile, session); + + QualityProfileDto profile2 = newQualityProfile().setName("p2"); + tester.get(QualityProfileDao.class).insert(profile2, session); + + session.commit(); + + RuleDto rule = newRuleDto(RuleKey.of(profile.getLanguage(), "S001")); + ruleDao.insert(rule, session); + + ActiveRuleDto activeRule = newActiveRule(profile, rule); + tester.get(ActiveRuleDao.class).insert(activeRule, session); + ActiveRuleDto activeRule2 = newActiveRule(profile2, rule); + tester.get(ActiveRuleDao.class).insert(activeRule2, session); + + session.commit(); + tester.get(RuleService.class).refresh(); + + + MockUserSession.set(); + WsTester.TestRequest request = wsTester.newGetRequest("api/rules2", "search"); + request.setParam("q","S001"); + request.setParam("activation","true"); + request.setParam("qprofile",profile2.getKey().toString()); + WsTester.Result result = request.execute(); + + result.assertJson(this.getClass(),"search_profile_active_rules.json"); + } + + @Test + public void search_all_active_rules_params() throws Exception { + QualityProfileDto profile = newQualityProfile(); + tester.get(QualityProfileDao.class).insert(profile, session); + + RuleDto rule = newRuleDto(RuleKey.of(profile.getLanguage(), "S001")); + ruleDao.insert(rule, session); + + session.commit(); RuleParamDto param = RuleParamDto.createFor(rule) .setDefaultValue("some value") @@ -210,8 +267,11 @@ public class RulesWebServiceTest { MockUserSession.set(); WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "search"); request.setParam("q", "S001"); + request.setParam("activation", "all"); + WsTester.Result result = request.execute(); + System.out.println("result.outputAsString() = " + result.outputAsString()); result.assertJson(this.getClass(),"search_active_rules_params.json"); } @@ -272,7 +332,7 @@ public class RulesWebServiceTest { private ActiveRuleDto newActiveRule(QualityProfileDto profile, RuleDto rule) { return ActiveRuleDto.createFor(profile, rule) - .setInheritance("NONE") + .setInheritance("none") .setSeverity("BLOCKER"); } } diff --git a/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json b/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json new file mode 100644 index 00000000000..592701ef71d --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json @@ -0,0 +1,20 @@ +{"total": 1, "p": 1, "ps": 25, "rules": [ + { + "key": "java:S001", + "repo": "java", + "lang": "js", + "name": "Rule S001", + "htmlDesc": "Description S001", + "status": "READY", + "template": false, + "internalKey": "InternalKeyS001", + "severity": "INFO", + "tags": [], + "sysTags": [], + "debtRemediationFunctionType": "LINEAR", + "debtRemediationFunctionCoefficient": "1h", + "debtRemediationFunctionOffset": "5min", + "params": [], + "actives": [] + } +]} diff --git a/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json b/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json new file mode 100644 index 00000000000..ee43cf79949 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json @@ -0,0 +1,32 @@ +{ + "p": 1, + "ps": 25, + "rules": [ + { + "actives": [ + { + "inherit": "NONE", + "key": "p2:java:java:S001", + "params": [], + "severity": "BLOCKER" + } + ], + "debtRemediationFunctionCoefficient": "1h", + "debtRemediationFunctionOffset": "5min", + "debtRemediationFunctionType": "LINEAR", + "htmlDesc": "Description S001", + "internalKey": "InternalKeyS001", + "key": "java:S001", + "lang": "js", + "name": "Rule S001", + "params": [], + "repo": "java", + "severity": "INFO", + "status": "READY", + "sysTags": [], + "tags": [], + "template": false + } + ], + "total": 1 +} -- 2.39.5