| /* |
| * Licensed to Metamarkets Group Inc. (Metamarkets) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. Metamarkets 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. |
| */ |
| |
| /* |
| * Druid - a distributed column store. |
| * Copyright 2015 - Yahoo! Inc. |
| * |
| * Licensed 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 io.druid.server; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Ordering; |
| import io.druid.client.DruidServer; |
| import io.druid.client.FilteredServerInventoryView; |
| import io.druid.client.TimelineServerView; |
| import io.druid.client.selector.HighestPriorityTierSelectorStrategy; |
| import io.druid.client.selector.RandomServerSelectorStrategy; |
| import io.druid.client.selector.ServerSelector; |
| import io.druid.java.util.common.Intervals; |
| import io.druid.query.TableDataSource; |
| import io.druid.query.metadata.SegmentMetadataQueryConfig; |
| import io.druid.server.coordination.ServerType; |
| import io.druid.server.security.AuthConfig; |
| import io.druid.timeline.DataSegment; |
| import io.druid.timeline.VersionedIntervalTimeline; |
| import io.druid.timeline.partition.NumberedShardSpec; |
| import io.druid.timeline.partition.ShardSpec; |
| import io.druid.timeline.partition.SingleElementPartitionChunk; |
| import org.easymock.EasyMock; |
| import org.joda.time.DateTime; |
| import org.joda.time.chrono.ISOChronology; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.util.List; |
| import java.util.Map; |
| |
| public class ClientInfoResourceTest |
| { |
| private static final String KEY_DIMENSIONS = "dimensions"; |
| private static final String KEY_METRICS = "metrics"; |
| private static final DateTime FIXED_TEST_TIME = new DateTime(2015, 9, 14, 0, 0, ISOChronology.getInstanceUTC()); /* always use the same current time for unit tests */ |
| |
| |
| private final String dataSource = "test-data-source"; |
| |
| private FilteredServerInventoryView serverInventoryView; |
| private TimelineServerView timelineServerView; |
| private ClientInfoResource resource; |
| |
| @Before |
| public void setup() |
| { |
| VersionedIntervalTimeline<String, ServerSelector> timeline = new VersionedIntervalTimeline<>(Ordering.<String>natural()); |
| DruidServer server = new DruidServer("name", "host", null, 1234, ServerType.HISTORICAL, "tier", 0); |
| |
| addSegment(timeline, server, "1960-02-13/1961-02-14", ImmutableList.of("d5"), ImmutableList.of("m5"), "v0"); |
| |
| // segments within [2014-02-13, 2014-02-18] |
| addSegment(timeline, server, "2014-02-13/2014-02-14", ImmutableList.of("d1"), ImmutableList.of("m1"), "v0"); |
| addSegment(timeline, server, "2014-02-14/2014-02-15", ImmutableList.of("d1"), ImmutableList.of("m1"), "v0"); |
| addSegment(timeline, server, "2014-02-16/2014-02-17", ImmutableList.of("d1"), ImmutableList.of("m1"), "v0"); |
| addSegment(timeline, server, "2014-02-17/2014-02-18", ImmutableList.of("d2"), ImmutableList.of("m2"), "v0"); |
| |
| // segments within [2015-02-01, 2015-02-13] |
| addSegment(timeline, server, "2015-02-01/2015-02-07", ImmutableList.of("d1"), ImmutableList.of("m1"), "v1"); |
| addSegment(timeline, server, "2015-02-07/2015-02-13", ImmutableList.of("d1"), ImmutableList.of("m1"), "v1"); |
| addSegmentWithShardSpec( |
| timeline, server, "2015-02-03/2015-02-05", |
| ImmutableList.of("d1", "d2"), |
| ImmutableList.of("m1", "m2"), |
| "v2", |
| new NumberedShardSpec(0, 2) |
| ); |
| addSegmentWithShardSpec( |
| timeline, server, "2015-02-03/2015-02-05", |
| ImmutableList.of("d1", "d2", "d3"), |
| ImmutableList.of("m1", "m2", "m3"), |
| "v2", |
| new NumberedShardSpec(1, 2) |
| ); |
| addSegment( |
| timeline, |
| server, |
| "2015-02-09/2015-02-10", |
| ImmutableList.of("d1", "d3"), |
| ImmutableList.of("m1", "m3"), |
| "v2" |
| ); |
| addSegment(timeline, server, "2015-02-11/2015-02-12", ImmutableList.of("d3"), ImmutableList.of("m3"), "v2"); |
| |
| // segments within [2015-03-13, 2015-03-19] |
| addSegment(timeline, server, "2015-03-13/2015-03-19", ImmutableList.of("d1"), ImmutableList.of("m1"), "v3"); |
| addSegment(timeline, server, "2015-03-13/2015-03-14", ImmutableList.of("d1"), ImmutableList.of("m1"), "v4"); |
| addSegment(timeline, server, "2015-03-14/2015-03-15", ImmutableList.of("d1"), ImmutableList.of("m1"), "v5"); |
| addSegment(timeline, server, "2015-03-15/2015-03-16", ImmutableList.of("d1"), ImmutableList.of("m1"), "v6"); |
| |
| // imcomplete segment |
| addSegmentWithShardSpec( |
| timeline, server, "2015-04-03/2015-04-05", |
| ImmutableList.of("d4"), |
| ImmutableList.of("m4"), |
| "v7", |
| new NumberedShardSpec(0, 2) |
| ); |
| |
| serverInventoryView = EasyMock.createMock(FilteredServerInventoryView.class); |
| EasyMock.expect(serverInventoryView.getInventory()).andReturn(ImmutableList.of(server)).anyTimes(); |
| |
| timelineServerView = EasyMock.createMock(TimelineServerView.class); |
| EasyMock.expect(timelineServerView.getTimeline(EasyMock.anyObject(TableDataSource.class))).andReturn(timeline); |
| |
| EasyMock.replay(serverInventoryView, timelineServerView); |
| |
| resource = getResourceTestHelper( |
| serverInventoryView, timelineServerView, |
| new SegmentMetadataQueryConfig() |
| ); |
| } |
| |
| @Test |
| public void testGetDatasourceNonFullWithInterval() |
| { |
| Map<String, Object> actual = resource.getDatasource(dataSource, "1975/2015", null); |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| KEY_DIMENSIONS, ImmutableSet.of("d1", "d2"), |
| KEY_METRICS, ImmutableSet.of("m1", "m2") |
| ); |
| EasyMock.verify(serverInventoryView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testGetDatasourceFullWithInterval() |
| { |
| Map<String, Object> actual = resource.getDatasource(dataSource, "1975/2015", "true"); |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| "2014-02-13T00:00:00.000Z/2014-02-15T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")), |
| "2014-02-16T00:00:00.000Z/2014-02-17T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")), |
| "2014-02-17T00:00:00.000Z/2014-02-18T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d2"), KEY_METRICS, ImmutableSet.of("m2")) |
| ); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testGetDatasourceFullWithSmallInterval() |
| { |
| Map<String, Object> actual = resource.getDatasource( |
| dataSource, |
| "2014-02-13T09:00:00.000Z/2014-02-17T23:00:00.000Z", |
| "true" |
| ); |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| "2014-02-13T09:00:00.000Z/2014-02-15T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")), |
| "2014-02-16T00:00:00.000Z/2014-02-17T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")), |
| "2014-02-17T00:00:00.000Z/2014-02-17T23:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d2"), KEY_METRICS, ImmutableSet.of("m2")) |
| ); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testGetDatasourceWithDefaultInterval() |
| { |
| Map<String, Object> actual = resource.getDatasource(dataSource, null, null); |
| Map<String, Object> expected = ImmutableMap.<String, Object>of(KEY_DIMENSIONS, ImmutableSet.of(), KEY_METRICS, ImmutableSet.of()); |
| |
| Assert.assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testGetDatasourceWithConfiguredDefaultInterval() |
| { |
| ClientInfoResource defaultResource = getResourceTestHelper( |
| serverInventoryView, timelineServerView, |
| new SegmentMetadataQueryConfig("P100Y") |
| ); |
| |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| KEY_DIMENSIONS, |
| ImmutableSet.of("d1", "d2", "d3", "d4", "d5"), |
| KEY_METRICS, |
| ImmutableSet.of("m1", "m2", "m3", "m4", "m5") |
| ); |
| |
| Map<String, Object> actual = defaultResource.getDatasource(dataSource, null, null); |
| |
| Assert.assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testGetDatasourceFullWithOvershadowedSegments1() |
| { |
| Map<String, Object> actual = resource.getDatasource( |
| dataSource, |
| "2015-02-02T09:00:00.000Z/2015-02-06T23:00:00.000Z", |
| "true" |
| ); |
| |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| "2015-02-02T09:00:00.000Z/2015-02-03T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")), |
| "2015-02-03T00:00:00.000Z/2015-02-05T00:00:00.000Z", |
| ImmutableMap.of( |
| KEY_DIMENSIONS, |
| ImmutableSet.of("d1", "d2", "d3"), |
| KEY_METRICS, |
| ImmutableSet.of("m1", "m2", "m3") |
| ), |
| "2015-02-05T00:00:00.000Z/2015-02-06T23:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| |
| } |
| |
| @Test |
| public void testGetDatasourceFullWithOvershadowedSegments2() |
| { |
| Map<String, Object> actual = resource.getDatasource( |
| dataSource, |
| "2015-02-09T09:00:00.000Z/2015-02-13T23:00:00.000Z", |
| "true" |
| ); |
| |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| "2015-02-09T09:00:00.000Z/2015-02-10T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1", "d3"), KEY_METRICS, ImmutableSet.of("m1", "m3")), |
| "2015-02-10T00:00:00.000Z/2015-02-11T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")), |
| "2015-02-11T00:00:00.000Z/2015-02-12T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d3"), KEY_METRICS, ImmutableSet.of("m3")), |
| "2015-02-12T00:00:00.000Z/2015-02-13T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| /** |
| * Though segments within [2015-03-13, 2015-03-19] have different versions, they all abut with each other and have |
| * same dimensions/metrics, so they all should be merged together. |
| */ |
| @Test |
| public void testGetDatasourceFullWithOvershadowedSegmentsMerged() |
| { |
| Map<String, Object> actual = resource.getDatasource( |
| dataSource, |
| "2015-03-13T02:00:00.000Z/2015-03-19T15:00:00.000Z", |
| "true" |
| ); |
| |
| Map<String, Object> expected = ImmutableMap.<String, Object>of( |
| "2015-03-13T02:00:00.000Z/2015-03-19T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| /** |
| * If "full" is specified, then dimensions/metrics that exist in an incompelte segment should be ingored |
| */ |
| @Test |
| public void testGetDatasourceFullWithIncompleteSegment() |
| { |
| Map<String, Object> actual = resource.getDatasource(dataSource, "2015-04-03/2015-04-05", "true"); |
| Map<String, Object> expected = ImmutableMap.of(); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testGetDatasourceFullWithLargeInterval() |
| { |
| Map<String, Object> actual = resource.getDatasource(dataSource, "1975/2050", "true"); |
| Map<String, Object> expected = ImmutableMap.<String, Object>builder().put( |
| "2014-02-13T00:00:00.000Z/2014-02-15T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).put( |
| "2014-02-16T00:00:00.000Z/2014-02-17T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).put( |
| "2014-02-17T00:00:00.000Z/2014-02-18T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d2"), KEY_METRICS, ImmutableSet.of("m2")) |
| ).put( |
| "2015-02-01T00:00:00.000Z/2015-02-03T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).put( |
| "2015-02-03T00:00:00.000Z/2015-02-05T00:00:00.000Z", |
| ImmutableMap.of( |
| KEY_DIMENSIONS, |
| ImmutableSet.of("d1", "d2", "d3"), |
| KEY_METRICS, |
| ImmutableSet.of("m1", "m2", "m3") |
| ) |
| ).put( |
| "2015-02-05T00:00:00.000Z/2015-02-09T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).put( |
| "2015-02-09T00:00:00.000Z/2015-02-10T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1", "d3"), KEY_METRICS, ImmutableSet.of("m1", "m3")) |
| ).put( |
| "2015-02-10T00:00:00.000Z/2015-02-11T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).put( |
| "2015-02-11T00:00:00.000Z/2015-02-12T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d3"), KEY_METRICS, ImmutableSet.of("m3")) |
| ).put( |
| "2015-02-12T00:00:00.000Z/2015-02-13T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).put( |
| "2015-03-13T00:00:00.000Z/2015-03-19T00:00:00.000Z", |
| ImmutableMap.of(KEY_DIMENSIONS, ImmutableSet.of("d1"), KEY_METRICS, ImmutableSet.of("m1")) |
| ).build(); |
| |
| EasyMock.verify(serverInventoryView, timelineServerView); |
| Assert.assertEquals(expected, actual); |
| } |
| |
| private void addSegment( |
| VersionedIntervalTimeline<String, ServerSelector> timeline, |
| DruidServer server, |
| String interval, |
| List<String> dims, |
| List<String> metrics, |
| String version |
| ) |
| { |
| DataSegment segment = DataSegment.builder() |
| .dataSource(dataSource) |
| .interval(Intervals.of(interval)) |
| .version(version) |
| .dimensions(dims) |
| .metrics(metrics) |
| .size(1) |
| .build(); |
| server.addDataSegment(segment); |
| ServerSelector ss = new ServerSelector(segment, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy())); |
| timeline.add(Intervals.of(interval), version, new SingleElementPartitionChunk<ServerSelector>(ss)); |
| } |
| |
| private void addSegmentWithShardSpec( |
| VersionedIntervalTimeline<String, ServerSelector> timeline, |
| DruidServer server, |
| String interval, |
| List<String> dims, |
| List<String> metrics, |
| String version, |
| ShardSpec shardSpec |
| ) |
| { |
| DataSegment segment = DataSegment.builder() |
| .dataSource(dataSource) |
| .interval(Intervals.of(interval)) |
| .version(version) |
| .dimensions(dims) |
| .metrics(metrics) |
| .shardSpec(shardSpec) |
| .size(1) |
| .build(); |
| server.addDataSegment(segment); |
| ServerSelector ss = new ServerSelector(segment, new HighestPriorityTierSelectorStrategy(new RandomServerSelectorStrategy())); |
| timeline.add(Intervals.of(interval), version, shardSpec.createChunk(ss)); |
| } |
| |
| private ClientInfoResource getResourceTestHelper( |
| FilteredServerInventoryView serverInventoryView, |
| TimelineServerView timelineServerView, |
| SegmentMetadataQueryConfig segmentMetadataQueryConfig |
| ) |
| { |
| return new ClientInfoResource( |
| serverInventoryView, |
| timelineServerView, |
| segmentMetadataQueryConfig, |
| new AuthConfig(), |
| null |
| ) |
| { |
| @Override |
| protected DateTime getCurrentTime() |
| { |
| return FIXED_TEST_TIME; |
| } |
| }; |
| } |
| } |