package com.linkedin.thirdeye.anomaly.alert.grouping;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.linkedin.thirdeye.api.DimensionMap;
import com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO;
import com.linkedin.thirdeye.datalayer.dto.GroupedAnomalyResultsDTO;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class DimensionalAlertGrouperTest {
private final static String EMAIL1 = "k1v1.com,k1v1.com2";
private final static String EMAIL2 = "k1v2.com,k1v2.com2";
private final static String EMAIL_NOT_USED = "k1v1k2v3.com";
private final static String GROUP_BY_DIMENSION_NAME = "K1";
private DimensionalAlertGrouper alertGrouper;
@Test
public void testCreate() {
Map<String, String> props = new HashMap<>();
props.put(DimensionalAlertGrouper.ROLL_UP_SINGLE_DIMENSION_KEY, "true");
props.put(DimensionalAlertGrouper.GROUP_BY_KEY, GROUP_BY_DIMENSION_NAME);
Map<DimensionMap, String> auxiliaryRecipients = new TreeMap<>();
DimensionMap dimensionMap1 = new DimensionMap();
dimensionMap1.put(GROUP_BY_DIMENSION_NAME, "V1");
auxiliaryRecipients.put(dimensionMap1, EMAIL1);
DimensionMap dimensionMap2 = new DimensionMap();
dimensionMap2.put(GROUP_BY_DIMENSION_NAME, "V2");
auxiliaryRecipients.put(dimensionMap2, EMAIL2);
DimensionMap dimensionMap3 = new DimensionMap();
dimensionMap3.put(GROUP_BY_DIMENSION_NAME, "V1");
dimensionMap3.put("K2", "V3");
auxiliaryRecipients.put(dimensionMap3, EMAIL_NOT_USED);
try {
ObjectMapper OBJECT_MAPPER = new ObjectMapper();
String writeValueAsString = OBJECT_MAPPER.writeValueAsString(auxiliaryRecipients);
props.put(DimensionalAlertGrouper.AUXILIARY_RECIPIENTS_MAP_KEY, writeValueAsString);
alertGrouper = new DimensionalAlertGrouper();
alertGrouper.setParameters(props);
NavigableMap<DimensionMap, String> auxiliaryRecipientsRecovered = alertGrouper.getAuxiliaryEmailRecipients();
// Test the map of auxiliary recipients
Assert.assertEquals(auxiliaryRecipientsRecovered.get(dimensionMap1), EMAIL1);
Assert.assertEquals(auxiliaryRecipientsRecovered.get(dimensionMap2), EMAIL2);
Assert.assertEquals(auxiliaryRecipientsRecovered.get(dimensionMap3), EMAIL_NOT_USED);
} catch (JsonProcessingException e) {
e.printStackTrace();
Assert.fail();
}
}
@Test(dependsOnMethods = { "testCreate" })
public void testConstructGroupKey() {
DimensionMap alertGroupKey = new DimensionMap();
alertGroupKey.put(GROUP_BY_DIMENSION_NAME, "V1");
// dimensionMap.put("K2", "V3"); // K2 should not affect group key
// DimensionMap alertGroupKey = alertGrouper.constructGroupKey(dimensionMap);
DimensionMap expectedDimensionMap = new DimensionMap();
expectedDimensionMap.put(GROUP_BY_DIMENSION_NAME, "V1");
Assert.assertEquals(alertGroupKey, expectedDimensionMap);
}
@Test(dataProvider = "prepareAnomalyGroups", dependsOnMethods = { "testCreate", "testConstructGroupKey" })
public void testGroup(List<MergedAnomalyResultDTO> anomalies, Set<MergedAnomalyResultDTO> expectedGroup1,
Set<MergedAnomalyResultDTO> expectedGroup2, Set<MergedAnomalyResultDTO> expectedRollUpGroup) {
Map<DimensionMap, GroupedAnomalyResultsDTO> groupedAnomalies = alertGrouper.group(anomalies);
Assert.assertEquals(groupedAnomalies.size(), 3);
// Test group 1
{
DimensionMap alertGroup1 = new DimensionMap();
alertGroup1.put(GROUP_BY_DIMENSION_NAME, "G1");
GroupedAnomalyResultsDTO groupedAnomaly1 = groupedAnomalies.get(alertGroup1);
List<MergedAnomalyResultDTO> anomalyGroup1 = groupedAnomaly1.getAnomalyResults();
Assert.assertEquals(anomalyGroup1.size(), 2);
Set<MergedAnomalyResultDTO> group1 = new HashSet<>();
group1.addAll(anomalyGroup1);
Assert.assertEquals(group1, expectedGroup1);
}
// Test group 2
{
DimensionMap alertGroup2 = new DimensionMap();
alertGroup2.put(GROUP_BY_DIMENSION_NAME, "G2");
GroupedAnomalyResultsDTO groupedAnomaly2 = groupedAnomalies.get(alertGroup2);
List<MergedAnomalyResultDTO> anomalyGroup2 = groupedAnomaly2.getAnomalyResults();
Assert.assertEquals(anomalyGroup2.size(), 2);
Set<MergedAnomalyResultDTO> group2 = new HashSet<>();
group2.addAll(anomalyGroup2);
Assert.assertEquals(group2, expectedGroup2);
}
// Test roll-up group
{
GroupedAnomalyResultsDTO groupedAnomaly = groupedAnomalies.get(new DimensionMap());
List<MergedAnomalyResultDTO> anomalyRollUpGroup = groupedAnomaly.getAnomalyResults();
Assert.assertEquals(anomalyRollUpGroup.size(), 2);
Set<MergedAnomalyResultDTO> rollUpGroup = new HashSet<>();
rollUpGroup.addAll(anomalyRollUpGroup);
Assert.assertEquals(rollUpGroup, expectedRollUpGroup);
}
}
@Test(dependsOnMethods = { "testCreate", "testConstructGroupKey" })
public void testGroupEmailRecipients() {
// Test AlertGroupKey to auxiliary recipients
DimensionMap alertGroupKey1 = new DimensionMap();
alertGroupKey1.put(GROUP_BY_DIMENSION_NAME, "V1");
Assert.assertEquals(alertGrouper.groupEmailRecipients(alertGroupKey1), EMAIL1);
DimensionMap alertGroupKey2 = new DimensionMap();
alertGroupKey2.put(GROUP_BY_DIMENSION_NAME, "V1");
Assert.assertEquals(alertGrouper.groupEmailRecipients(alertGroupKey2), EMAIL1);
// Test empty recipients
Assert.assertEquals(alertGrouper.groupEmailRecipients(new DimensionMap()), BaseAlertGrouper.EMPTY_RECIPIENTS);
Assert.assertEquals(alertGrouper.groupEmailRecipients(null), BaseAlertGrouper.EMPTY_RECIPIENTS);
DimensionMap dimensionMapNonExist = new DimensionMap();
dimensionMapNonExist.put("K2", "V1");
Assert.assertEquals(alertGrouper.groupEmailRecipients(dimensionMapNonExist), BaseAlertGrouper.EMPTY_RECIPIENTS);
}
@DataProvider(name = "prepareAnomalyGroups")
public static Object[][] prepareAnomalyGroups() {
List<MergedAnomalyResultDTO> anomalies = new ArrayList<>();
// Group 2
Set<MergedAnomalyResultDTO> expectedGroup2 = new HashSet<>();
{ // member 1
DimensionMap dimensionGroup2Member1 = new DimensionMap();
dimensionGroup2Member1.put(GROUP_BY_DIMENSION_NAME, "G2");
dimensionGroup2Member1.put("K2", "M1");
MergedAnomalyResultDTO anomalyG2M1 = new MergedAnomalyResultDTO();
anomalyG2M1.setDimensions(dimensionGroup2Member1);
anomalies.add(anomalyG2M1);
expectedGroup2.add(anomalyG2M1);
}
{ // member 2
DimensionMap dimensionGroup2Member2 = new DimensionMap();
dimensionGroup2Member2.put(GROUP_BY_DIMENSION_NAME, "G2");
dimensionGroup2Member2.put("K2", "M2");
MergedAnomalyResultDTO anomalyG2M2 = new MergedAnomalyResultDTO();
anomalyG2M2.setDimensions(dimensionGroup2Member2);
anomalies.add(anomalyG2M2);
expectedGroup2.add(anomalyG2M2);
}
// Group 1
Set<MergedAnomalyResultDTO> expectedGroup1 = new HashSet<>();
{ // member 2
DimensionMap dimensionGroup1Member2 = new DimensionMap();
dimensionGroup1Member2.put(GROUP_BY_DIMENSION_NAME, "G1");
dimensionGroup1Member2.put("K2", "M2");
MergedAnomalyResultDTO anomalyG1M2 = new MergedAnomalyResultDTO();
anomalyG1M2.setDimensions(dimensionGroup1Member2);
anomalies.add(anomalyG1M2);
expectedGroup1.add(anomalyG1M2);
}
{ // member 1
DimensionMap dimensionGroup1Member1 = new DimensionMap();
dimensionGroup1Member1.put(GROUP_BY_DIMENSION_NAME, "G1");
dimensionGroup1Member1.put("K2", "M1");
MergedAnomalyResultDTO anomalyG1M1 = new MergedAnomalyResultDTO();
anomalyG1M1.setDimensions(dimensionGroup1Member1);
anomalies.add(anomalyG1M1);
expectedGroup1.add(anomalyG1M1);
}
Set<MergedAnomalyResultDTO> expectedRollUpGroup = new HashSet<>();
// Group 3, which will be rolled up with group 4
{
DimensionMap dimensionGroup3 = new DimensionMap();
dimensionGroup3.put(GROUP_BY_DIMENSION_NAME, "G3");
dimensionGroup3.put("K2", "M1");
MergedAnomalyResultDTO anomalyG3 = new MergedAnomalyResultDTO();
anomalyG3.setDimensions(dimensionGroup3);
anomalies.add(anomalyG3);
expectedRollUpGroup.add(anomalyG3);
}
// Group 4, which will be rolled up with group 3
{
DimensionMap dimensionGroup4 = new DimensionMap();
dimensionGroup4.put(GROUP_BY_DIMENSION_NAME, "G4");
dimensionGroup4.put("K2", "M1");
MergedAnomalyResultDTO anomalyG4 = new MergedAnomalyResultDTO();
anomalyG4.setDimensions(dimensionGroup4);
anomalies.add(anomalyG4);
expectedRollUpGroup.add(anomalyG4);
}
List<Object[]> entries = new ArrayList<>();
entries.add(new Object[] {
anomalies, expectedGroup1, expectedGroup2, expectedRollUpGroup
});
return entries.toArray(new Object[entries.size()][]);
}
}