Notifications for health checks (#1664)

Add list of emergency contacts to global configuration. This user will receive e-mails and notification if some serious system error occurs like repository health check failed.
This commit is contained in:
Florian Scholdei
2021-05-20 08:30:20 +02:00
committed by GitHub
parent cb6806a36f
commit 42745c9e34
24 changed files with 551 additions and 405 deletions

View File

@@ -44,6 +44,7 @@ public class ConfigDtoToScmConfigurationMapperTest {
private ConfigDtoToScmConfigurationMapperImpl mapper;
private final String[] expectedExcludes = {"ex", "clude"};
private final String[] expectedUsers = {"trillian", "arthur"};
@Before
public void init() {
@@ -76,6 +77,7 @@ public class ConfigDtoToScmConfigurationMapperTest {
assertEquals("username", config.getNamespaceStrategy());
assertEquals("https://scm-manager.org/login-info", config.getLoginInfoUrl());
assertEquals("hitchhiker.mail", config.getMailDomainName());
assertTrue("emergencyContacts", config.getEmergencyContacts().containsAll(Arrays.asList(expectedUsers)));
}
@Test
@@ -115,6 +117,7 @@ public class ConfigDtoToScmConfigurationMapperTest {
configDto.setNamespaceStrategy("username");
configDto.setLoginInfoUrl("https://scm-manager.org/login-info");
configDto.setMailDomainName("hitchhiker.mail");
configDto.setEmergencyContacts(Sets.newSet(expectedUsers));
configDto.setEnabledUserConverter(false);
return configDto;

View File

@@ -49,11 +49,10 @@ import static org.mockito.MockitoAnnotations.initMocks;
public class ScmConfigurationToConfigDtoMapperTest {
private URI baseUri = URI.create("http://example.com/base/");
private final URI baseUri = URI.create("http://example.com/base/");
private String[] expectedUsers = {"trillian", "arthur"};
private String[] expectedGroups = {"admin", "plebs"};
private String[] expectedExcludes = {"ex", "clude"};
private final String[] expectedExcludes = {"ex", "clude"};
private final String[] expectedUsers = {"trillian", "arthur"};
@SuppressWarnings("unused") // Is injected
private ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
@@ -107,6 +106,7 @@ public class ScmConfigurationToConfigDtoMapperTest {
assertEquals("https://scm-manager.org/login-info", dto.getLoginInfoUrl());
assertEquals("https://www.scm-manager.org/download/rss.xml", dto.getReleaseFeedUrl());
assertEquals("scm-manager.local", dto.getMailDomainName());
assertTrue("emergencyContacts", dto.getEmergencyContacts().containsAll(Arrays.asList(expectedUsers)));
assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("self").get().getHref());
assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("update").get().getHref());
@@ -161,6 +161,7 @@ public class ScmConfigurationToConfigDtoMapperTest {
config.setNamespaceStrategy("username");
config.setLoginInfoUrl("https://scm-manager.org/login-info");
config.setReleaseFeedUrl("https://www.scm-manager.org/download/rss.xml");
config.setEmergencyContacts(Sets.newSet(expectedUsers));
return config;
}

View File

@@ -24,6 +24,7 @@
package sonia.scm.repository;
import com.google.common.collect.ImmutableSet;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
@@ -35,6 +36,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.NotFoundException;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.notifications.NotificationSender;
import sonia.scm.repository.api.Command;
import sonia.scm.repository.api.FullHealthCheckCommandBuilder;
import sonia.scm.repository.api.RepositoryService;
@@ -47,11 +50,14 @@ import static com.google.common.collect.ImmutableSet.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -74,6 +80,10 @@ class HealthCheckerTest {
private RepositoryService repositoryService;
@Mock
private RepositoryPostProcessor postProcessor;
@Mock
private ScmConfiguration scmConfiguration;
@Mock
private NotificationSender notificationSender;
@Mock
private Subject subject;
@@ -82,7 +92,7 @@ class HealthCheckerTest {
@BeforeEach
void initializeChecker() {
this.checker = new HealthChecker(of(healthCheck1, healthCheck2), repositoryManager, repositoryServiceFactory, postProcessor);
this.checker = new HealthChecker(of(healthCheck1, healthCheck2), repositoryManager, repositoryServiceFactory, postProcessor, scmConfiguration, notificationSender);
}
@BeforeEach
@@ -182,6 +192,7 @@ class HealthCheckerTest {
void setUpRepository() {
lenient().when(repositoryServiceFactory.create(repository)).thenReturn(repositoryService);
lenient().when(repositoryService.getFullCheckCommand()).thenReturn(fullHealthCheckCommand);
lenient().when(subject.getPrincipal()).thenReturn("trillian");
}
@Test
@@ -240,6 +251,32 @@ class HealthCheckerTest {
return true;
}));
}
@Test
void shouldNotifyCurrentUserOnlyOnce() throws IOException {
when(scmConfiguration.getEmergencyContacts()).thenReturn(ImmutableSet.of("trillian"));
when(healthCheck1.check(repository)).thenReturn(HealthCheckResult.healthy());
when(repositoryService.isSupported(Command.FULL_HEALTH_CHECK)).thenReturn(true);
when(fullHealthCheckCommand.check()).thenReturn(HealthCheckResult.unhealthy(createFailure("error")));
checker.fullCheck(repositoryId);
verify(notificationSender, never()).send(any());
verify(notificationSender,times(1)).send(any(), eq("trillian"));
}
@Test
void shouldNotifyEmergencyContacts() throws IOException {
when(scmConfiguration.getEmergencyContacts()).thenReturn(ImmutableSet.of("trillian", "Arthur"));
when(healthCheck1.check(repository)).thenReturn(HealthCheckResult.healthy());
when(repositoryService.isSupported(Command.FULL_HEALTH_CHECK)).thenReturn(true);
when(fullHealthCheckCommand.check()).thenReturn(HealthCheckResult.unhealthy(createFailure("error")));
checker.fullCheck(repositoryId);
verify(notificationSender).send(any(), eq("trillian"));
verify(notificationSender).send(any(), eq("Arthur"));
}
}
}