Java tutorial
/* * * 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.stellar; import com.google.common.collect.ImmutableMap; import org.apache.commons.lang3.Range; import org.apache.metron.common.dsl.Context; import org.apache.metron.common.dsl.ParseException; import org.apache.metron.common.dsl.functions.resolver.FunctionResolver; import org.apache.metron.common.dsl.functions.resolver.SimpleFunctionResolver; import org.apache.metron.common.stellar.StellarProcessor; import org.apache.metron.profiler.ProfilePeriod; import org.apache.metron.profiler.client.window.WindowProcessor; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; public class WindowLookbackTest { static FunctionResolver resolver; static Context context; @BeforeClass public static void setup() { resolver = new SimpleFunctionResolver().withClass(GetProfile.class).withClass(FixedLookback.class) .withClass(WindowLookback.class); context = new Context.Builder().with(Context.Capabilities.GLOBAL_CONFIG, () -> new HashMap<>()).build(); } @Test public void testSpecifyingConfig() throws Exception { //we should be able to specify the config and have it take hold. If we change the //profile duration to 1 minute instead of 15 minutes (the default), then we should see //the correct number of profiles. long durationMs = 60000; State state = test("1 hour", new Date(), Optional.of(ImmutableMap.of(ProfilerConfig.PROFILER_PERIOD.getKey(), 1)), Assertions.NOT_EMPTY, Assertions.CONTIGUOUS); Assert.assertEquals(TimeUnit.HOURS.toMillis(1) / durationMs, state.periods.size()); } @Test public void testSpecifyingOnlySelector() { String stellarStatement = "PROFILE_WINDOW('1 hour')"; Map<String, Object> variables = new HashMap<>(); StellarProcessor stellar = new StellarProcessor(); List<ProfilePeriod> periods = (List<ProfilePeriod>) stellar.parse(stellarStatement, k -> variables.get(k), resolver, context); Assert.assertEquals(TimeUnit.HOURS.toMillis(1) / getDurationMs(), periods.size()); } @Test public void testDenseLookback() throws Exception { State state = test("1 hour", Assertions.NOT_EMPTY, Assertions.CONTIGUOUS); Assert.assertEquals(TimeUnit.HOURS.toMillis(1) / getDurationMs(), state.periods.size()); } @Test public void testShiftedDenseLookback() throws Exception { State state = test("from 2 hours ago to 30 minutes ago", Assertions.NOT_EMPTY, Assertions.CONTIGUOUS, Assertions.INTERVALS_CONTAIN_ALL_PERIODS); Assert.assertEquals(TimeUnit.MINUTES.toMillis(90) / getDurationMs(), state.periods.size()); } @Test public void testShiftedSparseLookback() throws Exception { State state = test("30 minute window every 1 hour from 2 hours ago to 30 minutes ago", Assertions.NOT_EMPTY, Assertions.DISCONTIGUOUS, Assertions.INTERVALS_CONTAIN_ALL_PERIODS); Assert.assertEquals(TimeUnit.MINUTES.toMillis(60) / getDurationMs(), state.periods.size()); } @Test public void testEmptyDueToExclusions() throws Exception { test("30 minute window every 24 hours from 7 days ago including saturdays excluding weekends", Assertions.EMPTY); } @Test(expected = ParseException.class) public void testErrorInSelector() throws Exception { test("30 minute idow every 24 hours from 7 days ago including saturdays excluding weekends", Assertions.EMPTY); } long getDurationMs() { int duration = ProfilerConfig.PROFILER_PERIOD.getDefault(Integer.class); TimeUnit unit = TimeUnit.valueOf(ProfilerConfig.PROFILER_PERIOD_UNITS.getDefault(String.class)); return unit.toMillis(duration); } public State test(String windowSelector, Assertions... assertions) { return test(windowSelector, new Date(), Optional.empty(), assertions); } public State test(String windowSelector, Date now, Optional<Map<String, Object>> config, Assertions... assertions) { List<Range<Long>> windowIntervals = WindowProcessor.process(windowSelector).toIntervals(now.getTime()); String stellarStatement = "PROFILE_WINDOW('" + windowSelector + "', now" + (config.isPresent() ? ", config" : "") + ")"; Map<String, Object> variables = new HashMap<>(); variables.put("now", now.getTime()); if (config.isPresent()) { variables.put("config", config.get()); } StellarProcessor stellar = new StellarProcessor(); List<ProfilePeriod> periods = (List<ProfilePeriod>) stellar.parse(stellarStatement, k -> variables.get(k), resolver, context); State state = new State(windowIntervals, periods); for (Assertions assertion : assertions) { Assert.assertTrue(assertion.name(), assertion.test(state)); } return state; } private enum Assertions implements Predicate<State> { EMPTY(state -> state.windowIntervals.isEmpty() && state.periods.isEmpty()), NOT_EMPTY( state -> !state.windowIntervals.isEmpty() && !state.periods.isEmpty()), CONTIGUOUS(state -> { if (state.periods.size() < 2) { return true; } long duration = state.periods.get(1).getStartTimeMillis() - state.periods.get(0).getStartTimeMillis(); for (int i = 1; i < state.periods.size(); ++i) { long left = state.periods.get(i - 1).getStartTimeMillis(); long right = state.periods.get(i).getStartTimeMillis(); if (right - left != duration) { return false; } } return true; }), DISCONTIGUOUS(state -> !Assertions.CONTIGUOUS.test(state)), INTERVALS_CONTAIN_ALL_PERIODS( state -> { List<Range<Long>> windowIntervals = state.windowIntervals; List<ProfilePeriod> periods = state.periods; Set<Range<Long>> foundIntervals = new HashSet<>(); for (ProfilePeriod period : periods) { boolean found = false; for (Range<Long> interval : windowIntervals) { if (interval.contains(period.getStartTimeMillis())) { foundIntervals.add(interval); found = true; } } if (!found) { return false; } } return foundIntervals.size() == windowIntervals.size(); }); Predicate<State> predicate; Assertions(Predicate<State> predicate) { this.predicate = predicate; } @Override public boolean test(State s) { return predicate.test(s); } } private static class State { List<Range<Long>> windowIntervals; List<ProfilePeriod> periods; public State(List<Range<Long>> windowIntervals, List<ProfilePeriod> periods) { this.periods = periods; this.windowIntervals = windowIntervals; } } }