blob: 14099e388cc7089de7fd24e69e0a063db1b2e398 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.metron.rest.service.impl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.adrianwalker.multilinestring.Multiline;
import org.apache.metron.common.system.FakeClock;
import org.apache.metron.rest.MetronRestConstants;
import org.apache.metron.rest.model.AlertsUIUserSettings;
import org.apache.metron.rest.service.KafkaService;
import org.apache.metron.rest.user.UserSettingsClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.IOException;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class AlertsUIServiceImplTest {
public static ThreadLocal<ObjectMapper> _mapper = ThreadLocal.withInitial(() ->
new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL));
/**
* {
* "tableColumns": ["user1_field"]
* }
*/
@Multiline
public static String user1AlertUserSettings;
/**
* {
* "tableColumns": ["user2_field"]
* }
*/
@Multiline
public static String user2AlertUserSettings;
private KafkaService kafkaService;
private Environment environment;
private UserSettingsClient userSettingsClient;
private AlertsUIServiceImpl alertsUIService;
private String user1 = "user1";
private String user2 = "user2";
private FakeClock clock;
@BeforeEach
public void setUp() {
kafkaService = mock(KafkaService.class);
environment = mock(Environment.class);
userSettingsClient = mock(UserSettingsClient.class);
alertsUIService = new AlertsUIServiceImpl(kafkaService, environment, userSettingsClient);
// use a fake clock for testing
clock = new FakeClock();
clock.elapseSeconds(1000);
alertsUIService.setClock(clock);
// assume user1 is logged in for tests
Authentication authentication = Mockito.mock(Authentication.class);
UserDetails userDetails = Mockito.mock(UserDetails.class);
when(authentication.getPrincipal()).thenReturn(userDetails);
when(userDetails.getUsername()).thenReturn(user1);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
@Test
public void escalateAlertShouldSendMessageToKafka() throws Exception {
final String field = "field";
final String value1 = "value1";
final String value2 = "value2";
// define the escalation topic
final String escalationTopic = "escalation";
when(environment.getProperty(MetronRestConstants.KAFKA_TOPICS_ESCALATION_PROPERTY)).thenReturn(escalationTopic);
// create an alert along with the expected escalation message that is sent to kafka
final Map<String, Object> alert1 = mapOf(field, value1);
String escalationMessage1 = escalationMessage(field, value1, user1, clock.currentTimeMillis());
final Map<String, Object> alert2 = mapOf(field, value2);
String escalationMessage2 = escalationMessage(field, value2, user1, clock.currentTimeMillis());
// escalate the alerts and validate
alertsUIService.escalateAlerts(Arrays.asList(alert1, alert2));
verify(kafkaService).produceMessage(escalationTopic, escalationMessage1);
verify(kafkaService).produceMessage(escalationTopic, escalationMessage2);
verifyNoMoreInteractions(kafkaService);
}
@Test
public void getShouldProperlyReturnActiveProfile() throws Exception {
when(userSettingsClient.findOne(user1, AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE)).thenReturn(Optional.of(user1AlertUserSettings));
AlertsUIUserSettings expectedAlertsUIUserSettings = new AlertsUIUserSettings();
expectedAlertsUIUserSettings.setTableColumns(Collections.singletonList("user1_field"));
assertEquals(expectedAlertsUIUserSettings, alertsUIService.getAlertsUIUserSettings().get());
verify(userSettingsClient, times(1)).findOne(user1, AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE);
verifyNoMoreInteractions(userSettingsClient);
}
@Test
public void findAllShouldProperlyReturnActiveProfiles() throws Exception {
AlertsUIUserSettings alertsProfile1 = new AlertsUIUserSettings();
alertsProfile1.setUser(user1);
AlertsUIUserSettings alertsProfile2 = new AlertsUIUserSettings();
alertsProfile2.setUser(user1);
when(userSettingsClient.findAll(AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE))
.thenReturn(new HashMap<String, Optional<String>>() {{
put(user1, Optional.of(user1AlertUserSettings));
put(user2, Optional.of(user2AlertUserSettings));
}});
AlertsUIUserSettings expectedAlertsUIUserSettings1 = new AlertsUIUserSettings();
expectedAlertsUIUserSettings1.setTableColumns(Collections.singletonList("user1_field"));
AlertsUIUserSettings expectedAlertsUIUserSettings2 = new AlertsUIUserSettings();
expectedAlertsUIUserSettings2.setTableColumns(Collections.singletonList("user2_field"));
Map<String, AlertsUIUserSettings> actualAlertsProfiles = alertsUIService.findAllAlertsUIUserSettings();
assertEquals(2, actualAlertsProfiles.size());
assertEquals(expectedAlertsUIUserSettings1, actualAlertsProfiles.get(user1));
assertEquals(expectedAlertsUIUserSettings2, actualAlertsProfiles.get(user2));
verify(userSettingsClient, times(1)).findAll(AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE);
verifyNoMoreInteractions(userSettingsClient);
}
@Test
public void saveShouldProperlySaveActiveProfile() throws Exception {
AlertsUIUserSettings alertsUIUserSettings = new AlertsUIUserSettings();
alertsUIUserSettings.setTableColumns(Collections.singletonList("user1_field"));
alertsUIService.saveAlertsUIUserSettings(alertsUIUserSettings);
String expectedAlertUserSettings = _mapper.get().writeValueAsString(alertsUIUserSettings);
verify(userSettingsClient, times(1))
.save(user1, AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE, expectedAlertUserSettings);
verifyNoMoreInteractions(userSettingsClient);
}
@Test
public void deleteShouldProperlyDeleteActiveProfile() throws Exception {
assertTrue(alertsUIService.deleteAlertsUIUserSettings(user1));
doThrow(new IOException()).when(userSettingsClient).delete(user1, AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE);
assertFalse(alertsUIService.deleteAlertsUIUserSettings(user1));
verify(userSettingsClient, times(2)).delete(user1, AlertsUIServiceImpl.ALERT_USER_SETTING_TYPE);
verifyNoMoreInteractions(userSettingsClient);
}
/**
* Defines what the message sent to Kafka should look-like when an alert is escalated.
*
* @param field The field name.
* @param value The value of the field.
* @param user The user who escalated the alert.
* @param timestamp When the alert was escalated.
* @return The escalated message.
*/
private String escalationMessage(String field, String value, String user, Long timestamp) {
return String.format("{\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":%d}",
field,
value,
MetronRestConstants.METRON_ESCALATION_USER_FIELD,
user,
MetronRestConstants.METRON_ESCALATION_TIMESTAMP_FIELD,
timestamp);
}
private Map<String, Object> mapOf(String key, Object value) {
Map<String, Object> map = new HashMap<>();
map.put(key, value);
return map;
}
}