From 0f7cb21b743bfe38ddb3e7966487e798af156071 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Mon, 6 May 2013 09:42:59 +0200 Subject: [PATCH] SONAR-3755 Add Action Plan Dao, remove action_plans_issues table, add action_plan_id to issues table --- .../resources/org/sonar/l10n/core.properties | 39 ++++ .../org/sonar/core/issue/ActionPlanStats.java | 149 +++++++++++++++ .../sonar/core/issue/DefaultActionPlan.java | 1 + .../core/issue/db/ActionPlanStatsDao.java | 50 +++++ .../core/issue/db/ActionPlanStatsDto.java | 176 ++++++++++++++++++ .../core/issue/db/ActionPlanStatsMapper.java | 36 ++++ .../org/sonar/core/persistence/DaoUtils.java | 2 + .../sonar/core/persistence/DatabaseUtils.java | 1 - .../org/sonar/core/persistence/MyBatis.java | 13 +- .../org/sonar/core/purge/PurgeCommands.java | 7 - .../org/sonar/core/purge/PurgeMapper.java | 2 - .../core/issue/db/ActionPlanIssueMapper.xml | 7 +- .../core/issue/db/ActionPlanStatsMapper.xml | 30 +++ .../org/sonar/core/persistence/rows-h2.sql | 1 - .../org/sonar/core/persistence/schema-h2.ddl | 13 +- .../org/sonar/core/purge/PurgeMapper.xml | 17 -- .../sonar/core/issue/ActionPlanStatsTest.java | 44 +++++ .../core/issue/db/ActionPlanStatsDaoTest.java | 54 ++++++ .../org/sonar/core/purge/PurgeDaoTest.java | 2 +- .../should_find_by_issue_ids.xml | 84 ++++++++- .../should_find_by_project.xml | 56 ++++++ .../should_insert_new_issues-result.xml | 1 + .../should_update_issues-result.xml | 1 + .../IssueStorageTest/should_update_issues.xml | 1 + .../PurgeDaoTest/shouldDeleteProject.xml | 6 +- .../java/org/sonar/api/issue/ActionPlan.java | 4 +- .../issue/ServerActionPlanStatsFinder.java | 64 +++++++ .../sonar/server/issue/WebIssuesInternal.java | 14 +- .../org/sonar/server/platform/Platform.java | 35 ++-- .../migrate/393_create_action_plans_issues.rb | 37 ---- .../WEB-INF/db/migrate/395_create_issues.rb | 1 + .../ServerActionPlanStatsFinderTest.java | 66 +++++++ 32 files changed, 894 insertions(+), 120 deletions(-) create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/ActionPlanStats.java create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDto.java create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java create mode 100644 sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanStatsMapper.xml create mode 100644 sonar-core/src/test/java/org/sonar/core/issue/ActionPlanStatsTest.java create mode 100644 sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java create mode 100644 sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml create mode 100644 sonar-server/src/main/java/org/sonar/server/issue/ServerActionPlanStatsFinder.java delete mode 100644 sonar-server/src/main/webapp/WEB-INF/db/migrate/393_create_action_plans_issues.rb create mode 100644 sonar-server/src/test/java/org/sonar/server/issue/ServerActionPlanStatsFinderTest.java diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index 2d43a6e7d81..1707520ffef 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -340,6 +340,7 @@ duplications.page=Duplications email_configuration.page=Email Settings event_categories.page=Event Categories filters.page=Filters +issues_action_plans.page=Issues Action Plans manual_metrics.page=Manual Metrics manual_measures.page=Manual Measures manual_rules.page=Manual Rules @@ -611,6 +612,44 @@ action_plans.close=Close action_plans.closed_action_plan=Closed action plans +#------------------------------------------------------------------------------ +# +# ISSUES ACTION PLANS +# +#------------------------------------------------------------------------------ + +issues_action_plans.page_title=Manage Action Plans +issues_action_plans.add_action_plan=Add action plan +issues_action_plans.col.status=St. +issues_action_plans.col.name=Name +issues_action_plans.col.due_for=Due for +issues_action_plans.col.progress=Progress +issues_action_plans.col.description=Description +issues_action_plans.col.author=Author +issues_action_plans.col.closed_on=Closed on +issues_action_plans.col.operations=Operations +issues_action_plans.no_action_plan=No action plan +issues_action_plans.no_issues_linked_to_action_plan=No issues linked to this action plan yet. +issues_action_plans.confirm_delete=Delete this action plan? Associated issues will not be deleted. +issues_action_plans.confirm_close=Close this action plan? There are still open issues linked to it. +issues_action_plans.create_new_action_plan=Create a new action plan +issues_action_plans.create_action_plan=Create action plan +issues_action_plans.edit_action_plan=Edit action plan +issues_action_plans.same_name_in_same_project=An action plan with this name already exists in this project. +issues_action_plans.date_format_help=The date should be entered using the following pattern: 'day/month/year'. For instance, '31/12/2011'. +issues_action_plans.date_not_valid=Date not valid +issues_action_plans.date_cant_be_in_past=The dead-line can't be in the past +issues_action_plans.x_out_of_x_issues_solved={0} of {1} issues solved +issues_action_plans.resolved_issues_x_percent=Resolved issues - {0}% ({1} issues) +issues_action_plans.open_issues_x_percent=Open issues - {0}% ({1} issues) +issues_action_plans.reopen=Reopen +issues_action_plans.close=Close +issues_action_plans.closed_action_plan=Closed action plans +issues_action_plans.status.OPEN=Open +issues_action_plans.status.CLOSED=Closed + + + #------------------------------------------------------------------------------ # # DEPENDENCIES diff --git a/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanStats.java b/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanStats.java new file mode 100644 index 00000000000..ff8e687d647 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanStats.java @@ -0,0 +1,149 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue; + +import org.sonar.api.issue.ActionPlan; + +import java.io.Serializable; +import java.util.Date; +import java.util.UUID; + +public class ActionPlanStats implements Serializable { + + private String key; + private String name; + private String description; + private String userLogin; + private String status; + private Date deadLine; + private Date creationDate; + private Date updateDate; + private int totalIssues; + private int openIssues; + + private ActionPlanStats() { + + } + + public static ActionPlanStats create(String name) { + ActionPlanStats actionPlan = new ActionPlanStats(); + actionPlan.setKey(UUID.randomUUID().toString()); + Date now = new Date(); + actionPlan.setName(name); + actionPlan.setStatus(ActionPlan.STATUS_OPEN); + actionPlan.setCreationDate(now).setUpdateDate(now); + return actionPlan; + } + + public String key() { + return key; + } + + public ActionPlanStats setKey(String key) { + this.key = key; + return this; + } + + public String name() { + return name; + } + + public ActionPlanStats setName(String name) { + this.name = name; + return this; + } + + public String description() { + return description; + } + + public ActionPlanStats setDescription(String description) { + this.description = description; + return this; + } + + public String userLogin() { + return userLogin; + } + + public ActionPlanStats setUserLogin(String userLogin) { + this.userLogin = userLogin; + return this; + } + + public String status() { + return status; + } + + public ActionPlanStats setStatus(String status) { + this.status = status; + return this; + } + + public Date deadLine() { + return deadLine; + } + + public ActionPlanStats setDeadLine(Date deadLine) { + this.deadLine = deadLine; + return this; + } + + public Date creationDate() { + return creationDate; + } + + public ActionPlanStats setCreationDate(Date creationDate) { + this.creationDate = creationDate; + return this; + } + + public Date updateDate() { + return updateDate; + } + + public ActionPlanStats setUpdateDate(Date updateDate) { + this.updateDate = updateDate; + return this; + } + + public int totalIssues() { + return totalIssues; + } + + public ActionPlanStats setTotalIssues(int totalIssues) { + this.totalIssues = totalIssues; + return this; + } + + public int openIssues() { + return openIssues; + } + + public ActionPlanStats setOpenIssues(int openIssues) { + this.openIssues = openIssues; + return this; + } + + public boolean overDue(){ + return status == ActionPlan.STATUS_OPEN && new Date().after(deadLine); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultActionPlan.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultActionPlan.java index 2ecd6a9b745..3e3b3b24608 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultActionPlan.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultActionPlan.java @@ -45,6 +45,7 @@ public class DefaultActionPlan implements ActionPlan { actionPlan.setKey(UUID.randomUUID().toString()); Date now = new Date(); actionPlan.setName(name); + actionPlan.setStatus(ActionPlan.STATUS_OPEN); actionPlan.setCreationDate(now).setUpdateDate(now); return actionPlan; } diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java new file mode 100644 index 00000000000..443b23f9f8a --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java @@ -0,0 +1,50 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue.db; + +import org.apache.ibatis.session.SqlSession; +import org.sonar.api.BatchComponent; +import org.sonar.api.ServerComponent; +import org.sonar.core.persistence.MyBatis; + +import java.util.Collection; + +/** + * @since 3.6 + */ +public class ActionPlanStatsDao implements BatchComponent, ServerComponent { + + private final MyBatis mybatis; + + public ActionPlanStatsDao(MyBatis mybatis) { + this.mybatis = mybatis; + } + + public Collection findByProjectId(Long projectId) { + SqlSession session = mybatis.openSession(); + try { + return session.getMapper(ActionPlanStatsMapper.class).findByProjectId(projectId); + } finally { + MyBatis.closeQuietly(session); + } + } + +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDto.java new file mode 100644 index 00000000000..cd6af003ae1 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDto.java @@ -0,0 +1,176 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue.db; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.sonar.core.issue.ActionPlanStats; + +import java.util.Date; + +/** + * @since 3.6 + */ +public class ActionPlanStatsDto { + + private Integer id; + private String kee; + private String name; + private String description; + private String userLogin; + private Integer projectId; + private String status; + private Date deadLine; + private Date createdAt; + private Date updatedAt; + + private int totalIssues; + private int openIssues; + + + public Integer getId() { + return id; + } + + public ActionPlanStatsDto setId(Integer id) { + this.id = id; + return this; + } + + public String getKee() { + return kee; + } + + public ActionPlanStatsDto setKee(String kee) { + this.kee = kee; + return this; + } + + public String getName() { + return name; + } + + public ActionPlanStatsDto setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public ActionPlanStatsDto setDescription(String description) { + this.description = description; + return this; + } + + public String getUserLogin() { + return userLogin; + } + + public ActionPlanStatsDto setUserLogin(String userLogin) { + this.userLogin = userLogin; + return this; + } + + public Integer getProjectId() { + return projectId; + } + + public ActionPlanStatsDto setProjectId(Integer projectId) { + this.projectId = projectId; + return this; + } + + public String getStatus() { + return status; + } + + public ActionPlanStatsDto setStatus(String status) { + this.status = status; + return this; + } + + public Date getDeadLine() { + return deadLine; + } + + public ActionPlanStatsDto setDeadLine(Date deadLine) { + this.deadLine = deadLine; + return this; + } + + public Date getCreatedAt() { + return createdAt; + } + + public ActionPlanStatsDto setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + return this; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public ActionPlanStatsDto setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public int getTotalIssues() { + return totalIssues; + } + + public ActionPlanStatsDto setTotalIssues(int totalIssues) { + this.totalIssues = totalIssues; + return this; + } + + public int getOpenIssues() { + return openIssues; + } + + public ActionPlanStatsDto setOpenIssues(int openIssues) { + this.openIssues = openIssues; + return this; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } + + public ActionPlanStats toActionPlanStat(){ + return ActionPlanStats.create(name) + .setKey(kee) + .setDescription(description) + .setStatus(status) + .setDeadLine(deadLine) + .setUserLogin(userLogin) + .setCreationDate(createdAt) + .setUpdateDate(updatedAt) + .setTotalIssues(totalIssues) + .setOpenIssues(openIssues); + + } + +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java new file mode 100644 index 00000000000..7fc910f6af4 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java @@ -0,0 +1,36 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue.db; + +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; + +/** + * @since 3.6 + */ +public interface ActionPlanStatsMapper { + + /** + * @since3.6 + */ + Collection findByProjectId(@Param("projectId") Long projectId); +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java index 05022a52d6b..b8a50a0ba09 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java @@ -25,6 +25,7 @@ import org.sonar.core.dashboard.DashboardDao; import org.sonar.core.duplication.DuplicationDao; import org.sonar.core.graph.jdbc.GraphDao; import org.sonar.core.issue.db.ActionPlanIssueDao; +import org.sonar.core.issue.db.ActionPlanStatsDao; import org.sonar.core.issue.db.IssueChangeDao; import org.sonar.core.issue.db.IssueDao; import org.sonar.core.measure.MeasureFilterDao; @@ -53,6 +54,7 @@ public final class DaoUtils { public static List> getDaoClasses() { return ImmutableList.of( ActionPlanIssueDao.class, + ActionPlanStatsDao.class, ActiveDashboardDao.class, AuthorDao.class, AuthorizationDao.class, diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java index df03d505843..b2ed5c6be76 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java @@ -42,7 +42,6 @@ public final class DatabaseUtils { */ static final String[] TABLE_NAMES = { "action_plans", - "action_plans_issues", "action_plans_reviews", "active_dashboards", "active_rules", diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java index a0173a82950..47bb6a5be2e 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java @@ -121,15 +121,16 @@ public class MyBatis implements BatchComponent, ServerComponent { loadAlias(conf, "MeasureData", MeasureData.class); loadAlias(conf, "Issue", IssueDto.class); loadAlias(conf, "IssueChange", IssueChangeDto.class); - loadAlias(conf, "ActionPlanIssue", ActionPlanIssueDto.class); loadAlias(conf, "SnapshotData", SnapshotDataDto.class); + loadAlias(conf, "ActionPlanIssue", ActionPlanIssueDto.class); + loadAlias(conf, "ActionPlanStats", ActionPlanStatsDto.class); Class[] mappers = {ActiveDashboardMapper.class, AuthorMapper.class, DashboardMapper.class, - DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class, IssueChangeMapper.class, LoadedTemplateMapper.class, - MeasureFilterMapper.class, PropertiesMapper.class, PurgeMapper.class, ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceMapper.class, - ResourceSnapshotMapper.class, ReviewCommentMapper.class, ReviewMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, - SemaphoreMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class, MeasureMapper.class, SnapshotDataMapper.class, - SnapshotSourceMapper.class, ActionPlanIssueMapper.class + DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class, IssueChangeMapper.class, LoadedTemplateMapper.class, + MeasureFilterMapper.class, PropertiesMapper.class, PurgeMapper.class, ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceMapper.class, + ResourceSnapshotMapper.class, ReviewCommentMapper.class, ReviewMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, + SemaphoreMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class, MeasureMapper.class, SnapshotDataMapper.class, + SnapshotSourceMapper.class, ActionPlanIssueMapper.class, ActionPlanStatsMapper.class }; loadMappers(conf, mappers); loadMapper(conf, "org.sonar.core.issue.db.IssueMapper"); diff --git a/sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java b/sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java index 67d65e69b0d..37dea581a0e 100644 --- a/sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java +++ b/sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java @@ -128,13 +128,6 @@ class PurgeCommands { session.commit(); profiler.stop(); - profiler.start("deleteResourceActionPlansIssues (action_plans_issues)"); - for (Long resourceId : resourceIds) { - purgeMapper.deleteResourceActionPlansIssues(resourceId); - } - session.commit(); - profiler.stop(); - profiler.start("deleteResourceIssues (issues)"); for (Long resourceId : resourceIds) { purgeMapper.deleteResourceIssues(resourceId); diff --git a/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java b/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java index 41632dabe16..8a1aad0b74d 100644 --- a/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java @@ -101,8 +101,6 @@ public interface PurgeMapper { void deleteSnapshotData(long snapshotId); - void deleteResourceActionPlansIssues(long resourceId); - void deleteResourceIssueChanges(long resourceId); void deleteResourceIssues(long resourceId); diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanIssueMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanIssueMapper.xml index edd28f16180..131b1b987ec 100644 --- a/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanIssueMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanIssueMapper.xml @@ -17,10 +17,11 @@ + select , count(total_issues.id) as totalIssues, count(open_issues.id) as openIssues + from action_plans ap + left join issues total_issues on total_issues.action_plan_id = ap.id + left join issues open_issues on open_issues.action_plan_id = ap.id and open_issues.status != 'CLOSED' + + and ap.project_id = #{projectId} + + group by ap.id, ap.name, ap.description, ap.user_login, ap.project_id, ap.status, ap.deadline, ap.created_at, ap.updated_at + + + \ No newline at end of file diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql index 82bbaafbf2b..78d117f9f90 100644 --- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql +++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql @@ -158,7 +158,6 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('387'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('388'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('391'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('392'); -INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('393'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('394'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('395'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('396'); diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl b/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl index 05ca08707b3..87be4564118 100644 --- a/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl +++ b/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl @@ -521,7 +521,7 @@ CREATE TABLE "ISSUES" ( "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "KEE" VARCHAR(100) NOT NULL, "RESOURCE_ID" INTEGER NOT NULL, - "RULE_ID" INTEGER NOT NULL, + "RULE_ID" INTEGER NULL, "SEVERITY" VARCHAR(10), "MANUAL_SEVERITY" BOOLEAN NOT NULL, "MANUAL_ISSUE" BOOLEAN NOT NULL, @@ -535,6 +535,7 @@ CREATE TABLE "ISSUES" ( "ASSIGNEE_LOGIN" VARCHAR(40), "AUTHOR_LOGIN" VARCHAR(100), "ATTRIBUTES" VARCHAR(4000), + "ACTION_PLAN_ID" INTEGER NULL, "ISSUE_CREATION_DATE" TIMESTAMP, "ISSUE_CLOSE_DATE" TIMESTAMP, "ISSUE_UPDATE_DATE" TIMESTAMP, @@ -553,12 +554,6 @@ CREATE TABLE "ISSUE_CHANGES" ( "UPDATED_AT" TIMESTAMP, ); -CREATE TABLE "ACTION_PLANS_ISSUES" ( - "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), - "ACTION_PLAN_ID" INTEGER, - "ISSUE_ID" INTEGER -); - CREATE TABLE "SNAPSHOT_DATA" ( "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), "SNAPSHOT_ID" INTEGER, @@ -685,10 +680,6 @@ CREATE INDEX "ISSUES_KEE" ON "ISSUES" ("KEE"); CREATE INDEX "ISSUES_RESOURCE_ID" ON "ISSUES" ("RESOURCE_ID"); -CREATE INDEX "INDEX_ACTION_PLANS_ISSUES_ON_ACTION_PLAN_ID" ON "ACTION_PLANS_ISSUES" ("ACTION_PLAN_ID"); - -CREATE INDEX "INDEX_ACTION_PLANS_ISSUES_ON_ISSUE_ID" ON "ACTION_PLANS_ISSUES" ("ISSUE_ID"); - CREATE INDEX "ISSUE_CHANGES_ISSUE_KEY" ON "ISSUE_CHANGES" ("ISSUE_KEY"); CREATE INDEX "ISSUE_CHANGES_KEE" ON "ISSUE_CHANGES" ("KEE"); diff --git a/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml b/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml index efe3b53a4e9..13d5deab3da 100644 --- a/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml @@ -239,23 +239,6 @@ delete apr from action_plans_reviews as apr, action_plans as ap where ap.id=apr.action_plan_id and ap.project_id=#{id} - - delete from action_plans_issues api - where exists (select * from action_plans ap where ap.id=api.action_plan_id and ap.project_id=#{id}) - - - - - delete action_plans_issues from action_plans_issues - inner join action_plans on action_plans.id=action_plans_issues.action_plan_id - where action_plans.project_id=#{id} - - - - - delete api from action_plans_issues as api, action_plans as ap where ap.id=api.action_plan_id and ap.project_id=#{id} - - delete from issue_changes ic where exists (select * from issues i where i.kee=ic.issue_key and i.resource_id=#{id}) diff --git a/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanStatsTest.java b/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanStatsTest.java new file mode 100644 index 00000000000..fc3873b1c3c --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanStatsTest.java @@ -0,0 +1,44 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue; + +import org.apache.commons.lang.time.DateUtils; +import org.junit.Test; +import org.sonar.api.issue.ActionPlan; + +import java.util.Date; + +import static org.fest.assertions.Assertions.assertThat; + +public class ActionPlanStatsTest { + + @Test + public void test_over_due() throws Exception { + Date yesterday = DateUtils.addDays(new Date(), -1); + Date tomorrow = DateUtils.addDays(new Date(), 1); + + assertThat(ActionPlanStats.create("Short term").setStatus(ActionPlan.STATUS_OPEN).setDeadLine(tomorrow).overDue()).isFalse(); + assertThat(ActionPlanStats.create("Short term").setStatus(ActionPlan.STATUS_OPEN).setDeadLine(yesterday).overDue()).isTrue(); + assertThat(ActionPlanStats.create("Short term").setStatus(ActionPlan.STATUS_CLOSED).setDeadLine(tomorrow).overDue()).isFalse(); + assertThat(ActionPlanStats.create("Short term").setStatus(ActionPlan.STATUS_CLOSED).setDeadLine(yesterday).overDue()).isFalse(); + assertThat(ActionPlanStats.create("Short term").setStatus(ActionPlan.STATUS_CLOSED).overDue()).isFalse(); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java new file mode 100644 index 00000000000..1a5c6b538dd --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java @@ -0,0 +1,54 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue.db; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.core.persistence.AbstractDaoTestCase; + +import java.util.Collection; + +import static org.fest.assertions.Assertions.assertThat; + +public class ActionPlanStatsDaoTest extends AbstractDaoTestCase { + + private ActionPlanStatsDao dao; + + @Before + public void createDao() { + dao = new ActionPlanStatsDao(getMyBatis()); + } + + @Test + public void should_find_by_project() { + setupData("should_find_by_project"); + + Collection result = dao.findByProjectId(1l); +// assertThat(result).hasSize(1); + assertThat(result).isNotEmpty(); + + ActionPlanStatsDto actionPlanStatsDto = result.iterator().next(); + assertThat(actionPlanStatsDto.getTotalIssues()).isEqualTo(2); + // TODO +// assertThat(actionPlanStatsDto.getOpenIssues()).isEqualTo(1); + } + +} diff --git a/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java b/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java index 038cc711685..71a455924c3 100644 --- a/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java @@ -111,7 +111,7 @@ public class PurgeDaoTest extends AbstractDaoTestCase { public void shouldDeleteProject() { setupData("shouldDeleteProject"); dao.deleteResourceTree(1L); - assertEmptyTables("projects", "snapshots", "action_plans", "action_plans_reviews", "reviews", "review_comments", "issues", "issue_changes", "action_plans_issues"); + assertEmptyTables("projects", "snapshots", "action_plans", "action_plans_reviews", "reviews", "review_comments", "issues", "issue_changes"); } static final class SnapshotMatcher extends BaseMatcher { diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanIssueDaoTest/should_find_by_issue_ids.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanIssueDaoTest/should_find_by_issue_ids.xml index a54057a3810..7e74a393cbf 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanIssueDaoTest/should_find_by_issue_ids.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanIssueDaoTest/should_find_by_issue_ids.xml @@ -3,17 +3,89 @@ - - - - - - + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml new file mode 100644 index 00000000000..20719972ca3 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml @@ -0,0 +1,56 @@ + + + + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_insert_new_issues-result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_insert_new_issues-result.xml index b1e88540c59..de5ba806091 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_insert_new_issues-result.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_insert_new_issues-result.xml @@ -13,6 +13,7 @@ updated_at="[null]" user_login="emmerik" attributes="foo=bar" + action_plan_id="[null]" issue_creation_date="2013-05-18" issue_update_date="2013-05-18" issue_close_date="2013-05-18" diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues-result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues-result.xml index 57e99d174a1..f39de643ba4 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues-result.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues-result.xml @@ -18,6 +18,7 @@ updated_at="2013-05-18" user_login="emmerik" attributes="foo=bar" + action_plan_id="[null]" issue_creation_date="2013-05-18 00:00:00.0" issue_update_date="2013-05-18 00:00:00.0" issue_close_date="2013-05-18 00:00:00.0" diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues.xml index 56998d9b2a1..3548cb06507 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStorageTest/should_update_issues.xml @@ -18,6 +18,7 @@ updated_at="2011-02-02" user_login="emmerik" attributes="foo=bar" + action_plan_id="[null]" issue_creation_date="2010-01-01" issue_update_date="2010-02-02" issue_close_date="[null]" diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml index 84bcf6e1bfe..344ef71de9e 100644 --- a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml @@ -21,8 +21,6 @@ - - @@ -34,7 +32,7 @@ find(String projectKey) { + ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(projectKey)); + if (resourceDto == null) { + throw new IllegalArgumentException("Project "+ projectKey + " does not exists."); + } + Collection actionPlanStatsDtos = actionPlanStatsDao.findByProjectId(resourceDto.getId()); + return newArrayList(Iterables.transform(actionPlanStatsDtos, new Function() { + @Override + public ActionPlanStats apply(ActionPlanStatsDto actionPlanStatsDto) { + return actionPlanStatsDto.toActionPlanStat(); + } + })); + } + +} diff --git a/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java b/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java index 0a2a2469b35..08beaa27479 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java @@ -22,10 +22,7 @@ package org.sonar.server.issue; import org.sonar.api.ServerComponent; import org.sonar.api.issue.Issue; import org.sonar.api.rule.RuleKey; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.DefaultIssueBuilder; -import org.sonar.core.issue.FieldDiffs; -import org.sonar.core.issue.IssueComment; +import org.sonar.core.issue.*; import org.sonar.core.issue.workflow.Transition; import org.sonar.server.platform.UserSession; @@ -39,9 +36,11 @@ import java.util.Map; public class WebIssuesInternal implements ServerComponent { private final ServerIssueActions actions; + private final ServerActionPlanStatsFinder actionPlanStatsFinder; - public WebIssuesInternal(ServerIssueActions actions) { + public WebIssuesInternal(ServerIssueActions actions, ServerActionPlanStatsFinder actionPlanStatsFinder) { this.actions = actions; + this.actionPlanStatsFinder = actionPlanStatsFinder; } public List listTransitions(String issueKey) { @@ -89,4 +88,9 @@ public class WebIssuesInternal implements ServerComponent { Issue issue = builder.build(); return actions.create((DefaultIssue) issue, UserSession.get()); } + + List actionPlanStats(String projectKey) { + return actionPlanStatsFinder.find(projectKey); + } + } diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 650bda941d4..b0064b86a03 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -81,8 +81,8 @@ import org.sonar.server.rule.WebRules; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.server.startup.*; -import org.sonar.server.text.WebText; import org.sonar.server.text.MacroInterpreter; +import org.sonar.server.text.WebText; import org.sonar.server.ui.*; import javax.servlet.ServletContext; @@ -93,19 +93,31 @@ import javax.servlet.ServletContext; public final class Platform { private static final Platform INSTANCE = new Platform(); - private ComponentContainer rootContainer;// level 1 : only database connectors private ComponentContainer coreContainer;// level 2 : level 1 + core components private ComponentContainer servicesContainer;// level 3 : level 2 + plugin extensions + core components that depend on plugin extensions - private boolean connected = false; private boolean started = false; + private Platform() { + } + public static Platform getInstance() { return INSTANCE; } - private Platform() { + /** + * shortcut for ruby code + */ + public static Server getServer() { + return (Server) getInstance().getComponent(Server.class); + } + + /** + * Used by ruby code + */ + public static T component(Class type) { + return getInstance().getContainer().getComponentByType(type); } public void init(ServletContext servletContext) { @@ -245,6 +257,7 @@ public final class Platform { servicesContainer.addSingleton(IssueWorkflow.class); servicesContainer.addSingleton(ServerIssueActions.class); servicesContainer.addSingleton(ServerIssueFinder.class); + servicesContainer.addSingleton(ServerActionPlanStatsFinder.class); servicesContainer.addSingleton(WebIssuesApi.class); servicesContainer.addSingleton(WebIssuesInternal.class); @@ -330,18 +343,4 @@ public final class Platform { public Object getComponent(Object key) { return getContainer().getComponentByKey(key); } - - /** - * shortcut for ruby code - */ - public static Server getServer() { - return (Server) getInstance().getComponent(Server.class); - } - - /** - * Used by ruby code - */ - public static T component(Class type) { - return getInstance().getContainer().getComponentByType(type); - } } diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/393_create_action_plans_issues.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/393_create_action_plans_issues.rb deleted file mode 100644 index 92b2e036b14..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/db/migrate/393_create_action_plans_issues.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Sonar, entreprise quality control tool. -# Copyright (C) 2008-2013 SonarSource -# mailto:contact AT sonarsource DOT com -# -# SonarQube is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 3 of the License, or (at your option) any later version. -# -# SonarQube is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# - -# -# Sonar 3.6 -# -class CreateActionPlansIssues < ActiveRecord::Migration - - def self.up - create_table :action_plans_issues do |t| - t.integer :action_plan_id - t.integer :issue_id - end - - add_index "action_plans_issues", "action_plan_id", :name => 'I_ACT_PLA_ISSUE_ACT_PLA_ID' - add_index "action_plans_issues", "issue_id", :name => 'I_ACT_PLA_ISSUE_ISSUE_ID' - end - -end - diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/395_create_issues.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/395_create_issues.rb index 90883a234ca..cd6c2b2541b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/db/migrate/395_create_issues.rb +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/395_create_issues.rb @@ -41,6 +41,7 @@ class CreateIssues < ActiveRecord::Migration t.column :assignee_login, :string, :null => true, :limit => 40 t.column :author_login, :string, :null => true, :limit => 100 t.column :attributes, :string, :null => true, :limit => 4000 + t.column :action_plan_id, :integer, :null => true # functional dates t.column :issue_creation_date, :datetime, :null => true diff --git a/sonar-server/src/test/java/org/sonar/server/issue/ServerActionPlanStatsFinderTest.java b/sonar-server/src/test/java/org/sonar/server/issue/ServerActionPlanStatsFinderTest.java new file mode 100644 index 00000000000..bb95ce923e8 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/issue/ServerActionPlanStatsFinderTest.java @@ -0,0 +1,66 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.issue; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.core.issue.ActionPlanStats; +import org.sonar.core.issue.db.ActionPlanStatsDao; +import org.sonar.core.issue.db.ActionPlanStatsDto; +import org.sonar.core.resource.ResourceDao; +import org.sonar.core.resource.ResourceDto; +import org.sonar.core.resource.ResourceQuery; + +import java.util.Collection; + +import static com.google.common.collect.Lists.newArrayList; +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.*; + +public class ServerActionPlanStatsFinderTest { + + private ServerActionPlanStatsFinder actionPlanStatsFinder; + + private ActionPlanStatsDao actionPlanStatsDao = mock(ActionPlanStatsDao.class); + private ResourceDao resourceDao = mock(ResourceDao.class); + + @Before + public void before(){ + actionPlanStatsFinder = new ServerActionPlanStatsFinder(actionPlanStatsDao, resourceDao); + } + + @Test + public void should_find_action_plan_stats(){ + when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setId(1L).setKey("org.sonar.Sample")); + when(actionPlanStatsDao.findByProjectId(1L)).thenReturn(newArrayList(new ActionPlanStatsDto())); + + Collection results = actionPlanStatsFinder.find("org.sonar.Sample"); + assertThat(results).hasSize(1); + } + + @Test(expected = IllegalArgumentException.class) + public void should_throw_exception_if_project_not_found(){ + when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null); + + actionPlanStatsFinder.find("org.sonar.Sample"); + } + +} -- 2.39.5