/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see <http://www.gnu.org/licenses/>.
*/
package org.graylog2.alerts;
import com.google.common.collect.ImmutableList;
import com.lordofthejars.nosqlunit.annotation.UsingDataSet;
import com.lordofthejars.nosqlunit.core.LoadStrategyEnum;
import org.graylog2.alarmcallbacks.AlarmCallbackHistory;
import org.graylog2.alarmcallbacks.AlarmCallbackHistoryService;
import org.graylog2.database.MongoDBServiceTest;
import org.graylog2.plugin.Tools;
import org.graylog2.plugin.alarms.AlertCondition;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Seconds;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class AlertServiceImplTest extends MongoDBServiceTest {
private final String ALERT_ID = "581b3bff8e4dc4270055dfca";
private final String STREAM_ID = "5666df42bee80072613ce14e";
private final String CONDITION_ID = "ae7fbc4e-81b1-41b3-bbe6-eaf58d89bff7";
private AlertServiceImpl alertService;
@Mock
private AlertConditionFactory alertConditionFactory;
@Mock
private AlarmCallbackHistoryService alarmCallbackHistoryService;
@Before
public void setUpService() throws Exception {
this.alarmCallbackHistoryService = mock(AlarmCallbackHistoryService.class);
this.alertService = new AlertServiceImpl(mongoRule.getMongoConnection(), mapperProvider, alertConditionFactory, alarmCallbackHistoryService);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void loadRecentOfStreamQueriesByDate() throws Exception {
final List<Alert> alerts = alertService.loadRecentOfStream(STREAM_ID, new DateTime(0L, DateTimeZone.UTC), 300);
assertThat(alerts.size()).isEqualTo(2);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void loadRecentOfStreamLimitResults() throws Exception {
final List<Alert> alerts = alertService.loadRecentOfStream(STREAM_ID, new DateTime(0L, DateTimeZone.UTC), 1);
assertThat(alerts.size()).isEqualTo(1);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void loadRecentOfStreamsIsEmptyIfNoStreams() throws Exception {
final List<Alert> alerts = alertService.loadRecentOfStreams(
ImmutableList.of(),
new DateTime(0L, DateTimeZone.UTC),
300);
assertThat(alerts.size()).isEqualTo(0);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void loadRecentOfStreamsFiltersByStream() throws Exception {
final List<Alert> alerts = alertService.loadRecentOfStreams(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14f"),
new DateTime(0L, DateTimeZone.UTC),
300);
assertThat(alerts.size()).isEqualTo(2);
assertThat(alerts.get(0).getStreamId()).isNotEqualTo(STREAM_ID);
assertThat(alerts.get(1).getStreamId()).isNotEqualTo(STREAM_ID);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void loadRecentOfStreamsLimitsResults() throws Exception {
final List<Alert> alerts = alertService.loadRecentOfStreams(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14e", "5666df42bee80072613ce14f"),
new DateTime(0L, DateTimeZone.UTC),
1);
assertThat(alerts.size()).isEqualTo(1);
}
@Test
@UsingDataSet(locations = "unresolved-alert.json")
public void resolvedSecondsAgoOnExistingUnresolvedAlert() throws Exception {
assertThat(alertService.resolvedSecondsAgo(STREAM_ID, CONDITION_ID)).isEqualTo(-1);
}
@Test
@UsingDataSet(locations = "non-interval-alert.json")
public void resolvedSecondsAgoOnExistingNonIntervalAlert() throws Exception {
assertThat(alertService.resolvedSecondsAgo(STREAM_ID, CONDITION_ID)).isEqualTo(-1);
}
@Test
@UsingDataSet(locations = "resolved-alert.json")
public void resolvedSecondsAgoOnExistingResolvedAlert() throws Exception {
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
final int expectedResult = Seconds.secondsBetween(alert.getResolvedAt(), Tools.nowUTC()).getSeconds();
// Add a second threshold in case the clock changed since the previous call to Tools.nowUTC()
assertThat(alertService.resolvedSecondsAgo(STREAM_ID, CONDITION_ID)).isBetween(expectedResult, expectedResult + 1);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdFilterByStream() throws Exception {
final List<Alert> alerts = alertService.listForStreamId(STREAM_ID, 0, 4);
assertThat(alerts.size()).isEqualTo(2);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdSkips() throws Exception {
final List<Alert> allAlerts = alertService.listForStreamId(STREAM_ID, 0, 4);
final List<Alert> alerts = alertService.listForStreamId(STREAM_ID, 1, 4);
assertThat(alerts.size()).isEqualTo(1);
assertThat(alerts).doesNotContain(allAlerts.get(0));
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdLimits() throws Exception {
final List<Alert> alerts = alertService.listForStreamId(STREAM_ID, 0, 1);
assertThat(alerts.size()).isEqualTo(1);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdsFilterByStream() throws Exception {
final List<Alert> alerts = alertService.listForStreamIds(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14f"),
Alert.AlertState.ANY,
0,
4
);
assertThat(alerts.size()).isEqualTo(2);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdsSkips() throws Exception {
final List<Alert> allAlerts = alertService.listForStreamIds(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14e", "5666df42bee80072613ce14f"),
Alert.AlertState.ANY,
0,
4
);
final List<Alert> alerts = alertService.listForStreamIds(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14e", "5666df42bee80072613ce14f"),
Alert.AlertState.ANY,
2,
4
);
assertThat(alerts.size()).isEqualTo(2);
assertThat(alerts).doesNotContain(allAlerts.get(0)).doesNotContain(allAlerts.get(1));
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdsLimits() throws Exception {
final List<Alert> alerts = alertService.listForStreamIds(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14e", "5666df42bee80072613ce14f"),
Alert.AlertState.ANY,
0,
1
);
assertThat(alerts.size()).isEqualTo(1);
}
@Test
@UsingDataSet(locations = "multiple-alerts.json")
public void listForStreamIdsFilterByState() throws Exception {
final List<Alert> resolvedAlerts = alertService.listForStreamIds(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14e", "5666df42bee80072613ce14f"),
Alert.AlertState.RESOLVED,
0,
4
);
final List<Alert> unresolvedAlerts = alertService.listForStreamIds(
ImmutableList.of("5666df42bee80072613ce14d", "5666df42bee80072613ce14e", "5666df42bee80072613ce14f"),
Alert.AlertState.UNRESOLVED,
0,
4
);
assertThat(resolvedAlerts.size()).isEqualTo(3);
assertThat(unresolvedAlerts.size()).isEqualTo(1);
}
@Test
@UsingDataSet(loadStrategy = LoadStrategyEnum.DELETE_ALL)
public void resolvedSecondsAgoOnNonExistingAlert() throws Exception {
assertThat(alertService.resolvedSecondsAgo(STREAM_ID, CONDITION_ID)).isEqualTo(-1);
}
@Test
@UsingDataSet(locations = "unresolved-alert.json")
public void resolveUnresolvedAlert() throws Exception {
final Alert originalAlert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(originalAlert.getResolvedAt()).isNull();
final Alert alert = alertService.resolveAlert(originalAlert);
assertThat(alertService.load(ALERT_ID, STREAM_ID).getResolvedAt().isEqual(alert.getResolvedAt())).isTrue();
assertThat(alertService.load(ALERT_ID, STREAM_ID).getResolvedAt()).isNotNull();
}
@Test
@UsingDataSet(locations = "resolved-alert.json")
public void resolveNoopInResolvedAlert() throws Exception {
final Alert originalAlert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(originalAlert.getResolvedAt()).isNotNull();
final Alert alert = alertService.resolveAlert(originalAlert);
assertThat(alert.getResolvedAt()).isEqualTo(originalAlert.getResolvedAt());
}
@Test
@UsingDataSet(loadStrategy = LoadStrategyEnum.DELETE_ALL)
public void resolveNoopIfNoAlert() throws Exception {
final Alert alert = alertService.resolveAlert(null);
assertThat(alert).isNull();
}
@Test
@UsingDataSet(locations = "non-interval-alert.json")
public void resolveNoopIfNonIntervalAlert() throws Exception {
final Alert originalAlert = alertService.load(ALERT_ID, STREAM_ID);
final Alert alert = alertService.resolveAlert(originalAlert);
assertThat(alert.isInterval()).isFalse();
assertThat(alert.getResolvedAt()).isNull();
}
@Test
@UsingDataSet(locations = "resolved-alert.json")
public void resolvedAlertIsResolved() throws Exception {
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(alertService.isResolved(alert)).isTrue();
}
@Test
@UsingDataSet(locations = "non-interval-alert.json")
public void nonIntervalAlertIsResolved() throws Exception {
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(alertService.isResolved(alert)).isTrue();
}
@Test
@UsingDataSet(locations = "unresolved-alert.json")
public void unresolvedAlertIsUnresolved() throws Exception {
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(alertService.isResolved(alert)).isFalse();
}
@Test
@UsingDataSet(locations = "non-interval-alert.json")
public void nonIntervalAlertShouldNotRepeatNotifications() throws Exception {
final AlertCondition alertCondition = mock(AlertCondition.class);
when(alertCondition.shouldRepeatNotifications()).thenReturn(true);
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(alertService.shouldRepeatNotifications(alertCondition, alert)).isFalse();
}
@Test
@UsingDataSet(locations = "unresolved-alert.json")
public void shouldNotRepeatNotificationsWhenOptionIsDisabled() throws Exception {
final AlertCondition alertCondition = mock(AlertCondition.class);
when(alertCondition.shouldRepeatNotifications()).thenReturn(false);
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(alertService.shouldRepeatNotifications(alertCondition, alert)).isFalse();
}
@Test
@UsingDataSet(locations = "unresolved-alert.json")
public void repeatNotificationsOptionShouldComplyWithGracePeriod() throws Exception {
final AlertCondition alertCondition = mock(AlertCondition.class);
when(alertCondition.getGrace()).thenReturn(15);
when(alertCondition.shouldRepeatNotifications()).thenReturn(true);
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
// Should repeat notification when there was no previous alert
assertThat(alertService.shouldRepeatNotifications(alertCondition, alert)).isTrue();
final AlarmCallbackHistory alarmCallbackHistory = mock(AlarmCallbackHistory.class);
when(alarmCallbackHistory.createdAt()).thenReturn(DateTime.now(DateTimeZone.UTC).minusMinutes(14));
when(alarmCallbackHistoryService.getForAlertId(ALERT_ID)).thenReturn(ImmutableList.of(alarmCallbackHistory));
// Should not repeat notification if a notification was sent during grace period
assertThat(alertService.shouldRepeatNotifications(alertCondition, alert)).isFalse();
when(alarmCallbackHistory.createdAt()).thenReturn(DateTime.now(DateTimeZone.UTC).minusMinutes(15));
when(alarmCallbackHistoryService.getForAlertId(ALERT_ID)).thenReturn(ImmutableList.of(alarmCallbackHistory));
// Should repeat notification after grace period passed
assertThat(alertService.shouldRepeatNotifications(alertCondition, alert)).isTrue();
}
@Test
@UsingDataSet(locations = "unresolved-alert.json")
public void shouldRepeatNotificationsWhenOptionIsEnabled() throws Exception {
final AlertCondition alertCondition = mock(AlertCondition.class);
when(alertCondition.shouldRepeatNotifications()).thenReturn(true);
final Alert alert = alertService.load(ALERT_ID, STREAM_ID);
assertThat(alertService.shouldRepeatNotifications(alertCondition, alert)).isTrue();
}
}