]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8964 Drop overall notifications not related to the current user on SonarCloud
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 12 Feb 2018 11:03:26 +0000 (12:03 +0100)
committerGitHub <noreply@github.com>
Mon, 12 Feb 2018 11:03:26 +0000 (12:03 +0100)
* SONAR-8964 Remove some global notifications in api/notifications/list on SonarCloud
* SONAR-8964 Remove some global notifications in api/notifications/add on SonarCloud
* In WebServiceEngine, define web services in start()
* SONAR-8964 Remove some global notifications in api/notifications/remove on SonarCloud
* Move some user ITs to their own suite
* SONAR-8964 Add ITs on notifications (not for SonarCloud)
* SONAR-8964 Add ITs on notifications for SonarCloud

29 files changed:
cix.sh
server/sonar-server/src/main/java/org/sonar/server/notification/ws/AddAction.java
server/sonar-server/src/main/java/org/sonar/server/notification/ws/Dispatchers.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/notification/ws/DispatchersImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/notification/ws/ListAction.java
server/sonar-server/src/main/java/org/sonar/server/notification/ws/NotificationWsModule.java
server/sonar-server/src/main/java/org/sonar/server/notification/ws/RemoveAction.java
server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java
server/sonar-server/src/test/java/org/sonar/server/notification/ws/AddActionTest.java
server/sonar-server/src/test/java/org/sonar/server/notification/ws/DispatchersImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/notification/ws/ListActionTest.java
server/sonar-server/src/test/java/org/sonar/server/notification/ws/NotificationWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/notification/ws/RemoveActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java
tests/src/test/java/org/sonarqube/tests/Category1Suite.java
tests/src/test/java/org/sonarqube/tests/Category4Suite.java
tests/src/test/java/org/sonarqube/tests/user/BaseIdentityProviderTest.java
tests/src/test/java/org/sonarqube/tests/user/FavoritesWsTest.java
tests/src/test/java/org/sonarqube/tests/user/ForceAuthenticationTest.java
tests/src/test/java/org/sonarqube/tests/user/LocalAuthenticationTest.java
tests/src/test/java/org/sonarqube/tests/user/MyAccountPageTest.java
tests/src/test/java/org/sonarqube/tests/user/NotificationsWsTest.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/user/OAuth2IdentityProviderTest.java
tests/src/test/java/org/sonarqube/tests/user/RootUserInStandaloneModeTest.java
tests/src/test/java/org/sonarqube/tests/user/SonarCloudNotificationsWsTest.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/user/SonarCloudUserSuite.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/user/UserSuite.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/user/UsersPageTest.java

diff --git a/cix.sh b/cix.sh
index 2d2b0b50f71a9f4b17528fa99f8520e6474264b5..715a27db7c9380d970bcf01ee14ecc8dfbacbf57 100755 (executable)
--- a/cix.sh
+++ b/cix.sh
@@ -43,7 +43,7 @@ case "$RUN_ACTIVITY" in
           ;;
 
         Category4)
-          CATEGORY="Category4|duplication"
+          CATEGORY="Category4|duplication|user"
           ;;
 
         Category5)
index 896728af4e3409b97bab69a7f93765414c1e4787..b2ada687dadb851f14f7a601dd9b7b44673c49ce 100644 (file)
@@ -42,34 +42,30 @@ import org.sonar.server.ws.KeyExamples;
 
 import static java.util.Optional.empty;
 import static org.sonar.core.util.Protobuf.setNullable;
-import static org.sonar.core.util.stream.MoreCollectors.toList;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
-import static org.sonar.server.ws.WsUtils.checkFound;
-import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.ACTION_ADD;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_CHANNEL;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_LOGIN;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_PROJECT;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_TYPE;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkRequest;
 
 public class AddAction implements NotificationsWsAction {
   private final NotificationCenter notificationCenter;
   private final NotificationUpdater notificationUpdater;
+  private final Dispatchers dispatchers;
   private final DbClient dbClient;
   private final ComponentFinder componentFinder;
   private final UserSession userSession;
-  private final List<String> globalDispatchers;
-  private final List<String> projectDispatchers;
 
-  public AddAction(NotificationCenter notificationCenter, NotificationUpdater notificationUpdater, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession) {
+  public AddAction(NotificationCenter notificationCenter, NotificationUpdater notificationUpdater, Dispatchers dispatchers, DbClient dbClient, ComponentFinder componentFinder,
+    UserSession userSession) {
     this.notificationCenter = notificationCenter;
     this.notificationUpdater = notificationUpdater;
+    this.dispatchers = dispatchers;
     this.dbClient = dbClient;
     this.componentFinder = componentFinder;
     this.userSession = userSession;
-    this.globalDispatchers = notificationCenter.getDispatcherKeysForProperty(GLOBAL_NOTIFICATION, "true").stream().sorted().collect(toList());
-    this.projectDispatchers = notificationCenter.getDispatcherKeysForProperty(PER_PROJECT_NOTIFICATION, "true").stream().sorted().collect(toList());
   }
 
   @Override
@@ -101,8 +97,8 @@ public class AddAction implements NotificationsWsAction {
         "  <li>Global notifications: %s</li>" +
         "  <li>Per project notifications: %s</li>" +
         "</ul>",
-        String.join(", ", globalDispatchers),
-        String.join(", ", projectDispatchers))
+        String.join(", ", dispatchers.getGlobalDispatchers()),
+        String.join(", ", dispatchers.getProjectDispatchers()))
       .setRequired(true)
       .setExampleValue(MyNewIssuesNotificationDispatcher.KEY);
 
@@ -158,15 +154,15 @@ public class AddAction implements NotificationsWsAction {
     setNullable(request.param(PARAM_LOGIN), add::setLogin);
 
     if (add.getProject() == null) {
-      checkRequest(globalDispatchers.contains(add.getType()), "Value of parameter '%s' (%s) must be one of: %s",
+      checkRequest(dispatchers.getGlobalDispatchers().contains(add.getType()), "Value of parameter '%s' (%s) must be one of: %s",
         PARAM_TYPE,
         add.getType(),
-        globalDispatchers);
+        dispatchers.getGlobalDispatchers());
     } else {
-      checkRequest(projectDispatchers.contains(add.getType()), "Value of parameter '%s' (%s) must be one of: %s",
+      checkRequest(dispatchers.getProjectDispatchers().contains(add.getType()), "Value of parameter '%s' (%s) must be one of: %s",
         PARAM_TYPE,
         add.getType(),
-        projectDispatchers);
+        dispatchers.getProjectDispatchers());
     }
 
     return add;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/notification/ws/Dispatchers.java b/server/sonar-server/src/main/java/org/sonar/server/notification/ws/Dispatchers.java
new file mode 100644 (file)
index 0000000..b96959e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.notification.ws;
+
+import java.util.List;
+
+public interface Dispatchers {
+
+  List<String> getGlobalDispatchers();
+
+  List<String> getProjectDispatchers();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/notification/ws/DispatchersImpl.java b/server/sonar-server/src/main/java/org/sonar/server/notification/ws/DispatchersImpl.java
new file mode 100644 (file)
index 0000000..4032e18
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.notification.ws;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import org.sonar.api.Startable;
+import org.sonar.api.config.Configuration;
+import org.sonar.process.ProcessProperties;
+import org.sonar.server.event.NewAlerts;
+import org.sonar.server.issue.notification.DoNotFixNotificationDispatcher;
+import org.sonar.server.issue.notification.NewIssuesNotificationDispatcher;
+import org.sonar.server.notification.NotificationCenter;
+
+import static org.sonar.core.util.stream.MoreCollectors.toList;
+import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
+import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
+
+public class DispatchersImpl implements Dispatchers, Startable {
+
+  private static final Set<String> GLOBAL_DISPATCHERS_TO_IGNORE_ON_SONAR_CLOUD = ImmutableSet.of(
+    NewAlerts.KEY,
+    DoNotFixNotificationDispatcher.KEY,
+    NewIssuesNotificationDispatcher.KEY);
+
+  private final NotificationCenter notificationCenter;
+  private final Configuration configuration;
+
+  private List<String> projectDispatchers;
+  private List<String> globalDispatchers;
+
+  public DispatchersImpl(NotificationCenter notificationCenter, Configuration configuration) {
+    this.notificationCenter = notificationCenter;
+    this.configuration = configuration;
+  }
+
+  @Override
+  public List<String> getGlobalDispatchers() {
+    return globalDispatchers;
+  }
+
+  @Override
+  public List<String> getProjectDispatchers() {
+    return projectDispatchers;
+  }
+
+  @Override
+  public void start() {
+    boolean isOnSonarCloud = configuration.getBoolean(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey()).orElse(false);
+    this.globalDispatchers = notificationCenter.getDispatcherKeysForProperty(GLOBAL_NOTIFICATION, "true")
+      .stream()
+      .filter(filterDispatcherForSonarCloud(isOnSonarCloud))
+      .sorted()
+      .collect(toList());
+    this.projectDispatchers = notificationCenter.getDispatcherKeysForProperty(PER_PROJECT_NOTIFICATION, "true")
+      .stream()
+      .sorted()
+      .collect(toList());
+  }
+
+  private static Predicate<String> filterDispatcherForSonarCloud(boolean isOnSonarCloud) {
+    return dispatcher -> !(isOnSonarCloud && GLOBAL_DISPATCHERS_TO_IGNORE_ON_SONAR_CLOUD.contains(dispatcher));
+  }
+
+  @Override
+  public void stop() {
+    // nothing to do
+  }
+}
index e7c5c60afe58a33d8f06f0d6d35bcb614442d18b..9f15c5e64ac4b102e58a695f3494ebc632baf29c 100644 (file)
@@ -53,28 +53,25 @@ import static java.util.Comparator.naturalOrder;
 import static java.util.Comparator.nullsFirst;
 import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.core.util.stream.MoreCollectors.toOneElement;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
-import static org.sonar.server.ws.WsUtils.checkFound;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.ACTION_LIST;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_LOGIN;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 public class ListAction implements NotificationsWsAction {
+
   private static final Splitter PROPERTY_KEY_SPLITTER = Splitter.on(".");
 
   private final DbClient dbClient;
   private final UserSession userSession;
-  private final List<String> globalDispatchers;
-  private final List<String> perProjectDispatchers;
   private final List<String> channels;
+  private final Dispatchers dispatchers;
 
-  public ListAction(NotificationCenter notificationCenter, DbClient dbClient, UserSession userSession) {
+  public ListAction(NotificationCenter notificationCenter, DbClient dbClient, UserSession userSession, Dispatchers dispatchers) {
     this.dbClient = dbClient;
     this.userSession = userSession;
-    this.globalDispatchers = notificationCenter.getDispatcherKeysForProperty(GLOBAL_NOTIFICATION, "true").stream().sorted().collect(MoreCollectors.toList());
-    this.perProjectDispatchers = notificationCenter.getDispatcherKeysForProperty(PER_PROJECT_NOTIFICATION, "true").stream().sorted().collect(MoreCollectors.toList());
     this.channels = notificationCenter.getChannels().stream().map(NotificationChannel::getKey).sorted().collect(MoreCollectors.toList());
+    this.dispatchers = dispatchers;
   }
 
   @Override
@@ -110,8 +107,8 @@ public class ListAction implements NotificationsWsAction {
       return Stream
         .of(ListResponse.newBuilder())
         .map(r -> r.addAllChannels(channels))
-        .map(r -> r.addAllGlobalTypes(globalDispatchers))
-        .map(r -> r.addAllPerProjectTypes(perProjectDispatchers))
+        .map(r -> r.addAllGlobalTypes(dispatchers.getGlobalDispatchers()))
+        .map(r -> r.addAllPerProjectTypes(dispatchers.getProjectDispatchers()))
         .map(addNotifications(dbSession, user))
         .map(ListResponse.Builder::build)
         .collect(toOneElement());
@@ -158,7 +155,7 @@ public class ListAction implements NotificationsWsAction {
   }
 
   private boolean isDispatcherAuthorized(PropertyDto prop, String dispatcher) {
-    return (prop.getResourceId() != null && perProjectDispatchers.contains(dispatcher)) || globalDispatchers.contains(dispatcher);
+    return (prop.getResourceId() != null && dispatchers.getProjectDispatchers().contains(dispatcher)) || dispatchers.getGlobalDispatchers().contains(dispatcher);
   }
 
   private Map<Long, ComponentDto> searchProjects(DbSession dbSession, List<PropertyDto> properties) {
index 9f9aa9ac64f0ac922b7fc6f14f6f884b2982ed5a..6011559edcca292f2b403b6e09cacd68161b8bfc 100644 (file)
@@ -25,6 +25,7 @@ public class NotificationWsModule extends Module {
   @Override
   protected void configureModule() {
     add(
+      DispatchersImpl.class,
       // WS
       NotificationsWs.class,
       AddAction.class,
index 1a6ea326db864363bb0b30fd0660bbc28e344584..bc5e6349bdfc7e67e6e3a0602087ac612eb68bb9 100644 (file)
@@ -42,33 +42,30 @@ import org.sonar.server.ws.KeyExamples;
 
 import static java.util.Optional.empty;
 import static org.sonar.core.util.Protobuf.setNullable;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
-import static org.sonar.server.ws.WsUtils.checkFound;
-import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.ACTION_REMOVE;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_CHANNEL;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_LOGIN;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_PROJECT;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_TYPE;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkRequest;
 
 public class RemoveAction implements NotificationsWsAction {
   private final NotificationCenter notificationCenter;
   private final NotificationUpdater notificationUpdater;
+  private final Dispatchers dispatchers;
   private final DbClient dbClient;
   private final ComponentFinder componentFinder;
   private final UserSession userSession;
-  private final List<String> globalDispatchers;
-  private final List<String> projectDispatchers;
 
-  public RemoveAction(NotificationCenter notificationCenter, NotificationUpdater notificationUpdater, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession) {
+  public RemoveAction(NotificationCenter notificationCenter, NotificationUpdater notificationUpdater, Dispatchers dispatchers, DbClient dbClient, ComponentFinder componentFinder,
+    UserSession userSession) {
     this.notificationCenter = notificationCenter;
     this.notificationUpdater = notificationUpdater;
+    this.dispatchers = dispatchers;
     this.dbClient = dbClient;
     this.componentFinder = componentFinder;
     this.userSession = userSession;
-    this.globalDispatchers = notificationCenter.getDispatcherKeysForProperty(GLOBAL_NOTIFICATION, "true");
-    this.projectDispatchers = notificationCenter.getDispatcherKeysForProperty(PER_PROJECT_NOTIFICATION, "true");
   }
 
   @Override
@@ -100,8 +97,8 @@ public class RemoveAction implements NotificationsWsAction {
         "  <li>Global notifications: %s</li>" +
         "  <li>Per project notifications: %s</li>" +
         "</ul>",
-        globalDispatchers.stream().sorted().collect(Collectors.joining(", ")),
-        projectDispatchers.stream().sorted().collect(Collectors.joining(", ")))
+        dispatchers.getGlobalDispatchers().stream().sorted().collect(Collectors.joining(", ")),
+        dispatchers.getProjectDispatchers().stream().sorted().collect(Collectors.joining(", ")))
       .setRequired(true)
       .setExampleValue(MyNewIssuesNotificationDispatcher.KEY);
 
@@ -156,15 +153,15 @@ public class RemoveAction implements NotificationsWsAction {
     setNullable(request.param(PARAM_LOGIN), remove::setLogin);
 
     if (remove.getProject() == null) {
-      checkRequest(globalDispatchers.contains(remove.getType()), "Value of parameter '%s' (%s) must be one of: %s",
+      checkRequest(dispatchers.getGlobalDispatchers().contains(remove.getType()), "Value of parameter '%s' (%s) must be one of: %s",
         PARAM_TYPE,
         remove.getType(),
-        globalDispatchers);
+        dispatchers.getGlobalDispatchers());
     } else {
-      checkRequest(projectDispatchers.contains(remove.getType()), "Value of parameter '%s' (%s) must be one of: %s",
+      checkRequest(dispatchers.getProjectDispatchers().contains(remove.getType()), "Value of parameter '%s' (%s) must be one of: %s",
         PARAM_TYPE,
         remove.getType(),
-        projectDispatchers);
+        dispatchers.getProjectDispatchers());
     }
 
     return remove;
index a4be25f44ee293e8ac4ecac6d4a4109619688929..2b2ed031c70132558a036c218596c167a2bb467f 100644 (file)
@@ -44,6 +44,7 @@ import org.sonarqube.ws.MediaTypes;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static java.util.Collections.singletonList;
+import static java.util.Objects.requireNonNull;
 import static org.apache.commons.lang.StringUtils.substring;
 import static org.apache.commons.lang.StringUtils.substringAfterLast;
 import static org.apache.commons.lang.StringUtils.substringBeforeLast;
@@ -59,19 +60,20 @@ public class WebServiceEngine implements LocalConnector, Startable {
 
   private static final Logger LOGGER = Loggers.get(WebServiceEngine.class);
 
-  private final WebService.Context context;
+  private final WebService[] webServices;
+
+  private WebService.Context context;
 
   public WebServiceEngine(WebService[] webServices) {
-    context = new WebService.Context();
-    for (WebService webService : webServices) {
-      webService.define(context);
-    }
+    this.webServices = webServices;
   }
 
   @Override
   public void start() {
-    // Force execution of constructor to be sure that web services
-    // are validated and initialized at server startup.
+    context = new WebService.Context();
+    for (WebService webService : webServices) {
+      webService.define(context);
+    }
   }
 
   @Override
@@ -79,8 +81,12 @@ public class WebServiceEngine implements LocalConnector, Startable {
     // nothing
   }
 
+  private WebService.Context getContext() {
+    return requireNonNull(context, "Web services has not yet been initialized");
+  }
+
   List<WebService.Controller> controllers() {
-    return context.controllers();
+    return getContext().controllers();
   }
 
   @Override
@@ -117,7 +123,7 @@ public class WebServiceEngine implements LocalConnector, Startable {
   private WebService.Action getAction(ActionExtractor actionExtractor) {
     String controllerPath = actionExtractor.getController();
     String actionKey = actionExtractor.getAction();
-    WebService.Controller controller = context.controller(controllerPath);
+    WebService.Controller controller = getContext().controller(controllerPath);
     return controller == null ? null : controller.action(actionKey);
   }
 
index 156e6f8efae8452c0e1465062a990f9b4c963cbd..6d2b8365c32c827bb50a1e7cd12431408db3fd76 100644 (file)
 package org.sonar.server.notification.ws;
 
 import javax.annotation.Nullable;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
-import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
@@ -46,11 +44,14 @@ import org.sonar.server.ws.WsActionTester;
 
 import static java.lang.String.format;
 import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.db.component.ComponentTesting.newView;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_CHANNEL;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_LOGIN;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_PROJECT;
@@ -60,12 +61,11 @@ public class AddActionTest {
   private static final String NOTIF_MY_NEW_ISSUES = "Dispatcher1";
   private static final String NOTIF_NEW_ISSUES = "Dispatcher2";
   private static final String NOTIF_NEW_QUALITY_GATE_STATUS = "Dispatcher3";
-  private static final String USER_LOGIN = "george.orwell";
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
   @Rule
-  public UserSessionRule userSession;
+  public UserSessionRule userSession = UserSessionRule.standalone();
   @Rule
   public DbTester db = DbTester.create();
 
@@ -76,35 +76,19 @@ public class AddActionTest {
   // default channel, based on class simple name
   private NotificationChannel defaultChannel = new FakeNotificationChannel("EmailNotificationChannel");
 
-  private UserDto user;
-
-  private NotificationCenter notificationCenter;
-  private AddAction underTest;
-  private WsActionTester ws;
-
-  @Before
-  public void setUp() {
-    NotificationDispatcherMetadata metadata1 = NotificationDispatcherMetadata.create(NOTIF_MY_NEW_ISSUES)
-      .setProperty(GLOBAL_NOTIFICATION, "true")
-      .setProperty(PER_PROJECT_NOTIFICATION, "true");
-    NotificationDispatcherMetadata metadata2 = NotificationDispatcherMetadata.create(NOTIF_NEW_ISSUES)
-      .setProperty(GLOBAL_NOTIFICATION, "true");
-    NotificationDispatcherMetadata metadata3 = NotificationDispatcherMetadata.create(NOTIF_NEW_QUALITY_GATE_STATUS)
-      .setProperty(GLOBAL_NOTIFICATION, "true")
-      .setProperty(PER_PROJECT_NOTIFICATION, "true");
-
-    user = db.users().insertUser(USER_LOGIN);
-    userSession = UserSessionRule.standalone().logIn(user);
-
-    notificationCenter = new NotificationCenter(
-      new NotificationDispatcherMetadata[] {metadata1, metadata2, metadata3},
-      new NotificationChannel[] {emailChannel, twitterChannel, defaultChannel});
-    underTest = new AddAction(notificationCenter, new NotificationUpdater(dbClient), dbClient, TestComponentFinder.from(db), userSession);
-    ws = new WsActionTester(underTest);
-  }
+  private Dispatchers dispatchers = mock(Dispatchers.class);
+
+  private WsActionTester ws = new WsActionTester(new AddAction(new NotificationCenter(
+    new NotificationDispatcherMetadata[] {},
+    new NotificationChannel[] {emailChannel, twitterChannel, defaultChannel}),
+    new NotificationUpdater(dbClient), dispatchers, dbClient, TestComponentFinder.from(db), userSession));
 
   @Test
   public void add_to_email_channel_by_default() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     call(NOTIF_MY_NEW_ISSUES, null, null, null);
 
     db.notifications().assertExists(defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, userSession.getUserId(), null);
@@ -112,6 +96,10 @@ public class AddActionTest {
 
   @Test
   public void add_to_a_specific_channel() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+
     call(NOTIF_NEW_QUALITY_GATE_STATUS, twitterChannel.getKey(), null, null);
 
     db.notifications().assertExists(twitterChannel.getKey(), NOTIF_NEW_QUALITY_GATE_STATUS, userSession.getUserId(), null);
@@ -119,8 +107,12 @@ public class AddActionTest {
 
   @Test
   public void add_notification_on_private_with_USER_permission() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
     ComponentDto project = db.components().insertPrivateProject();
-    userSession.addProjectPermission(UserRole.USER, project);
+    userSession.addProjectPermission(USER, project);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     call(NOTIF_MY_NEW_ISSUES, null, project.getDbKey(), null);
 
@@ -129,8 +121,13 @@ public class AddActionTest {
 
   @Test
   public void add_notification_on_public_project() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
     ComponentDto project = db.components().insertPublicProject();
     userSession.registerComponents(project);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     call(NOTIF_MY_NEW_ISSUES, null, project.getDbKey(), null);
 
     db.notifications().assertExists(defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, userSession.getUserId(), project);
@@ -138,8 +135,12 @@ public class AddActionTest {
 
   @Test
   public void add_a_global_notification_when_a_project_one_exists() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertPrivateProject();
-    userSession.addProjectPermission(UserRole.USER, project);
+    userSession.addProjectPermission(USER, project);
     call(NOTIF_MY_NEW_ISSUES, null, project.getDbKey(), null);
 
     call(NOTIF_MY_NEW_ISSUES, null, null, null);
@@ -150,19 +151,26 @@ public class AddActionTest {
 
   @Test
   public void add_a_notification_on_private_project_when_a_global_one_exists() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertPrivateProject();
     call(NOTIF_MY_NEW_ISSUES, null, null, null);
 
-    userSession.addProjectPermission(UserRole.USER, project);
+    userSession.addProjectPermission(USER, project);
     call(NOTIF_MY_NEW_ISSUES, null, project.getDbKey(), null);
 
     db.notifications().assertExists(defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, userSession.getUserId(), project);
     db.notifications().assertExists(defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, userSession.getUserId(), null);
   }
 
-
   @Test
   public void add_a_notification_on_public_project_when_a_global_one_exists() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertPublicProject();
     userSession.registerComponents(project);
     call(NOTIF_MY_NEW_ISSUES, null, null, null);
@@ -175,6 +183,10 @@ public class AddActionTest {
 
   @Test
   public void http_no_content() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     TestResponse result = call(NOTIF_MY_NEW_ISSUES, null, null, null);
 
     assertThat(result.getStatus()).isEqualTo(HTTP_NO_CONTENT);
@@ -182,7 +194,9 @@ public class AddActionTest {
 
   @Test
   public void add_a_notification_to_a_user_as_system_administrator() {
-    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user).setSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     call(NOTIF_MY_NEW_ISSUES, null, null, user.getLogin());
 
@@ -191,7 +205,9 @@ public class AddActionTest {
 
   @Test
   public void fail_if_login_is_provided_and_unknown() {
-    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user).setSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("User 'LOGIN 404' not found");
@@ -201,7 +217,9 @@ public class AddActionTest {
 
   @Test
   public void fail_if_login_provided_and_not_system_administrator() {
-    userSession.logIn().setNonSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user).setNonSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(ForbiddenException.class);
 
@@ -210,6 +228,9 @@ public class AddActionTest {
 
   @Test
   public void fail_when_notification_already_exists() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     call(NOTIF_MY_NEW_ISSUES, null, null, null);
 
     expectedException.expect(IllegalArgumentException.class);
@@ -227,8 +248,12 @@ public class AddActionTest {
 
   @Test
   public void fail_when_unknown_global_dispatcher() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1, Dispatcher2, Dispatcher3]");
+    expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1]");
 
     call("Dispatcher42", null, null, null);
   }
@@ -236,22 +261,28 @@ public class AddActionTest {
   @Test
   public void fail_when_unknown_project_dispatcher_on_private_project() {
     ComponentDto project = db.components().insertPrivateProject();
-    userSession.addProjectPermission(UserRole.USER, project);
+    userSession.addProjectPermission(USER, project);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES));
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1, Dispatcher3]");
+    expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1, Dispatcher2]");
 
-    call("Dispatcher42", null, project.getDbKey(), null);
+    call("Dispatcher42", null, project.getKey(), null);
   }
 
   @Test
   public void fail_when_unknown_project_dispatcher_on_public_project() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
     ComponentDto project = db.components().insertPublicProject();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES));
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1, Dispatcher3]");
+    expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1, Dispatcher2]");
 
-    call("Dispatcher42", null, project.getDbKey(), null);
+    call("Dispatcher42", null, project.getKey(), null);
   }
 
   @Test
@@ -263,6 +294,11 @@ public class AddActionTest {
 
   @Test
   public void fail_when_project_is_unknown() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     expectedException.expect(NotFoundException.class);
 
     call(NOTIF_MY_NEW_ISSUES, null, "Project-42", null);
@@ -270,7 +306,11 @@ public class AddActionTest {
 
   @Test
   public void fail_when_component_is_not_a_project() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
     db.components().insertViewAndSnapshot(newView(db.organizations().insert()).setDbKey("VIEW_1"));
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(BadRequestException.class);
     expectedException.expectMessage("Component 'VIEW_1' must be a project");
@@ -281,6 +321,7 @@ public class AddActionTest {
   @Test
   public void fail_when_not_authenticated() {
     userSession.anonymous();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(UnauthorizedException.class);
 
@@ -289,6 +330,9 @@ public class AddActionTest {
 
   @Test
   public void fail_when_using_branch_db_key() throws Exception {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertMainBranch();
     ComponentDto branch = db.components().insertProjectBranch(project);
 
@@ -302,6 +346,8 @@ public class AddActionTest {
   public void fail_when_user_does_not_have_USER_permission_on_private_project() {
     ComponentDto project = db.components().insertPrivateProject();
     userSession.logIn().setNonRoot().setNonSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(ForbiddenException.class);
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/notification/ws/DispatchersImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/notification/ws/DispatchersImplTest.java
new file mode 100644 (file)
index 0000000..1ea655d
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.notification.ws;
+
+import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.server.event.NewAlerts;
+import org.sonar.server.issue.notification.DoNotFixNotificationDispatcher;
+import org.sonar.server.issue.notification.MyNewIssuesNotificationDispatcher;
+import org.sonar.server.issue.notification.NewIssuesNotificationDispatcher;
+import org.sonar.server.notification.NotificationCenter;
+import org.sonar.server.notification.NotificationDispatcherMetadata;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
+import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
+
+public class DispatchersImplTest {
+
+  private NotificationCenter notificationCenter = new NotificationCenter(
+    new NotificationDispatcherMetadata[] {
+      NotificationDispatcherMetadata.create(MyNewIssuesNotificationDispatcher.KEY)
+        .setProperty(GLOBAL_NOTIFICATION, "true")
+        .setProperty(PER_PROJECT_NOTIFICATION, "true"),
+      NotificationDispatcherMetadata.create(NewIssuesNotificationDispatcher.KEY)
+        .setProperty(GLOBAL_NOTIFICATION, "true"),
+      NotificationDispatcherMetadata.create(NewAlerts.KEY)
+        .setProperty(GLOBAL_NOTIFICATION, "true")
+        .setProperty(PER_PROJECT_NOTIFICATION, "true"),
+      NotificationDispatcherMetadata.create(DoNotFixNotificationDispatcher.KEY)
+        .setProperty(GLOBAL_NOTIFICATION, "true")
+        .setProperty(PER_PROJECT_NOTIFICATION, "true")
+    },
+    new NotificationChannel[] {});
+
+  private final MapSettings settings = new MapSettings();
+
+  private DispatchersImpl underTest = new DispatchersImpl(notificationCenter, settings.asConfig());
+
+  @Test
+  public void get_sorted_global_dispatchers() {
+    underTest.start();
+
+    assertThat(underTest.getGlobalDispatchers()).containsExactly(
+      NewAlerts.KEY, DoNotFixNotificationDispatcher.KEY, NewIssuesNotificationDispatcher.KEY, MyNewIssuesNotificationDispatcher.KEY);
+  }
+
+  @Test
+  public void get_global_dispatchers_on_sonar_cloud() {
+    settings.setProperty("sonar.sonarcloud.enabled", "true");
+
+    underTest.start();
+
+    assertThat(underTest.getGlobalDispatchers()).containsOnly(MyNewIssuesNotificationDispatcher.KEY);
+  }
+
+  @Test
+  public void get_sorted_project_dispatchers() {
+    underTest.start();
+
+    assertThat(underTest.getProjectDispatchers()).containsExactly(
+      NewAlerts.KEY, DoNotFixNotificationDispatcher.KEY, MyNewIssuesNotificationDispatcher.KEY);
+  }
+
+  @Test
+  public void get_project_dispatchers_on_sonar_cloud() {
+    settings.setProperty("sonar.sonarcloud.enabled", "true");
+
+    underTest.start();
+
+    assertThat(underTest.getProjectDispatchers()).containsOnly(
+      MyNewIssuesNotificationDispatcher.KEY, NewAlerts.KEY, DoNotFixNotificationDispatcher.KEY);
+  }
+}
index 00affd980b1bc67c481b3f15ae017032a0dbcf74..f909bc781e775575d8ca0e183756529e7d3eca37 100644 (file)
  */
 package org.sonar.server.notification.ws;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.notifications.NotificationChannel;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.permission.UserPermissionDto;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
@@ -45,10 +41,13 @@ import org.sonar.server.ws.WsActionTester;
 import org.sonarqube.ws.Notifications.ListResponse;
 import org.sonarqube.ws.Notifications.Notification;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.test.JsonAssert.assertJson;
 
@@ -60,7 +59,7 @@ public class ListActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
   @Rule
-  public UserSessionRule userSession;
+  public UserSessionRule userSession = UserSessionRule.standalone();
   @Rule
   public DbTester db = DbTester.create();
 
@@ -69,36 +68,20 @@ public class ListActionTest {
 
   private NotificationChannel emailChannel = new FakeNotificationChannel("EmailChannel");
   private NotificationChannel twitterChannel = new FakeNotificationChannel("TwitterChannel");
-  private UserDto user;
-
-  private NotificationUpdater notificationUpdater;
-
-  private WsActionTester ws;
-
-  @Before
-  public void setUp() {
-    NotificationDispatcherMetadata metadata1 = NotificationDispatcherMetadata.create(NOTIF_MY_NEW_ISSUES)
-      .setProperty(GLOBAL_NOTIFICATION, "true")
-      .setProperty(PER_PROJECT_NOTIFICATION, "true");
-    NotificationDispatcherMetadata metadata2 = NotificationDispatcherMetadata.create(NOTIF_NEW_ISSUES)
-      .setProperty(GLOBAL_NOTIFICATION, "true");
-    NotificationDispatcherMetadata metadata3 = NotificationDispatcherMetadata.create(NOTIF_NEW_QUALITY_GATE_STATUS)
-      .setProperty(GLOBAL_NOTIFICATION, "true")
-      .setProperty(PER_PROJECT_NOTIFICATION, "true");
-
-    user = db.users().insertUser();
-    userSession = UserSessionRule.standalone().logIn(user);
-
-    NotificationCenter notificationCenter = new NotificationCenter(
-      new NotificationDispatcherMetadata[] {metadata1, metadata2, metadata3},
-      new NotificationChannel[] {emailChannel, twitterChannel});
-    notificationUpdater = new NotificationUpdater(dbClient);
-    ListAction underTest = new ListAction(notificationCenter, dbClient, userSession);
-    ws = new WsActionTester(underTest);
-  }
+
+  private NotificationUpdater notificationUpdater = new NotificationUpdater(dbClient);
+  private Dispatchers dispatchers = mock(Dispatchers.class);
+
+  private WsActionTester ws = new WsActionTester(new ListAction(new NotificationCenter(
+    new NotificationDispatcherMetadata[] {},
+    new NotificationChannel[] {emailChannel, twitterChannel}),
+    dbClient, userSession, dispatchers));
 
   @Test
   public void channels() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+
     ListResponse result = call();
 
     assertThat(result.getChannelsList()).containsExactly(emailChannel.getKey(), twitterChannel.getKey());
@@ -106,6 +89,10 @@ public class ListActionTest {
 
   @Test
   public void overall_dispatchers() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+
     ListResponse result = call();
 
     assertThat(result.getGlobalTypesList()).containsExactly(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS);
@@ -113,6 +100,10 @@ public class ListActionTest {
 
   @Test
   public void per_project_dispatchers() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+
     ListResponse result = call();
 
     assertThat(result.getPerProjectTypesList()).containsExactly(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS);
@@ -120,7 +111,12 @@ public class ListActionTest {
 
   @Test
   public void filter_unauthorized_projects() {
-    ComponentDto project = addComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("K1"));
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    ComponentDto project = db.components().insertPrivateProject();
+    db.users().insertProjectPermissionOnUser(user, USER, project);
     ComponentDto anotherProject = db.components().insertPrivateProject();
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, project);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, anotherProject);
@@ -128,11 +124,14 @@ public class ListActionTest {
 
     ListResponse result = call();
 
-    assertThat(result.getNotificationsList()).extracting(Notification::getProject).containsOnly("K1");
+    assertThat(result.getNotificationsList()).extracting(Notification::getProject).containsOnly(project.getKey());
   }
 
   @Test
   public void filter_channels() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, "Unknown Channel", NOTIF_MY_NEW_ISSUES, user, null);
     dbSession.commit();
@@ -144,6 +143,9 @@ public class ListActionTest {
 
   @Test
   public void filter_overall_dispatchers() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), "Unknown Notification", user, null);
     dbSession.commit();
@@ -155,7 +157,11 @@ public class ListActionTest {
 
   @Test
   public void filter_per_project_dispatchers() {
-    ComponentDto project = addComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("K1"));
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    ComponentDto project = db.components().insertPrivateProject();
+    db.users().insertProjectPermissionOnUser(user, USER, project);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, project);
     notificationUpdater.add(dbSession, emailChannel.getKey(), "Unknown Notification", user, project);
     dbSession.commit();
@@ -169,8 +175,13 @@ public class ListActionTest {
 
   @Test
   public void order_with_global_then_by_channel_and_dispatcher() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
     OrganizationDto organization = db.organizations().insert();
-    ComponentDto project = addComponent(ComponentTesting.newPrivateProjectDto(organization).setDbKey("K1"));
+    ComponentDto project = db.components().insertPrivateProject(organization);
+    db.users().insertProjectPermissionOnUser(user, USER, project);
     notificationUpdater.add(dbSession, twitterChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_NEW_ISSUES, user, null);
@@ -187,15 +198,16 @@ public class ListActionTest {
         tuple(emailChannel.getKey(), "", NOTIF_MY_NEW_ISSUES, ""),
         tuple(emailChannel.getKey(), "", NOTIF_NEW_ISSUES, ""),
         tuple(twitterChannel.getKey(), "", NOTIF_MY_NEW_ISSUES, ""),
-        tuple(emailChannel.getKey(), organization.getKey(), NOTIF_MY_NEW_ISSUES, "K1"),
-        tuple(emailChannel.getKey(), organization.getKey(), NOTIF_NEW_QUALITY_GATE_STATUS, "K1"),
-        tuple(twitterChannel.getKey(), organization.getKey(), NOTIF_MY_NEW_ISSUES, "K1"));
+        tuple(emailChannel.getKey(), organization.getKey(), NOTIF_MY_NEW_ISSUES, project.getKey()),
+        tuple(emailChannel.getKey(), organization.getKey(), NOTIF_NEW_QUALITY_GATE_STATUS, project.getKey()),
+        tuple(twitterChannel.getKey(), organization.getKey(), NOTIF_MY_NEW_ISSUES, project.getKey()));
   }
 
   @Test
   public void list_user_notifications_as_system_admin() {
-    userSession.logIn().setSystemAdministrator();
-
+    UserDto user = db.users().insertUser();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+    userSession.logIn(user).setSystemAdministrator();
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_NEW_ISSUES, user, null);
     dbSession.commit();
@@ -209,7 +221,9 @@ public class ListActionTest {
 
   @Test
   public void fail_if_login_and_not_system_admin() {
-    userSession.logIn().setNonSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user).setNonSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     dbSession.commit();
 
@@ -230,8 +244,13 @@ public class ListActionTest {
 
   @Test
   public void json_example() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
     OrganizationDto organization = db.organizations().insertForKey("my-org-1");
-    ComponentDto project = addComponent(ComponentTesting.newPrivateProjectDto(organization).setDbKey(KEY_PROJECT_EXAMPLE_001).setName("My Project"));
+    ComponentDto project = db.components().insertPrivateProject(organization, p -> p.setDbKey(KEY_PROJECT_EXAMPLE_001).setName("My Project"));
+    db.users().insertProjectPermissionOnUser(user, USER, project);
     notificationUpdater.add(dbSession, twitterChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_NEW_ISSUES, user, null);
@@ -279,14 +298,6 @@ public class ListActionTest {
     return ws.newRequest().setParam("login", login).executeProtobuf(ListResponse.class);
   }
 
-  private ComponentDto addComponent(ComponentDto component) {
-    db.components().insertComponent(component);
-    dbClient.userPermissionDao().insert(dbSession, new UserPermissionDto(component.getOrganizationUuid(), UserRole.USER, user.getId(), component.getId()));
-    db.commit();
-
-    return component;
-  }
-
   private static class FakeNotificationChannel extends NotificationChannel {
     private final String key;
 
index 6164a893750f4f14cb71c7808e51bc0d22887127..792269526c6ef54bb89c0580c824f42f1c8d5b80 100644 (file)
@@ -29,6 +29,6 @@ public class NotificationWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new NotificationWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(4 + 2);
+    assertThat(container.size()).isEqualTo(5 + 2);
   }
 }
index a21bfa28eb345200c5484bdd65e61d291fcd178e..f94dce62d3d0682b09cb8a7366faa1dad3eb2e6f 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.notification.ws;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -46,11 +45,13 @@ import org.sonar.server.ws.WsActionTester;
 
 import static java.lang.String.format;
 import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.db.component.ComponentTesting.newView;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
-import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_CHANNEL;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_LOGIN;
 import static org.sonar.server.notification.ws.NotificationsWsParameters.PARAM_PROJECT;
@@ -63,7 +64,7 @@ public class RemoveActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
   @Rule
-  public UserSessionRule userSession;
+  public UserSessionRule userSession = UserSessionRule.standalone();
   @Rule
   public DbTester db = DbTester.create();
   private DbClient dbClient = db.getDbClient();
@@ -74,39 +75,20 @@ public class RemoveActionTest {
   // default channel, based on class simple name
   private NotificationChannel defaultChannel = new FakeNotificationChannel("EmailNotificationChannel");
 
-  private NotificationCenter notificationCenter;
-  private NotificationUpdater notificationUpdater;
-  private RemoveAction underTest;
+  private NotificationUpdater notificationUpdater = new NotificationUpdater(dbClient);
+  private Dispatchers dispatchers = mock(Dispatchers.class);
 
-  private WsActionTester ws;
   private RemoveRequest request = new RemoveRequest().setType(NOTIF_MY_NEW_ISSUES);
 
-  private UserDto user;
-
-  @Before
-  public void setUp() {
-    user = db.users().insertUser();
-    userSession = UserSessionRule.standalone().logIn(user);
-
-    NotificationDispatcherMetadata metadata1 = NotificationDispatcherMetadata.create(NOTIF_MY_NEW_ISSUES)
-      .setProperty(GLOBAL_NOTIFICATION, "true")
-      .setProperty(PER_PROJECT_NOTIFICATION, "true");
-    NotificationDispatcherMetadata metadata2 = NotificationDispatcherMetadata.create(NOTIF_NEW_ISSUES)
-      .setProperty(GLOBAL_NOTIFICATION, "true");
-    NotificationDispatcherMetadata metadata3 = NotificationDispatcherMetadata.create(NOTIF_NEW_QUALITY_GATE_STATUS)
-      .setProperty(GLOBAL_NOTIFICATION, "true")
-      .setProperty(PER_PROJECT_NOTIFICATION, "true");
-
-    notificationCenter = new NotificationCenter(
-      new NotificationDispatcherMetadata[] {metadata1, metadata2, metadata3},
-      new NotificationChannel[] {emailChannel, twitterChannel, defaultChannel});
-    notificationUpdater = new NotificationUpdater(dbClient);
-    underTest = new RemoveAction(notificationCenter, notificationUpdater, dbClient, TestComponentFinder.from(db), userSession);
-    ws = new WsActionTester(underTest);
-  }
+  private WsActionTester ws = new WsActionTester(new RemoveAction(new NotificationCenter(
+    new NotificationDispatcherMetadata[] {},
+    new NotificationChannel[] {emailChannel, twitterChannel, defaultChannel}), notificationUpdater, dispatchers, dbClient, TestComponentFinder.from(db), userSession));
 
   @Test
   public void remove_to_email_channel_by_default() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     dbSession.commit();
 
@@ -117,6 +99,9 @@ public class RemoveActionTest {
 
   @Test
   public void remove_from_a_specific_channel() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_NEW_QUALITY_GATE_STATUS));
     notificationUpdater.add(dbSession, twitterChannel.getKey(), NOTIF_NEW_QUALITY_GATE_STATUS, user, null);
     dbSession.commit();
 
@@ -127,6 +112,10 @@ public class RemoveActionTest {
 
   @Test
   public void remove_a_project_notification() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertPrivateProject();
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, project);
     dbSession.commit();
@@ -138,6 +127,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_remove_a_global_notification_when_a_project_one_exists() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertPrivateProject();
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, project);
     dbSession.commit();
@@ -150,6 +143,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_remove_a_project_notification_when_a_global_one_exists() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertPrivateProject();
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     dbSession.commit();
@@ -162,6 +159,10 @@ public class RemoveActionTest {
 
   @Test
   public void http_no_content() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     dbSession.commit();
 
@@ -172,6 +173,9 @@ public class RemoveActionTest {
 
   @Test
   public void remove_a_notification_from_a_user_as_system_administrator() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     db.notifications().assertExists(defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user.getId(), null);
     userSession.logIn().setSystemAdministrator();
@@ -184,7 +188,9 @@ public class RemoveActionTest {
 
   @Test
   public void fail_if_login_is_provided_and_unknown() {
-    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user).setSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("User 'LOGIN 404' not found");
@@ -194,7 +200,9 @@ public class RemoveActionTest {
 
   @Test
   public void fail_if_login_provided_and_not_system_administrator() {
-    userSession.logIn().setNonSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user).setNonSystemAdministrator();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     notificationUpdater.add(dbSession, defaultChannel.getKey(), NOTIF_MY_NEW_ISSUES, user, null);
     dbSession.commit();
 
@@ -205,6 +213,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_notification_does_not_exist() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Notification doesn't exist");
 
@@ -213,6 +225,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_unknown_channel() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     expectedException.expect(IllegalArgumentException.class);
 
     call(request.setChannel("Channel42"));
@@ -220,6 +236,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_unknown_global_dispatcher() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
+
     expectedException.expect(BadRequestException.class);
     expectedException.expectMessage("Value of parameter 'type' (Dispatcher42) must be one of: [Dispatcher1, Dispatcher2, Dispatcher3]");
 
@@ -228,6 +248,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_unknown_project_dispatcher() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(asList(NOTIF_MY_NEW_ISSUES, NOTIF_NEW_QUALITY_GATE_STATUS));
     ComponentDto project = db.components().insertPrivateProject();
 
     expectedException.expect(BadRequestException.class);
@@ -237,14 +261,24 @@ public class RemoveActionTest {
   }
 
   @Test
-  public void fail_when_no_dispatcher() {
+  public void fail_when_no_type_parameter() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("The 'type' parameter is missing");
 
     ws.newRequest().execute();
   }
 
   @Test
   public void fail_when_project_is_unknown() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+
     expectedException.expect(NotFoundException.class);
 
     call(request.setProject("Project-42"));
@@ -252,6 +286,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_component_is_not_a_project() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     db.components().insertViewAndSnapshot(newView(db.organizations().insert()).setDbKey("VIEW_1"));
 
     expectedException.expect(BadRequestException.class);
@@ -263,6 +301,7 @@ public class RemoveActionTest {
   @Test
   public void fail_when_not_authenticated() {
     userSession.anonymous();
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
 
     expectedException.expect(UnauthorizedException.class);
 
@@ -271,6 +310,10 @@ public class RemoveActionTest {
 
   @Test
   public void fail_when_using_branch_db_key() throws Exception {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    when(dispatchers.getGlobalDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
+    when(dispatchers.getProjectDispatchers()).thenReturn(singletonList(NOTIF_MY_NEW_ISSUES));
     ComponentDto project = db.components().insertMainBranch();
     ComponentDto branch = db.components().insertProjectBranch(project);
 
index d4310413a0bd20729e72eebba4c1e46e5ced82e5..72983d3761ffdc6f9289ed681685cbb7a6114e90 100644 (file)
@@ -24,7 +24,6 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
@@ -65,7 +64,6 @@ public class SearchActionTest {
   public DbTester db = DbTester.create();
 
   private DbClient dbClient = db.getDbClient();
-  private DbSession dbSession = db.getSession();
   private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
 
   private SearchAction underTest = new SearchAction(dbClient, userSession, new QualityGateFinder(dbClient),
index 5c1490a1063f3c69715f4c8f8b6dd1bb908be254..9036782894811e235f1a0c581ac2525811929a97 100644 (file)
@@ -56,8 +56,10 @@ public class WebServiceEngineTest {
   @Test
   public void load_ws_definitions_at_startup() {
     WebServiceEngine underTest = new WebServiceEngine(new WebService[] {
-      newWs("api/foo/index", a -> {}),
-      newWs("api/bar/index", a -> {})
+      newWs("api/foo/index", a -> {
+      }),
+      newWs("api/bar/index", a -> {
+      })
     });
     underTest.start();
     try {
@@ -204,8 +206,7 @@ public class WebServiceEngineTest {
   public void fail_if_reading_an_undefined_parameter() {
     Request request = new TestRequest().setPath("api/foo").setParam("unknown", "Unknown");
 
-    DumbResponse response = run(request, newWs("api/foo", a ->
-      a.setHandler((req, resp) -> request.param("unknown"))));
+    DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> request.param("unknown"))));
 
     assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"BUG - parameter 'unknown' is undefined for action 'foo'\"}]}");
     assertThat(response.stream().status()).isEqualTo(400);
@@ -404,6 +405,18 @@ public class WebServiceEngineTest {
     assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Fail to process request api/foo");
   }
 
+  @Test
+  public void fail_when_start_in_not_called() {
+    Request request = new TestRequest().setPath("/api/ping");
+    DumbResponse response = new DumbResponse();
+    WebServiceEngine underTest = new WebServiceEngine(new WebService[] {newPingWs(a -> {
+    })});
+
+    underTest.execute(request, response);
+
+    assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Fail to process request /api/ping");
+  }
+
   private static WebService newWs(String path, Consumer<WebService.NewAction> consumer) {
     return context -> {
       WebService.NewController controller = context.createController(substringBeforeLast(path, "/"));
@@ -430,7 +443,7 @@ public class WebServiceEngineTest {
 
   private static DumbResponse run(Request request, WebService... webServices) {
     DumbResponse response = new DumbResponse();
-    return (DumbResponse)run(request, response, webServices);
+    return (DumbResponse) run(request, response, webServices);
   }
 
   private static Response run(Request request, Response response, WebService... webServices) {
index b29280ba12f3df4c42db2a02b098a19ea78d5297..89368b1488a40102e0e6d8568128ca9838940e59 100644 (file)
@@ -28,7 +28,6 @@ import org.sonarqube.tests.settings.DeprecatedPropertiesWsTest;
 import org.sonarqube.tests.settings.EmailsTest;
 import org.sonarqube.tests.settings.PropertySetsTest;
 import org.sonarqube.tests.settings.SettingsTest;
-import org.sonarqube.tests.user.UsersPageTest;
 
 import static util.ItUtils.pluginArtifact;
 import static util.ItUtils.xooPlugin;
@@ -40,7 +39,6 @@ import static util.ItUtils.xooPlugin;
 @Deprecated
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-  UsersPageTest.class,
   BackgroundTasksTest.class,
   DeprecatedPropertiesWsTest.class,
   EmailsTest.class,
@@ -61,7 +59,6 @@ public class Category1Suite {
     // Used in SettingsTest.should_get_settings_default_value
     .addPlugin(pluginArtifact("server-plugin"))
 
-
     // Used in I18nTest
     .addPlugin(pluginArtifact("l10n-fr-pack"))
 
index 3745186d27a2bf5c3129c6319beea7851acc1f7b..332ef87afe1b40c1ffb5aaaebac65422478bcfff 100644 (file)
@@ -36,13 +36,6 @@ import org.sonarqube.tests.serverSystem.ServerSystemTest;
 import org.sonarqube.tests.serverSystem.SystemInfoTest;
 import org.sonarqube.tests.ui.UiExtensionsTest;
 import org.sonarqube.tests.ui.UiTest;
-import org.sonarqube.tests.user.BaseIdentityProviderTest;
-import org.sonarqube.tests.user.FavoritesWsTest;
-import org.sonarqube.tests.user.ForceAuthenticationTest;
-import org.sonarqube.tests.user.LocalAuthenticationTest;
-import org.sonarqube.tests.user.MyAccountPageTest;
-import org.sonarqube.tests.user.OAuth2IdentityProviderTest;
-import org.sonarqube.tests.user.RootUserInStandaloneModeTest;
 import org.sonarqube.tests.ws.WsLocalCallTest;
 import org.sonarqube.tests.ws.WsTest;
 
@@ -56,20 +49,10 @@ import static util.ItUtils.xooPlugin;
 @Deprecated
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-  // organization
-  RootUserInStandaloneModeTest.class,
   // server system
   ServerSystemTest.class,
   SystemInfoTest.class,
   PingTest.class,
-  // user
-  MyAccountPageTest.class,
-  FavoritesWsTest.class,
-  // authentication
-  ForceAuthenticationTest.class,
-  LocalAuthenticationTest.class,
-  BaseIdentityProviderTest.class,
-  OAuth2IdentityProviderTest.class,
   // analysis exclusion
   FileExclusionsTest.class,
   IssueExclusionsTest.class,
@@ -95,12 +78,6 @@ public class Category4Suite {
   public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv()
     .addPlugin(xooPlugin())
 
-    // Used in BaseIdentityProviderTest
-    .addPlugin(pluginArtifact("base-auth-plugin"))
-
-    // Used in OAuth2IdentityProviderTest
-    .addPlugin(pluginArtifact("oauth2-auth-plugin"))
-
     // Used in UiExtensionsTest
     .addPlugin(pluginArtifact("ui-extensions-plugin"))
 
@@ -113,7 +90,5 @@ public class Category4Suite {
     // reduce memory for Elasticsearch to 128M
     .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m")
 
-    .setServerProperty("sonar.web.javaAdditionalOpts", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8001")
-
     .build();
 }
index e445488536d8cc1d7a6ce00fce15f8ebd550d8f7..9ecf5aa4e3aa780efb924b01aecabdd619c4e0ef 100644 (file)
@@ -31,7 +31,6 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
 import org.sonarqube.qa.util.pageobjects.Navigation;
-import org.sonarqube.tests.Category4Suite;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.WsClient;
 import org.sonarqube.ws.client.users.CreateRequest;
@@ -51,7 +50,7 @@ import static util.selenium.Selenese.runSelenese;
 public class BaseIdentityProviderTest {
 
   @ClassRule
-  public static Orchestrator ORCHESTRATOR = Category4Suite.ORCHESTRATOR;
+  public static Orchestrator ORCHESTRATOR = UserSuite.ORCHESTRATOR;
 
   private static UserRule userRule = UserRule.from(ORCHESTRATOR);
 
index 55b09ea4b64da295dac16e3a4b75d6771391d538..0dac746ecd934488c163869157342e772dc51664 100644 (file)
@@ -25,7 +25,6 @@ import java.util.List;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
-import org.sonarqube.tests.Category4Suite;
 import org.sonarqube.ws.Favorites.Favorite;
 import org.sonarqube.ws.client.WsClient;
 import org.sonarqube.ws.client.favorites.AddRequest;
@@ -42,7 +41,8 @@ import static util.ItUtils.projectDir;
 public class FavoritesWsTest {
 
   @ClassRule
-  public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static final Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
+
   private static WsClient adminClient;
 
   @Before
index d3a4cb71cb704c9204ce7456872a5ab695ddae95..4bf5885476cfeebc320ad578c5186b00e5c58dc9 100644 (file)
 package org.sonarqube.tests.user;
 
 import com.sonar.orchestrator.Orchestrator;
-import org.sonarqube.tests.Category4Suite;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonarqube.qa.util.Tester;
+import org.sonarqube.qa.util.pageobjects.Navigation;
 import org.sonarqube.ws.Users.CreateWsResponse.User;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.PostRequest;
@@ -34,7 +34,6 @@ import org.sonarqube.ws.client.WsClient;
 import org.sonarqube.ws.client.WsConnector;
 import org.sonarqube.ws.client.WsRequest;
 import org.sonarqube.ws.client.WsResponse;
-import org.sonarqube.qa.util.pageobjects.Navigation;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonarqube.ws.client.WsRequest.Method.GET;
@@ -45,7 +44,7 @@ import static util.ItUtils.setServerProperty;
 public class ForceAuthenticationTest {
 
   @ClassRule
-  public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static final Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
 
   @Rule
   public Tester tester = new Tester(orchestrator).disableOrganizations();
index fc3707f322e8c644440d39506600d254d693e984..3f56905e7b23211da337f8c2b09998f9fac7c6c6 100644 (file)
@@ -29,7 +29,6 @@ import org.junit.Test;
 import org.sonarqube.qa.util.Tester;
 import org.sonarqube.qa.util.pageobjects.LoginPage;
 import org.sonarqube.qa.util.pageobjects.Navigation;
-import org.sonarqube.tests.Category4Suite;
 import org.sonarqube.ws.UserTokens;
 import org.sonarqube.ws.Users;
 import org.sonarqube.ws.Users.CreateWsResponse.User;
@@ -56,7 +55,7 @@ import static util.ItUtils.setServerProperty;
 public class LocalAuthenticationTest {
 
   @ClassRule
-  public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
 
   @Rule
   public Tester tester = new Tester(orchestrator).disableOrganizations();
index 226082b75b11a44376dd021bb9cb3c0d554ae7db..ec7ddee74746345c084fd4329cc0fa0a91730f82 100644 (file)
@@ -25,9 +25,8 @@ import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonarqube.qa.util.pageobjects.Navigation;
-import org.sonarqube.tests.Category4Suite;
 import org.sonarqube.qa.util.Tester;
+import org.sonarqube.qa.util.pageobjects.Navigation;
 import org.sonarqube.ws.Users.CreateWsResponse.User;
 import org.sonarqube.ws.client.PostRequest;
 
@@ -40,7 +39,7 @@ import static util.selenium.Selenese.runSelenese;
 public class MyAccountPageTest {
 
   @ClassRule
-  public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
 
   @Rule
   public Tester tester = new Tester(orchestrator).disableOrganizations();
diff --git a/tests/src/test/java/org/sonarqube/tests/user/NotificationsWsTest.java b/tests/src/test/java/org/sonarqube/tests/user/NotificationsWsTest.java
new file mode 100644 (file)
index 0000000..2dc9de4
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonarqube.tests.user;
+
+import com.sonar.orchestrator.Orchestrator;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.qa.util.Tester;
+import org.sonarqube.ws.Notifications;
+import org.sonarqube.ws.Notifications.Notification;
+import org.sonarqube.ws.Projects;
+import org.sonarqube.ws.Users;
+import org.sonarqube.ws.client.notifications.AddRequest;
+import org.sonarqube.ws.client.notifications.ListRequest;
+import org.sonarqube.ws.client.notifications.RemoveRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class NotificationsWsTest {
+
+  @ClassRule
+  public static final Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
+
+  @Rule
+  public Tester tester = new Tester(orchestrator).disableOrganizations();
+
+  @Test
+  public void list_notifications() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+
+    Notifications.ListResponse list = tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest());
+
+    assertThat(list.getNotificationsList()).isEmpty();
+    assertThat(list.getChannelsList()).containsExactlyInAnyOrder("EmailNotificationChannel");
+    assertThat(list.getGlobalTypesList()).containsExactlyInAnyOrder(
+      "CeReportTaskFailure", "ChangesOnMyIssue", "NewAlerts", "NewFalsePositiveIssue", "NewIssues", "SQ-MyNewIssues");
+    assertThat(list.getPerProjectTypesList()).containsExactlyInAnyOrder(
+      "CeReportTaskFailure", "ChangesOnMyIssue", "NewAlerts", "NewFalsePositiveIssue", "NewIssues", "SQ-MyNewIssues");
+  }
+
+  @Test
+  public void add_global_and_project_notifications() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+    Projects.CreateWsResponse.Project project = tester.projects().provision();
+
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList())
+      .extracting(Notification::getChannel, Notification::getType, Notification::getProject, Notification::getProjectName)
+      .containsExactlyInAnyOrder(
+        tuple("EmailNotificationChannel", "ChangesOnMyIssue", "", ""),
+        tuple("EmailNotificationChannel", "NewIssues", project.getKey(), project.getName()));
+  }
+
+  @Test
+  public void remove_global_and_project_notifications() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+    Projects.CreateWsResponse.Project project = tester.projects().provision();
+    // These 2 notifications will be removed
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+    // These 2 notifications will not be removed
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("NewAlerts"));
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("SQ-MyNewIssues").setProject(project.getKey()));
+
+    tester.as(user.getLogin()).wsClient().notifications().remove(new RemoveRequest().setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(user.getLogin()).wsClient().notifications().remove(new RemoveRequest().setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList())
+      .extracting(Notification::getType, Notification::getProject)
+      .containsExactlyInAnyOrder(
+        tuple("NewAlerts", ""),
+        tuple("SQ-MyNewIssues", project.getKey()));
+  }
+
+  @Test
+  public void add_global_and_project_notifications_on_another_user_as_a_system_administrator() {
+    Users.CreateWsResponse.User admin = tester.users().generateAdministratorOnDefaultOrganization();
+    Users.CreateWsResponse.User user = tester.users().generate();
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+    Projects.CreateWsResponse.Project project = tester.projects().provision();
+
+    tester.as(admin.getLogin()).wsClient().notifications().add(new AddRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(admin.getLogin()).wsClient().notifications().add(new AddRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    assertThat(tester.as(admin.getLogin()).wsClient().notifications().list(new ListRequest().setLogin(user.getLogin())).getNotificationsList())
+      .extracting(Notification::getChannel, Notification::getType, Notification::getProject, Notification::getProjectName)
+      .containsExactlyInAnyOrder(
+        tuple("EmailNotificationChannel", "ChangesOnMyIssue", "", ""),
+        tuple("EmailNotificationChannel", "NewIssues", project.getKey(), project.getName()));
+  }
+
+  @Test
+  public void remove_global_and_project_notifications_on_another_user_as_a_system_administrator() {
+    Users.CreateWsResponse.User admin = tester.users().generateAdministratorOnDefaultOrganization();
+    Users.CreateWsResponse.User user = tester.users().generate();
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+    Projects.CreateWsResponse.Project project = tester.projects().provision();
+    // These 2 notifications will be removed
+    tester.as(admin.getLogin()).wsClient().notifications().add(new AddRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(admin.getLogin()).wsClient().notifications().add(new AddRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+    // These 2 notifications will not be removed
+    tester.as(admin.getLogin()).wsClient().notifications().add(new AddRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("NewAlerts"));
+    tester.as(admin.getLogin()).wsClient().notifications().add(new AddRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("SQ-MyNewIssues").setProject(project.getKey()));
+
+    tester.as(admin.getLogin()).wsClient().notifications().remove(new RemoveRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(admin.getLogin()).wsClient().notifications().remove(new RemoveRequest().setLogin(user.getLogin()).setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    assertThat(tester.as(admin.getLogin()).wsClient().notifications().list(new ListRequest().setLogin(user.getLogin())).getNotificationsList())
+      .extracting(Notification::getType, Notification::getProject)
+      .containsExactlyInAnyOrder(
+        tuple("NewAlerts", ""),
+        tuple("SQ-MyNewIssues", project.getKey()));
+  }
+}
index 9ad8f1a79ccbd04368f2bcb24fbb94a6eb0b86c7..103b634ccd7b225100a27834fbd386c4e49f11e1 100644 (file)
@@ -33,7 +33,6 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.sonarqube.qa.util.Tester;
 import org.sonarqube.qa.util.pageobjects.Navigation;
-import org.sonarqube.tests.Category4Suite;
 import org.sonarqube.ws.Users.SearchWsResponse.User;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.permissions.AddUserRequest;
@@ -50,7 +49,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 public class OAuth2IdentityProviderTest {
 
   @ClassRule
-  public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
 
   private static String FAKE_PROVIDER_KEY = "fake-oauth2-id-provider";
 
index fcb1d62c868db74c4be6164293f096977c41a9e8..bb5fe85f6b3baa30a6028d1f2bbf8c69b9d25533 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonarqube.tests.user;
 
 import com.sonar.orchestrator.Orchestrator;
-import org.sonarqube.tests.Category4Suite;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
@@ -31,7 +30,7 @@ import static util.ItUtils.expectForbiddenError;
 public class RootUserInStandaloneModeTest {
 
   @ClassRule
-  public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
 
   @Rule
   public Tester tester = new Tester(orchestrator).disableOrganizations();
diff --git a/tests/src/test/java/org/sonarqube/tests/user/SonarCloudNotificationsWsTest.java b/tests/src/test/java/org/sonarqube/tests/user/SonarCloudNotificationsWsTest.java
new file mode 100644 (file)
index 0000000..f6426b4
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonarqube.tests.user;
+
+import com.sonar.orchestrator.Orchestrator;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.qa.util.Tester;
+import org.sonarqube.ws.Notifications;
+import org.sonarqube.ws.Notifications.Notification;
+import org.sonarqube.ws.Projects;
+import org.sonarqube.ws.Users;
+import org.sonarqube.ws.client.notifications.AddRequest;
+import org.sonarqube.ws.client.notifications.ListRequest;
+import org.sonarqube.ws.client.notifications.RemoveRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static util.ItUtils.expectHttpError;
+
+public class SonarCloudNotificationsWsTest {
+
+  @ClassRule
+  public static final Orchestrator orchestrator = SonarCloudUserSuite.ORCHESTRATOR;
+
+  @Rule
+  public Tester tester = new Tester(orchestrator);
+
+  @Test
+  public void list_notifications() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+
+    Notifications.ListResponse list = tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest());
+
+    assertThat(list.getNotificationsList()).isEmpty();
+    assertThat(list.getChannelsList()).containsExactlyInAnyOrder("EmailNotificationChannel");
+    assertThat(list.getGlobalTypesList())
+      .containsExactlyInAnyOrder(
+        "CeReportTaskFailure", "ChangesOnMyIssue", "SQ-MyNewIssues")
+      .doesNotContain("NewAlerts", "NewFalsePositiveIssue", "NewIssues");
+    assertThat(list.getPerProjectTypesList()).containsExactlyInAnyOrder(
+      "CeReportTaskFailure", "ChangesOnMyIssue", "NewAlerts", "NewFalsePositiveIssue", "NewIssues", "SQ-MyNewIssues");
+  }
+
+  @Test
+  public void add_global_and_project_notifications() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+    Projects.CreateWsResponse.Project project = tester.projects().provision();
+
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList())
+      .extracting(Notification::getChannel, Notification::getType, Notification::getProject, Notification::getProjectName)
+      .containsExactlyInAnyOrder(
+        tuple("EmailNotificationChannel", "ChangesOnMyIssue", "", ""),
+        tuple("EmailNotificationChannel", "NewIssues", project.getKey(), project.getName()));
+  }
+
+  @Test
+  public void remove_global_and_project_notifications() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+    Projects.CreateWsResponse.Project project = tester.projects().provision();
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    tester.as(user.getLogin()).wsClient().notifications().remove(new RemoveRequest().setChannel("EmailNotificationChannel").setType("ChangesOnMyIssue"));
+    tester.as(user.getLogin()).wsClient().notifications().remove(new RemoveRequest().setChannel("EmailNotificationChannel").setType("NewIssues").setProject(project.getKey()));
+
+    assertThat(tester.as(user.getLogin()).wsClient().notifications().list(new ListRequest()).getNotificationsList()).isEmpty();
+  }
+
+  @Test
+  public void fail_to_add_global_new_issues_notification() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+
+    expectHttpError(400,
+      "Value of parameter 'type' (NewIssues) must be one of: [CeReportTaskFailure, ChangesOnMyIssue, SQ-MyNewIssues]",
+      () -> tester.as(user.getLogin()).wsClient().notifications().add(new AddRequest().setChannel("EmailNotificationChannel").setType("NewIssues")));
+  }
+
+  @Test
+  public void fail_to_remove_global_new_issues_notification() {
+    Users.CreateWsResponse.User user = tester.users().generate();
+
+    expectHttpError(400,
+      "Value of parameter 'type' (NewIssues) must be one of: [CeReportTaskFailure, ChangesOnMyIssue, SQ-MyNewIssues]",
+      () -> tester.as(user.getLogin()).wsClient().notifications().remove(new RemoveRequest().setChannel("EmailNotificationChannel").setType("NewIssues")));
+  }
+}
diff --git a/tests/src/test/java/org/sonarqube/tests/user/SonarCloudUserSuite.java b/tests/src/test/java/org/sonarqube/tests/user/SonarCloudUserSuite.java
new file mode 100644 (file)
index 0000000..b14ad6d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonarqube.tests.user;
+
+import com.sonar.orchestrator.Orchestrator;
+import org.junit.ClassRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+import static util.ItUtils.xooPlugin;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  SonarCloudNotificationsWsTest.class
+})
+public class SonarCloudUserSuite {
+
+  @ClassRule
+  public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv()
+    .addPlugin(xooPlugin())
+
+    .setServerProperty("sonar.sonarcloud.enabled", "true")
+
+    // reduce memory for Elasticsearch
+    .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m")
+
+    .build();
+
+}
diff --git a/tests/src/test/java/org/sonarqube/tests/user/UserSuite.java b/tests/src/test/java/org/sonarqube/tests/user/UserSuite.java
new file mode 100644 (file)
index 0000000..d6b4ddb
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonarqube.tests.user;
+
+import com.sonar.orchestrator.Orchestrator;
+import org.junit.ClassRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+import static util.ItUtils.pluginArtifact;
+import static util.ItUtils.xooPlugin;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  BaseIdentityProviderTest.class,
+  FavoritesWsTest.class,
+  ForceAuthenticationTest.class,
+  LocalAuthenticationTest.class,
+  MyAccountPageTest.class,
+  NotificationsWsTest.class,
+  OAuth2IdentityProviderTest.class,
+  RootUserInStandaloneModeTest.class,
+  UsersPageTest.class
+})
+public class UserSuite {
+
+  @ClassRule
+  public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv()
+    .addPlugin(xooPlugin())
+
+    // Used in BaseIdentityProviderTest
+    .addPlugin(pluginArtifact("base-auth-plugin"))
+
+    // Used in OAuth2IdentityProviderTest
+    .addPlugin(pluginArtifact("oauth2-auth-plugin"))
+
+    // reduce memory for Elasticsearch
+    .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m")
+
+    .build();
+
+}
index a71f4305511831206a3d640a9ddc6824ca2f5fe0..072d9d0bfd319bce286b4b71c6faca378fc39ad1 100644 (file)
@@ -28,7 +28,6 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.sonarqube.qa.util.Tester;
 import org.sonarqube.qa.util.pageobjects.UsersManagementPage;
-import org.sonarqube.tests.Category1Suite;
 import org.sonarqube.ws.Users;
 import org.sonarqube.ws.Users.CreateWsResponse.User;
 import org.sonarqube.ws.client.users.GroupsRequest;
@@ -42,7 +41,7 @@ public class UsersPageTest {
   private User adminUser;
 
   @ClassRule
-  public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR;
+  public static Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
 
   @Rule
   public UserRule userRule = UserRule.from(orchestrator);