From 37468f764f473f720e05861513a6c8e4f1b09e20 Mon Sep 17 00:00:00 2001 From: Jeremy Dahlgren Date: Wed, 4 Jun 2025 15:20:33 -0400 Subject: [PATCH 1/5] Fix SnapshotStats toXContent()/fromXContent() round trip serialization toXContent() has a check to omit the "processed" sub-object if the processedFileCount equals the incrementalFileCount. In the scenario where they are equal and greater than zero, if you were to read the JSON back in with fromXContent(), the SnapshotStats object would not be the same as the original since processedFileCount is not parsed and set. This change adds a fix and a unit test for this scenario. --- .../snapshots/status/SnapshotStats.java | 10 ++++++++-- .../snapshots/status/SnapshotStatsTests.java | 20 +++++++++++++++++++ .../test/AbstractXContentTestCase.java | 9 ++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index 03b01f88a3a20..ab04e294f6a6c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -204,10 +204,10 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti long time = 0; int incrementalFileCount = 0; int totalFileCount = 0; - int processedFileCount = 0; + int processedFileCount = Integer.MIN_VALUE; long incrementalSize = 0; long totalSize = 0; - long processedSize = 0; + long processedSize = Long.MIN_VALUE; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); String currentName = parser.currentName(); @@ -282,6 +282,12 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti } } } + // Handle the case where the "processed" sub-object is omitted in toXContent() when processedFileCount == incrementalFileCount. + if (processedFileCount == Integer.MIN_VALUE) { + assert processedSize == Long.MIN_VALUE; + processedFileCount = incrementalFileCount; + processedSize = incrementalSize; + } return new SnapshotStats( startTime, time, diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index e0411254e1280..2f928eeefcbb4 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -39,6 +39,26 @@ protected SnapshotStats createTestInstance() { ); } + public void testXContentSerializationWhenProcessedFileCountEqualsIncrementalFileCount() throws IOException { + final var instance = createTestInstance(); + final var incrementalSameAsProcessed = new SnapshotStats( + instance.getStartTime(), + instance.getTime(), + instance.getIncrementalFileCount(), + instance.getTotalFileCount(), + instance.getIncrementalFileCount(), // processedFileCount + instance.getIncrementalSize(), + instance.getTotalSize(), + instance.getIncrementalSize() // processedSize + ); + // toXContent() omits the "processed" sub-object in this case, make sure the processed values are set as expected in fromXContent(). + testFromXContent(() -> incrementalSameAsProcessed); + } + + public void testXContentSerializationForEmptyStats() throws IOException { + testFromXContent(SnapshotStats::new); + } + @Override protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { return SnapshotStats.fromXContent(parser); diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java index 39b0f2b60662e..bd39f11541ac5 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java @@ -284,9 +284,16 @@ public static void testFromXContent( * both for equality and asserts equality on the two queries. */ public final void testFromXContent() throws IOException { + testFromXContent(this::createTestInstance); + } + + /** + * Generic test that creates a new instance using the given supplier and verifies XContent round trip serialization. + */ + public final void testFromXContent(Supplier testInstanceSupplier) throws IOException { testFromXContent( NUMBER_OF_TEST_RUNS, - this::createTestInstance, + testInstanceSupplier, supportsUnknownFields(), getShuffleFieldsExceptions(), getRandomFieldsExcludeFilter(), From 7d47a7b7e00b5e7108682d72da83dd07ae61f6f9 Mon Sep 17 00:00:00 2001 From: Jeremy Dahlgren Date: Wed, 4 Jun 2025 15:48:32 -0400 Subject: [PATCH 2/5] Update docs/changelog/128928.yaml --- docs/changelog/128928.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changelog/128928.yaml diff --git a/docs/changelog/128928.yaml b/docs/changelog/128928.yaml new file mode 100644 index 0000000000000..ef42818219a8c --- /dev/null +++ b/docs/changelog/128928.yaml @@ -0,0 +1,5 @@ +pr: 128928 +summary: Fix `SnapshotStats` toXContent()/fromXContent() round trip serialization +area: Snapshot/Restore +type: bug +issues: [] From fb6b61631560f64e220484f2de5cfa6094f1fee6 Mon Sep 17 00:00:00 2001 From: Jeremy Dahlgren Date: Wed, 4 Jun 2025 17:22:47 -0400 Subject: [PATCH 3/5] Move SnapshotStats.fromXContent() to SnapshotStatsTest --- .../snapshots/status/SnapshotStats.java | 110 ----------------- .../status/SnapshotIndexShardStatusTests.java | 6 +- .../status/SnapshotIndexStatusTests.java | 6 +- .../snapshots/status/SnapshotStatsTests.java | 111 +++++++++++++++++- .../snapshots/status/SnapshotStatusTests.java | 2 +- 5 files changed, 121 insertions(+), 114 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index ab04e294f6a6c..62f475ebfa36f 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -14,12 +14,10 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.unit.ByteSizeValue; -import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.core.TimeValue; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xcontent.XContentParser; import java.io.IOException; @@ -192,114 +190,6 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par return builder.endObject(); } - public static SnapshotStats fromXContent(XContentParser parser) throws IOException { - // Parse this old school style instead of using the ObjectParser since there's an impedance mismatch between how the - // object has historically been written as JSON versus how it is structured in Java. - XContentParser.Token token = parser.currentToken(); - if (token == null) { - token = parser.nextToken(); - } - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); - long startTime = 0; - long time = 0; - int incrementalFileCount = 0; - int totalFileCount = 0; - int processedFileCount = Integer.MIN_VALUE; - long incrementalSize = 0; - long totalSize = 0; - long processedSize = Long.MIN_VALUE; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); - String currentName = parser.currentName(); - token = parser.nextToken(); - if (currentName.equals(Fields.INCREMENTAL)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); - String innerName = parser.currentName(); - token = parser.nextToken(); - if (innerName.equals(Fields.FILE_COUNT)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - incrementalFileCount = parser.intValue(); - } else if (innerName.equals(Fields.SIZE_IN_BYTES)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - incrementalSize = parser.longValue(); - } else { - // Unknown sub field, skip - if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { - parser.skipChildren(); - } - } - } - } else if (currentName.equals(Fields.PROCESSED)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); - String innerName = parser.currentName(); - token = parser.nextToken(); - if (innerName.equals(Fields.FILE_COUNT)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - processedFileCount = parser.intValue(); - } else if (innerName.equals(Fields.SIZE_IN_BYTES)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - processedSize = parser.longValue(); - } else { - // Unknown sub field, skip - if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { - parser.skipChildren(); - } - } - } - } else if (currentName.equals(Fields.TOTAL)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); - String innerName = parser.currentName(); - token = parser.nextToken(); - if (innerName.equals(Fields.FILE_COUNT)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - totalFileCount = parser.intValue(); - } else if (innerName.equals(Fields.SIZE_IN_BYTES)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - totalSize = parser.longValue(); - } else { - // Unknown sub field, skip - if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { - parser.skipChildren(); - } - } - } - } else if (currentName.equals(Fields.START_TIME_IN_MILLIS)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - startTime = parser.longValue(); - } else if (currentName.equals(Fields.TIME_IN_MILLIS)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); - time = parser.longValue(); - } else { - // Unknown field, skip - if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { - parser.skipChildren(); - } - } - } - // Handle the case where the "processed" sub-object is omitted in toXContent() when processedFileCount == incrementalFileCount. - if (processedFileCount == Integer.MIN_VALUE) { - assert processedSize == Long.MIN_VALUE; - processedFileCount = incrementalFileCount; - processedSize = incrementalSize; - } - return new SnapshotStats( - startTime, - time, - incrementalFileCount, - totalFileCount, - processedFileCount, - incrementalSize, - totalSize, - processedSize - ); - } - /** * Add stats instance to the total * @param stats Stats instance to add diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java index f79bd5f6ad864..2a2e39d562c7f 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java @@ -95,7 +95,11 @@ protected boolean supportsUnknownFields() { innerParser.declareString(constructorArg(), new ParseField(SnapshotIndexShardStatus.Fields.STAGE)); innerParser.declareString(optionalConstructorArg(), new ParseField(SnapshotIndexShardStatus.Fields.NODE)); innerParser.declareString(optionalConstructorArg(), new ParseField(SnapshotIndexShardStatus.Fields.REASON)); - innerParser.declareObject(constructorArg(), (p, c) -> SnapshotStats.fromXContent(p), new ParseField(SnapshotStats.Fields.STATS)); + innerParser.declareObject( + constructorArg(), + (p, c) -> SnapshotStatsTests.fromXContent(p), + new ParseField(SnapshotStats.Fields.STATS) + ); PARSER = (p, indexId, shardName) -> { // Combine the index name in the context with the shard name passed in for the named object parser // into a ShardId to pass as context for the inner parser. diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java index 27e47b9a961e7..f93878652684b 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java @@ -57,7 +57,11 @@ public class SnapshotIndexStatusTests extends AbstractXContentTestCase SnapshotShardsStatsTests.PARSER.apply(p, null), new ParseField(SnapshotShardsStats.Fields.SHARDS_STATS) ); - innerParser.declareObject(constructorArg(), (p, c) -> SnapshotStats.fromXContent(p), new ParseField(SnapshotStats.Fields.STATS)); + innerParser.declareObject( + constructorArg(), + (p, c) -> SnapshotStatsTests.fromXContent(p), + new ParseField(SnapshotStats.Fields.STATS) + ); innerParser.declareNamedObjects( constructorArg(), SnapshotIndexShardStatusTests.PARSER, diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index 2f928eeefcbb4..bcb7b0b6aec37 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -9,6 +9,7 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; +import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.test.AbstractXContentTestCase; import org.elasticsearch.xcontent.XContentParser; @@ -61,11 +62,119 @@ public void testXContentSerializationForEmptyStats() throws IOException { @Override protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { - return SnapshotStats.fromXContent(parser); + return fromXContent(parser); } @Override protected boolean supportsUnknownFields() { return true; } + + static SnapshotStats fromXContent(XContentParser parser) throws IOException { + // Parse this old school style instead of using the ObjectParser since there's an impedance mismatch between how the + // object has historically been written as JSON versus how it is structured in Java. + XContentParser.Token token = parser.currentToken(); + if (token == null) { + token = parser.nextToken(); + } + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); + long startTime = 0; + long time = 0; + int incrementalFileCount = 0; + int totalFileCount = 0; + int processedFileCount = Integer.MIN_VALUE; + long incrementalSize = 0; + long totalSize = 0; + long processedSize = Long.MIN_VALUE; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); + String currentName = parser.currentName(); + token = parser.nextToken(); + if (currentName.equals(SnapshotStats.Fields.INCREMENTAL)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); + String innerName = parser.currentName(); + token = parser.nextToken(); + if (innerName.equals(SnapshotStats.Fields.FILE_COUNT)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + incrementalFileCount = parser.intValue(); + } else if (innerName.equals(SnapshotStats.Fields.SIZE_IN_BYTES)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + incrementalSize = parser.longValue(); + } else { + // Unknown sub field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } + } + } + } else if (currentName.equals(SnapshotStats.Fields.PROCESSED)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); + String innerName = parser.currentName(); + token = parser.nextToken(); + if (innerName.equals(SnapshotStats.Fields.FILE_COUNT)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + processedFileCount = parser.intValue(); + } else if (innerName.equals(SnapshotStats.Fields.SIZE_IN_BYTES)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + processedSize = parser.longValue(); + } else { + // Unknown sub field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } + } + } + } else if (currentName.equals(SnapshotStats.Fields.TOTAL)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser); + String innerName = parser.currentName(); + token = parser.nextToken(); + if (innerName.equals(SnapshotStats.Fields.FILE_COUNT)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + totalFileCount = parser.intValue(); + } else if (innerName.equals(SnapshotStats.Fields.SIZE_IN_BYTES)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + totalSize = parser.longValue(); + } else { + // Unknown sub field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } + } + } + } else if (currentName.equals(SnapshotStats.Fields.START_TIME_IN_MILLIS)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + startTime = parser.longValue(); + } else if (currentName.equals(SnapshotStats.Fields.TIME_IN_MILLIS)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser); + time = parser.longValue(); + } else { + // Unknown field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } + } + } + // Handle the case where the "processed" sub-object is omitted in toXContent() when processedFileCount == incrementalFileCount. + if (processedFileCount == Integer.MIN_VALUE) { + assert processedSize == Long.MIN_VALUE; + processedFileCount = incrementalFileCount; + processedSize = incrementalSize; + } + return new SnapshotStats( + startTime, + time, + incrementalFileCount, + totalFileCount, + processedFileCount, + incrementalSize, + totalSize, + processedSize + ); + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java index 31efa53ab8aee..01b09ed0b8198 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java @@ -77,7 +77,7 @@ public class SnapshotStatusTests extends AbstractChunkedSerializingTestCase Date: Wed, 4 Jun 2025 17:26:53 -0400 Subject: [PATCH 4/5] Delete docs/changelog/128928.yaml --- docs/changelog/128928.yaml | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 docs/changelog/128928.yaml diff --git a/docs/changelog/128928.yaml b/docs/changelog/128928.yaml deleted file mode 100644 index ef42818219a8c..0000000000000 --- a/docs/changelog/128928.yaml +++ /dev/null @@ -1,5 +0,0 @@ -pr: 128928 -summary: Fix `SnapshotStats` toXContent()/fromXContent() round trip serialization -area: Snapshot/Restore -type: bug -issues: [] From 165314c56d1c1498f7aee150511f3dfd40a16732 Mon Sep 17 00:00:00 2001 From: Jeremy Dahlgren Date: Thu, 5 Jun 2025 08:10:42 -0400 Subject: [PATCH 5/5] Revert change to AbstractXContentTestCase --- .../snapshots/status/SnapshotStatsTests.java | 28 ++++++------------- .../test/AbstractXContentTestCase.java | 9 +----- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index bcb7b0b6aec37..86403b1142c74 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -28,6 +28,14 @@ protected SnapshotStats createTestInstance() { long incrementalSize = ((long) randomIntBetween(0, Integer.MAX_VALUE)) * 2; long totalSize = ((long) randomIntBetween(0, Integer.MAX_VALUE)) * 2; long processedSize = ((long) randomIntBetween(0, Integer.MAX_VALUE)) * 2; + + // toXContent() omits the "processed" sub-object if processedFileCount == incrementalFileCount, so here we increase the probability + // of that scenario so we can make sure the processed values are set as expected in fromXContent(). + if (randomBoolean()) { + processedFileCount = incrementalFileCount; + processedSize = incrementalSize; + } + return new SnapshotStats( startTime, time, @@ -40,26 +48,6 @@ protected SnapshotStats createTestInstance() { ); } - public void testXContentSerializationWhenProcessedFileCountEqualsIncrementalFileCount() throws IOException { - final var instance = createTestInstance(); - final var incrementalSameAsProcessed = new SnapshotStats( - instance.getStartTime(), - instance.getTime(), - instance.getIncrementalFileCount(), - instance.getTotalFileCount(), - instance.getIncrementalFileCount(), // processedFileCount - instance.getIncrementalSize(), - instance.getTotalSize(), - instance.getIncrementalSize() // processedSize - ); - // toXContent() omits the "processed" sub-object in this case, make sure the processed values are set as expected in fromXContent(). - testFromXContent(() -> incrementalSameAsProcessed); - } - - public void testXContentSerializationForEmptyStats() throws IOException { - testFromXContent(SnapshotStats::new); - } - @Override protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { return fromXContent(parser); diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java index bd39f11541ac5..39b0f2b60662e 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java @@ -284,16 +284,9 @@ public static void testFromXContent( * both for equality and asserts equality on the two queries. */ public final void testFromXContent() throws IOException { - testFromXContent(this::createTestInstance); - } - - /** - * Generic test that creates a new instance using the given supplier and verifies XContent round trip serialization. - */ - public final void testFromXContent(Supplier testInstanceSupplier) throws IOException { testFromXContent( NUMBER_OF_TEST_RUNS, - testInstanceSupplier, + this::createTestInstance, supportsUnknownFields(), getShuffleFieldsExceptions(), getRandomFieldsExcludeFilter(),