blob: 5b513abee101db5bbef1638046278b86c216ee83 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.metron.profiler.client;
import org.apache.metron.hbase.mock.MockHBaseTableProvider;
import org.apache.metron.hbase.mock.MockHTable;
import org.apache.metron.profiler.ProfileMeasurement;
import org.apache.metron.profiler.hbase.ColumnBuilder;
import org.apache.metron.profiler.hbase.RowKeyBuilder;
import org.apache.metron.profiler.hbase.SaltyRowKeyBuilder;
import org.apache.metron.profiler.hbase.ValueOnlyColumnBuilder;
import org.apache.metron.stellar.common.DefaultStellarStatefulExecutor;
import org.apache.metron.stellar.common.StellarStatefulExecutor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests the HBaseProfilerClient.
*
* The naming used in this test attempts to be as similar to how the 'groupBy'
* functionality might be used 'in the wild'. This test involves reading and
* writing two separate groups originating from the same Profile and Entity.
* There is a 'weekdays' group which contains all measurements taken on weekdays.
* There is also a 'weekend' group which contains all measurements taken on weekends.
*/
public class HBaseProfilerClientTest {
private static final String tableName = "profiler";
private static final String columnFamily = "P";
private static final long periodDuration = 15;
private static final TimeUnit periodUnits = TimeUnit.MINUTES;
private static final int periodsPerHour = 4;
private HBaseProfilerClient client;
private StellarStatefulExecutor executor;
private MockHBaseTableProvider provider;
private ProfileWriter profileWriter;
@BeforeEach
public void setup() {
provider = new MockHBaseTableProvider();
executor = new DefaultStellarStatefulExecutor();
MockHBaseTableProvider.addToCache(tableName, columnFamily);
// writes values to be read during testing
long periodDurationMillis = periodUnits.toMillis(periodDuration);
RowKeyBuilder rowKeyBuilder = new SaltyRowKeyBuilder();
ColumnBuilder columnBuilder = new ValueOnlyColumnBuilder(columnFamily);
profileWriter = new ProfileWriter(rowKeyBuilder, columnBuilder, provider, periodDurationMillis,
tableName, null);
client = new HBaseProfilerClient(provider, rowKeyBuilder, columnBuilder, periodDurationMillis,
tableName, null);
}
@AfterEach
public void tearDown() throws Exception {
((MockHTable) provider.getTable(null, tableName)).clear();
}
@Test
public void Should_ReturnMeasurements_When_DataExistsForAGroup() {
final String profile = "profile1";
final String entity = "entity1";
final int expectedValue = 2302;
final int hours = 2;
final int count = hours * periodsPerHour + 1;
final long startTime = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(hours);
// setup - write two groups of measurements - 'weekends' and 'weekdays'
ProfileMeasurement prototype = new ProfileMeasurement()
.withProfileName(profile)
.withEntity(entity)
.withPeriod(startTime, periodDuration, periodUnits);
profileWriter.write(prototype, count, Arrays.asList("weekdays"), val -> expectedValue);
profileWriter.write(prototype, count, Arrays.asList("weekends"), val -> 0);
long end = System.currentTimeMillis();
long start = end - TimeUnit.HOURS.toMillis(2);
{
//validate "weekday" results
List<Object> groups = Arrays.asList("weekdays");
List<ProfileMeasurement> results = client.fetch(Integer.class, profile, entity, groups, start, end, Optional.empty());
assertEquals(count, results.size());
results.forEach(actual -> {
assertEquals(profile, actual.getProfileName());
assertEquals(entity, actual.getEntity());
assertEquals(groups, actual.getGroups());
assertEquals(expectedValue, actual.getProfileValue());
});
}
{
//validate "weekend" results
List<Object> groups = Arrays.asList("weekends");
List<ProfileMeasurement> results = client.fetch(Integer.class, profile, entity, groups, start, end, Optional.empty());
assertEquals(count, results.size());
results.forEach(actual -> {
assertEquals(profile, actual.getProfileName());
assertEquals(entity, actual.getEntity());
assertEquals(groups, actual.getGroups());
assertEquals(0, actual.getProfileValue());
});
}
}
@Test
public void Should_ReturnResultFromGroup_When_MultipleGroupsExist() {
final String profile = "profile1";
final String entity = "entity1";
final int periodsPerHour = 4;
final int expectedValue = 2302;
final int hours = 2;
final int count = hours * periodsPerHour;
final long endTime = System.currentTimeMillis();
final long startTime = endTime - TimeUnit.HOURS.toMillis(hours);
// setup - write two groups of measurements - 'weekends' and 'weekdays'
ProfileMeasurement m = new ProfileMeasurement()
.withProfileName("profile1")
.withEntity("entity1")
.withPeriod(startTime, periodDuration, periodUnits);
profileWriter.write(m, count, Arrays.asList("weekdays"), val -> expectedValue);
profileWriter.write(m, count, Arrays.asList("weekends"), val -> 0);
List<Object> weekdays = Arrays.asList("weekdays");
List<ProfileMeasurement> results = client.fetch(Integer.class, profile, entity, weekdays, startTime, endTime, Optional.empty());
// should only return results from 'weekdays' group
assertEquals(count, results.size());
results.forEach(actual -> assertEquals(weekdays, actual.getGroups()));
}
@Test
public void Should_ReturnNoResults_When_GroupDoesNotExist() {
final String profile = "profile1";
final String entity = "entity1";
final int periodsPerHour = 4;
final int expectedValue = 2302;
final int hours = 2;
final int count = hours * periodsPerHour;
final long endTime = System.currentTimeMillis();
final long startTime = endTime - TimeUnit.HOURS.toMillis(hours);
// create two groups of measurements - one on weekdays and one on weekends
ProfileMeasurement m = new ProfileMeasurement()
.withProfileName("profile1")
.withEntity("entity1")
.withPeriod(startTime, periodDuration, periodUnits);
profileWriter.write(m, count, Arrays.asList("weekdays"), val -> expectedValue);
profileWriter.write(m, count, Arrays.asList("weekends"), val -> 0);
// should return no results when the group does not exist
List<Object> groups = Arrays.asList("does-not-exist");
List<ProfileMeasurement> results = client.fetch(Integer.class, profile, entity, groups, startTime, endTime, Optional.empty());
assertEquals(0, results.size());
}
@Test
public void Should_ReturnNoResults_When_NoDataInStartToEnd() {
final String profile = "profile1";
final String entity = "entity1";
final int hours = 2;
int numberToWrite = hours * periodsPerHour;
final List<Object> group = Arrays.asList("weekends");
final long measurementTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
// write some data with a timestamp of s1 day ago
ProfileMeasurement prototype = new ProfileMeasurement()
.withProfileName("profile1")
.withEntity("entity1")
.withPeriod(measurementTime, periodDuration, periodUnits);
profileWriter.write(prototype, numberToWrite, group, val -> 1000);
// should return no results when [start,end] is long after when test data was written
final long endFetchAt = System.currentTimeMillis();
final long startFetchAt = endFetchAt - TimeUnit.MILLISECONDS.toMillis(30);
List<ProfileMeasurement> results = client.fetch(Integer.class, profile, entity, group, startFetchAt, endFetchAt, Optional.empty());
assertEquals(0, results.size());
}
}