Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Unknown NamedWriteable error in InternalAggregation (Add extra round trip to aggs tests) #79638

Merged

Conversation

nik9000
Copy link
Member

@nik9000 nik9000 commented Oct 21, 2021

This tries to automatically detect problems seriealization aggregation
results by round tripping the results in our usual AggregatorTestCase.
It's "free" testing in that we already have the tests written and we'll
get round trip testing "on the side". But it's kind of sneaky because we
aren't trying to test serialization here. So they failures can be
surprising. But surprising test failures are better than bugs. At least
that is what I tell myself so I can sleep at night.

EDIT:

This actually uncovered a real bug that'd show up as "Unknown NamedWriteable"
when using certain pipeline aggregations in async search. So I've marked this as
>bug. And will backport to 7.16.

Closes #73680

@nik9000 nik9000 added >test Issues or PRs that are addressing/adding tests :Analytics/Aggregations Aggregations v8.0.0 labels Oct 21, 2021
@elasticmachine elasticmachine added the Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) label Oct 21, 2021
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-analytics-geo (Team:Analytics)

This tries to automatically detect problems seriealization aggregation
results by round tripping the results in our usual `AggregatorTestCase`.
It's "free" testing in that we already have the tests written and we'll
get round trip testing "on the side". But it's kind of sneaky because we
aren't *trying* to test serialization here. So they failures can be
surprising. But surprising test failures are better than bugs. At least
that is what I tell myself so I can sleep at night.

Closes elastic#73680
@@ -317,6 +317,26 @@ public double parseDouble(String value, boolean roundUp, LongSupplier now) {
public String toString() {
return "DocValueFormat.DateTime(" + formatter + ", " + timeZone + ", " + resolution + ")";
}

@Override
public boolean equals(Object o) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use actual date formats in the DateHistogramAggregatorTests and they didn't have equals.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zoinks. Nice catch.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's only important for the tests. But that's ok.

@@ -134,15 +134,14 @@ public boolean equals(Object o) {
}

Bucket<?> that = (Bucket<?>) o;
return bucketOrd == that.bucketOrd
&& Double.compare(that.score, score) == 0
return Double.compare(that.score, score) == 0
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bucketOrd is lost in serialization. It's a transient part of building the bucket and not really part of the identity.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth leaving as a comment on the member declaration.

return Objects.equals(docCount, that.docCount)
&& Objects.equals(docCountError, that.docCountError)
&& Objects.equals(showDocCountError, that.showDocCountError)
&& Objects.equals(format, that.format)
&& Objects.equals(aggregations, that.aggregations);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things going on here:

  1. docCountError is converted into -1 by the serialization process if showDocCountError is false. I looked into making it consistent but that seemed more complex than it was worth.
  2. We may as well actually check the extra stuff. It doesn't cost us anything.

@@ -111,6 +111,9 @@ public boolean equals(Object obj) {
if (super.equals(obj) == false) return false;

InternalCardinality other = (InternalCardinality) obj;
if (counts == null) {
return other.counts == null;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes it's null but we never handled that in equals/hashcode

@@ -206,7 +206,6 @@ public boolean equals(Object obj) {
ScoreDoc otherDoc = other.topDocs.topDocs.scoreDocs[d];
if (thisDoc.doc != otherDoc.doc) return false;
if (Double.compare(thisDoc.score, otherDoc.score) != 0) return false;
if (thisDoc.shardIndex != otherDoc.shardIndex) return false;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shardIndex is destroyed by serialization.

@@ -111,7 +111,7 @@ public void testGetAppropriateRoundingUsesCorrectIntervals() {
long startingDate = randomLongBetween(0, utcMillis("2050-01-01"));
RoundingInfo[] roundingInfos = AutoDateHistogramAggregationBuilder.buildRoundings(null, null);
int roundingIndex = between(0, roundingInfos.length - 1);
DocValueFormat format = randomNumericDocValueFormat();
DocValueFormat format = randomDateDocValueFormat();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May as well use a proper doc value format now that I've made it work with tests. You'll see this in a bunch of places.

ZoneOffset.UTC,
Resolution.MILLISECONDS
);
return createTestInstance(name, metadata, subAggs, xContentCompatibleFormat);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of neat. Random doc value formats may generate json with duplicate keys which we can't parse. That's never been considered really a bug. Just, like, don't configure the agg that way. But random tests will and those are valid for serialization. But not valid for xcontent. We've had this createTestInstanceForXContent style for a while. So I extended it here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, testing against random formats is hard. I think this pattern continues to make sense.

@@ -433,11 +433,11 @@ public void testUnmappedWithBadMissingField() {
public void testSubAggCollectsFromSingleBucketIfOneRange() throws IOException {
RangeAggregationBuilder aggregationBuilder = new RangeAggregationBuilder("test").field(NUMBER_FIELD_NAME)
.addRange(0d, 10d)
.subAggregation(aggCardinality("c"));
.subAggregation(aggCardinalityUpperBound("c"));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this because it was confusing to me when I bumped into it while fixing its serialization errors.

protected void doWriteTo(StreamOutput out) throws IOException {
out.writeVInt(cardinality.map(i -> i));
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We round trip this now.

originalBytes = toXContent(aggregation, xContentType, params, humanReadable);
}
} catch (IOException e) {
throw new IOException("error converting " + aggregation, e);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message was useless.

Copy link
Member

@not-napoleon not-napoleon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@@ -317,6 +317,26 @@ public double parseDouble(String value, boolean roundUp, LongSupplier now) {
public String toString() {
return "DocValueFormat.DateTime(" + formatter + ", " + timeZone + ", " + resolution + ")";
}

@Override
public boolean equals(Object o) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zoinks. Nice catch.

@@ -134,15 +134,14 @@ public boolean equals(Object o) {
}

Bucket<?> that = (Bucket<?>) o;
return bucketOrd == that.bucketOrd
&& Double.compare(that.score, score) == 0
return Double.compare(that.score, score) == 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth leaving as a comment on the member declaration.

ZoneOffset.UTC,
Resolution.MILLISECONDS
);
return createTestInstance(name, metadata, subAggs, xContentCompatibleFormat);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, testing against random formats is hard. I think this pattern continues to make sense.

@@ -526,9 +532,9 @@ public final void testFromXContentWithRandomFields() throws IOException {
protected Predicate<String> excludePathsFromXContentInsertion() {
return path -> false;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Trailing white space?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. will zap.

/**
* @return a random {@link DocValueFormat} that can be used in aggregations which
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind, but I'm curious why you don't think @return is appropriate here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks better when I mouse over and get the javadoc. I think if we ever wanted to look at the html it'd be much better, but I never really do.

But it's really just a silly pet peeve of mine. I'll try to contain it.

@nik9000 nik9000 added the auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) label Oct 25, 2021
@elasticsearchmachine elasticsearchmachine merged commit 2b5f6ce into elastic:master Oct 25, 2021
lockewritesdocs pushed a commit to lockewritesdocs/elasticsearch that referenced this pull request Oct 28, 2021
This tries to automatically detect problems seriealization aggregation
results by round tripping the results in our usual `AggregatorTestCase`.
It's "free" testing in that we already have the tests written and we'll
get round trip testing "on the side". But it's kind of sneaky because we
aren't *trying* to test serialization here. So they failures can be
surprising. But surprising test failures are better than bugs. At least
that is what I tell myself so I can sleep at night. Closes elastic#73680
@nik9000 nik9000 added >bug v7.16.0 v8.1.0 and removed >test Issues or PRs that are addressing/adding tests labels Nov 10, 2021
nik9000 added a commit to nik9000/elasticsearch that referenced this pull request Nov 10, 2021
This tries to automatically detect problems seriealization aggregation
results by round tripping the results in our usual `AggregatorTestCase`.
It's "free" testing in that we already have the tests written and we'll
get round trip testing "on the side". But it's kind of sneaky because we
aren't *trying* to test serialization here. So they failures can be
surprising. But surprising test failures are better than bugs. At least
that is what I tell myself so I can sleep at night. Closes elastic#73680
@nik9000
Copy link
Member Author

nik9000 commented Nov 10, 2021

7.16 is #80632
8.1 is just this PR. We forked 8.1 after this.

nik9000 added a commit that referenced this pull request Nov 10, 2021
This tries to automatically detect problems seriealization aggregation
results by round tripping the results in our usual `AggregatorTestCase`.
It's "free" testing in that we already have the tests written and we'll
get round trip testing "on the side". But it's kind of sneaky because we
aren't *trying* to test serialization here. So they failures can be
surprising. But surprising test failures are better than bugs. At least
that is what I tell myself so I can sleep at night. Closes #73680
@imotov imotov changed the title Add extra round trip to aggs tests Fix Unknown NamedWriteable error in InternalAggregation (Add extra round trip to aggs tests) Dec 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Analytics/Aggregations Aggregations auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) >bug Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v7.16.0 v8.0.0-beta1 v8.1.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pipeline aggregations shouldn't serialize to remote clusters in cross-cluster search
5 participants