Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add priority to alert model, add sorting in display of Alerts page #77

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,25 @@
import com.google.appengine.api.datastore.KeyFactory;
import com.google.gson.Gson;
import com.google.models.Alert;
import java.io.BufferedReader;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** Servlet that returns data for requested specific Alert. */
/**
* Servlet that handles specific Alert data.
* Returns data for requested specific Alert and returns JSON.
* Given user input, changes Alert priority in the Datastore.
*/
@WebServlet("/api/v1/alert-visualization")
public class AlertVisualizationServlet extends HttpServlet {

private static final String EMPTY_BODY_ERROR = "No data was sent in HTTP request body.";
private static final String WRONG_ALERT_DATA = "Incorrect alert data sent in HTTP request.";

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Expand All @@ -46,4 +54,20 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
throw new ServletException(e);
}
}

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Long id = Long.parseLong(request.getParameter("id"));
String priority = request.getParameter("priority");

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
try {
Entity alertEntity = datastore.get(KeyFactory.createKey(Alert.ALERT_ENTITY_KIND, id));
alertEntity.setProperty(Alert.PRIORITY_PROPERTY, priority);
datastore.put(alertEntity);
} catch (EntityNotFoundException e) {
throw new ServletException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@
public class AlertsDataServlet extends HttpServlet {

private static final int DEFAULT_ALERTS_LIMIT = 5;
private static final String EMPTY_BODY_ERROR = "No data was sent in HTTP request body.";
private static final String WRONG_ALERT_DATA = "Incorrect alert data sent in HTTP request.";
private static final Logger log = Logger.getLogger(AlertsDataServlet.class.getName());

@Override
Expand Down Expand Up @@ -76,9 +74,8 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String[] data = processRequestBody(request);
Long id = Long.parseLong(data[0]);
String status = data[1];
Long id = Long.parseLong(request.getParameter("id"));
String status = request.getParameter("status");

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
try {
Expand All @@ -89,22 +86,4 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
throw new ServletException(e);
}
}

/**
* Read from the request body, which contains data in the format "alertId statusToChangeTo".
* For example, the body could be "4785074604081152 RESOLVED".
*/
private String[] processRequestBody(HttpServletRequest request)
throws IOException, ServletException {
BufferedReader reader = request.getReader();
String body = reader.readLine();
if (body == null) {
throw new ServletException(EMPTY_BODY_ERROR);
}
String[] data = body.split(" ");
if (data.length != 2) {
throw new ServletException(WRONG_ALERT_DATA);
}
return data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public DummyAlertGenerator(AnomalyGenerator anomalyGenerator) {
alerts = new ArrayList<Alert>();
for (int k = 0; k < SET_ALERT_GROUP_SIZE; k++) {
alerts.add(Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(k),
anomalyGenerator.getAnomalies(), Alert.StatusType.UNRESOLVED));
anomalyGenerator.getAnomalies(), Alert.StatusType.UNRESOLVED,
Alert.PriorityLevel.P2));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ private static ImmutableList<Alert> groupAnomaliesToAlerts(List<DataInfo> topics

return anomalyGroups.keySet().stream()
.map(key -> Alert.createAlertWithoutId(key, anomalyGroups.get(key),
Alert.StatusType.UNRESOLVED)).collect(ImmutableList.toImmutableList());
Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2))
.collect(ImmutableList.toImmutableList());
}

public List<Alert> getAlerts() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ private static ImmutableList<Alert> groupAnomaliesToAlerts(AnomalyGenerator anom
}

return anomalyGroups.keySet().stream()
.map(key -> Alert.createAlertWithoutId(key, anomalyGroups.get(key), Alert.StatusType.UNRESOLVED))
.map(key -> Alert.createAlertWithoutId(key, anomalyGroups.get(key),
Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2))
.collect(ImmutableList.toImmutableList());
}

Expand Down
23 changes: 20 additions & 3 deletions backend/src/main/java/com/google/models/Alert.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,32 @@
public final class Alert {
public static final String ALERT_ENTITY_KIND = "alert";
public static final String STATUS_PROPERTY = "status";
public static final String PRIORITY_PROPERTY = "priority";
public static final String ANOMALIES_LIST_PROPERTY = "anomaliesList";
public static enum StatusType {
RESOLVED,
UNRESOLVED
};
public static enum PriorityLevel {
P0,
P1,
P2
};

private static final long DEFAULT_ID = 0L;

private final Timestamp timestampDate;
private final ImmutableList<Anomaly> anomalies;
private final OptionalLong id;
private StatusType status;
private PriorityLevel priority;

private Alert(Timestamp timestampDate, List<Anomaly> anomalies, StatusType status, OptionalLong id) {
private Alert(Timestamp timestampDate, List<Anomaly> anomalies, StatusType status,
PriorityLevel priority, OptionalLong id) {
this.timestampDate = timestampDate;
this.anomalies = ImmutableList.copyOf(anomalies);
this.status = status;
this.priority = priority;
this.id = id;
}

Expand All @@ -59,6 +68,10 @@ public StatusType getStatus() {
return status;
}

public PriorityLevel getPriority() {
return priority;
}

public long getAlertId() {
return id.orElse(DEFAULT_ID);
}
Expand All @@ -72,6 +85,7 @@ public String toString() {
StringBuilder str = new StringBuilder()
.append("Timestamp: ").append(timestampDate).append("\n")
.append("Status: ").append(status.name()).append("\n")
.append("Priority: ").append(priority.name()).append("\n")
.append("Anomalies: \n");
anomalies.forEach(str::append);
return str.toString();
Expand All @@ -91,6 +105,7 @@ public boolean equals(Object o) {

return target.timestampDate.equals(timestampDate)
&& target.status.equals(status)
&& target.priority.equals(priority)
&& target.anomalies.equals(anomalies)
&& target.getAlertId() == getAlertId();
}
Expand All @@ -99,6 +114,7 @@ public Entity toEntity() {
Entity alertEntity = new Entity(ALERT_ENTITY_KIND);
alertEntity.setProperty(Timestamp.TIMESTAMP_PROPERTY, timestampDate.toEpochDay());
alertEntity.setProperty(STATUS_PROPERTY, status.name());
alertEntity.setProperty(PRIORITY_PROPERTY, priority.name());

List<EmbeddedEntity> list = anomalies.stream()
.map(Anomaly::toEmbeddedEntity)
Expand All @@ -111,8 +127,8 @@ public Entity toEntity() {

/** Used when an alert is first created and not converted from an entity. */
public static Alert createAlertWithoutId(Timestamp timestampDate,
List<Anomaly> anomalies, StatusType status) {
return new Alert(timestampDate, anomalies, status, OptionalLong.empty());
List<Anomaly> anomalies, StatusType status, PriorityLevel priority) {
return new Alert(timestampDate, anomalies, status, priority, OptionalLong.empty());
}

@SuppressWarnings("unchecked")
Expand All @@ -132,6 +148,7 @@ public static Alert createAlertFromEntity(Entity alertEntity) {
Timestamp.of((long) alertEntity.getProperty(Timestamp.TIMESTAMP_PROPERTY)),
listAnomaly,
StatusType.valueOf((String) alertEntity.getProperty(STATUS_PROPERTY)),
PriorityLevel.valueOf((String) alertEntity.getProperty(PRIORITY_PROPERTY)),
OptionalLong.of(alertEntity.getKey().getId())
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public class AlertVisualizationServletTest {
public ExpectedException thrown = ExpectedException.none();

private static final String RESPONSE_CONTENT_TYPE = "application/json;";
private static final String REQUEST_CHARSET = "UTF-8";
private static final String ID_PARAM = "id";
private static final String PRIORITY_PARAM = "priority";
private static final Long FAKE_ID = 1L;

private static final AlertVisualizationServlet alertVisualizationServlet = new AlertVisualizationServlet();
Expand All @@ -78,7 +80,7 @@ public void tearDown() {
public void doGet_ReturnsRequestedAlertEntity() throws IOException, ServletException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Alert newAlert = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(0),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED);
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
datastore.put(newAlert.toEntity());

Query query = new Query(Alert.ALERT_ENTITY_KIND);
Expand All @@ -104,4 +106,22 @@ public void doGet_AlertIdNotFound_ThrowsException() throws IOException, ServletE
alertVisualizationServlet.doGet(request, response);
}

@Test
public void doPost_ChangesAlertPriorityInDatastore() throws IOException, ServletException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Alert newAlert = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(0),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
Entity newAlertEntity = newAlert.toEntity();
datastore.put(newAlertEntity);
Long id = newAlertEntity.getKey().getId();
when(request.getParameter(ID_PARAM)).thenReturn(Long.toString(id));
when(request.getParameter(PRIORITY_PARAM)).thenReturn(Alert.PriorityLevel.P0.name());

alertVisualizationServlet.doPost(request, response);

assertEquals(1, datastore.prepare(new Query(Alert.ALERT_ENTITY_KIND)).countEntities(withLimit(10)));
Query query = new Query(Alert.ALERT_ENTITY_KIND);
Entity resultEntity = datastore.prepare(query).asSingleEntity();
assertEquals(Alert.PriorityLevel.P0.name(), resultEntity.getProperty(Alert.PRIORITY_PROPERTY).toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ public class AlertsDataServletTest {
public ExpectedException thrown = ExpectedException.none();

private static final String RESPONSE_CONTENT_TYPE = "application/json;";
private static final String REQUEST_CONTENT_TYPE = "text/plain;";
private static final String REQUEST_CHARSET = "UTF-8";
private static final Long FAKE_ID = 1L;
private static final String EMPTY_BODY_ERROR = "No data was sent in HTTP request body.";
private static final String LIMIT_PARAM = "limit";
private static final String ID_PARAM = "id";
private static final String STATUS_PARAM = "status";
private static final String FAKE_LIMIT = "2";

private static final AlertsDataServlet alertsDataServlet = new AlertsDataServlet();
Expand All @@ -84,7 +83,7 @@ public void tearDown() {
public void doGet_ReturnsAlertEntityAsJson() throws IOException, ServletException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Alert newAlert = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(0),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED);
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
datastore.put(newAlert.toEntity());
// The new alert needs to be queried from the datastore in order to contain a valid id.
Query query = new Query(Alert.ALERT_ENTITY_KIND);
Expand All @@ -105,11 +104,11 @@ public void doGet_ReturnsAlertEntityAsJson() throws IOException, ServletExceptio
public void doGet_ReturnsLimitedNumberOfSortedAlerts() throws IOException, ServletException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Alert newAlertOne = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(0),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED);
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
Alert newAlertTwo = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(1),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED);
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
Alert newAlertThree = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(2),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED);
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
datastore.put(newAlertOne.toEntity());
datastore.put(newAlertTwo.toEntity());
datastore.put(newAlertThree.toEntity());
Expand Down Expand Up @@ -140,15 +139,12 @@ public void doGet_ReturnsLimitedNumberOfSortedAlerts() throws IOException, Servl
public void doPost_ChangesAlertStatusInDatastore() throws IOException, ServletException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Alert newAlert = Alert.createAlertWithoutId(Timestamp.getDummyTimestamp(0),
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED);
Arrays.asList(Anomaly.getDummyAnomaly()), Alert.StatusType.UNRESOLVED, Alert.PriorityLevel.P2);
Entity newAlertEntity = newAlert.toEntity();
datastore.put(newAlertEntity);
Long id = newAlertEntity.getKey().getId();

String data = id + " " + Alert.StatusType.RESOLVED;
when(request.getReader()).thenReturn(new BufferedReader(new StringReader(data)));
when(request.getContentType()).thenReturn(REQUEST_CONTENT_TYPE);
when(request.getCharacterEncoding()).thenReturn(REQUEST_CHARSET);
when(request.getParameter(ID_PARAM)).thenReturn(Long.toString(id));
when(request.getParameter(STATUS_PARAM)).thenReturn(Alert.StatusType.RESOLVED.name());


alertsDataServlet.doPost(request, response);
Expand All @@ -158,28 +154,4 @@ public void doPost_ChangesAlertStatusInDatastore() throws IOException, ServletEx
Entity resultEntity = datastore.prepare(query).asSingleEntity();
assertEquals(Alert.StatusType.RESOLVED.name(), resultEntity.getProperty(Alert.STATUS_PROPERTY).toString());
}

@Test
public void doPost_EmptyRequestBody_ThrowsException() throws IOException, ServletException {
when(request.getReader()).thenReturn(new BufferedReader(new StringReader("")));
when(request.getContentType()).thenReturn(REQUEST_CONTENT_TYPE);
when(request.getCharacterEncoding()).thenReturn(REQUEST_CHARSET);

thrown.expect(ServletException.class);
thrown.expectMessage(EMPTY_BODY_ERROR);
alertsDataServlet.doPost(request, response);
}

@Test
public void doPost_EntityNotInDatastore_ThrowsException() throws IOException, ServletException {
String data = FAKE_ID + " " + Alert.StatusType.RESOLVED;
when(request.getReader()).thenReturn(new BufferedReader(new StringReader(data)));
when(request.getContentType()).thenReturn(REQUEST_CONTENT_TYPE);
when(request.getCharacterEncoding()).thenReturn(REQUEST_CHARSET);

thrown.expect(ServletException.class);
thrown.expectCause(IsInstanceOf.<Throwable>instanceOf(EntityNotFoundException.class));
alertsDataServlet.doPost(request, response);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public void getAlerts_returnsListOfAlerts() {
Alert expectedAlertJuly = Alert.createAlertWithoutId(
new Timestamp("2019-08-01"),
Arrays.asList(expectedAnomalyGroup1),
Alert.StatusType.UNRESOLVED
Alert.StatusType.UNRESOLVED,
Alert.PriorityLevel.P2
);
// Create second expected alert which contains two anomalies that occurs in August.
ImmutableMap<Timestamp, MetricValue> expectedDataPoints2 = ImmutableMap.of(
Expand All @@ -102,7 +103,8 @@ public void getAlerts_returnsListOfAlerts() {
Alert expectedAlertAugust = Alert.createAlertWithoutId(
new Timestamp("2019-09-01"),
Arrays.asList(expectedAnomalyGroup2_1, expectedAnomalyGroup2_2),
Alert.StatusType.UNRESOLVED
Alert.StatusType.UNRESOLVED,
Alert.PriorityLevel.P2
);

List<Alert> generatedAlerts = ALERT_GENERATOR.getAlerts();
Expand Down
Loading