Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F78231057
HeartbeatTest.groovy
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Aug 19, 07:21
Size
8 KB
Mime Type
text/x-c++
Expires
Wed, Aug 21, 07:21 (2 d)
Engine
blob
Format
Raw Data
Handle
20006348
Attached To
R2664 SHRINE MedCo Fork
HeartbeatTest.groovy
View Options
package net.shrine.utilities.heartbeat
import groovy.sql.GroovyRowResult
import groovy.sql.Sql
import org.junit.After
import org.junit.Before
import org.junit.Test
import static junit.framework.Assert.*
/**
* @author Bill Simons
* @date 1/19/11
* @link http://cbmi.med.harvard.edu
* @link http://chip.org
* <p/>
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @link http://www.gnu.org/licenses/lgpl.html
*/
class HeartbeatTest {
Sql sql
Heartbeat heartbeat
List nodes = ['FINISHED_NODE', 'ERROR_NODE', 'PROCESSING_NODE', 'NOT_RESPONDING_NODE']
@Before
void setUp() {
setUpSql()
heartbeat = new Heartbeat([expectedNumberOfNodes: 3, failureThreshold: [businessHours: 2, offHours: 2], period: [hours: 2]], sql)
}
def setUpSql() {
sql = Sql.newInstance("jdbc:h2:mem:test", "sa", "", "org.h2.Driver")
sql.execute('''create table NODE (
ID integer not null auto_increment primary key,
NAME varchar(20),
FAILURE_COUNT integer default 0,
constraint NODE_NAME_IX unique (NAME)
)''')
sql.execute('''create table HEARTBEAT_FAILURE (
ID integer not null auto_increment primary key,
FAILURE_TIME timestamp default CURRENT_TIMESTAMP,
MESSAGE varchar(512)
)''')
sql.execute('''create table NODE_FAILURE (
ID integer not null auto_increment primary key,
FAILURE_ID integer,
NODE_ID integer,
constraint FK_NODE_FAILURE_HEARTBEAT_FAILURE_FAILURE_ID foreign key (FAILURE_ID) references HEARTBEAT_FAILURE (ID),
constraint FK_NODE_FAILURE_NODE_NODE_ID foreign key (NODE_ID) references NODE (ID)
)''')
sql.execute('''create table EMAIL_NOTIFICATION (
LAST_NOTIFICATION timestamp default CURRENT_TIMESTAMP
)''')
def nodeFailureCounts = sql.dataSet('NODE')
nodes.each {
nodeFailureCounts.add(name: it)
}
}
@After
void tearDownTables() {
sql.execute('drop table NODE')
sql.execute('drop table HEARTBEAT_FAILURE')
sql.execute('drop table NODE_FAILURE')
sql.execute('drop table EMAIL_NOTIFICATION')
}
@Test
void testGenerateReport() {
InputStream stream = HeartbeatTest.class.getResourceAsStream('/net/shrine/utilities/heartbeat/test_response.xml')
assertNotNull stream
def report = heartbeat.generateReport(heartbeat.parseResponse(stream.text))
assertEquals 3, report.numberOfResults
assertEquals 3, report.nodeResults.size()
assertTrue report.nodeResults.contains([name: "FINISHED_NODE", status: "FINISHED", statusMessage: ""])
assertTrue report.nodeResults.contains([name: "ERROR_NODE", status: "ERROR", statusMessage: "Panel 1 contains no mappable terms"])
assertTrue report.nodeResults.contains([name: "PROCESSING_NODE", status: "PROCESSING", statusMessage: ""])
assertEquals 3, report.alertingNodes.size()
assertTrue report.alertingNodes.contains("ERROR_NODE") //error
assertTrue report.alertingNodes.contains("PROCESSING_NODE") //processing
assertTrue report.alertingNodes.contains("NOT_RESPONDING_NODE") //not reporting
assertEquals 2, report.errorNodes.size()
assertTrue report.errorNodes.contains("ERROR_NODE") //error
assertTrue report.errorNodes.contains("PROCESSING_NODE") //processing
assertEquals 1, report.nonReportingNodes.size()
assertTrue report.nonReportingNodes.contains("NOT_RESPONDING_NODE")
}
@Test
void testGenerateAlertMessage() {
InputStream stream = HeartbeatTest.class.getResourceAsStream('/net/shrine/utilities/heartbeat/test_response.xml')
assertNotNull stream
def report = [:]
report.queryCompleted = true
report.numberOfResults = 3
report.nodeResults = []
report.nodeResults << [name: "FINISHED_NODE", status: "FINISHED", statusMessage: "FINISHED"]
report.nodeResults << [name: "ERROR_NODE", status: "ERROR", statusMessage: "Adaptor Mapping error"]
report.nodeResults << [name: "PROCESSING_NODE", status: "PROCESSING", statusMessage: "PROCESSING"]
report.nonReportingNodes = ["NOT_RESPONDING_NODE"]
String alertMessage = heartbeat.generateAlertMessage(report)
assertNotNull alertMessage
assertEquals """\
3 of 4 nodes reporting:
FINISHED_NODE reported status FINISHED
ERROR_NODE reported status ERROR: Adaptor Mapping error
PROCESSING_NODE reported status PROCESSING
1 of 4 nodes did not report:
NOT_RESPONDING_NODE
""".stripIndent(), alertMessage
}
@Test
public void testUpdateDbNodeFailureCount() {
heartbeat.updateDbNodeFailureCount nodes
nodes.each { nodeName ->
def row = sql.firstRow("select * from NODE where NAME=${nodeName}")
assertNotNull row
assertEquals 1, row.failure_count
}
def nodeName = nodes[0]
heartbeat.updateDbNodeFailureCount([nodeName])
def row = sql.firstRow("select * from NODE where NAME=${nodeName}")
assertNotNull row
assertEquals 2, row.failure_count
sql.eachRow("select * from NODE where NAME != ${nodeName}") {
assertEquals 0, it.failure_count
}
heartbeat.updateDbNodeFailureCount([])
assertNull sql.firstRow("select * from NODE where FAILURE_COUNT > 0")
heartbeat.updateDbNodeFailureCount(null)
assertNull sql.firstRow("select * from NODE where FAILURE_COUNT > 0")
}
@Test
public void testIdentifyNonReportingNodes() {
InputStream stream = HeartbeatTest.class.getResourceAsStream('/net/shrine/utilities/heartbeat/test_response.xml')
assertNotNull stream
List nonReportingNodes = heartbeat.identifyNonReportingNodes(heartbeat.parseResponse(stream.text))
assertEquals 1, nonReportingNodes.size()
assertTrue nonReportingNodes.contains("NOT_RESPONDING_NODE")
nonReportingNodes = heartbeat.identifyNonReportingNodes(null)
assertEquals 4, nonReportingNodes.size()
}
@Test
public void testIdentifyNonNormalNodes() {
InputStream stream = HeartbeatTest.class.getResourceAsStream('/net/shrine/utilities/heartbeat/test_response.xml')
assertNotNull stream
List nonNormalNodes = heartbeat.identifyErrorNodes(heartbeat.parseResponse(stream.text))
assertEquals 2, nonNormalNodes.size()
assertTrue nonNormalNodes.contains("ERROR_NODE")
assertTrue nonNormalNodes.contains("PROCESSING_NODE")
}
@Test
public void testExpectedNumberOfNodes() {
assertEquals nodes.size(), heartbeat.expectedNumberOfNodes()
}
@Test
public void testThresholdExceeded() {
assertFalse heartbeat.thresholdExceeded()
sql.executeUpdate "update NODE set FAILURE_COUNT = 2 where NAME = 'ERROR_NODE'"
assertTrue heartbeat.thresholdExceeded()
}
@Test
public void testEmailSentToday() {
sql.executeUpdate "insert into EMAIL_NOTIFICATION VALUES(CURRENT_TIMESTAMP())"
assertTrue heartbeat.alreadyEmailedThisPeriod()
sql.executeUpdate "update EMAIL_NOTIFICATION set LAST_NOTIFICATION= DATEADD('HOUR', -1, CURRENT_TIMESTAMP())"
assertTrue heartbeat.alreadyEmailedThisPeriod()
sql.executeUpdate "update EMAIL_NOTIFICATION set LAST_NOTIFICATION= DATEADD('HOUR', -3, CURRENT_TIMESTAMP())"
assertFalse heartbeat.alreadyEmailedThisPeriod()
}
@Test
public void testAuditAlert() {
def alertMessage = 'alert message'
heartbeat.auditAlert alertMessage, nodes
List<GroovyRowResult> failRows = sql.rows('select * from HEARTBEAT_FAILURE')
assertEquals 1, failRows.size()
assertEquals alertMessage, failRows[0].message
assertNotNull failRows[0].failure_time
List<GroovyRowResult> failNodeRows = sql.rows("select * from NODE_FAILURE where FAILURE_ID=${failRows[0].id}")
assertEquals nodes.size(), failNodeRows.size()
}
@Test
public void testInBusinessHours() {
Calendar testTime = Calendar.instance
println testTime.time
testTime[Calendar.DAY_OF_WEEK] = Calendar.SUNDAY
println testTime.time
assertFalse(heartbeat.inBusinessHours(testTime))
testTime[Calendar.DAY_OF_WEEK] = Calendar.MONDAY
testTime[Calendar.HOUR_OF_DAY] = 10
println testTime.time
assertTrue(heartbeat.inBusinessHours(testTime))
testTime[Calendar.HOUR_OF_DAY] = 13
assertTrue(heartbeat.inBusinessHours(testTime))
testTime[Calendar.HOUR_OF_DAY] = 8
assertFalse(heartbeat.inBusinessHours(testTime))
testTime[Calendar.HOUR_OF_DAY] = 17
testTime[Calendar.MINUTE] = 1
assertFalse(heartbeat.inBusinessHours(testTime))
}
}
Event Timeline
Log In to Comment