diff --git a/src/main/java/org/elasticsearch/common/rounding/Rounding.java b/src/main/java/org/elasticsearch/common/rounding/Rounding.java
index 57cd94b10e3..8d5372106cf 100644
--- a/src/main/java/org/elasticsearch/common/rounding/Rounding.java
+++ b/src/main/java/org/elasticsearch/common/rounding/Rounding.java
@@ -19,6 +19,7 @@
package org.elasticsearch.common.rounding;
import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
@@ -218,15 +219,25 @@ public abstract class Rounding implements Streamable {
@Override
public void readFrom(StreamInput in) throws IOException {
rounding = Rounding.Streams.read(in);
- preOffset = in.readVLong();
- postOffset = in.readVLong();
+ if (in.getVersion().before(Version.V_1_4_0)) {
+ preOffset = in.readVLong();
+ postOffset = in.readVLong();
+ } else {
+ preOffset = in.readLong();
+ postOffset = in.readLong();
+ }
}
@Override
public void writeTo(StreamOutput out) throws IOException {
Rounding.Streams.write(rounding, out);
- out.writeVLong(preOffset);
- out.writeVLong(postOffset);
+ if (out.getVersion().before(Version.V_1_4_0)) {
+ out.writeVLong(preOffset);
+ out.writeVLong(postOffset);
+ } else {
+ out.writeLong(preOffset);
+ out.writeLong(postOffset);
+ }
}
}
diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramOffsetTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramOffsetTests.java
new file mode 100644
index 00000000000..7281ad827ff
--- /dev/null
+++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramOffsetTests.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.search.aggregations.bucket;
+
+import org.elasticsearch.Version;
+import org.elasticsearch.action.index.IndexRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.mapper.core.DateFieldMapper;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram;
+import org.elasticsearch.test.ElasticsearchIntegrationTest;
+import org.elasticsearch.test.transport.AssertingLocalTransport;
+import org.hamcrest.Matchers;
+import org.joda.time.DateTime;
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.search.aggregations.AggregationBuilders.dateHistogram;
+import static org.hamcrest.Matchers.equalTo;
+
+/**
+ * The serialisation of pre and post offsets for the date histogram aggregation was corrected in version 1.4 to allow negative offsets and as such the
+ * serialisation of negative offsets in these tests would break in pre 1.4 versions. These tests are separated from the other DateHistogramTests so the
+ * AssertingLocalTransport for these tests can be set to only use versions 1.4 onwards while keeping the other tests using all versions
+ */
+@ElasticsearchIntegrationTest.SuiteScopeTest
+@ElasticsearchIntegrationTest.ClusterScope(scope=ElasticsearchIntegrationTest.Scope.SUITE)
+public class DateHistogramOffsetTests extends ElasticsearchIntegrationTest {
+
+ private DateTime date(String date) {
+ return DateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().parseDateTime(date);
+ }
+
+ @Override
+ protected Settings nodeSettings(int nodeOrdinal) {
+ return ImmutableSettings.builder()
+ .put(AssertingLocalTransport.ASSERTING_TRANSPORT_MIN_VERSION_KEY, Version.V_1_4_0).build();
+ }
+
+ @After
+ public void afterEachTest() throws IOException {
+ internalCluster().wipeIndices("idx2");
+ }
+
+ @Test
+ public void singleValue_WithPreOffset() throws Exception {
+ prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
+ IndexRequestBuilder[] reqs = new IndexRequestBuilder[5];
+ DateTime date = date("2014-03-11T00:00:00+00:00");
+ for (int i = 0; i < reqs.length; i++) {
+ reqs[i] = client().prepareIndex("idx2", "type", "" + i).setSource(jsonBuilder().startObject().field("date", date).endObject());
+ date = date.plusHours(1);
+ }
+ indexRandom(true, reqs);
+
+ SearchResponse response = client().prepareSearch("idx2")
+ .setQuery(matchAllQuery())
+ .addAggregation(dateHistogram("date_histo")
+ .field("date")
+ .preOffset("-2h")
+ .interval(DateHistogram.Interval.DAY)
+ .format("yyyy-MM-dd"))
+ .execute().actionGet();
+
+ assertThat(response.getHits().getTotalHits(), equalTo(5l));
+
+ DateHistogram histo = response.getAggregations().get("date_histo");
+ Collection extends DateHistogram.Bucket> buckets = histo.getBuckets();
+ assertThat(buckets.size(), equalTo(2));
+
+ DateHistogram.Bucket bucket = histo.getBucketByKey("2014-03-10");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(2l));
+
+ bucket = histo.getBucketByKey("2014-03-11");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(3l));
+ }
+
+ @Test
+ public void singleValue_WithPreOffset_MinDocCount() throws Exception {
+ prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
+ IndexRequestBuilder[] reqs = new IndexRequestBuilder[5];
+ DateTime date = date("2014-03-11T00:00:00+00:00");
+ for (int i = 0; i < reqs.length; i++) {
+ reqs[i] = client().prepareIndex("idx2", "type", "" + i).setSource(jsonBuilder().startObject().field("date", date).endObject());
+ date = date.plusHours(1);
+ }
+ indexRandom(true, reqs);
+
+ SearchResponse response = client().prepareSearch("idx2")
+ .setQuery(matchAllQuery())
+ .addAggregation(dateHistogram("date_histo")
+ .field("date")
+ .preOffset("-2h")
+ .minDocCount(0)
+ .interval(DateHistogram.Interval.DAY)
+ .format("yyyy-MM-dd"))
+ .execute().actionGet();
+
+ assertThat(response.getHits().getTotalHits(), equalTo(5l));
+
+ DateHistogram histo = response.getAggregations().get("date_histo");
+ Collection extends DateHistogram.Bucket> buckets = histo.getBuckets();
+ assertThat(buckets.size(), equalTo(2));
+
+ DateHistogram.Bucket bucket = histo.getBucketByKey("2014-03-10");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(2l));
+
+ bucket = histo.getBucketByKey("2014-03-11");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(3l));
+ }
+
+ @Test
+ public void singleValue_WithPostOffset() throws Exception {
+ prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
+ IndexRequestBuilder[] reqs = new IndexRequestBuilder[5];
+ DateTime date = date("2014-03-11T00:00:00+00:00");
+ for (int i = 0; i < reqs.length; i++) {
+ reqs[i] = client().prepareIndex("idx2", "type", "" + i).setSource(jsonBuilder().startObject().field("date", date).endObject());
+ date = date.plusHours(6);
+ }
+ indexRandom(true, reqs);
+
+ SearchResponse response = client().prepareSearch("idx2")
+ .setQuery(matchAllQuery())
+ .addAggregation(dateHistogram("date_histo")
+ .field("date")
+ .postOffset("2d")
+ .interval(DateHistogram.Interval.DAY)
+ .format("yyyy-MM-dd"))
+ .execute().actionGet();
+
+ assertThat(response.getHits().getTotalHits(), equalTo(5l));
+
+ DateHistogram histo = response.getAggregations().get("date_histo");
+ Collection extends DateHistogram.Bucket> buckets = histo.getBuckets();
+ assertThat(buckets.size(), equalTo(2));
+
+ DateHistogram.Bucket bucket = histo.getBucketByKey("2014-03-13");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(4l));
+
+ bucket = histo.getBucketByKey("2014-03-14");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(1l));
+ }
+
+ @Test
+ public void singleValue_WithPostOffset_MinDocCount() throws Exception {
+ prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
+ IndexRequestBuilder[] reqs = new IndexRequestBuilder[5];
+ DateTime date = date("2014-03-11T00:00:00+00:00");
+ for (int i = 0; i < reqs.length; i++) {
+ reqs[i] = client().prepareIndex("idx2", "type", "" + i).setSource(jsonBuilder().startObject().field("date", date).endObject());
+ date = date.plusHours(6);
+ }
+ indexRandom(true, reqs);
+
+ SearchResponse response = client().prepareSearch("idx2")
+ .setQuery(matchAllQuery())
+ .addAggregation(dateHistogram("date_histo")
+ .field("date")
+ .postOffset("2d")
+ .minDocCount(0)
+ .interval(DateHistogram.Interval.DAY)
+ .format("yyyy-MM-dd"))
+ .execute().actionGet();
+
+ assertThat(response.getHits().getTotalHits(), equalTo(5l));
+
+ DateHistogram histo = response.getAggregations().get("date_histo");
+ Collection extends DateHistogram.Bucket> buckets = histo.getBuckets();
+ assertThat(buckets.size(), equalTo(2));
+
+ DateHistogram.Bucket bucket = histo.getBucketByKey("2014-03-13");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(4l));
+
+ bucket = histo.getBucketByKey("2014-03-14");
+ assertThat(bucket, Matchers.notNullValue());
+ assertThat(bucket.getDocCount(), equalTo(1l));
+ }
+}
diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java
index 021632fc92e..9a07b6928d9 100644
--- a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java
+++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java
@@ -1051,76 +1051,6 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
assertThat(bucket.getDocCount(), equalTo(3l));
}
- @Test
- public void singleValue_WithPreOffset() throws Exception {
- prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
- IndexRequestBuilder[] reqs = new IndexRequestBuilder[5];
- DateTime date = date("2014-03-11T00:00:00+00:00");
- for (int i = 0; i < reqs.length; i++) {
- reqs[i] = client().prepareIndex("idx2", "type", "" + i).setSource(jsonBuilder().startObject().field("date", date).endObject());
- date = date.plusHours(1);
- }
- indexRandom(true, reqs);
-
- SearchResponse response = client().prepareSearch("idx2")
- .setQuery(matchAllQuery())
- .addAggregation(dateHistogram("date_histo")
- .field("date")
- .preOffset("-2h")
- .interval(DateHistogram.Interval.DAY)
- .format("yyyy-MM-dd"))
- .execute().actionGet();
-
- assertThat(response.getHits().getTotalHits(), equalTo(5l));
-
- DateHistogram histo = response.getAggregations().get("date_histo");
- Collection extends DateHistogram.Bucket> buckets = histo.getBuckets();
- assertThat(buckets.size(), equalTo(2));
-
- DateHistogram.Bucket bucket = histo.getBucketByKey("2014-03-10");
- assertThat(bucket, Matchers.notNullValue());
- assertThat(bucket.getDocCount(), equalTo(2l));
-
- bucket = histo.getBucketByKey("2014-03-11");
- assertThat(bucket, Matchers.notNullValue());
- assertThat(bucket.getDocCount(), equalTo(3l));
- }
-
- @Test
- public void singleValue_WithPostOffset() throws Exception {
- prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
- IndexRequestBuilder[] reqs = new IndexRequestBuilder[5];
- DateTime date = date("2014-03-11T00:00:00+00:00");
- for (int i = 0; i < reqs.length; i++) {
- reqs[i] = client().prepareIndex("idx2", "type", "" + i).setSource(jsonBuilder().startObject().field("date", date).endObject());
- date = date.plusHours(6);
- }
- indexRandom(true, reqs);
-
- SearchResponse response = client().prepareSearch("idx2")
- .setQuery(matchAllQuery())
- .addAggregation(dateHistogram("date_histo")
- .field("date")
- .postOffset("2d")
- .interval(DateHistogram.Interval.DAY)
- .format("yyyy-MM-dd"))
- .execute().actionGet();
-
- assertThat(response.getHits().getTotalHits(), equalTo(5l));
-
- DateHistogram histo = response.getAggregations().get("date_histo");
- Collection extends DateHistogram.Bucket> buckets = histo.getBuckets();
- assertThat(buckets.size(), equalTo(2));
-
- DateHistogram.Bucket bucket = histo.getBucketByKey("2014-03-13");
- assertThat(bucket, Matchers.notNullValue());
- assertThat(bucket.getDocCount(), equalTo(4l));
-
- bucket = histo.getBucketByKey("2014-03-14");
- assertThat(bucket, Matchers.notNullValue());
- assertThat(bucket.getDocCount(), equalTo(1l));
- }
-
@Test
public void singleValue_WithPreZone_WithAadjustLargeInterval() throws Exception {
prepareCreate("idx2").addMapping("type", "date", "type=date").execute().actionGet();
diff --git a/src/test/java/org/elasticsearch/test/ElasticsearchTestCase.java b/src/test/java/org/elasticsearch/test/ElasticsearchTestCase.java
index 14c0e5a1b47..87e3dc15088 100644
--- a/src/test/java/org/elasticsearch/test/ElasticsearchTestCase.java
+++ b/src/test/java/org/elasticsearch/test/ElasticsearchTestCase.java
@@ -19,14 +19,10 @@
package org.elasticsearch.test;
import com.carrotsearch.randomizedtesting.RandomizedTest;
-import com.carrotsearch.randomizedtesting.annotations.Listeners;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import com.carrotsearch.randomizedtesting.annotations.*;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
-import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.util.AbstractRandomizedTest;
@@ -297,20 +293,84 @@ public abstract class ElasticsearchTestCase extends AbstractRandomizedTest {
SORTED_VERSIONS = version.build();
}
+ /**
+ * @return the {@link Version} before the {@link Version#CURRENT}
+ */
public static Version getPreviousVersion() {
Version version = SORTED_VERSIONS.get(1);
assert version.before(Version.CURRENT);
return version;
}
-
+
+ /**
+ * A random {@link Version}.
+ *
+ * @return a random {@link Version} from all available versions
+ */
public static Version randomVersion() {
return randomVersion(getRandom());
}
-
+
+ /**
+ * A random {@link Version}.
+ *
+ * @param random
+ * the {@link Random} to use to generate the random version
+ *
+ * @return a random {@link Version} from all available versions
+ */
public static Version randomVersion(Random random) {
return SORTED_VERSIONS.get(random.nextInt(SORTED_VERSIONS.size()));
}
+ /**
+ * A random {@link Version} from minVersion
to
+ * maxVersion
(inclusive).
+ *
+ * @param minVersion
+ * the minimum version (inclusive)
+ * @param maxVersion
+ * the maximum version (inclusive)
+ * @return a random {@link Version} from minVersion
to
+ * maxVersion
(inclusive)
+ */
+ public static Version randomVersionBetween(Version minVersion, Version maxVersion) {
+ return randomVersionBetween(getRandom(), minVersion, maxVersion);
+ }
+
+ /**
+ * A random {@link Version} from minVersion
to
+ * maxVersion
(inclusive).
+ *
+ * @param random
+ * the {@link Random} to use to generate the random version
+ * @param minVersion
+ * the minimum version (inclusive)
+ * @param maxVersion
+ * the maximum version (inclusive)
+ * @return a random {@link Version} from minVersion
to
+ * maxVersion
(inclusive)
+ */
+ public static Version randomVersionBetween(Random random, Version minVersion, Version maxVersion) {
+ int minVersionIndex = SORTED_VERSIONS.size();
+ if (minVersion != null) {
+ minVersionIndex = SORTED_VERSIONS.indexOf(minVersion);
+ }
+ int maxVersionIndex = 0;
+ if (maxVersion != null) {
+ maxVersionIndex = SORTED_VERSIONS.indexOf(maxVersion);
+ }
+ if (minVersionIndex == -1) {
+ throw new IllegalArgumentException("minVersion [" + minVersion + "] does not exist.");
+ } else if (maxVersionIndex == -1) {
+ throw new IllegalArgumentException("maxVersion [" + maxVersion + "] does not exist.");
+ } else {
+ // minVersionIndex is inclusive so need to add 1 to this index
+ int range = minVersionIndex + 1 - maxVersionIndex;
+ return SORTED_VERSIONS.get(maxVersionIndex + random.nextInt(range));
+ }
+ }
+
static final class ElasticsearchUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler parent;
diff --git a/src/test/java/org/elasticsearch/test/transport/AssertingLocalTransport.java b/src/test/java/org/elasticsearch/test/transport/AssertingLocalTransport.java
index b9fd4cf6986..5a2f4f560fb 100644
--- a/src/test/java/org/elasticsearch/test/transport/AssertingLocalTransport.java
+++ b/src/test/java/org/elasticsearch/test/transport/AssertingLocalTransport.java
@@ -37,24 +37,31 @@ import java.util.Random;
*
*/
public class AssertingLocalTransport extends LocalTransport {
+
+ public static final String ASSERTING_TRANSPORT_MIN_VERSION_KEY = "transport.asserting.version.min";
+ public static final String ASSERTING_TRANSPORT_MAX_VERSION_KEY = "transport.asserting.version.max";
private final Random random;
+ private final Version minVersion;
+ private final Version maxVersion;
@Inject
public AssertingLocalTransport(Settings settings, ThreadPool threadPool, Version version) {
super(settings, threadPool, version);
final long seed = settings.getAsLong(ElasticsearchIntegrationTest.SETTING_INDEX_SEED, 0l);
random = new Random(seed);
+ minVersion = settings.getAsVersion(ASSERTING_TRANSPORT_MIN_VERSION_KEY, Version.V_0_18_0);
+ maxVersion = settings.getAsVersion(ASSERTING_TRANSPORT_MAX_VERSION_KEY, Version.CURRENT);
}
@Override
protected void handleParsedResponse(final TransportResponse response, final TransportResponseHandler handler) {
- ElasticsearchAssertions.assertVersionSerializable(ElasticsearchTestCase.randomVersion(random), response);
+ ElasticsearchAssertions.assertVersionSerializable(ElasticsearchTestCase.randomVersionBetween(random, minVersion, maxVersion), response);
super.handleParsedResponse(response, handler);
}
@Override
public void sendRequest(final DiscoveryNode node, final long requestId, final String action, final TransportRequest request, TransportRequestOptions options) throws IOException, TransportException {
- ElasticsearchAssertions.assertVersionSerializable(ElasticsearchTestCase.randomVersion(random), request);
+ ElasticsearchAssertions.assertVersionSerializable(ElasticsearchTestCase.randomVersionBetween(random, minVersion, maxVersion), request);
super.sendRequest(node, requestId, action, request, options);
}
}