From 7c03664400952bb5497e07a76e4d26bd9a22b7d3 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Fri, 25 May 2012 08:45:45 +0200 Subject: [PATCH] Create 'My Favourites' Dashboard through extension point. The dashboard is created but not activated. --- .../org/sonar/plugins/core/CorePlugin.java | 3 + .../dashboards/AbstractFilterDashboard.java | 50 ++++++ .../dashboards/MyFavouritesDashboard.java | 45 +++++ .../core/dashboards/ProjectsDashboard.java | 21 +-- .../core/dashboards/TreemapDashboard.java | 21 +-- .../dashboards/MyFavouritesDashboardTest.java | 55 ++++++ .../core/dashboard/ActiveDashboardDto.java | 18 +- .../org/sonar/core/dashboard/WidgetDto.java | 38 +++-- .../core/dashboard/WidgetPropertyDto.java | 14 +- .../org/sonar/core/persistence/rows-derby.sql | 9 - .../java/org/sonar/api/web/Dashboard.java | 23 ++- .../server/startup/RegisterNewDashboards.java | 78 ++++----- .../server/startup/RegisterNewFilters.java | 7 - .../migrate/305_ignore_loaded_dashboards.rb | 1 + .../startup/RegisterNewDashboardsTest.java | 158 ++++++++---------- .../startup/RegisterNewFiltersTest.java | 9 - .../java/org/sonar/test/MoreConditions.java | 9 + .../org/sonar/test/MoreConditionsTest.java | 20 +++ 18 files changed, 366 insertions(+), 213 deletions(-) create mode 100644 plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/AbstractFilterDashboard.java create mode 100644 plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboard.java create mode 100644 plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboardTest.java diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 21f7e163bc6..b2d3748cff1 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -19,6 +19,8 @@ */ package org.sonar.plugins.core; +import org.sonar.plugins.core.dashboards.MyFavouritesDashboard; + import com.google.common.collect.Lists; import org.sonar.api.CoreProperties; import org.sonar.api.Extension; @@ -344,6 +346,7 @@ public final class CorePlugin extends SonarPlugin { extensions.add(TimeMachineDashboard.class); extensions.add(ProjectsDashboard.class); extensions.add(TreemapDashboard.class); + extensions.add(MyFavouritesDashboard.class); // chart extensions.add(XradarChart.class); diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/AbstractFilterDashboard.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/AbstractFilterDashboard.java new file mode 100644 index 00000000000..7f824f9745e --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/AbstractFilterDashboard.java @@ -0,0 +1,50 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.dashboards; + +import org.sonar.plugins.core.widgets.FilterWidget; + +import org.sonar.api.web.Dashboard.Widget; + +import org.sonar.api.web.Dashboard; +import org.sonar.api.web.DashboardLayout; +import org.sonar.api.web.DashboardTemplate; + +/** + * Base class for global dashboard containing a single + * filter widget. + * + * @since 3.1 + */ +abstract class AbstractFilterDashboard extends DashboardTemplate { + protected abstract String getFilterKey(); + + @Override + public Dashboard createDashboard() { + Dashboard dashboard = Dashboard.create() + .setGlobal(true) + .setLayout(DashboardLayout.ONE_COLUMN); + + Widget filterWidget = dashboard.addWidget("filter", 1) + .setProperty(FilterWidget.FILTER, getFilterKey()); + + return dashboard; + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboard.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboard.java new file mode 100644 index 00000000000..8e0e6582ba4 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboard.java @@ -0,0 +1,45 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.dashboards; + +import org.sonar.api.web.Dashboard; +import org.sonar.plugins.core.filters.MyFavouritesFilter; + +/** + * My favorites global dashboard for Sonar + * + * @since 3.1 + */ +public final class MyFavouritesDashboard extends AbstractFilterDashboard { + @Override + public String getName() { + return "My Favourites"; + } + + @Override + protected String getFilterKey() { + return new MyFavouritesFilter().getName(); + } + + @Override + public Dashboard createDashboard() { + return super.createDashboard().setActivated(false); + } +} \ No newline at end of file diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/ProjectsDashboard.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/ProjectsDashboard.java index 3483cee4866..49fd4f3043a 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/ProjectsDashboard.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/ProjectsDashboard.java @@ -19,34 +19,21 @@ */ package org.sonar.plugins.core.dashboards; -import org.sonar.plugins.core.widgets.FilterWidget; - -import org.sonar.api.web.Dashboard.Widget; - -import org.sonar.api.web.Dashboard; -import org.sonar.api.web.DashboardLayout; -import org.sonar.api.web.DashboardTemplate; +import org.sonar.plugins.core.filters.ProjectFilter; /** * Projects global dashboard for Sonar * * @since 3.1 */ -public final class ProjectsDashboard extends DashboardTemplate { +public final class ProjectsDashboard extends AbstractFilterDashboard { @Override public String getName() { return "Projects"; } @Override - public Dashboard createDashboard() { - Dashboard dashboard = Dashboard.create(); - dashboard.setGlobal(true); - dashboard.setLayout(DashboardLayout.ONE_COLUMN); - - Widget filterWidget = dashboard.addWidget("filter", 1); - filterWidget.setProperty(FilterWidget.FILTER, "Projects"); - - return dashboard; + protected String getFilterKey() { + return new ProjectFilter().getName(); } } \ No newline at end of file diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/TreemapDashboard.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/TreemapDashboard.java index f782704c4eb..29bf58530bb 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/TreemapDashboard.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/TreemapDashboard.java @@ -19,34 +19,21 @@ */ package org.sonar.plugins.core.dashboards; -import org.sonar.plugins.core.widgets.FilterWidget; - -import org.sonar.api.web.Dashboard.Widget; - -import org.sonar.api.web.Dashboard; -import org.sonar.api.web.DashboardLayout; -import org.sonar.api.web.DashboardTemplate; +import org.sonar.plugins.core.filters.TreeMapFilter; /** * Treemap global dashboard for Sonar * * @since 3.1 */ -public final class TreemapDashboard extends DashboardTemplate { +public final class TreemapDashboard extends AbstractFilterDashboard { @Override public String getName() { return "Treemap"; } @Override - public Dashboard createDashboard() { - Dashboard dashboard = Dashboard.create(); - dashboard.setGlobal(true); - dashboard.setLayout(DashboardLayout.ONE_COLUMN); - - Widget filterWidget = dashboard.addWidget("filter", 1); - filterWidget.setProperty(FilterWidget.FILTER, "Treemap"); - - return dashboard; + protected String getFilterKey() { + return new TreeMapFilter().getName(); } } \ No newline at end of file diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboardTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboardTest.java new file mode 100644 index 00000000000..d3cd570b876 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/dashboards/MyFavouritesDashboardTest.java @@ -0,0 +1,55 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.dashboards; + +import com.google.common.collect.Iterables; +import org.junit.Test; +import org.sonar.api.web.Dashboard; +import org.sonar.api.web.Dashboard.Widget; +import org.sonar.plugins.core.CorePlugin; +import org.sonar.plugins.core.filters.MyFavouritesFilter; +import org.sonar.plugins.core.widgets.FilterWidget; + +import static org.fest.assertions.Assertions.assertThat; + +public class MyFavouritesDashboardTest { + MyFavouritesDashboard template = new MyFavouritesDashboard(); + + @Test + public void should_have_a_name() { + assertThat(template.getName()).isEqualTo("My Favourites"); + } + + @Test + public void should_be_registered_as_an_extension() { + assertThat(new CorePlugin().getExtensions()).contains(template.getClass()); + } + + @Test + public void should_create_global_dashboard_with_one_filter() { + Dashboard dashboard = template.createDashboard(); + Widget widget = Iterables.getOnlyElement(dashboard.getWidgets()); + + assertThat(dashboard.isGlobal()).isTrue(); + assertThat(dashboard.isActivated()).isFalse(); + assertThat(widget.getId()).isEqualTo(new FilterWidget().getId()); + assertThat(widget.getProperty("filter")).isEqualTo(new MyFavouritesFilter().getName()); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDto.java b/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDto.java index a4cc714262d..8df7d3a460d 100644 --- a/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDto.java +++ b/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDto.java @@ -19,8 +19,9 @@ */ package org.sonar.core.dashboard; -public final class ActiveDashboardDto { +import com.google.common.base.Objects; +public final class ActiveDashboardDto { private Long id; private Long dashboardId; private Long userId; @@ -36,8 +37,9 @@ public final class ActiveDashboardDto { /** * @param id the id to set */ - public void setId(Long id) { + public ActiveDashboardDto setId(Long id) { this.id = id; + return this; } /** @@ -50,8 +52,9 @@ public final class ActiveDashboardDto { /** * @param dashboardId the dashboardId to set */ - public void setDashboardId(Long dashboardId) { + public ActiveDashboardDto setDashboardId(Long dashboardId) { this.dashboardId = dashboardId; + return this; } /** @@ -64,8 +67,9 @@ public final class ActiveDashboardDto { /** * @param userId the userId to set */ - public void setUserId(Long userId) { + public ActiveDashboardDto setUserId(Long userId) { this.userId = userId; + return this; } /** @@ -78,8 +82,9 @@ public final class ActiveDashboardDto { /** * @param orderIndex the orderIndex to set */ - public void setOrderIndex(Integer orderIndex) { + public ActiveDashboardDto setOrderIndex(Integer orderIndex) { this.orderIndex = orderIndex; + return this; } @Override @@ -92,11 +97,10 @@ public final class ActiveDashboardDto { } ActiveDashboardDto that = (ActiveDashboardDto) o; return !(id != null ? !id.equals(that.id) : that.id != null); - } @Override public int hashCode() { - return id != null ? id.hashCode() : 0; + return Objects.hashCode(id); } } diff --git a/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetDto.java b/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetDto.java index 87c62115f54..2674481299c 100644 --- a/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetDto.java +++ b/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetDto.java @@ -26,7 +26,6 @@ import java.util.Date; import java.util.List; public final class WidgetDto { - private Long id; private Long dashboardId; private String key; @@ -50,8 +49,9 @@ public final class WidgetDto { /** * @param id the id to set */ - public void setId(Long id) { + public WidgetDto setId(Long id) { this.id = id; + return this; } /** @@ -64,8 +64,9 @@ public final class WidgetDto { /** * @param dashboardId the dashboardId to set */ - public void setDashboardId(Long dashboardId) { + public WidgetDto setDashboardId(Long dashboardId) { this.dashboardId = dashboardId; + return this; } /** @@ -78,8 +79,9 @@ public final class WidgetDto { /** * @param key the key to set */ - public void setKey(String key) { + public WidgetDto setKey(String key) { this.key = key; + return this; } /** @@ -92,8 +94,9 @@ public final class WidgetDto { /** * @param name the name to set */ - public void setName(String name) { + public WidgetDto setName(String name) { this.name = name; + return this; } /** @@ -106,8 +109,9 @@ public final class WidgetDto { /** * @param description the description to set */ - public void setDescription(String description) { + public WidgetDto setDescription(String description) { this.description = description; + return this; } /** @@ -120,8 +124,9 @@ public final class WidgetDto { /** * @param columnIndex the columnIndex to set */ - public void setColumnIndex(Integer columnIndex) { + public WidgetDto setColumnIndex(Integer columnIndex) { this.columnIndex = columnIndex; + return this; } /** @@ -134,8 +139,9 @@ public final class WidgetDto { /** * @param rowIndex the rowIndex to set */ - public void setRowIndex(Integer rowIndex) { + public WidgetDto setRowIndex(Integer rowIndex) { this.rowIndex = rowIndex; + return this; } /** @@ -148,8 +154,9 @@ public final class WidgetDto { /** * @param configured the configured to set */ - public void setConfigured(boolean configured) { + public WidgetDto setConfigured(boolean configured) { this.configured = configured; + return this; } /** @@ -162,8 +169,9 @@ public final class WidgetDto { /** * @param createdAt the createdAt to set */ - public void setCreatedAt(Date createdAt) { + public WidgetDto setCreatedAt(Date createdAt) { this.createdAt = createdAt; + return this; } /** @@ -176,8 +184,9 @@ public final class WidgetDto { /** * @param updatedAt the updatedAt to set */ - public void setUpdatedAt(Date updatedAt) { + public WidgetDto setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; + return this; } /** @@ -190,8 +199,9 @@ public final class WidgetDto { /** * @param widgetPropertyDto the widgetProperty to set */ - public void addWidgetProperty(WidgetPropertyDto widgetPropertyDto) { + public WidgetDto addWidgetProperty(WidgetPropertyDto widgetPropertyDto) { widgetPropertyDtos.add(widgetPropertyDto); + return this; } /** @@ -206,8 +216,8 @@ public final class WidgetDto { * @param resourceId the resourceId to set * @since 3.1 */ - public void setResourceId(Integer resourceId) { + public WidgetDto setResourceId(Integer resourceId) { this.resourceId = resourceId; + return this; } - } diff --git a/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetPropertyDto.java b/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetPropertyDto.java index e622804f3ab..d2450c61e0a 100644 --- a/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetPropertyDto.java +++ b/sonar-core/src/main/java/org/sonar/core/dashboard/WidgetPropertyDto.java @@ -20,7 +20,6 @@ package org.sonar.core.dashboard; public final class WidgetPropertyDto { - private Long id; private Long widgetId; private String key; @@ -36,8 +35,9 @@ public final class WidgetPropertyDto { /** * @param id the id to set */ - public void setId(Long id) { + public WidgetPropertyDto setId(Long id) { this.id = id; + return this; } /** @@ -50,8 +50,9 @@ public final class WidgetPropertyDto { /** * @param widgetId the widgetId to set */ - public void setWidgetId(Long widgetId) { + public WidgetPropertyDto setWidgetId(Long widgetId) { this.widgetId = widgetId; + return this; } /** @@ -64,8 +65,9 @@ public final class WidgetPropertyDto { /** * @param key the key to set */ - public void setKey(String key) { + public WidgetPropertyDto setKey(String key) { this.key = key; + return this; } /** @@ -78,8 +80,8 @@ public final class WidgetPropertyDto { /** * @param value the value to set */ - public void setValue(String value) { + public WidgetPropertyDto setValue(String value) { this.value = value; + return this; } - } diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql index 52fd3ebd7b6..07abf09b976 100644 --- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql +++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql @@ -1,14 +1,5 @@ -- All the rows inserted during Rails migrations. Rows inserted during server startup tasks (Java) are excluded : rules, profiles, metrics, ... -INSERT INTO DASHBOARDS(ID, USER_ID, NAME, DESCRIPTION, COLUMN_LAYOUT, SHARED, IS_GLOBAL) VALUES (1, null, 'My favourites', null, '100%', true, true); -ALTER TABLE DASHBOARDS ALTER COLUMN ID RESTART WITH 2; - -INSERT INTO WIDGETS(ID, DASHBOARD_ID, WIDGET_KEY, NAME, DESCRIPTION, COLUMN_INDEX, ROW_INDEX, CONFIGURED, RESOURCE_ID) VALUES (1, 1, 'filter', 'Filter', null, 1, 1, true , null); -ALTER TABLE WIDGETS ALTER COLUMN ID RESTART WITH 2; - -INSERT INTO WIDGET_PROPERTIES(ID, WIDGET_ID, KEE, TEXT_VALUE) VALUES (1, 1, 'filter', 'My favourites'); -ALTER TABLE WIDGET_PROPERTIES ALTER COLUMN ID RESTART WITH 2; - INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (1, 1, null, 'admin'); INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (2, 1, null, 'default-admin'); INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (3, 2, null, 'default-user'); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/Dashboard.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/Dashboard.java index e914142116e..6b6a60c24a1 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/web/Dashboard.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/web/Dashboard.java @@ -41,6 +41,7 @@ public final class Dashboard { private DashboardLayout layout = DashboardLayout.TWO_COLUMNS; private ListMultimap widgetsByColumn = ArrayListMultimap.create(); private boolean global = false; + private boolean activated = true; private Dashboard() { } @@ -137,6 +138,27 @@ public final class Dashboard { return this; } + /** + * A dashboard can be activated for all anonymous users or users who haven't configured their own dashboards. + *

Before version 3.1 every dashboard created through this extension point was automatically activated. + * This is still the default behavior.

+ * + * @since 3.1 + */ + public boolean isActivated() { + return activated; + } + + /** + * Set whether the dashboard is activated for all anonymous users or users who haven't configured their own dashboards. + * + * @since 3.1 + */ + public Dashboard setActivated(boolean activated) { + this.activated = activated; + return this; + } + /** * Note that this class is an inner class to avoid confusion with the extension point org.sonar.api.web.Widget. */ @@ -176,5 +198,4 @@ public final class Dashboard { return id; } } - } diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewDashboards.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewDashboards.java index e284678871a..d601f2de2c5 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewDashboards.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewDashboards.java @@ -20,17 +20,21 @@ package org.sonar.server.startup; import com.google.common.collect.Lists; +import com.google.common.collect.Ordering; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.utils.TimeProfiler; import org.sonar.api.web.Dashboard; import org.sonar.api.web.DashboardTemplate; -import org.sonar.core.dashboard.*; +import org.sonar.core.dashboard.ActiveDashboardDao; +import org.sonar.core.dashboard.ActiveDashboardDto; +import org.sonar.core.dashboard.DashboardDao; +import org.sonar.core.dashboard.DashboardDto; +import org.sonar.core.dashboard.WidgetDto; +import org.sonar.core.dashboard.WidgetPropertyDto; import org.sonar.core.template.LoadedTemplateDao; import org.sonar.core.template.LoadedTemplateDto; -import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map.Entry; @@ -39,18 +43,13 @@ import java.util.Map.Entry; * @since 2.13 */ public final class RegisterNewDashboards { - private static final Logger LOG = LoggerFactory.getLogger(RegisterNewDashboards.class); static final String DEFAULT_DASHBOARD_NAME = "Dashboard"; - private List dashboardTemplates; - private DashboardDao dashboardDao; - private ActiveDashboardDao activeDashboardDao; - private LoadedTemplateDao loadedTemplateDao; - - public RegisterNewDashboards(DashboardDao dashboardDao, ActiveDashboardDao activeDashboardDao, LoadedTemplateDao loadedTemplateDao) { - this(new DashboardTemplate[] {}, dashboardDao, activeDashboardDao, loadedTemplateDao); - } + private final List dashboardTemplates; + private final DashboardDao dashboardDao; + private final ActiveDashboardDao activeDashboardDao; + private final LoadedTemplateDao loadedTemplateDao; public RegisterNewDashboards(DashboardTemplate[] dashboardTemplatesArray, DashboardDao dashboardDao, ActiveDashboardDao activeDashboardDao, LoadedTemplateDao loadedTemplateDao) { @@ -68,7 +67,7 @@ public final class RegisterNewDashboards { if (shouldRegister(template.getName())) { Dashboard dashboard = template.createDashboard(); DashboardDto dto = register(template.getName(), dashboard); - if (dto != null) { + if ((dto != null) && (dashboard.isActivated())) { registeredDashboards.add(dto); } } @@ -81,17 +80,18 @@ public final class RegisterNewDashboards { protected void activate(List loadedDashboards) { int nextOrderIndex = activeDashboardDao.selectMaxOrderIndexForNullUser() + 1; - Collections.sort(loadedDashboards, new DashboardComparator()); - for (DashboardDto dashboardDto : loadedDashboards) { + + for (DashboardDto dashboardDto : new DashboardOrdering().sortedCopy(loadedDashboards)) { activate(dashboardDto, nextOrderIndex++); } } private void activate(DashboardDto dashboardDto, int index) { - ActiveDashboardDto activeDashboardDto = new ActiveDashboardDto(); - activeDashboardDto.setDashboardId(dashboardDto.getId()); - activeDashboardDto.setOrderIndex(index); + ActiveDashboardDto activeDashboardDto = new ActiveDashboardDto() + .setDashboardId(dashboardDto.getId()) + .setOrderIndex(index); activeDashboardDao.insert(activeDashboardDto); + LOG.info("New dashboard '" + dashboardDto.getName() + "' registered"); } @@ -108,36 +108,36 @@ public final class RegisterNewDashboards { protected DashboardDto createDtoFromExtension(String name, Dashboard dashboard) { Date now = new Date(); - DashboardDto dashboardDto = new DashboardDto(); - dashboardDto.setName(name); - dashboardDto.setDescription(dashboard.getDescription()); - dashboardDto.setColumnLayout(dashboard.getLayout().getCode()); - dashboardDto.setShared(true); - dashboardDto.setGlobal(dashboard.isGlobal()); - dashboardDto.setCreatedAt(now); - dashboardDto.setUpdatedAt(now); + + DashboardDto dashboardDto = new DashboardDto() + .setName(name) + .setDescription(dashboard.getDescription()) + .setColumnLayout(dashboard.getLayout().getCode()) + .setShared(true) + .setGlobal(dashboard.isGlobal()) + .setCreatedAt(now) + .setUpdatedAt(now); for (int columnIndex = 1; columnIndex <= dashboard.getLayout().getColumns(); columnIndex++) { List widgets = dashboard.getWidgetsOfColumn(columnIndex); for (int rowIndex = 1; rowIndex <= widgets.size(); rowIndex++) { Dashboard.Widget widget = widgets.get(rowIndex - 1); - WidgetDto widgetDto = new WidgetDto(); - widgetDto.setKey(widget.getId()); - widgetDto.setColumnIndex(columnIndex); - widgetDto.setRowIndex(rowIndex); - widgetDto.setConfigured(true); - widgetDto.setCreatedAt(now); - widgetDto.setUpdatedAt(now); + WidgetDto widgetDto = new WidgetDto() + .setKey(widget.getId()) + .setColumnIndex(columnIndex) + .setRowIndex(rowIndex) + .setConfigured(true) + .setCreatedAt(now) + .setUpdatedAt(now); dashboardDto.addWidget(widgetDto); for (Entry property : widget.getProperties().entrySet()) { - WidgetPropertyDto propDto = new WidgetPropertyDto(); - propDto.setKey(property.getKey()); - propDto.setValue(property.getValue()); + WidgetPropertyDto propDto = new WidgetPropertyDto() + .setKey(property.getKey()) + .setValue(property.getValue()); widgetDto.addWidgetProperty(propDto); } } - } return dashboardDto; } @@ -146,7 +146,8 @@ public final class RegisterNewDashboards { return loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.DASHBOARD_TYPE, dashboardName) == 0; } - protected static class DashboardComparator implements Comparator { + private static class DashboardOrdering extends Ordering { + @Override public int compare(DashboardDto d1, DashboardDto d2) { // the default dashboard must be the first one to be activated if (d1.getName().equals(DEFAULT_DASHBOARD_NAME)) { @@ -158,5 +159,4 @@ public final class RegisterNewDashboards { return d1.getName().compareTo(d2.getName()); } } - } diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewFilters.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewFilters.java index 01e33d0fb6c..470a2eeaad5 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewFilters.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewFilters.java @@ -46,13 +46,6 @@ public final class RegisterNewFilters { private final FilterDao filterDao; private final LoadedTemplateDao loadedTemplateDao; - /** - * Constructor used in case there is no {@link FilterTemplate}. - */ - public RegisterNewFilters(FilterDao filterDao, LoadedTemplateDao loadedTemplateDao) { - this(new FilterTemplate[0], filterDao, loadedTemplateDao); - } - public RegisterNewFilters(FilterTemplate[] filterTemplates, FilterDao filterDao, LoadedTemplateDao loadedTemplateDao) { this.filterTemplates = ImmutableList.copyOf(filterTemplates); this.filterDao = filterDao; diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/305_ignore_loaded_dashboards.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/305_ignore_loaded_dashboards.rb index 75dd8c7a7be..88bd4213c6d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/db/migrate/305_ignore_loaded_dashboards.rb +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/305_ignore_loaded_dashboards.rb @@ -31,6 +31,7 @@ class IgnoreLoadedDashboards < ActiveRecord::Migration def self.up mark_dashboard_as_loaded('Projects') mark_dashboard_as_loaded('Treemap') + mark_dashboard_as_loaded('My Favourites') end def self.mark_dashboard_as_loaded(name) diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewDashboardsTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewDashboardsTest.java index b7c9c82993c..89959de4dcd 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewDashboardsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewDashboardsTest.java @@ -19,11 +19,11 @@ */ package org.sonar.server.startup; -import com.google.common.collect.Lists; +import com.google.common.collect.Iterables; import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatcher; import org.sonar.api.web.Dashboard; import org.sonar.api.web.DashboardLayout; import org.sonar.api.web.DashboardTemplate; @@ -36,22 +36,20 @@ import org.sonar.core.dashboard.WidgetPropertyDto; import org.sonar.core.template.LoadedTemplateDao; import org.sonar.core.template.LoadedTemplateDto; -import java.util.Collections; +import java.util.Arrays; import java.util.List; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.sonar.test.MoreConditions.contains; public class RegisterNewDashboardsTest { - private RegisterNewDashboards task; private DashboardDao dashboardDao; private ActiveDashboardDao activeDashboardDao; @@ -63,16 +61,18 @@ public class RegisterNewDashboardsTest { dashboardDao = mock(DashboardDao.class); activeDashboardDao = mock(ActiveDashboardDao.class); loadedTemplateDao = mock(LoadedTemplateDao.class); + fakeDashboardTemplate = mock(DashboardTemplate.class); - fakeDashboardTemplate = new FakeDashboard(); - - task = new RegisterNewDashboards(new DashboardTemplate[]{fakeDashboardTemplate}, dashboardDao, + task = new RegisterNewDashboards(new DashboardTemplate[] {fakeDashboardTemplate}, dashboardDao, activeDashboardDao, loadedTemplateDao); } @Test public void testStart() { + when(fakeDashboardTemplate.createDashboard()).thenReturn(Dashboard.create()); + task.start(); + verify(dashboardDao).insert(any(DashboardDto.class)); verify(loadedTemplateDao).insert(any(LoadedTemplateDto.class)); verify(activeDashboardDao).insert(any(ActiveDashboardDto.class)); @@ -81,116 +81,100 @@ public class RegisterNewDashboardsTest { @Test public void shouldNotRegister() { when(loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.DASHBOARD_TYPE, "Fake")).thenReturn(1); - assertThat(task.shouldRegister("Fake"), is(false)); + + assertThat(task.shouldRegister("Fake")).isFalse(); } @Test public void shouldRegisterDashboard() { when(loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.DASHBOARD_TYPE, "Fake")).thenReturn(0); - assertThat(task.shouldRegister("Fake"), is(true)); + + assertThat(task.shouldRegister("Fake")).isTrue(); } @Test - public void testRegisterDashboard() { + public void should_register_and_activate_dashboard() { + when(fakeDashboardTemplate.createDashboard()).thenReturn(Dashboard.create()); + DashboardDto dashboardDto = task.register("Fake", fakeDashboardTemplate.createDashboard()); - assertNotNull(dashboardDto); - verify(dashboardDao).insert(dashboardDto); + verify(dashboardDao).insert(any(DashboardDto.class)); verify(loadedTemplateDao).insert(eq(new LoadedTemplateDto("Fake", LoadedTemplateDto.DASHBOARD_TYPE))); } @Test - public void shouldCreateDtoFromExtension() { - DashboardDto dto = task.createDtoFromExtension("Fake", fakeDashboardTemplate.createDashboard()); - assertThat(dto.getUserId(), is(nullValue())); - assertThat(dto.getName(), is("Fake")); - assertThat(dto.getDescription(), nullValue()); - assertThat(dto.getColumnLayout(), is("30%-70%")); - assertThat(dto.getShared(), is(true)); - assertThat(dto.getGlobal(), is(true)); - assertNotNull(dto.getCreatedAt()); - assertNotNull(dto.getUpdatedAt()); - - WidgetDto widgetDto = dto.getWidgets().iterator().next(); - assertThat(widgetDto.getKey(), is("fake-widget")); - assertThat(widgetDto.getDescription(), is(nullValue())); - assertThat(widgetDto.getColumnIndex(), is(1)); - assertThat(widgetDto.getRowIndex(), is(1)); - assertThat(widgetDto.getConfigured(), is(true)); - assertNotNull(widgetDto.getCreatedAt()); - assertNotNull(widgetDto.getUpdatedAt()); - - WidgetPropertyDto widgetPropertyDto = widgetDto.getWidgetProperties().iterator().next(); - assertThat(widgetPropertyDto.getKey(), is("fake-property")); - assertThat(widgetPropertyDto.getValue(), is("fake_metric")); - } + public void should_activate_dashboard() { + Dashboard dashboard = Dashboard.create(); + when(fakeDashboardTemplate.createDashboard()).thenReturn(dashboard); - @Test - public void shouldCompareDashboards() throws Exception { - DashboardDto d1 = new DashboardDto().setName("Foo"); - DashboardDto d2 = new DashboardDto().setName("Bar"); - List dashboardDtos = Lists.newArrayList(d1, d2); - Collections.sort(dashboardDtos, new RegisterNewDashboards.DashboardComparator()); + task.start(); - assertThat(dashboardDtos.get(0).getName(), is("Bar")); + verify(activeDashboardDao).insert(any(ActiveDashboardDto.class)); } @Test - public void shouldActivateDashboards() throws Exception { - DashboardDto d1 = new DashboardDto().setName("Foo").setId(14L); - DashboardDto d2 = new DashboardDto().setName("Bar").setId(16L); - List loadedDashboards = Lists.newArrayList(d1, d2); + public void should_disable_activation() { + Dashboard dashboard = Dashboard.create(); + dashboard.setActivated(false); + when(fakeDashboardTemplate.createDashboard()).thenReturn(dashboard); + + task.start(); - when(activeDashboardDao.selectMaxOrderIndexForNullUser()).thenReturn(4); + verify(activeDashboardDao, never()).insert(any(ActiveDashboardDto.class)); + } - task.activate(loadedDashboards); + @Test + public void shouldCreateDtoFromExtension() { + Dashboard dashboard = Dashboard.create() + .setGlobal(true) + .setLayout(DashboardLayout.TWO_COLUMNS_30_70); + Dashboard.Widget widget = dashboard.addWidget("fake-widget", 1); + widget.setProperty("fake-property", "fake_metric"); + when(fakeDashboardTemplate.createDashboard()).thenReturn(dashboard); - verify(activeDashboardDao).insert(argThat(matchActiveDashboard(16L, 5))); - verify(activeDashboardDao).insert(argThat(matchActiveDashboard(14L, 6))); + DashboardDto dto = task.createDtoFromExtension("Fake", fakeDashboardTemplate.createDashboard()); + assertThat(dto.getUserId()).isNull(); + assertThat(dto.getName()).isEqualTo("Fake"); + assertThat(dto.getDescription()).isNull(); + assertThat(dto.getColumnLayout()).isEqualTo("30%-70%"); + assertThat(dto.getShared()).isTrue(); + assertThat(dto.getGlobal()).isTrue(); + assertThat(dto.getCreatedAt()).isNotNull(); + assertThat(dto.getUpdatedAt()).isNotNull(); + + WidgetDto widgetDto = Iterables.getOnlyElement(dto.getWidgets()); + assertThat(widgetDto.getKey()).isEqualTo("fake-widget"); + assertThat(widgetDto.getDescription()).isNull(); + assertThat(widgetDto.getColumnIndex()).isEqualTo(1); + assertThat(widgetDto.getRowIndex()).isEqualTo(1); + assertThat(widgetDto.getConfigured()).isTrue(); + assertThat(widgetDto.getCreatedAt()).isNotNull(); + assertThat(widgetDto.getUpdatedAt()).isNotNull(); + + assertThat(widgetDto.getWidgetProperties()).satisfies(contains(new WidgetPropertyDto().setKey("fake-property").setValue("fake_metric"))); } @Test - public void defaultDashboardShouldBeTheFirstActivatedDashboard() throws Exception { - DashboardDto defaultDashboard = new DashboardDto() - .setName(RegisterNewDashboards.DEFAULT_DASHBOARD_NAME) - .setId(10L); - DashboardDto other = new DashboardDto() - .setName("Bar") - .setId(11L); - List dashboards = Lists.newArrayList(other, defaultDashboard); + public void defaultDashboardShouldBeTheFirstActivatedDashboard() { + DashboardDto defaultDashboard = new DashboardDto().setId(10L).setName(RegisterNewDashboards.DEFAULT_DASHBOARD_NAME); + DashboardDto second = new DashboardDto().setId(11L).setName("Bar"); + DashboardDto third = new DashboardDto().setId(12L).setName("Foo"); + List dashboards = Arrays.asList(third, defaultDashboard, second); task.activate(dashboards); - verify(activeDashboardDao).insert(argThat(matchActiveDashboard(10L, 1))); - verify(activeDashboardDao).insert(argThat(matchActiveDashboard(11L, 2))); + verify(activeDashboardDao).insert(argThat(matchActiveDashboardDto(10L, 1))); + verify(activeDashboardDao).insert(argThat(matchActiveDashboardDto(11L, 2))); + verify(activeDashboardDao).insert(argThat(matchActiveDashboardDto(12L, 3))); } - private BaseMatcher matchActiveDashboard(final long dashboardId, final int orderId) { - return new BaseMatcher() { + private BaseMatcher matchActiveDashboardDto(final long dashboardId, final int orderId) { + return new ArgumentMatcher() { + @Override public boolean matches(Object o) { ActiveDashboardDto dto = (ActiveDashboardDto) o; return dto.getDashboardId() == dashboardId && dto.getOrderIndex() == orderId; } - - public void describeTo(Description description) { - } }; } - - public class FakeDashboard extends DashboardTemplate { - @Override - public String getName() { - return "Fake"; - } - - @Override - public Dashboard createDashboard() { - Dashboard dashboard = Dashboard.create(); - dashboard.setGlobal(true); - dashboard.setLayout(DashboardLayout.TWO_COLUMNS_30_70); - Dashboard.Widget widget = dashboard.addWidget("fake-widget", 1); - widget.setProperty("fake-property", "fake_metric"); - return dashboard; - } - } } diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewFiltersTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewFiltersTest.java index e4debe6d2cb..e19969742d1 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewFiltersTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/RegisterNewFiltersTest.java @@ -68,15 +68,6 @@ public class RegisterNewFiltersTest { verify(loadedTemplateDao).insert(any(LoadedTemplateDto.class)); } - @Test - public void should_insert_nothing_if_no_template_is_available() { - register = new RegisterNewFilters(filterDao, loadedTemplateDao); - register.start(); - - verify(filterDao, never()).insert(any(FilterDto.class)); - verify(loadedTemplateDao, never()).insert(any(LoadedTemplateDto.class)); - } - @Test public void should_insert_nothing_if_templates_are_alreday_loaded() { when(loadedTemplateDao.countByTypeAndKey(eq(LoadedTemplateDto.FILTER_TYPE), anyString())).thenReturn(1); diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/MoreConditions.java b/sonar-testing-harness/src/main/java/org/sonar/test/MoreConditions.java index c06b78a65e6..0f4b24b5a5d 100644 --- a/sonar-testing-harness/src/main/java/org/sonar/test/MoreConditions.java +++ b/sonar-testing-harness/src/main/java/org/sonar/test/MoreConditions.java @@ -59,4 +59,13 @@ public final class MoreConditions { } }; } + + public static Condition reflectionEqualTo(final Object expected) { + return new Condition() { + @Override + public boolean matches(Object actual) { + return EqualsBuilder.reflectionEquals(expected, actual); + } + }; + } } diff --git a/sonar-testing-harness/src/test/java/org/sonar/test/MoreConditionsTest.java b/sonar-testing-harness/src/test/java/org/sonar/test/MoreConditionsTest.java index ad83811e999..6cdd18b53ad 100644 --- a/sonar-testing-harness/src/test/java/org/sonar/test/MoreConditionsTest.java +++ b/sonar-testing-harness/src/test/java/org/sonar/test/MoreConditionsTest.java @@ -24,6 +24,8 @@ import org.junit.Test; import java.util.Arrays; import java.util.Collection; +import static org.sonar.test.MoreConditions.reflectionEqualTo; + import static org.fest.assertions.Assertions.assertThat; import static org.sonar.test.MoreConditions.contains; import static org.sonar.test.MoreConditions.equalsIgnoreEOL; @@ -77,6 +79,24 @@ public class MoreConditionsTest { assertThat(collection).doesNotSatisfy(contains(new Bean("", ""))); } + @Test + public void should_compare_using_reflection() { + Bean bean1 = new Bean("key1", "value1"); + Bean bean2 = new Bean("key2", "value2"); + + assertThat(bean1).is(reflectionEqualTo(bean1)); + assertThat(bean2).is(reflectionEqualTo(bean2)); + assertThat(bean1).isNot(reflectionEqualTo(bean2)); + assertThat(bean2).isNot(reflectionEqualTo(bean1)); + assertThat(bean1).isNot(reflectionEqualTo(null)); + assertThat(bean2).isNot(reflectionEqualTo(null)); + assertThat(bean1).isNot(reflectionEqualTo(new Object())); + assertThat(bean2).isNot(reflectionEqualTo(new Object())); + assertThat(bean1).isNot(reflectionEqualTo(new Bean("key1", "value2"))); + assertThat(bean1).isNot(reflectionEqualTo(new Bean("key2", "value1"))); + assertThat(bean1).isNot(reflectionEqualTo(new Bean("", ""))); + } + static final class Bean { final String key; final String value; -- 2.39.5