@BeforeClass public static void setupClass() throws Exception { incrementalIndex = new OnheapIncrementalIndex( 0, QueryGranularities.NONE, new AggregatorFactory[] {new CountAggregatorFactory("count")}, true, true, true, 5000); StringInputRowParser parser = new StringInputRowParser( new CSVParseSpec( new TimestampSpec("timestamp", "iso", null), new DimensionsSpec( DimensionsSpec.getDefaultSchemas(ImmutableList.of("product", "tags")), null, null), "\t", ImmutableList.of("timestamp", "product", "tags")), "UTF-8"); String[] rows = new String[] { "2011-01-12T00:00:00.000Z,product_1,t1\tt2\tt3", "2011-01-13T00:00:00.000Z,product_2,t3\tt4\tt5", "2011-01-14T00:00:00.000Z,product_3,t5\tt6\tt7", }; for (String row : rows) { incrementalIndex.add(parser.parse(row)); } persistedSegmentDir = Files.createTempDir(); TestHelper.getTestIndexMerger().persist(incrementalIndex, persistedSegmentDir, new IndexSpec()); queryableIndex = TestHelper.getTestIndexIO().loadIndex(persistedSegmentDir); }
@Parameterized.Parameters(name = "{1}") public static Collection<Object[]> constructorFeeder() throws IOException { final IndexSpec indexSpec = new IndexSpec(); final HeapMemoryTaskStorage ts = new HeapMemoryTaskStorage(new TaskStorageConfig(null) {}); final IncrementalIndexSchema schema = new IncrementalIndexSchema.Builder() .withQueryGranularity(QueryGranularities.NONE) .withMinTimestamp(JodaUtils.MIN_INSTANT) .withDimensionsSpec(ROW_PARSER) .withMetrics( new AggregatorFactory[] { new LongSumAggregatorFactory(METRIC_LONG_NAME, DIM_LONG_NAME), new DoubleSumAggregatorFactory(METRIC_FLOAT_NAME, DIM_FLOAT_NAME) }) .build(); final OnheapIncrementalIndex index = new OnheapIncrementalIndex(schema, true, MAX_ROWS * MAX_SHARD_NUMBER); for (Integer i = 0; i < MAX_ROWS; ++i) { index.add(ROW_PARSER.parse(buildRow(i.longValue()))); } if (!persistDir.mkdirs() && !persistDir.exists()) { throw new IOException( String.format("Could not create directory at [%s]", persistDir.getAbsolutePath())); } INDEX_MERGER.persist(index, persistDir, indexSpec); final TaskLockbox tl = new TaskLockbox(ts); final IndexerSQLMetadataStorageCoordinator mdc = new IndexerSQLMetadataStorageCoordinator(null, null, null) { private final Set<DataSegment> published = Sets.newHashSet(); private final Set<DataSegment> nuked = Sets.newHashSet(); @Override public List<DataSegment> getUsedSegmentsForInterval(String dataSource, Interval interval) throws IOException { return ImmutableList.copyOf(segmentSet); } @Override public List<DataSegment> getUsedSegmentsForIntervals( String dataSource, List<Interval> interval) throws IOException { return ImmutableList.copyOf(segmentSet); } @Override public List<DataSegment> getUnusedSegmentsForInterval( String dataSource, Interval interval) { return ImmutableList.of(); } @Override public Set<DataSegment> announceHistoricalSegments(Set<DataSegment> segments) { Set<DataSegment> added = Sets.newHashSet(); for (final DataSegment segment : segments) { if (published.add(segment)) { added.add(segment); } } return ImmutableSet.copyOf(added); } @Override public void deleteSegments(Set<DataSegment> segments) { nuked.addAll(segments); } }; final LocalTaskActionClientFactory tac = new LocalTaskActionClientFactory(ts, new TaskActionToolbox(tl, mdc, newMockEmitter())); SegmentHandoffNotifierFactory notifierFactory = EasyMock.createNiceMock(SegmentHandoffNotifierFactory.class); EasyMock.replay(notifierFactory); final TaskToolboxFactory taskToolboxFactory = new TaskToolboxFactory( new TaskConfig(tmpDir.getAbsolutePath(), null, null, 50000, null, false, null, null), tac, newMockEmitter(), new DataSegmentPusher() { @Deprecated @Override public String getPathForHadoop(String dataSource) { return getPathForHadoop(); } @Override public String getPathForHadoop() { throw new UnsupportedOperationException(); } @Override public DataSegment push(File file, DataSegment segment) throws IOException { return segment; } }, new DataSegmentKiller() { @Override public void kill(DataSegment segments) throws SegmentLoadingException {} }, new DataSegmentMover() { @Override public DataSegment move(DataSegment dataSegment, Map<String, Object> targetLoadSpec) throws SegmentLoadingException { return dataSegment; } }, new DataSegmentArchiver() { @Override public DataSegment archive(DataSegment segment) throws SegmentLoadingException { return segment; } @Override public DataSegment restore(DataSegment segment) throws SegmentLoadingException { return segment; } }, null, // segment announcer notifierFactory, null, // query runner factory conglomerate corporation unionized collective null, // query executor service null, // monitor scheduler new SegmentLoaderFactory( new SegmentLoaderLocalCacheManager( null, new SegmentLoaderConfig() { @Override public List<StorageLocationConfig> getLocations() { return Lists.newArrayList(); } }, MAPPER)), MAPPER, INDEX_MERGER, INDEX_IO, null, null, INDEX_MERGER_V9); Collection<Object[]> values = new LinkedList<>(); for (InputRowParser parser : Arrays.<InputRowParser>asList( ROW_PARSER, new MapInputRowParser( new JSONParseSpec( new TimestampSpec(TIME_COLUMN, "auto", null), new DimensionsSpec( DimensionsSpec.getDefaultSchemas(ImmutableList.<String>of()), ImmutableList.of(DIM_FLOAT_NAME, DIM_LONG_NAME), ImmutableList.<SpatialDimensionSchema>of()), null, null)))) { for (List<String> dim_names : Arrays.<List<String>>asList(null, ImmutableList.of(DIM_NAME))) { for (List<String> metric_names : Arrays.<List<String>>asList( null, ImmutableList.of(METRIC_LONG_NAME, METRIC_FLOAT_NAME))) { values.add( new Object[] { new IngestSegmentFirehoseFactory( DATA_SOURCE_NAME, FOREVER, new SelectorDimFilter(DIM_NAME, DIM_VALUE, null), dim_names, metric_names, Guice.createInjector( new Module() { @Override public void configure(Binder binder) { binder.bind(TaskToolboxFactory.class).toInstance(taskToolboxFactory); } }), INDEX_IO), String.format( "DimNames[%s]MetricNames[%s]ParserDimNames[%s]", dim_names == null ? "null" : "dims", metric_names == null ? "null" : "metrics", parser == ROW_PARSER ? "dims" : "null"), parser }); } } } return values; }
@RunWith(Parameterized.class) public class IngestSegmentFirehoseFactoryTest { private static final ObjectMapper MAPPER; private static final IndexMerger INDEX_MERGER; private static final IndexMergerV9 INDEX_MERGER_V9; private static final IndexIO INDEX_IO; static { TestUtils testUtils = new TestUtils(); MAPPER = setupInjectablesInObjectMapper(testUtils.getTestObjectMapper()); INDEX_MERGER = testUtils.getTestIndexMerger(); INDEX_MERGER_V9 = testUtils.getTestIndexMergerV9(); INDEX_IO = testUtils.getTestIndexIO(); } @Parameterized.Parameters(name = "{1}") public static Collection<Object[]> constructorFeeder() throws IOException { final IndexSpec indexSpec = new IndexSpec(); final HeapMemoryTaskStorage ts = new HeapMemoryTaskStorage(new TaskStorageConfig(null) {}); final IncrementalIndexSchema schema = new IncrementalIndexSchema.Builder() .withQueryGranularity(QueryGranularities.NONE) .withMinTimestamp(JodaUtils.MIN_INSTANT) .withDimensionsSpec(ROW_PARSER) .withMetrics( new AggregatorFactory[] { new LongSumAggregatorFactory(METRIC_LONG_NAME, DIM_LONG_NAME), new DoubleSumAggregatorFactory(METRIC_FLOAT_NAME, DIM_FLOAT_NAME) }) .build(); final OnheapIncrementalIndex index = new OnheapIncrementalIndex(schema, true, MAX_ROWS * MAX_SHARD_NUMBER); for (Integer i = 0; i < MAX_ROWS; ++i) { index.add(ROW_PARSER.parse(buildRow(i.longValue()))); } if (!persistDir.mkdirs() && !persistDir.exists()) { throw new IOException( String.format("Could not create directory at [%s]", persistDir.getAbsolutePath())); } INDEX_MERGER.persist(index, persistDir, indexSpec); final TaskLockbox tl = new TaskLockbox(ts); final IndexerSQLMetadataStorageCoordinator mdc = new IndexerSQLMetadataStorageCoordinator(null, null, null) { private final Set<DataSegment> published = Sets.newHashSet(); private final Set<DataSegment> nuked = Sets.newHashSet(); @Override public List<DataSegment> getUsedSegmentsForInterval(String dataSource, Interval interval) throws IOException { return ImmutableList.copyOf(segmentSet); } @Override public List<DataSegment> getUsedSegmentsForIntervals( String dataSource, List<Interval> interval) throws IOException { return ImmutableList.copyOf(segmentSet); } @Override public List<DataSegment> getUnusedSegmentsForInterval( String dataSource, Interval interval) { return ImmutableList.of(); } @Override public Set<DataSegment> announceHistoricalSegments(Set<DataSegment> segments) { Set<DataSegment> added = Sets.newHashSet(); for (final DataSegment segment : segments) { if (published.add(segment)) { added.add(segment); } } return ImmutableSet.copyOf(added); } @Override public void deleteSegments(Set<DataSegment> segments) { nuked.addAll(segments); } }; final LocalTaskActionClientFactory tac = new LocalTaskActionClientFactory(ts, new TaskActionToolbox(tl, mdc, newMockEmitter())); SegmentHandoffNotifierFactory notifierFactory = EasyMock.createNiceMock(SegmentHandoffNotifierFactory.class); EasyMock.replay(notifierFactory); final TaskToolboxFactory taskToolboxFactory = new TaskToolboxFactory( new TaskConfig(tmpDir.getAbsolutePath(), null, null, 50000, null, false, null, null), tac, newMockEmitter(), new DataSegmentPusher() { @Deprecated @Override public String getPathForHadoop(String dataSource) { return getPathForHadoop(); } @Override public String getPathForHadoop() { throw new UnsupportedOperationException(); } @Override public DataSegment push(File file, DataSegment segment) throws IOException { return segment; } }, new DataSegmentKiller() { @Override public void kill(DataSegment segments) throws SegmentLoadingException {} }, new DataSegmentMover() { @Override public DataSegment move(DataSegment dataSegment, Map<String, Object> targetLoadSpec) throws SegmentLoadingException { return dataSegment; } }, new DataSegmentArchiver() { @Override public DataSegment archive(DataSegment segment) throws SegmentLoadingException { return segment; } @Override public DataSegment restore(DataSegment segment) throws SegmentLoadingException { return segment; } }, null, // segment announcer notifierFactory, null, // query runner factory conglomerate corporation unionized collective null, // query executor service null, // monitor scheduler new SegmentLoaderFactory( new SegmentLoaderLocalCacheManager( null, new SegmentLoaderConfig() { @Override public List<StorageLocationConfig> getLocations() { return Lists.newArrayList(); } }, MAPPER)), MAPPER, INDEX_MERGER, INDEX_IO, null, null, INDEX_MERGER_V9); Collection<Object[]> values = new LinkedList<>(); for (InputRowParser parser : Arrays.<InputRowParser>asList( ROW_PARSER, new MapInputRowParser( new JSONParseSpec( new TimestampSpec(TIME_COLUMN, "auto", null), new DimensionsSpec( DimensionsSpec.getDefaultSchemas(ImmutableList.<String>of()), ImmutableList.of(DIM_FLOAT_NAME, DIM_LONG_NAME), ImmutableList.<SpatialDimensionSchema>of()), null, null)))) { for (List<String> dim_names : Arrays.<List<String>>asList(null, ImmutableList.of(DIM_NAME))) { for (List<String> metric_names : Arrays.<List<String>>asList( null, ImmutableList.of(METRIC_LONG_NAME, METRIC_FLOAT_NAME))) { values.add( new Object[] { new IngestSegmentFirehoseFactory( DATA_SOURCE_NAME, FOREVER, new SelectorDimFilter(DIM_NAME, DIM_VALUE, null), dim_names, metric_names, Guice.createInjector( new Module() { @Override public void configure(Binder binder) { binder.bind(TaskToolboxFactory.class).toInstance(taskToolboxFactory); } }), INDEX_IO), String.format( "DimNames[%s]MetricNames[%s]ParserDimNames[%s]", dim_names == null ? "null" : "dims", metric_names == null ? "null" : "metrics", parser == ROW_PARSER ? "dims" : "null"), parser }); } } } return values; } public static ObjectMapper setupInjectablesInObjectMapper(ObjectMapper objectMapper) { objectMapper.registerModule( new SimpleModule("testModule").registerSubtypes(LocalLoadSpec.class)); final GuiceAnnotationIntrospector guiceIntrospector = new GuiceAnnotationIntrospector(); objectMapper.setAnnotationIntrospectors( new AnnotationIntrospectorPair( guiceIntrospector, objectMapper.getSerializationConfig().getAnnotationIntrospector()), new AnnotationIntrospectorPair( guiceIntrospector, objectMapper.getDeserializationConfig().getAnnotationIntrospector())); objectMapper.setInjectableValues( new GuiceInjectableValues( GuiceInjectors.makeStartupInjectorWithModules( ImmutableList.of( new Module() { @Override public void configure(Binder binder) { binder.bind(LocalDataSegmentPuller.class); } })))); return objectMapper; } public IngestSegmentFirehoseFactoryTest( IngestSegmentFirehoseFactory factory, String testName, InputRowParser rowParser) { this.factory = factory; this.rowParser = rowParser; } private static final Logger log = new Logger(IngestSegmentFirehoseFactoryTest.class); private static final Interval FOREVER = new Interval(JodaUtils.MIN_INSTANT, JodaUtils.MAX_INSTANT); private static final String DATA_SOURCE_NAME = "testDataSource"; private static final String DATA_SOURCE_VERSION = "version"; private static final Integer BINARY_VERSION = -1; private static final String DIM_NAME = "testDimName"; private static final String DIM_VALUE = "testDimValue"; private static final String DIM_LONG_NAME = "testDimLongName"; private static final String DIM_FLOAT_NAME = "testDimFloatName"; private static final String METRIC_LONG_NAME = "testLongMetric"; private static final String METRIC_FLOAT_NAME = "testFloatMetric"; private static final Long METRIC_LONG_VALUE = 1L; private static final Float METRIC_FLOAT_VALUE = 1.0f; private static final String TIME_COLUMN = "ts"; private static final Integer MAX_SHARD_NUMBER = 10; private static final Integer MAX_ROWS = 10; private static final File tmpDir = Files.createTempDir(); private static final File persistDir = Paths.get(tmpDir.getAbsolutePath(), "indexTestMerger").toFile(); private static final List<DataSegment> segmentSet = new ArrayList<>(MAX_SHARD_NUMBER); private final IngestSegmentFirehoseFactory factory; private final InputRowParser rowParser; private static final InputRowParser<Map<String, Object>> ROW_PARSER = new MapInputRowParser( new JSONParseSpec( new TimestampSpec(TIME_COLUMN, "auto", null), new DimensionsSpec( DimensionsSpec.getDefaultSchemas(ImmutableList.of(DIM_NAME)), ImmutableList.of(DIM_FLOAT_NAME, DIM_LONG_NAME), ImmutableList.<SpatialDimensionSchema>of()), null, null)); private static Map<String, Object> buildRow(Long ts) { return ImmutableMap.<String, Object>of( TIME_COLUMN, ts, DIM_NAME, DIM_VALUE, DIM_FLOAT_NAME, METRIC_FLOAT_VALUE, DIM_LONG_NAME, METRIC_LONG_VALUE); } private static DataSegment buildSegment(Integer shardNumber) { Preconditions.checkArgument(shardNumber < MAX_SHARD_NUMBER); Preconditions.checkArgument(shardNumber >= 0); return new DataSegment( DATA_SOURCE_NAME, FOREVER, DATA_SOURCE_VERSION, ImmutableMap.<String, Object>of("type", "local", "path", persistDir.getAbsolutePath()), ImmutableList.of(DIM_NAME), ImmutableList.of(METRIC_LONG_NAME, METRIC_FLOAT_NAME), new NumberedShardSpec(shardNumber, MAX_SHARD_NUMBER), BINARY_VERSION, 0L); } @BeforeClass public static void setUpStatic() throws IOException { for (int i = 0; i < MAX_SHARD_NUMBER; ++i) { segmentSet.add(buildSegment(i)); } } @AfterClass public static void tearDownStatic() { recursivelyDelete(tmpDir); } private static void recursivelyDelete(final File dir) { if (dir != null) { if (dir.isDirectory()) { final File[] files = dir.listFiles(); if (files != null) { for (File file : files) { recursivelyDelete(file); } } } else { if (!dir.delete()) { log.warn("Could not delete file at [%s]", dir.getAbsolutePath()); } } } } @Test public void sanityTest() { Assert.assertEquals(DATA_SOURCE_NAME, factory.getDataSource()); if (factory.getDimensions() != null) { Assert.assertArrayEquals(new String[] {DIM_NAME}, factory.getDimensions().toArray()); } Assert.assertEquals(FOREVER, factory.getInterval()); if (factory.getMetrics() != null) { Assert.assertEquals( ImmutableSet.of(METRIC_LONG_NAME, METRIC_FLOAT_NAME), ImmutableSet.copyOf(factory.getMetrics())); } } @Test public void simpleFirehoseReadingTest() throws IOException { Assert.assertEquals(MAX_SHARD_NUMBER.longValue(), segmentSet.size()); Integer rowcount = 0; try (final IngestSegmentFirehose firehose = (IngestSegmentFirehose) factory.connect(rowParser)) { while (firehose.hasMore()) { InputRow row = firehose.nextRow(); Assert.assertArrayEquals(new String[] {DIM_NAME}, row.getDimensions().toArray()); Assert.assertArrayEquals(new String[] {DIM_VALUE}, row.getDimension(DIM_NAME).toArray()); Assert.assertEquals(METRIC_LONG_VALUE.longValue(), row.getLongMetric(METRIC_LONG_NAME)); Assert.assertEquals( METRIC_FLOAT_VALUE, row.getFloatMetric(METRIC_FLOAT_NAME), METRIC_FLOAT_VALUE * 0.0001); ++rowcount; } } Assert.assertEquals((int) MAX_SHARD_NUMBER * MAX_ROWS, (int) rowcount); } private static ServiceEmitter newMockEmitter() { return new ServiceEmitter(null, null, null) { @Override public void emit(Event event) {} @Override public void emit(ServiceEventBuilder builder) {} }; } }