/*
* 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.beam.sdk.transforms.windowing;
import static org.apache.beam.sdk.testing.WindowFnTestUtils.runWindowFn;
import static org.apache.beam.sdk.testing.WindowFnTestUtils.set;
import static org.apache.beam.sdk.transforms.display.DisplayDataMatchers.hasDisplayItem;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.beam.sdk.testing.WindowFnTestUtils;
import org.apache.beam.sdk.transforms.display.DisplayData;
import org.hamcrest.Matchers;
import org.joda.time.Duration;
import org.joda.time.Instant;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests for FixedWindows WindowFn.
*/
@RunWith(JUnit4.class)
public class FixedWindowsTest {
@Rule public ExpectedException thrown = ExpectedException.none();
@Test
public void testSimpleFixedWindow() throws Exception {
Map<IntervalWindow, Set<String>> expected = new HashMap<>();
expected.put(new IntervalWindow(new Instant(0), new Instant(10)), set(1, 2, 5, 9));
expected.put(new IntervalWindow(new Instant(10), new Instant(20)), set(10, 11));
expected.put(new IntervalWindow(new Instant(100), new Instant(110)), set(100));
assertEquals(
expected,
runWindowFn(
FixedWindows.of(new Duration(10)),
Arrays.asList(1L, 2L, 5L, 9L, 10L, 11L, 100L)));
}
@Test
public void testFixedOffsetWindow() throws Exception {
Map<IntervalWindow, Set<String>> expected = new HashMap<>();
expected.put(new IntervalWindow(new Instant(-5), new Instant(5)), set(1, 2));
expected.put(new IntervalWindow(new Instant(5), new Instant(15)), set(5, 9, 10, 11));
expected.put(new IntervalWindow(new Instant(95), new Instant(105)), set(100));
assertEquals(
expected,
runWindowFn(
FixedWindows.of(new Duration(10)).withOffset(new Duration(5)),
Arrays.asList(1L, 2L, 5L, 9L, 10L, 11L, 100L)));
}
@Test
public void testTimeUnit() throws Exception {
Map<IntervalWindow, Set<String>> expected = new HashMap<>();
expected.put(new IntervalWindow(new Instant(-5000), new Instant(5000)), set(1, 2, 1000));
expected.put(new IntervalWindow(new Instant(5000), new Instant(15000)), set(5000, 5001, 10000));
assertEquals(
expected,
runWindowFn(
FixedWindows.of(Duration.standardSeconds(10)).withOffset(Duration.standardSeconds(5)),
Arrays.asList(1L, 2L, 1000L, 5000L, 5001L, 10000L)));
}
@Test
public void testDefaultWindowMappingFn() {
PartitioningWindowFn<?, ?> windowFn = FixedWindows.of(Duration.standardMinutes(20L));
WindowMappingFn<?> mapping = windowFn.getDefaultWindowMappingFn();
assertThat(
mapping.getSideInputWindow(
new BoundedWindow() {
@Override
public Instant maxTimestamp() {
return new Instant(100L);
}
}),
Matchers.<BoundedWindow>equalTo(
new IntervalWindow(
new Instant(0L), new Instant(0L).plus(Duration.standardMinutes(20L)))));
assertThat(mapping.maximumLookback(), equalTo(Duration.ZERO));
}
@Test
public void testDefaultWindowMappingFnGlobalWindow() {
PartitioningWindowFn<?, ?> windowFn = FixedWindows.of(Duration.standardMinutes(20L));
WindowMappingFn<?> mapping = windowFn.getDefaultWindowMappingFn();
thrown.expect(IllegalArgumentException.class);
mapping.getSideInputWindow(GlobalWindow.INSTANCE);
}
void checkConstructionFailure(int size, int offset) {
try {
FixedWindows.of(Duration.standardSeconds(size)).withOffset(Duration.standardSeconds(offset));
fail("should have failed");
} catch (IllegalArgumentException e) {
assertThat(e.toString(),
containsString("FixedWindows WindowingStrategies must have 0 <= offset < size"));
}
}
@Test
public void testInvalidInput() throws Exception {
checkConstructionFailure(-1, 0);
checkConstructionFailure(1, 2);
checkConstructionFailure(1, -1);
}
@Test
public void testEquality() {
assertTrue(FixedWindows.of(new Duration(10)).isCompatible(FixedWindows.of(new Duration(10))));
assertTrue(
FixedWindows.of(new Duration(10)).isCompatible(
FixedWindows.of(new Duration(10))));
assertTrue(
FixedWindows.of(new Duration(10)).isCompatible(
FixedWindows.of(new Duration(10))));
assertFalse(FixedWindows.of(new Duration(10)).isCompatible(FixedWindows.of(new Duration(20))));
assertFalse(FixedWindows.of(new Duration(10)).isCompatible(
FixedWindows.of(new Duration(20))));
}
@Test
public void testVerifyCompatibility() throws IncompatibleWindowException {
FixedWindows.of(new Duration(10)).verifyCompatibility(FixedWindows.of(new Duration(10)));
thrown.expect(IncompatibleWindowException.class);
FixedWindows.of(new Duration(10)).verifyCompatibility(FixedWindows.of(new Duration(20)));
}
@Test
public void testValidOutputTimes() throws Exception {
for (long timestamp : Arrays.asList(200, 800, 700)) {
WindowFnTestUtils.validateGetOutputTimestamp(
FixedWindows.of(new Duration(500)), timestamp);
}
}
@Test
public void testDisplayData() {
Duration offset = Duration.standardSeconds(1234);
Duration size = Duration.standardSeconds(2345);
FixedWindows fixedWindows = FixedWindows.of(size).withOffset(offset);
DisplayData displayData = DisplayData.from(fixedWindows);
assertThat(displayData, hasDisplayItem("size", size));
assertThat(displayData, hasDisplayItem("offset", offset));
}
}