Skip to content

Commit

Permalink
HWKALERTS-99 Fix EventCondition deserialization
Browse files Browse the repository at this point in the history
Add additional end-to-end tests
  • Loading branch information
lucasponce committed Nov 5, 2015
1 parent 2773f8a commit 16b51c6
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import org.hawkular.alerts.api.model.condition.CompareConditionEval;
import org.hawkular.alerts.api.model.condition.Condition;
import org.hawkular.alerts.api.model.condition.ConditionEval;
import org.hawkular.alerts.api.model.condition.EventCondition;
import org.hawkular.alerts.api.model.condition.EventConditionEval;
import org.hawkular.alerts.api.model.condition.ExternalCondition;
import org.hawkular.alerts.api.model.condition.ExternalConditionEval;
import org.hawkular.alerts.api.model.condition.StringCondition;
Expand All @@ -41,6 +43,7 @@
import org.hawkular.alerts.api.model.condition.ThresholdRangeConditionEval;
import org.hawkular.alerts.api.model.data.AvailabilityType;
import org.hawkular.alerts.api.model.event.Alert;
import org.hawkular.alerts.api.model.event.Event;
import org.hawkular.alerts.api.model.event.Thin;
import org.hawkular.alerts.api.model.trigger.Mode;

Expand Down Expand Up @@ -151,6 +154,17 @@ public ConditionEval deserialize(JsonParser jp, DeserializationContext ctxt)
}
break;
}
case EVENT: {
conditionEval = new EventConditionEval();
EventConditionEval evConditionEval = (EventConditionEval) conditionEval;
if (condition instanceof EventCondition) {
evConditionEval.setCondition((EventCondition) condition);
}
if (node.get("value") != null) {
evConditionEval.setValue(node.get("value").traverse(objectCodec).readValueAs(Event.class));
}
break;
}
default: {
throw new ConditionEvalException("Unexpected Condition type [" + condition.getType().name() + "]");
}
Expand Down Expand Up @@ -287,6 +301,17 @@ public static Condition deserializeCondition(JsonNode node) throws JsonProcessin
}
break;
}
case EVENT: {
condition = new EventCondition();
EventCondition evCondition = (EventCondition) condition;
if (node.get("dataId") != null) {
evCondition.setDataId(node.get("dataId").textValue());
}
if (node.get("expression") != null) {
evCondition.setExpression(node.get("expression").textValue());
}
break;
}
default:
throw new ConditionEvalException("Unexpected Condition Type [" + conditionType.name() + "]");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.hawkular.alerts.api.model.condition.AvailabilityCondition;
import org.hawkular.alerts.api.model.condition.CompareCondition;
import org.hawkular.alerts.api.model.condition.Condition;
import org.hawkular.alerts.api.model.condition.EventCondition;
import org.hawkular.alerts.api.model.condition.ExternalCondition;
import org.hawkular.alerts.api.model.condition.StringCondition;
import org.hawkular.alerts.api.model.condition.ThresholdCondition;
Expand Down Expand Up @@ -1969,6 +1970,8 @@ public Collection<Condition> setConditions(String tenantId, String triggerId, Mo
PreparedStatement insertConditionCompare = CassStatement.get(session, CassStatement.INSERT_CONDITION_COMPARE);
PreparedStatement insertConditionExternal = CassStatement
.get(session, CassStatement.INSERT_CONDITION_EXTERNAL);
PreparedStatement insertConditionEvent = CassStatement
.get(session, CassStatement.INSERT_CONDITION_EVENT);
PreparedStatement insertConditionString = CassStatement.get(session, CassStatement.INSERT_CONDITION_STRING);
PreparedStatement insertConditionThreshold = CassStatement.get(session,
CassStatement.INSERT_CONDITION_THRESHOLD);
Expand All @@ -1977,6 +1980,7 @@ public Collection<Condition> setConditions(String tenantId, String triggerId, Mo
if (insertConditionAvailability == null
|| insertConditionCompare == null
|| insertConditionExternal == null
|| insertConditionEvent == null
|| insertConditionString == null
|| insertConditionThreshold == null
|| insertConditionThresholdRange == null) {
Expand Down Expand Up @@ -2027,6 +2031,14 @@ public Collection<Condition> setConditions(String tenantId, String triggerId, Mo
eCond.getConditionSetSize(), eCond.getConditionSetIndex(), eCond.getConditionId(),
eCond.getDataId(), eCond.getSystemId(), eCond.getExpression())));

} else if (cond instanceof EventCondition) {

EventCondition evCond = (EventCondition) cond;
futures.add(session.executeAsync(insertConditionEvent.bind(evCond.getTenantId(),
evCond.getTriggerId(), evCond.getTriggerMode().name(), evCond.getContext(),
evCond.getConditionSetSize(), evCond.getConditionSetIndex(), evCond.getConditionId(),
evCond.getDataId(), evCond.getExpression())));

} else if (cond instanceof StringCondition) {

StringCondition sCond = (StringCondition) cond;
Expand Down Expand Up @@ -2287,6 +2299,18 @@ private Condition mapCondition(Row row) throws Exception {
eCondition.setContext(row.getMap("context", String.class, String.class));
condition = eCondition;
break;
case EVENT:
EventCondition evCondition = new EventCondition();
evCondition.setTenantId(row.getString("tenantId"));
evCondition.setTriggerId(row.getString("triggerId"));
evCondition.setTriggerMode(Mode.valueOf(row.getString("triggerMode")));
evCondition.setConditionSetSize(row.getInt("conditionSetSize"));
evCondition.setConditionSetIndex(row.getInt("conditionSetIndex"));
evCondition.setDataId(row.getString("dataId"));
evCondition.setExpression(row.getString("pattern"));
evCondition.setContext(row.getMap("context", String.class, String.class));
condition = evCondition;
break;
case RANGE:
ThresholdRangeCondition rCondition = new ThresholdRangeCondition();
rCondition.setTenantId(row.getString("tenantId"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class CassStatement {
public static final String INSERT_CONDITION_AVAILABILITY;
public static final String INSERT_CONDITION_COMPARE;
public static final String INSERT_CONDITION_EXTERNAL;
public static final String INSERT_CONDITION_EVENT;
public static final String INSERT_CONDITION_STRING;
public static final String INSERT_CONDITION_THRESHOLD;
public static final String INSERT_CONDITION_THRESHOLD_RANGE;
Expand Down Expand Up @@ -269,6 +270,10 @@ public class CassStatement {
+ "(tenantId, triggerId, triggerMode, type, context, conditionSetSize, conditionSetIndex, " +
"conditionId, dataId, operator, pattern) VALUES (?, ?, ?, 'EXTERNAL', ?, ?, ?, ?, ?, ?, ?) ";

INSERT_CONDITION_EVENT = "INSERT INTO " + keyspace + ".conditions "
+ "(tenantId, triggerId, triggerMode, type, context, conditionSetSize, conditionSetIndex, " +
"conditionId, dataId, pattern) VALUES (?, ?, ?, 'EVENT', ?, ?, ?, ?, ?, ?) ";

INSERT_CONDITION_STRING = "INSERT INTO " + keyspace + ".conditions "
+ "(tenantId, triggerId, triggerMode, type, context, conditionSetSize, conditionSetIndex, " +
"conditionId, dataId, operator, pattern, ignoreCase) " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public void fire() {
// execution of the rules. So, if we find multiple Data instances for the same Id, defer all but
// the oldest to a subsequent run. Note that pendingData is already sorted by (id ASC, timestamp ASC) so
// the iterator will present Data with the same id together, and time-ordered.
log.debugf("firing rules...");
int fireCycle = 0;
while (!pendingData.isEmpty() || !pendingEvents.isEmpty()) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.hawkular.alerts.rest

import org.hawkular.alerts.api.model.condition.Condition
import org.hawkular.alerts.api.model.condition.EventCondition
import org.hawkular.alerts.api.model.event.EventCategory
import org.hawkular.alerts.api.model.event.EventType
import org.hawkular.alerts.api.model.trigger.Trigger
import org.junit.FixMethodOrder
import org.junit.Test

import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertTrue
import static org.junit.runners.MethodSorters.NAME_ASCENDING

/**
* Events lifecycle end-to-end tests.
*
* @author Jay Shaughnessy
* @author Lucas Ponce
*/
@FixMethodOrder(NAME_ASCENDING)
class EventsLifecycleITest extends AbstractITestBase {

static host = System.getProperty('hawkular.host') ?: '127.0.0.1'
static port = Integer.valueOf(System.getProperty('hawkular.port') ?: "8080")

@Test
void t01_eventsBasicTest() {
println( "Running t01_eventsBasicTest" )

String start = String.valueOf(System.currentTimeMillis())

// Clean previous tests
def resp = client.delete(path: "triggers/test-events-t01")
assert(200 == resp.status || 404 == resp.status)

// Trigger to fire alerts
Trigger t01 = new Trigger("test-events-t01", "Basic trigger for Events tests");

resp = client.post(path: "triggers", body: t01)
assertEquals(200, resp.status)

// Add a condition over events
EventCondition firingCond = new EventCondition("test-events-t01", "test-app.war");
Collection<Condition> conditions = new ArrayList<>(1);
conditions.add( firingCond );

resp = client.put(path: "triggers/test-events-t01/conditions/firing", body: conditions)
assertEquals(200, resp.status)
assertEquals(1, resp.data.size())

// Enable trigger
t01.setEnabled(true);

resp = client.put(path: "triggers/test-events-t01/", body: t01)
assertEquals(200, resp.status)

String jsonEvent = "{" +
"\"id\":\"" + UUID.randomUUID().toString() + "\"," +
"\"ctime\":" + System.currentTimeMillis() + "," +
"\"category\":\"" + EventCategory.DEPLOYMENT.toString() + "\"," +
"\"dataId\":\"test-app.war\"" +
"}";

resp = client.post(path: "events", body: jsonEvent);
assertEquals(200, resp.status)

// The alert processing happens async, so give it a little time before failing...
for ( int i=0; i < 100; ++i ) {
Thread.sleep(100);

// FETCH recent alerts for trigger, there should be 1
resp = client.get(path: "", query: [startTime:start,triggerIds:"test-events-t01"] )
if ( resp.status == 200 && resp.data != null && resp.data.size > 0) {
if ( i > 50 ) {
println( "Perf: passing but sleep iterations high [" + i + "]" );
}
break;
}
assertEquals(200, resp.status)
}
assertEquals(200, resp.status)
assertEquals(1, resp.data.size())

}

@Test
void t02_eventsChainedTest() {
println( "Running t02_eventsChainedTest" )

String start = String.valueOf(System.currentTimeMillis())

// Clean previous tests
def resp = client.delete(path: "triggers/test-events-t02-app1")
assert(200 == resp.status || 404 == resp.status)

resp = client.delete(path: "triggers/test-events-t02-app2")
assert(200 == resp.status || 404 == resp.status)

resp = client.delete(path: "triggers/test-events-t02-combined")
assert(200 == resp.status || 404 == resp.status)

// Triggers to fire events
Trigger t02app1 = new Trigger("test-events-t02-app1", "Check if app1 is down");
t02app1.setEventType(EventType.EVENT);

resp = client.post(path: "triggers", body: t02app1)
assertEquals(200, resp.status)

// Add a condition over events
EventCondition firingCond1 = new EventCondition("test-events-t02-app1", "app1.war", "text == 'DOWN'");
Collection<Condition> conditions1 = new ArrayList<>(1);
conditions1.add( firingCond1 );

resp = client.put(path: "triggers/test-events-t02-app1/conditions/firing", body: conditions1)
assertEquals(200, resp.status)
assertEquals(1, resp.data.size())

// Enable trigger
t02app1.setEnabled(true);

resp = client.put(path: "triggers/test-events-t02-app1", body: t02app1)
assertEquals(200, resp.status)

// Triggers to fire events
Trigger t02app2 = new Trigger("test-events-t02-app2", "Check if app2 is down");
t02app2.setEventType(EventType.EVENT);

resp = client.post(path: "triggers", body: t02app2)
assertEquals(200, resp.status)

// Add a condition over events
EventCondition firingCond2 = new EventCondition("test-events-t02-app2", "app2.war", "text == 'DOWN'");
Collection<Condition> conditions2 = new ArrayList<>(1);
conditions2.add( firingCond2 );

resp = client.put(path: "triggers/test-events-t02-app2/conditions/firing", body: conditions2)
assertEquals(200, resp.status)
assertEquals(1, resp.data.size())

// Enable trigger
t02app2.setEnabled(true);

resp = client.put(path: "triggers/test-events-t02-app2", body: t02app2)
assertEquals(200, resp.status)

// Trigger to fire alerts
Trigger t02combined = new Trigger("test-events-t02-combined", "App1 and App2 are down");

resp = client.post(path: "triggers", body: t02combined)
assertEquals(200, resp.status)

// Add a condition over events
EventCondition firingCond3 = new EventCondition("test-events-t02-combined", "test-events-t02-app1");
EventCondition firingCond4 = new EventCondition("test-events-t02-combined", "test-events-t02-app2");

Collection<Condition> conditions3 = new ArrayList<>(2);
conditions3.add( firingCond3 );
conditions3.add( firingCond4 );

resp = client.put(path: "triggers/test-events-t02-combined/conditions/firing", body: conditions3)
assertEquals(200, resp.status)
assertEquals(2, resp.data.size())

// Enable trigger
t02combined.setEnabled(true);

resp = client.put(path: "triggers/test-events-t02-combined/", body: t02combined)
assertEquals(200, resp.status)

String jsonEventApp1Down = "{" +
"\"id\":\"" + UUID.randomUUID().toString() + "\"," +
"\"ctime\":" + System.currentTimeMillis() + "," +
"\"category\":\"" + EventCategory.DEPLOYMENT.toString() + "\"," +
"\"dataId\":\"app1.war\"," +
"\"text\":\"DOWN\"" +
"}";

resp = client.post(path: "events", body: jsonEventApp1Down);
assertEquals(200, resp.status)

String jsonEventApp2Down = "{" +
"\"id\":\"" + UUID.randomUUID().toString() + "\"," +
"\"ctime\":" + System.currentTimeMillis() + "," +
"\"category\":\"" + EventCategory.DEPLOYMENT.toString() + "\"," +
"\"dataId\":\"app2.war\"," +
"\"text\":\"DOWN\"" +
"}";

resp = client.post(path: "events", body: jsonEventApp2Down);
assertEquals(200, resp.status)

// The alert processing happens async, so give it a little time before failing...
for ( int i=0; i < 100; ++i ) {
Thread.sleep(100);

// FETCH recent alerts for trigger, there should be 1
resp = client.get(path: "", query: [startTime:start,triggerIds:"test-events-t02-combined"] )
if ( resp.status == 200 && resp.data != null && resp.data.size > 0) {
if ( i > 50 ) {
println( "Perf: passing but sleep iterations high [" + i + "]" );
}
break;
}
assertEquals(200, resp.status)
}
assertEquals(200, resp.status)
assertEquals(1, resp.data.size())
}

@Test
void t100_eventsCleanup() {
println("Running t100_eventsCleanup")

// clean up triggers
def resp = client.delete(path: "triggers/test-events-t01")
assert(200 == resp.status || 404 == resp.status)

resp = client.delete(path: "triggers/test-events-t02-app1")
assert(200 == resp.status || 404 == resp.status)

resp = client.delete(path: "triggers/test-events-t02-app2")
assert(200 == resp.status || 404 == resp.status)

resp = client.delete(path: "triggers/test-events-t02-combined")
assert(200 == resp.status || 404 == resp.status)

// clean up alerts
resp = client.put(path: "delete", query: [triggerIds:"test-events-t01"])
assertEquals(200, resp.status)

resp = client.put(path: "delete", query: [triggerIds:"test-events-t02-combined"])
assertEquals(200, resp.status)

// clean up events
resp = client.put(path: "events/delete", query: [categories:"DEPLOYMENT"] )
assertEquals(200, resp.status)
}

}

0 comments on commit 16b51c6

Please sign in to comment.