/** * 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.migrations; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.graylog2.alarmcallbacks.AlarmCallbackConfiguration; import org.graylog2.alarmcallbacks.AlarmCallbackConfigurationService; import org.graylog2.alarmcallbacks.EmailAlarmCallback; import org.graylog2.plugin.alarms.AlertCondition; import org.graylog2.plugin.cluster.ClusterConfigService; import org.graylog2.plugin.configuration.ConfigurationRequest; import org.graylog2.plugin.configuration.fields.ConfigurationField; import org.graylog2.plugin.database.users.User; import org.graylog2.plugin.streams.Stream; import org.graylog2.rest.models.alarmcallbacks.requests.CreateAlarmCallbackRequest; import org.graylog2.shared.users.UserService; import org.graylog2.streams.StreamService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.Collections; import java.util.Map; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class V20161125142400_EmailAlarmCallbackMigrationTest { @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); private V20161125142400_EmailAlarmCallbackMigration emailAlarmCallbackMigrationPeriodical; @Mock private ClusterConfigService clusterConfigService; @Mock private StreamService streamService; @Mock private AlarmCallbackConfigurationService alarmCallbackConfigurationService; @Mock private EmailAlarmCallback emailAlarmCallback; @Mock private UserService userService; private final static String localAdminId = "local:adminMock"; @Before public void setUp() throws Exception { final User localAdmin = mock(User.class); when(localAdmin.getId()).thenReturn(localAdminId); when(userService.getAdminUser()).thenReturn(localAdmin); this.emailAlarmCallbackMigrationPeriodical = new V20161125142400_EmailAlarmCallbackMigration(clusterConfigService, streamService, alarmCallbackConfigurationService, emailAlarmCallback, userService); } @Test public void doNotMigrateAnythingWithoutStreams() throws Exception { when(this.streamService.loadAll()).thenReturn(Collections.emptyList()); this.emailAlarmCallbackMigrationPeriodical.upgrade(); verify(this.alarmCallbackConfigurationService, never()).create(any(), any(), any()); verifyMigrationCompletedWasPosted(); } @Test public void doNotMigrateAnythingWithoutQualifyingStreams() throws Exception { final Stream stream1 = mock(Stream.class); when(stream1.getAlertReceivers()).thenReturn(Collections.emptyMap()); final Stream stream2 = mock(Stream.class); when(stream2.getAlertReceivers()).thenReturn(ImmutableMap.of( "users", Collections.emptyList(), "emails", Collections.emptyList()) ); when(this.streamService.loadAll()).thenReturn(ImmutableList.of(stream1, stream2)); this.emailAlarmCallbackMigrationPeriodical.upgrade(); verify(this.streamService, never()).getAlertConditions(any()); verify(this.alarmCallbackConfigurationService, never()).getForStream(any()); verify(this.alarmCallbackConfigurationService, never()).create(any(), any(), any()); verifyMigrationCompletedWasPosted(); } @Test public void doMigrateSingleQualifyingStream() throws Exception { final String matchingStreamId = "matchingStreamId"; final Stream stream1 = mock(Stream.class); when(stream1.getAlertReceivers()).thenReturn(Collections.emptyMap()); final Stream stream2 = mock(Stream.class); when(stream2.getAlertReceivers()).thenReturn(ImmutableMap.of( "users", ImmutableList.of("foouser"), "emails", ImmutableList.of("foo@bar.com") )); when(stream2.getId()).thenReturn(matchingStreamId); when(this.streamService.loadAll()).thenReturn(ImmutableList.of(stream1, stream2)); final AlertCondition alertCondition = mock(AlertCondition.class); when(this.streamService.getAlertConditions(eq(stream2))).thenReturn(ImmutableList.of(alertCondition)); final ConfigurationRequest configurationRequest = mock(ConfigurationRequest.class); when(emailAlarmCallback.getRequestedConfiguration()).thenReturn(configurationRequest); when(configurationRequest.getFields()).thenReturn(Collections.emptyMap()); final AlarmCallbackConfiguration newAlarmCallback = mock(AlarmCallbackConfiguration.class); final String newAlarmCallbackId = "newAlarmCallbackId"; when(alarmCallbackConfigurationService.create(eq(matchingStreamId), any(CreateAlarmCallbackRequest.class), eq(localAdminId))).thenReturn(newAlarmCallback); when(alarmCallbackConfigurationService.save(eq(newAlarmCallback))).thenReturn(newAlarmCallbackId); this.emailAlarmCallbackMigrationPeriodical.upgrade(); final ArgumentCaptor<String> streamIdCaptor = ArgumentCaptor.forClass(String.class); final ArgumentCaptor<CreateAlarmCallbackRequest> createAlarmCallbackRequestCaptor = ArgumentCaptor.forClass(CreateAlarmCallbackRequest.class); final ArgumentCaptor<String> userIdCaptor = ArgumentCaptor.forClass(String.class); verify(this.alarmCallbackConfigurationService, times(1)).create(streamIdCaptor.capture(), createAlarmCallbackRequestCaptor.capture(), userIdCaptor.capture()); assertThat(streamIdCaptor.getValue()) .isNotNull() .isNotEmpty() .isEqualTo(matchingStreamId); final CreateAlarmCallbackRequest createAlarmCallbackRequest = createAlarmCallbackRequestCaptor.getValue(); assertThat(createAlarmCallbackRequest.type()).isEqualTo(EmailAlarmCallback.class.getCanonicalName()); final ArgumentCaptor<AlarmCallbackConfiguration> alarmCallbackConfigurationCaptor = ArgumentCaptor.forClass(AlarmCallbackConfiguration.class); verify(this.alarmCallbackConfigurationService, times(1)).save(alarmCallbackConfigurationCaptor.capture()); assertThat(alarmCallbackConfigurationCaptor.getValue()).isEqualTo(newAlarmCallback); verifyMigrationCompletedWasPosted(ImmutableMap.of( matchingStreamId, Optional.of(newAlarmCallbackId) )); } @Test public void doMigrateMultipleQualifyingStreams() throws Exception { final String matchingStreamId1 = "matchingStreamId1"; final String matchingStreamId2 = "matchingStreamId2"; final Stream stream1 = mock(Stream.class); when(stream1.getAlertReceivers()).thenReturn(Collections.emptyMap()); final Stream stream2 = mock(Stream.class); when(stream2.getAlertReceivers()).thenReturn(ImmutableMap.of( "users", ImmutableList.of("foouser"), "emails", ImmutableList.of("foo@bar.com") )); when(stream2.getId()).thenReturn(matchingStreamId1); final Stream stream3 = mock(Stream.class); when(stream3.getAlertReceivers()).thenReturn(ImmutableMap.of( "users", ImmutableList.of("foouser2") )); when(stream3.getId()).thenReturn(matchingStreamId2); when(this.streamService.loadAll()).thenReturn(ImmutableList.of(stream1, stream2, stream3)); final AlertCondition alertCondition1 = mock(AlertCondition.class); final AlertCondition alertCondition2 = mock(AlertCondition.class); when(this.streamService.getAlertConditions(eq(stream2))).thenReturn(ImmutableList.of(alertCondition1)); when(this.streamService.getAlertConditions(eq(stream3))).thenReturn(ImmutableList.of(alertCondition2)); final ConfigurationRequest configurationRequest = mock(ConfigurationRequest.class); when(emailAlarmCallback.getRequestedConfiguration()).thenReturn(configurationRequest); when(configurationRequest.getFields()).thenReturn(Collections.emptyMap()); final AlarmCallbackConfiguration newAlarmCallback1 = mock(AlarmCallbackConfiguration.class); final String newAlarmCallbackId1 = "newAlarmCallbackId1"; final AlarmCallbackConfiguration newAlarmCallback2 = mock(AlarmCallbackConfiguration.class); final String newAlarmCallbackId2 = "newAlarmCallbackId2"; when(alarmCallbackConfigurationService.create(eq(matchingStreamId1), any(CreateAlarmCallbackRequest.class), eq(localAdminId))).thenReturn(newAlarmCallback1); when(alarmCallbackConfigurationService.create(eq(matchingStreamId2), any(CreateAlarmCallbackRequest.class), eq(localAdminId))).thenReturn(newAlarmCallback2); when(alarmCallbackConfigurationService.save(eq(newAlarmCallback1))).thenReturn(newAlarmCallbackId1); when(alarmCallbackConfigurationService.save(eq(newAlarmCallback2))).thenReturn(newAlarmCallbackId2); this.emailAlarmCallbackMigrationPeriodical.upgrade(); final ArgumentCaptor<String> streamIdCaptor = ArgumentCaptor.forClass(String.class); final ArgumentCaptor<CreateAlarmCallbackRequest> createAlarmCallbackRequestCaptor = ArgumentCaptor.forClass(CreateAlarmCallbackRequest.class); final ArgumentCaptor<String> userIdCaptor = ArgumentCaptor.forClass(String.class); verify(this.alarmCallbackConfigurationService, times(2)).create(streamIdCaptor.capture(), createAlarmCallbackRequestCaptor.capture(), userIdCaptor.capture()); assertThat(streamIdCaptor.getAllValues()) .isNotNull() .isNotEmpty() .contains(matchingStreamId1) .contains(matchingStreamId2); createAlarmCallbackRequestCaptor.getAllValues() .forEach(createAlarmCallbackRequest -> assertThat(createAlarmCallbackRequest.type()).isEqualTo(EmailAlarmCallback.class.getCanonicalName())); final ArgumentCaptor<AlarmCallbackConfiguration> alarmCallbackConfigurationCaptor = ArgumentCaptor.forClass(AlarmCallbackConfiguration.class); verify(this.alarmCallbackConfigurationService, times(2)).save(alarmCallbackConfigurationCaptor.capture()); assertThat(alarmCallbackConfigurationCaptor.getAllValues()) .isNotNull() .isNotEmpty() .hasSize(2) .contains(newAlarmCallback1) .contains(newAlarmCallback2); verifyMigrationCompletedWasPosted(ImmutableMap.of( matchingStreamId1, Optional.of(newAlarmCallbackId1), matchingStreamId2, Optional.of(newAlarmCallbackId2) )); } @Test public void extractEmptyDefaultValuesFromEmptyEmailAlarmCallbackConfiguration() throws Exception { final ConfigurationRequest configurationRequest = mock(ConfigurationRequest.class); when(emailAlarmCallback.getRequestedConfiguration()).thenReturn(configurationRequest); final Map<String, Object> defaultConfig = this.emailAlarmCallbackMigrationPeriodical.getDefaultEmailAlarmCallbackConfig(); assertThat(defaultConfig).isNotNull().isEmpty(); } @Test public void extractDefaultValuesFromEmailAlarmCallbackConfiguration() throws Exception { final ConfigurationRequest configurationRequest = mock(ConfigurationRequest.class); when(emailAlarmCallback.getRequestedConfiguration()).thenReturn(configurationRequest); final ConfigurationField configurationField1 = mock(ConfigurationField.class); when(configurationField1.getDefaultValue()).thenReturn(42); final ConfigurationField configurationField2 = mock(ConfigurationField.class); when(configurationField2.getDefaultValue()).thenReturn("foobar"); final ConfigurationField configurationField3 = mock(ConfigurationField.class); when(configurationField3.getDefaultValue()).thenReturn(true); final Map<String, ConfigurationField> configurationFields = ImmutableMap.of( "field1", configurationField1, "field2", configurationField2, "field3", configurationField3 ); when(configurationRequest.getFields()).thenReturn(configurationFields); final Map<String, Object> defaultConfig = this.emailAlarmCallbackMigrationPeriodical.getDefaultEmailAlarmCallbackConfig(); assertThat(defaultConfig) .isNotNull() .isNotEmpty() .hasSize(3) .isEqualTo(ImmutableMap.of( "field1", 42, "field2", "foobar", "field3", true )); } private void verifyMigrationCompletedWasPosted() { verifyMigrationCompletedWasPosted(Collections.emptyMap()); } private void verifyMigrationCompletedWasPosted(Map<String, Optional<String>> migratedStreams) { final ArgumentCaptor<V20161125142400_EmailAlarmCallbackMigration.MigrationCompleted> argumentCaptor = ArgumentCaptor.forClass(V20161125142400_EmailAlarmCallbackMigration.MigrationCompleted.class); verify(this.clusterConfigService, times(1)).write(argumentCaptor.capture()); final V20161125142400_EmailAlarmCallbackMigration.MigrationCompleted emailAlarmCallbackMigrated = argumentCaptor.getValue(); assertThat(emailAlarmCallbackMigrated) .isNotNull() .isEqualTo(V20161125142400_EmailAlarmCallbackMigration.MigrationCompleted.create(migratedStreams)); } }