/*
*
* * RHQ Management Platform
* * Copyright (C) 2005-2012 Red Hat, Inc.
* * All rights reserved.
* *
* * This program is free software; you can redistribute it and/or modify
* * it under the terms of the GNU General Public License, version 2, as
* * published by the Free Software Foundation, and/or the GNU Lesser
* * General Public License, version 2.1, also as published by the Free
* * Software Foundation.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License and the GNU Lesser General Public License
* * for more details.
* *
* * You should have received a copy of the GNU General Public License
* * and the GNU Lesser General Public License along with this program;
* * if not, write to the Free Software Foundation, Inc.,
* * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package org.rhq.server.metrics;
import static java.util.Arrays.asList;
import static org.testng.Assert.assertEquals;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.cassandra.schema.Table;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.server.metrics.domain.AggregateNumericMetric;
import org.rhq.server.metrics.domain.AggregateType;
import org.rhq.server.metrics.domain.Bucket;
import org.rhq.server.metrics.domain.IndexBucket;
import org.rhq.server.metrics.domain.IndexEntry;
import org.rhq.server.metrics.domain.RawNumericMetric;
import org.rhq.server.metrics.domain.RawNumericMetricMapper;
/**
* @author John Sanda
*/
public class MetricsDAOTest extends CassandraIntegrationTest {
private final Log log = LogFactory.getLog(MetricsDAOTest.class);
private static final boolean ENABLED = true;
private final long SECOND = 1000;
private final long MINUTE = 60 * SECOND;
private final long HOUR = 60 * MINUTE;
private MetricsDAO dao;
@BeforeClass
public void initDAO() throws Exception {
dao = new MetricsDAO(storageSession, new MetricsConfiguration());
}
@BeforeMethod
public void resetDB() throws Exception {
for (Table table : Table.values()) {
session.execute("TRUNCATE " + table.getTableName());
}
}
@Test(enabled = ENABLED)
public void insertAndFindRawData() throws Exception {
DateTime hour0 = hour0();
DateTime currentTime = hour0.plusHours(4).plusMinutes(44);
DateTime threeMinutesAgo = currentTime.minusMinutes(3);
int scheduleId = 1;
MeasurementDataNumeric expected = new MeasurementDataNumeric(threeMinutesAgo.getMillis(), scheduleId, 1.23);
WaitForWrite waitForResults = new WaitForWrite(1);
StorageResultSetFuture resultSetFuture = dao.insertRawData(expected);
Futures.addCallback(resultSetFuture, waitForResults);
waitForResults.await("Failed to insert raw data");
List<RawNumericMetric> actualMetrics = Lists.newArrayList(dao.findRawMetrics(scheduleId,
threeMinutesAgo.minusSeconds(1).getMillis(), threeMinutesAgo.plusSeconds(1).getMillis()));
assertEquals(actualMetrics.size(), 1, "Expected to get back one raw metric");
assertEquals(actualMetrics.get(0), new RawNumericMetric(scheduleId, expected.getTimestamp(),
expected.getValue()), "The raw metric does not match the expected value");
}
@Test(enabled = ENABLED)
public void findLatestRawMetric() throws Exception {
DateTime hour0 = hour0();
DateTime currentTime = hour0.plusHours(4).plusMinutes(44);
DateTime threeMinutesAgo = currentTime.minusMinutes(3);
DateTime twoMinutesAgo = currentTime.minusMinutes(2);
DateTime oneMinuteAgo = currentTime.minusMinutes(1);
int scheduleId = 1;
List<MeasurementDataNumeric> data = new ArrayList<MeasurementDataNumeric>();
data.add(new MeasurementDataNumeric(threeMinutesAgo.getMillis(), scheduleId, 3.2));
data.add(new MeasurementDataNumeric(twoMinutesAgo.getMillis(), scheduleId, 3.9));
data.add(new MeasurementDataNumeric(oneMinuteAgo.getMillis(), scheduleId, 2.6));
WaitForWrite waitForWrite = new WaitForWrite(data.size());
for (MeasurementDataNumeric raw : data) {
StorageResultSetFuture resultSetFuture = dao.insertRawData(raw);
Futures.addCallback(resultSetFuture, waitForWrite);
}
waitForWrite.await("Failed to insert raw data");
RawNumericMetric actual = dao.findLatestRawMetric(scheduleId);
RawNumericMetric expected = new RawNumericMetric(scheduleId, oneMinuteAgo.getMillis(), 2.6);
assertEquals(actual, expected, "Failed to find latest raw metric");
}
@Test(enabled = ENABLED)
public void findRawDataAsync() throws Exception {
DateTime hour0 = hour0();
DateTime currentTime = hour0.plusHours(4).plusMinutes(44);
DateTime threeMinutesAgo = currentTime.minusMinutes(3);
DateTime twoMinutesAgo = currentTime.minusMinutes(2);
DateTime oneMinuteAgo = currentTime.minusMinutes(1);
int scheduleId = 1;
List<MeasurementDataNumeric> data = new ArrayList<MeasurementDataNumeric>();
data.add(new MeasurementDataNumeric(threeMinutesAgo.getMillis(), scheduleId, 3.2));
data.add(new MeasurementDataNumeric(twoMinutesAgo.getMillis(), scheduleId, 3.9));
data.add(new MeasurementDataNumeric(oneMinuteAgo.getMillis(), scheduleId, 2.6));
WaitForWrite waitForWrite = new WaitForWrite(data.size());
for (MeasurementDataNumeric raw : data) {
StorageResultSetFuture resultSetFuture = dao.insertRawData(raw);
Futures.addCallback(resultSetFuture, waitForWrite);
}
waitForWrite.await("Failed to insert raw data");
RawNumericMetricMapper mapper = new RawNumericMetricMapper();
WaitForRead<RawNumericMetric> waitForRead = new WaitForRead<RawNumericMetric>(mapper);
StorageResultSetFuture resultSetFuture = dao.findRawMetricsAsync(scheduleId,
threeMinutesAgo.minusSeconds(5).getMillis(), oneMinuteAgo.plusSeconds(5).getMillis());
Futures.addCallback(resultSetFuture, waitForRead);
waitForRead.await("Failed to fetch raw data");
List<RawNumericMetric> actual = waitForRead.getResults();
List<RawNumericMetric> expected = map(data);
assertEquals(actual, expected, "Async read of raw data failed");
}
@Test(enabled = ENABLED)
public void findRawMetricsForMultipleSchedules() throws Exception {
DateTime currentTime = hour0().plusHours(4).plusMinutes(44);
DateTime currentHour = currentTime.hourOfDay().roundFloorCopy();
DateTime threeMinutesAgo = currentTime.minusMinutes(3);
DateTime twoMinutesAgo = currentTime.minusMinutes(2);
DateTime oneMinuteAgo = currentTime.minusMinutes(1);
int scheduleId1 = 1;
int scheduleId2 = 2;
Set<MeasurementDataNumeric> data = new HashSet<MeasurementDataNumeric>();
data.add(new MeasurementDataNumeric(threeMinutesAgo.getMillis(), scheduleId1, 1.1));
data.add(new MeasurementDataNumeric(threeMinutesAgo.getMillis(), scheduleId2, 1.2));
data.add(new MeasurementDataNumeric(twoMinutesAgo.getMillis(), scheduleId1, 2.1));
data.add(new MeasurementDataNumeric(twoMinutesAgo.getMillis(), scheduleId2, 2.2));
data.add(new MeasurementDataNumeric(oneMinuteAgo.getMillis(), scheduleId1, 3.1));
data.add(new MeasurementDataNumeric(oneMinuteAgo.getMillis(), scheduleId2, 3.2));
WaitForWrite waitForWrite = new WaitForWrite(data.size());
for (MeasurementDataNumeric raw : data) {
StorageResultSetFuture resultSetFuture = dao.insertRawData(raw);
Futures.addCallback(resultSetFuture, waitForWrite);
}
waitForWrite.await("Failed to insert raw data");
List<RawNumericMetric> actualMetrics = Lists.newArrayList(dao.findRawMetrics(asList(scheduleId1, scheduleId2),
currentHour.getMillis(), currentHour.plusHours(1).getMillis()));
List<RawNumericMetric> expectedMetrics = asList(
new RawNumericMetric(scheduleId1, threeMinutesAgo.getMillis(), 1.1),
new RawNumericMetric(scheduleId1, twoMinutesAgo.getMillis(), 2.1),
new RawNumericMetric(scheduleId1, oneMinuteAgo.getMillis(), 3.1),
new RawNumericMetric(scheduleId2, threeMinutesAgo.getMillis(), 1.2),
new RawNumericMetric(scheduleId2, twoMinutesAgo.getMillis(), 2.2),
new RawNumericMetric(scheduleId2, oneMinuteAgo.getMillis(), 3.2)
);
assertEquals(actualMetrics, expectedMetrics, "Failed to find raw metrics for multiple schedules");
}
@Test(enabled = ENABLED)
public void insertAndFind1HourMetrics() {
int scheduleId = 100;
AggregateNumericMetric metric1 = new AggregateNumericMetric(scheduleId, Bucket.ONE_HOUR, 3.0, 1.0, 8.0,
hour(0).getMillis());
AggregateNumericMetric metric2 = new AggregateNumericMetric(scheduleId, Bucket.ONE_HOUR, 4.0, 2.0, 10.0,
hour(0).plusMinutes(5).getMillis());
AggregateNumericMetric metric3 = new AggregateNumericMetric(scheduleId + 1, Bucket.ONE_HOUR, 2.0, 2.0, 2.0,
hour(0).getMillis());
dao.insert1HourData(metric1).get();
dao.insert1HourData(metric2).get();
dao.insert1HourData(metric3).get();
List<AggregateNumericMetric> expected = asList(metric1, metric2);
List<AggregateNumericMetric> actual = dao.findAggregateMetrics(scheduleId, Bucket.ONE_HOUR, hour0().getMillis(),
hour(1).getMillis());
assertEquals(actual, expected, "Failed to find 1 hour metrics");
}
@Test(enabled = ENABLED)
public void insertAndFind6HourMetrics() {
int scheduleId = 100;
AggregateNumericMetric metric1 = new AggregateNumericMetric(scheduleId, Bucket.SIX_HOUR, 3.0, 3.0, 3.0,
hour(0).getMillis());
AggregateNumericMetric metric2 = new AggregateNumericMetric(scheduleId, Bucket.SIX_HOUR, 4.0, 4.0, 4.0,
hour(6).getMillis());
AggregateNumericMetric metric3 = new AggregateNumericMetric(scheduleId, Bucket.SIX_HOUR, 5.0, 5.0, 5.0,
hour(12).getMillis());
AggregateNumericMetric metric4 = new AggregateNumericMetric(scheduleId + 1, Bucket.SIX_HOUR, 5.0, 5.0, 5.0,
hour(6).getMillis());
dao.insert6HourData(metric1).get();
dao.insert6HourData(metric2).get();
dao.insert6HourData(metric3).get();
dao.insert6HourData(metric4).get();
List<AggregateNumericMetric> expected = asList(metric2, metric3);
List<AggregateNumericMetric> actual = dao.findAggregateMetrics(scheduleId, Bucket.SIX_HOUR, hour(6).getMillis(),
hour(18).getMillis());
assertEquals(actual, expected, "Failed to find 6 hour metrics");
}
@Test(enabled = ENABLED)
public void insertAndFind24HourMetrics() {
int scheduleId = 100;
AggregateNumericMetric metric1 = new AggregateNumericMetric(scheduleId, Bucket.TWENTY_FOUR_HOUR, 3.0, 3.0, 3.0,
hour(0).getMillis());
AggregateNumericMetric metric2 = new AggregateNumericMetric(scheduleId, Bucket.TWENTY_FOUR_HOUR, 4.0, 4.0, 4.0,
hour(0).plusDays(2).getMillis());
AggregateNumericMetric metric3 = new AggregateNumericMetric(scheduleId, Bucket.TWENTY_FOUR_HOUR, 5.0, 5.0, 5.0,
hour(0).plusDays(3).getMillis());
AggregateNumericMetric metric4 = new AggregateNumericMetric(scheduleId, Bucket.TWENTY_FOUR_HOUR, 6.0, 6.0, 6.0,
hour(0).plusDays(4).getMillis());
AggregateNumericMetric metric5 = new AggregateNumericMetric(scheduleId + 1, Bucket.TWENTY_FOUR_HOUR, 4.0, 4.0,
4.0, hour(0).plusDays(2).getMillis());
dao.insert24HourData(metric1).get();
dao.insert24HourData(metric2).get();
dao.insert24HourData(metric3).get();
dao.insert24HourData(metric4).get();
dao.insert24HourData(metric5).get();
List<AggregateNumericMetric> expected = asList(metric2, metric3);
List<AggregateNumericMetric> actual = dao.findAggregateMetrics(scheduleId, Bucket.TWENTY_FOUR_HOUR,
hour(0).plusDays(2).getMillis(), hour(0).plusDays(4).getMillis());
assertEquals(actual, expected, "Failed to find 24 hour metrics");
}
@Test(enabled = ENABLED)
public void insertAndFindIndexEntries() {
dao = new MetricsDAO(storageSession, new MetricsConfiguration().setIndexPageSize(2).setIndexPartitions(1));
IndexEntry entry1 = new IndexEntry(IndexBucket.RAW, 0, hour(2).getMillis(), 100);
IndexEntry entry2 = new IndexEntry(IndexBucket.RAW, 0, hour(2).getMillis(), 101);
IndexEntry entry5 = new IndexEntry(IndexBucket.RAW, 0, hour(2).getMillis(), 103);
IndexEntry entry6 = new IndexEntry(IndexBucket.RAW, 0, hour(2).getMillis(), 104);
dao.updateIndex(IndexBucket.RAW, hour(2).getMillis(), 100).get();
dao.updateIndex(IndexBucket.RAW, hour(2).getMillis(), 101).get();
dao.updateIndex(IndexBucket.RAW, hour(2).getMillis(), 102).get();
dao.updateIndex(IndexBucket.RAW, hour(3).getMillis(), 101).get();
dao.updateIndex(IndexBucket.RAW, hour(2).getMillis(), 103).get();
dao.updateIndex(IndexBucket.RAW, hour(2).getMillis(), 104).get();
dao.updateIndex(IndexBucket.RAW, hour(2).getMillis(), 105).get();
List<IndexEntry> expected = asList(entry1, entry2);
List<IndexEntry> actual = new ArrayList<IndexEntry>();
ResultSet resultSet = dao.findIndexEntries(IndexBucket.RAW, 0, hour(2).getMillis()).get();
for (Row row : resultSet) {
actual.add(new IndexEntry(IndexBucket.RAW, 0, hour(2).getMillis(), row.getInt(0)));
}
assertEquals(actual, expected, "The first page of index entries is wrong");
actual.clear();
resultSet = dao.findIndexEntries(IndexBucket.RAW, 0, hour(2).getMillis(), 102).get();
expected = asList(entry5, entry6);
for (Row row : resultSet) {
actual.add(new IndexEntry(IndexBucket.RAW, 0, hour(2).getMillis(), row.getInt(0)));
}
assertEquals(actual, expected, "The next page of index entries is wrong");
}
private List<RawNumericMetric> map(List<MeasurementDataNumeric> data) {
List<RawNumericMetric> raw = new ArrayList<RawNumericMetric>(data.size());
for (MeasurementDataNumeric datum : data) {
raw.add(new RawNumericMetric(datum.getScheduleId(), datum.getTimestamp(), datum.getValue()));
}
return raw;
}
}