mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-03 06:18:43 +02:00
@@ -260,4 +260,13 @@ class MeDtoFactoryTest {
|
||||
MeDto dto = meDtoFactory.create();
|
||||
assertThat(dto.getLinks().getLinkBy("apiKeys")).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAppendNotificationsLink() {
|
||||
User user = UserTestData.createTrillian();
|
||||
prepareSubject(user);
|
||||
|
||||
MeDto dto = meDtoFactory.create();
|
||||
assertThat(dto.getLinks().getLinkBy("notifications").get().getHref()).isEqualTo("https://scm.hitchhiker.com/scm/v2/me/notifications");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,8 @@ public class MeResourceTest {
|
||||
private PasswordService passwordService;
|
||||
private User originalUser;
|
||||
|
||||
@Mock
|
||||
private NotificationResource notificationResource;
|
||||
|
||||
@Before
|
||||
public void prepareEnvironment() {
|
||||
@@ -127,7 +129,7 @@ public class MeResourceTest {
|
||||
when(userManager.getDefaultType()).thenReturn("xml");
|
||||
ApiKeyCollectionToDtoMapper apiKeyCollectionMapper = new ApiKeyCollectionToDtoMapper(apiKeyMapper, resourceLinks);
|
||||
ApiKeyResource apiKeyResource = new ApiKeyResource(apiKeyService, apiKeyCollectionMapper, apiKeyMapper, resourceLinks);
|
||||
MeResource meResource = new MeResource(meDtoFactory, userManager, passwordService, of(apiKeyResource));
|
||||
MeResource meResource = new MeResource(meDtoFactory, userManager, passwordService, of(apiKeyResource), of(notificationResource));
|
||||
when(uriInfo.getApiRestUri()).thenReturn(URI.create("/"));
|
||||
when(scmPathInfoStore.get()).thenReturn(uriInfo);
|
||||
dispatcher.addSingletonResource(meResource);
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.notifications.Notification;
|
||||
import sonia.scm.notifications.NotificationStore;
|
||||
import sonia.scm.notifications.StoredNotification;
|
||||
import sonia.scm.notifications.Type;
|
||||
import sonia.scm.sse.ChannelRegistry;
|
||||
import sonia.scm.web.RestDispatcher;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.Path;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class NotificationResourceTest {
|
||||
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Mock
|
||||
private NotificationStore store;
|
||||
|
||||
@Mock
|
||||
private ChannelRegistry channelRegistry;
|
||||
|
||||
private RestDispatcher dispatcher;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
dispatcher = new RestDispatcher();
|
||||
dispatcher.addSingletonResource(
|
||||
new TestingRootResource(
|
||||
new NotificationResource(store, channelRegistry)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAllNotifications() throws IOException, URISyntaxException {
|
||||
notifications("One", "Two", "Three");
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/api/v2/notifications");
|
||||
MockHttpResponse response = invoke(request);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
JsonNode node = mapper.readTree(response.getContentAsString());
|
||||
JsonNode notificationNodes = node.get("_embedded").get("notifications");
|
||||
assertThat(notificationNodes.get(0).get("message").asText()).isEqualTo("One");
|
||||
assertThat(notificationNodes.get(1).get("message").asText()).isEqualTo("Two");
|
||||
assertThat(notificationNodes.get(2).get("message").asText()).isEqualTo("Three");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnDismissLink() throws IOException, URISyntaxException {
|
||||
String id = notifications("One").get(0).getId();
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/api/v2/notifications");
|
||||
MockHttpResponse response = invoke(request);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
|
||||
JsonNode node = mapper.readTree(response.getContentAsString());
|
||||
String dismissHref = node.get("_embedded")
|
||||
.get("notifications")
|
||||
.get(0)
|
||||
.get("_links")
|
||||
.get("dismiss")
|
||||
.get("href")
|
||||
.asText();
|
||||
|
||||
assertThat(dismissHref).isEqualTo("/api/v2/notifications/" + id);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnCollectionLinks() throws IOException, URISyntaxException {
|
||||
notifications();
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/api/v2/notifications");
|
||||
MockHttpResponse response = invoke(request);
|
||||
|
||||
JsonNode node = mapper.readTree(response.getContentAsString());
|
||||
JsonNode links = node.get("_links");
|
||||
|
||||
assertThat(links.get("self").get("href").asText()).isEqualTo("/api/v2/notifications");
|
||||
assertThat(links.get("clear").get("href").asText()).isEqualTo("/api/v2/notifications");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRemoveNotification() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.delete("/api/v2/notifications/abc42");
|
||||
MockHttpResponse response = invoke(request);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_NO_CONTENT);
|
||||
|
||||
verify(store).remove("abc42");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldClear() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.delete("/api/v2/notifications");
|
||||
MockHttpResponse response = invoke(request);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_NO_CONTENT);
|
||||
verify(store).clear();
|
||||
}
|
||||
|
||||
private MockHttpResponse invoke(MockHttpRequest request) {
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private List<StoredNotification> notifications(String... messages) {
|
||||
List<StoredNotification> notifications = Arrays.stream(messages)
|
||||
.map(this::notification)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
when(store.getAll()).thenReturn(notifications);
|
||||
return notifications;
|
||||
}
|
||||
|
||||
private StoredNotification notification(String m) {
|
||||
return new StoredNotification(UUID.randomUUID().toString(), Type.INFO, "/notify", m, Instant.now());
|
||||
}
|
||||
|
||||
@Path("/api/v2")
|
||||
public static class TestingRootResource {
|
||||
|
||||
private final NotificationResource resource;
|
||||
|
||||
public TestingRootResource(NotificationResource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
@Path("notifications")
|
||||
public NotificationResource notifications() {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import sonia.scm.NotFoundException;
|
||||
import sonia.scm.PageResult;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.importexport.ExportFileExtensionResolver;
|
||||
import sonia.scm.importexport.ExportNotificationHandler;
|
||||
import sonia.scm.importexport.ExportService;
|
||||
import sonia.scm.importexport.ExportStatus;
|
||||
import sonia.scm.importexport.FromBundleImporter;
|
||||
@@ -160,6 +161,8 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
private ExportService exportService;
|
||||
@Mock
|
||||
private HealthCheckService healthCheckService;
|
||||
@Mock
|
||||
private ExportNotificationHandler notificationHandler;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<Predicate<Repository>> filterCaptor;
|
||||
@@ -182,7 +185,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
|
||||
super.repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks, repositoryInitializer);
|
||||
super.repositoryImportResource = new RepositoryImportResource(dtoToRepositoryMapper, resourceLinks, fullScmRepositoryImporter, new RepositoryImportDtoToRepositoryImportParametersMapperImpl(), repositoryImportExportEncryption, fromUrlImporter, fromBundleImporter, importLoggerFactory);
|
||||
super.repositoryExportResource = new RepositoryExportResource(repositoryManager, serviceFactory, fullScmRepositoryExporter, repositoryImportExportEncryption, exportService, exportInformationToDtoMapper, fileExtensionResolver, resourceLinks, new SimpleMeterRegistry());
|
||||
super.repositoryExportResource = new RepositoryExportResource(repositoryManager, serviceFactory, fullScmRepositoryExporter, repositoryImportExportEncryption, exportService, exportInformationToDtoMapper, fileExtensionResolver, resourceLinks, new SimpleMeterRegistry(), notificationHandler);
|
||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
doReturn(ImmutableSet.of(new CustomNamespaceStrategy()).iterator()).when(strategies).iterator();
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.importexport;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.notifications.NotificationSender;
|
||||
import sonia.scm.notifications.Type;
|
||||
import sonia.scm.repository.RepositoryTestData;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ExportNotificationHandlerTest {
|
||||
|
||||
@Mock
|
||||
private NotificationSender sender;
|
||||
|
||||
@InjectMocks
|
||||
private ExportNotificationHandler handler;
|
||||
|
||||
@Test
|
||||
void shouldSendFailedNotification() {
|
||||
handler.handleFailedExport(RepositoryTestData.create42Puzzle());
|
||||
|
||||
verify(sender).send(argThat(notification -> {
|
||||
assertThat(notification.getType()).isEqualTo(Type.ERROR);
|
||||
assertThat(notification.getLink()).isEqualTo("/repo/hitchhiker/42Puzzle/settings/general");
|
||||
assertThat(notification.getMessage()).isEqualTo("exportFailed");
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendSuccessfulNotification() {
|
||||
handler.handleSuccessfulExport(RepositoryTestData.create42Puzzle());
|
||||
|
||||
verify(sender).send(argThat(notification -> {
|
||||
assertThat(notification.getType()).isEqualTo(Type.SUCCESS);
|
||||
assertThat(notification.getLink()).isEqualTo("/repo/hitchhiker/42Puzzle/settings/general");
|
||||
assertThat(notification.getMessage()).isEqualTo("exportFinished");
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.notifications.Type;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryTestData;
|
||||
import sonia.scm.store.Blob;
|
||||
@@ -55,9 +56,11 @@ import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.importexport.ExportService.STORE_NAME;
|
||||
|
||||
@@ -75,6 +78,9 @@ class ExportServiceTest {
|
||||
@Mock
|
||||
private ExportFileExtensionResolver resolver;
|
||||
|
||||
@Mock
|
||||
private ExportNotificationHandler notificationHandler;
|
||||
|
||||
private BlobStore blobStore;
|
||||
private DataStore<RepositoryExportInformation> dataStore;
|
||||
|
||||
@@ -136,6 +142,7 @@ class ExportServiceTest {
|
||||
|
||||
exportService.setExportFinished(REPOSITORY);
|
||||
assertThat(exportService.isExporting(REPOSITORY)).isFalse();
|
||||
verify(notificationHandler).handleSuccessfulExport(REPOSITORY);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.notifications;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.sse.Channel;
|
||||
import sonia.scm.sse.ChannelRegistry;
|
||||
import sonia.scm.sse.Message;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DefaultNotificationSenderTest {
|
||||
|
||||
@Mock
|
||||
private NotificationStore store;
|
||||
|
||||
@Mock
|
||||
private ChannelRegistry channelRegistry;
|
||||
|
||||
@InjectMocks
|
||||
private DefaultNotificationSender sender;
|
||||
|
||||
@Mock
|
||||
private Channel channel;
|
||||
|
||||
@Test
|
||||
void shouldDelegateToStore() {
|
||||
when(channelRegistry.channel(any())).thenReturn(channel);
|
||||
|
||||
Notification notification = new Notification(Type.ERROR, "/fail", "Everything has failed");
|
||||
|
||||
sender.send(notification, "trillian");
|
||||
|
||||
verify(store).add(notification, "trillian");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendToChannel() {
|
||||
NotificationChannelId channelId = new NotificationChannelId("trillian");
|
||||
when(channelRegistry.channel(channelId)).thenReturn(channel);
|
||||
|
||||
Notification notification = new Notification(Type.WARNING, "/warn", "Everything looks strange");
|
||||
|
||||
sender.send(notification, "trillian");
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(channel).broadcast(messageCaptor.capture());
|
||||
|
||||
Message message = messageCaptor.getValue();
|
||||
assertThat(message.getName()).isEqualTo(DefaultNotificationSender.MESSAGE_NAME);
|
||||
assertThat(message.getType()).isEqualTo(Notification.class);
|
||||
assertThat(message.getData()).isEqualTo(notification);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.notifications;
|
||||
|
||||
import org.github.sdorra.jse.ShiroExtension;
|
||||
import org.github.sdorra.jse.SubjectAware;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.security.KeyGenerator;
|
||||
import sonia.scm.security.UUIDKeyGenerator;
|
||||
import sonia.scm.store.InMemoryByteDataStoreFactory;
|
||||
import sonia.scm.user.UserEvent;
|
||||
import sonia.scm.user.UserTestData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ExtendWith(ShiroExtension.class)
|
||||
class NotificationStoreTest {
|
||||
|
||||
private NotificationStore store;
|
||||
private final KeyGenerator keyGenerator = new UUIDKeyGenerator();
|
||||
|
||||
private AtomicInteger counter;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
counter = new AtomicInteger();
|
||||
store = new NotificationStore(new InMemoryByteDataStoreFactory(), keyGenerator);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("trillian")
|
||||
void shouldAddNotification() {
|
||||
Notification notification = notification();
|
||||
|
||||
store.add(notification, "trillian");
|
||||
|
||||
containsMessage(notification);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("trillian")
|
||||
void shouldReturnId() {
|
||||
Notification notification = notification();
|
||||
|
||||
String id = store.add(notification, "trillian");
|
||||
assertThat(id).isNotNull().isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("trillian")
|
||||
void shouldAssignId() {
|
||||
Notification notification = notification();
|
||||
|
||||
store.add(notification, "trillian");
|
||||
|
||||
StoredNotification storedNotification = store.getAll().get(0);
|
||||
assertThat(storedNotification.getId()).isNotNull().isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("trillian")
|
||||
void shouldCopyProperties() {
|
||||
Notification notification = notification();
|
||||
|
||||
store.add(notification, "trillian");
|
||||
|
||||
StoredNotification storedNotification = store.getAll().get(0);
|
||||
assertThat(storedNotification)
|
||||
.usingRecursiveComparison()
|
||||
.ignoringFields("id")
|
||||
.isEqualTo(notification);
|
||||
}
|
||||
|
||||
private void containsMessage(Notification... notifications) {
|
||||
String[] messages = Arrays.stream(notifications).map(Notification::getMessage).toArray(String[]::new);
|
||||
Stream<String> storedMessages = store.getAll().stream().map(StoredNotification::getMessage);
|
||||
assertThat(storedMessages).containsOnly(messages);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("trillian")
|
||||
void shouldOnlyReturnNotificationsForPrincipal() {
|
||||
Notification one = notification();
|
||||
Notification two = notification();
|
||||
Notification three = notification();
|
||||
|
||||
store.add(one, "trillian");
|
||||
store.add(two, "dent");
|
||||
store.add(three, "trillian");
|
||||
|
||||
containsMessage(one, three);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("slarti")
|
||||
void shouldClearOnlyPrincipalNotifications() {
|
||||
Notification one = notification();
|
||||
Notification two = notification();
|
||||
Notification three = notification();
|
||||
|
||||
store.add(one, "slarti");
|
||||
store.add(two, "slarti");
|
||||
store.add(three, "slarti");
|
||||
|
||||
store.clear();
|
||||
assertThat(store.getAll()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("slarti")
|
||||
void shouldRemoveNotificationWithId() {
|
||||
Notification one = notification();
|
||||
Notification two = notification();
|
||||
|
||||
String id = store.add(one, "slarti");
|
||||
store.add(two, "slarti");
|
||||
|
||||
store.remove(id);
|
||||
|
||||
containsMessage(two);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SubjectAware("slarti")
|
||||
void shouldRemoveEntryIfUserIsDeleted() {
|
||||
store.add(notification(), "slarti");
|
||||
store.handle(new UserEvent(HandlerEventType.DELETE, UserTestData.createSlarti()));
|
||||
|
||||
assertThat(store.getAll()).isEmpty();
|
||||
}
|
||||
|
||||
@SubjectAware("slarti")
|
||||
@ParameterizedTest(name = "shouldIgnoreEvent_{argumentsWithNames}")
|
||||
@EnumSource(value = HandlerEventType.class, mode = EnumSource.Mode.EXCLUDE, names = "DELETE")
|
||||
void shouldIgnoreNonDeleteEvents(HandlerEventType event) {
|
||||
store.add(notification(), "slarti");
|
||||
store.handle(new UserEvent(event, UserTestData.createSlarti()));
|
||||
|
||||
assertThat(store.getAll()).hasSize(1);
|
||||
}
|
||||
|
||||
private Notification notification() {
|
||||
return new Notification(Type.INFO, "/greeting", "Hello " + counter.incrementAndGet());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user