| /* |
| * |
| * 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()); |
| } |
| } |