/* * 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.kafka.streams.state.internals; import org.apache.kafka.common.metrics.Metrics; import org.apache.kafka.common.serialization.Serdes; import org.apache.kafka.streams.processor.internals.MockStreamsMetrics; import org.apache.kafka.test.MockProcessorContext; import org.apache.kafka.test.NoOpRecordCollector; import org.apache.kafka.test.TestUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.File; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class SegmentsTest { private static final int NUM_SEGMENTS = 5; private MockProcessorContext context; private Segments segments; @Before public void createContext() { context = new MockProcessorContext(TestUtils.tempDirectory(), Serdes.String(), Serdes.Long(), new NoOpRecordCollector(), new ThreadCache("testCache", 0, new MockStreamsMetrics(new Metrics()))); segments = new Segments("test", 4 * 60 * 1000, NUM_SEGMENTS); } @After public void close() { context.close(); segments.close(); } @Test public void shouldGetSegmentIdsFromTimestamp() throws Exception { assertEquals(0, segments.segmentId(0)); assertEquals(1, segments.segmentId(60000)); assertEquals(2, segments.segmentId(120000)); assertEquals(3, segments.segmentId(180000)); } @Test public void shouldBaseSegmentIntervalOnRetentionAndNumSegments() throws Exception { final Segments segments = new Segments("test", 8 * 60 * 1000, 5); assertEquals(0, segments.segmentId(0)); assertEquals(0, segments.segmentId(60000)); assertEquals(1, segments.segmentId(120000)); } @Test public void shouldGetSegmentNameFromId() throws Exception { assertEquals("test-197001010000", segments.segmentName(0)); assertEquals("test-197001010001", segments.segmentName(1)); assertEquals("test-197001010002", segments.segmentName(2)); } @Test public void shouldCreateSegments() throws Exception { final Segment segment1 = segments.getOrCreateSegment(0, context); final Segment segment2 = segments.getOrCreateSegment(1, context); final Segment segment3 = segments.getOrCreateSegment(2, context); assertTrue(new File(context.stateDir(), "test/test-197001010000").isDirectory()); assertTrue(new File(context.stateDir(), "test/test-197001010001").isDirectory()); assertTrue(new File(context.stateDir(), "test/test-197001010002").isDirectory()); assertEquals(true, segment1.isOpen()); assertEquals(true, segment2.isOpen()); assertEquals(true, segment3.isOpen()); } @Test public void shouldNotCreateSegmentThatIsAlreadyExpired() throws Exception { segments.getOrCreateSegment(7, context); assertNull(segments.getOrCreateSegment(0, context)); assertFalse(new File(context.stateDir(), "test/test-197001010000").exists()); } @Test public void shouldCleanupSegmentsThatHaveExpired() throws Exception { final Segment segment1 = segments.getOrCreateSegment(0, context); final Segment segment2 = segments.getOrCreateSegment(0, context); final Segment segment3 = segments.getOrCreateSegment(7, context); assertFalse(segment1.isOpen()); assertFalse(segment2.isOpen()); assertTrue(segment3.isOpen()); assertFalse(new File(context.stateDir(), "test/test-197001010000").exists()); assertFalse(new File(context.stateDir(), "test/test-197001010001").exists()); assertTrue(new File(context.stateDir(), "test/test-197001010007").exists()); } @Test public void shouldGetSegmentForTimestamp() throws Exception { final Segment segment = segments.getOrCreateSegment(0, context); segments.getOrCreateSegment(1, context); assertEquals(segment, segments.getSegmentForTimestamp(0L)); } @Test public void shouldCloseAllOpenSegments() throws Exception { final Segment first = segments.getOrCreateSegment(0, context); final Segment second = segments.getOrCreateSegment(1, context); final Segment third = segments.getOrCreateSegment(2, context); segments.close(); assertFalse(first.isOpen()); assertFalse(second.isOpen()); assertFalse(third.isOpen()); } @Test public void shouldOpenExistingSegments() throws Exception { segments.getOrCreateSegment(0, context); segments.getOrCreateSegment(1, context); segments.getOrCreateSegment(2, context); segments.getOrCreateSegment(3, context); segments.getOrCreateSegment(4, context); // close existing. segments.close(); segments = new Segments("test", 4 * 60 * 1000, 5); segments.openExisting(context); assertTrue(segments.getSegmentForTimestamp(0).isOpen()); assertTrue(segments.getSegmentForTimestamp(1).isOpen()); assertTrue(segments.getSegmentForTimestamp(2).isOpen()); assertTrue(segments.getSegmentForTimestamp(3).isOpen()); assertTrue(segments.getSegmentForTimestamp(4).isOpen()); } @Test public void shouldGetSegmentsWithinTimeRange() throws Exception { segments.getOrCreateSegment(0, context); segments.getOrCreateSegment(1, context); segments.getOrCreateSegment(2, context); segments.getOrCreateSegment(3, context); segments.getOrCreateSegment(4, context); final List<Segment> segments = this.segments.segments(0, 2 * 60 * 1000); assertEquals(3, segments.size()); assertEquals(0, segments.get(0).id); assertEquals(1, segments.get(1).id); assertEquals(2, segments.get(2).id); } @Test public void shouldRollSegments() throws Exception { segments.getOrCreateSegment(0, context); verifyCorrectSegments(0, 1); segments.getOrCreateSegment(1, context); verifyCorrectSegments(0, 2); segments.getOrCreateSegment(2, context); verifyCorrectSegments(0, 3); segments.getOrCreateSegment(3, context); verifyCorrectSegments(0, 4); segments.getOrCreateSegment(4, context); verifyCorrectSegments(0, 5); segments.getOrCreateSegment(5, context); verifyCorrectSegments(1, 5); segments.getOrCreateSegment(6, context); verifyCorrectSegments(2, 5); } private void verifyCorrectSegments(final long first, final int numSegments) { final List<Segment> result = this.segments.segments(0, Long.MAX_VALUE); assertEquals(numSegments, result.size()); for (int i = 0; i < numSegments; i++) { assertEquals(i + first, result.get(i).id); } } }