Просмотр исходного кода

Remove IngestDocument equals/hashCode (#99598)

Joe Gallo 2 лет назад
Родитель
Сommit
d87b93f317

+ 2 - 2
modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorTests.java

@@ -344,7 +344,7 @@ public class ForEachProcessorTests extends ESTestCase {
         execProcessor(processor, ingestDocument, (result, e) -> {});
         assertThat(testProcessor.getInvokedCounter(), equalTo(2));
         ingestDocument.removeField("_ingest._value");
-        assertThat(ingestDocument, equalTo(originalIngestDocument));
+        assertIngestDocument(ingestDocument, originalIngestDocument);
     }
 
     public void testRemovingFromTheSameField() {
@@ -355,7 +355,7 @@ public class ForEachProcessorTests extends ESTestCase {
         execProcessor(processor, ingestDocument, (result, e) -> {});
         assertThat(testProcessor.getInvokedCounter(), equalTo(2));
         ingestDocument.removeField("_ingest._value");
-        assertThat(ingestDocument, equalTo(originalIngestDocument));
+        assertIngestDocument(ingestDocument, originalIngestDocument);
     }
 
     public void testMapIteration() {

+ 1 - 1
modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/GrokProcessorTests.java

@@ -114,7 +114,7 @@ public class GrokProcessorTests extends ESTestCase {
             MatcherWatchdog.noop()
         );
         processor.execute(doc);
-        assertThat(doc, equalTo(originalDoc));
+        assertIngestDocument(doc, originalDoc);
     }
 
     public void testNullField() {

+ 0 - 18
server/src/main/java/org/elasticsearch/action/ingest/WriteableIngestDocument.java

@@ -25,7 +25,6 @@ import org.elasticsearch.xcontent.XContentParser;
 import java.io.IOException;
 import java.time.ZonedDateTime;
 import java.util.Map;
-import java.util.Objects;
 
 import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
 import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
@@ -140,23 +139,6 @@ final class WriteableIngestDocument implements Writeable, ToXContentFragment {
         return PARSER.apply(parser, null);
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        WriteableIngestDocument that = (WriteableIngestDocument) o;
-        return Objects.equals(ingestDocument, that.ingestDocument);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(ingestDocument);
-    }
-
     @Override
     public String toString() {
         return ingestDocument.toString();

+ 0 - 18
server/src/main/java/org/elasticsearch/ingest/IngestDocument.java

@@ -911,24 +911,6 @@ public final class IngestDocument {
         this.doNoSelfReferencesCheck = doNoSelfReferencesCheck;
     }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-
-        IngestDocument other = (IngestDocument) obj;
-        return Objects.equals(ctxMap, other.ctxMap) && Maps.deepEquals(ingestMetadata, other.ingestMetadata);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(ctxMap, ingestMetadata);
-    }
-
     @Override
     public String toString() {
         return "IngestDocument{" + " sourceAndMetadata=" + ctxMap + ", ingestMetadata=" + ingestMetadata + '}';

+ 2 - 3
server/src/main/java/org/elasticsearch/script/CtxMap.java

@@ -8,7 +8,6 @@
 
 package org.elasticsearch.script;
 
-import org.elasticsearch.common.util.Maps;
 import org.elasticsearch.common.util.set.Sets;
 
 import java.util.AbstractCollection;
@@ -337,9 +336,9 @@ public class CtxMap<T extends Metadata> extends AbstractMap<String, Object> {
     public boolean equals(Object o) {
         if (this == o) return true;
         if ((o instanceof CtxMap) == false) return false;
+        if (super.equals(o) == false) return false;
         CtxMap<?> ctxMap = (CtxMap<?>) o;
-        if (Maps.deepEquals(this, ctxMap) == false) return false;
-        return Maps.deepEquals(source, ctxMap.source) && metadata.equals(ctxMap.metadata);
+        return source.equals(ctxMap.source) && metadata.equals(ctxMap.metadata);
     }
 
     @Override

+ 1 - 1
server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentBaseResultTests.java

@@ -88,7 +88,7 @@ public class SimulateDocumentBaseResultTests extends AbstractXContentTestCase<Si
     }
 
     public static void assertEqualDocs(SimulateDocumentBaseResult response, SimulateDocumentBaseResult parsedResponse) {
-        assertEquals(response.getIngestDocument(), parsedResponse.getIngestDocument());
+        assertIngestDocument(response.getIngestDocument(), parsedResponse.getIngestDocument());
         if (response.getFailure() != null) {
             assertNotNull(parsedResponse.getFailure());
             assertThat(parsedResponse.getFailure().getMessage(), containsString(response.getFailure().getMessage()));

+ 1 - 1
server/src/test/java/org/elasticsearch/action/ingest/SimulateExecutionServiceTests.java

@@ -108,7 +108,7 @@ public class SimulateExecutionServiceTests extends ESTestCase {
         assertThat(processor.getInvokedCounter(), equalTo(2));
         assertThat(actualItemResponse, instanceOf(SimulateDocumentBaseResult.class));
         SimulateDocumentBaseResult simulateDocumentBaseResult = (SimulateDocumentBaseResult) actualItemResponse;
-        assertThat(simulateDocumentBaseResult.getIngestDocument(), equalTo(ingestDocument));
+        assertIngestDocument(simulateDocumentBaseResult.getIngestDocument(), ingestDocument);
         assertThat(simulateDocumentBaseResult.getFailure(), nullValue());
     }
 

+ 1 - 1
server/src/test/java/org/elasticsearch/action/ingest/SimulateProcessorResultTests.java

@@ -127,7 +127,7 @@ public class SimulateProcessorResultTests extends AbstractXContentTestCase<Simul
 
     static void assertEqualProcessorResults(SimulateProcessorResult response, SimulateProcessorResult parsedResponse) {
         assertEquals(response.getProcessorTag(), parsedResponse.getProcessorTag());
-        assertEquals(response.getIngestDocument(), parsedResponse.getIngestDocument());
+        assertIngestDocument(response.getIngestDocument(), parsedResponse.getIngestDocument());
         if (response.getFailure() != null) {
             assertNotNull(parsedResponse.getFailure());
             assertThat(parsedResponse.getFailure().getMessage(), containsString(response.getFailure().getMessage()));

+ 9 - 69
server/src/test/java/org/elasticsearch/action/ingest/WriteableIngestDocumentTests.java

@@ -26,7 +26,6 @@ import org.elasticsearch.xcontent.XContentType;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -45,72 +44,14 @@ import static org.hamcrest.Matchers.sameInstance;
 
 public class WriteableIngestDocumentTests extends AbstractXContentTestCase<WriteableIngestDocument> {
 
-    @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/99403")
-    public void testEqualsAndHashcode() throws Exception {
-        Map<String, Object> sourceAndMetadata = RandomDocumentPicks.randomSource(random());
-        int numFields = randomIntBetween(1, IngestDocument.Metadata.values().length);
-        sourceAndMetadata.put(VERSION.getFieldName(), TestIngestDocument.randomVersion());
-        for (int i = 0; i < numFields; i++) {
-            Tuple<String, Object> metadata = TestIngestDocument.randomMetadata();
-            sourceAndMetadata.put(metadata.v1(), metadata.v2());
-        }
-        Map<String, Object> ingestMetadata = new HashMap<>();
-        numFields = randomIntBetween(1, 5);
-        for (int i = 0; i < numFields; i++) {
-            ingestMetadata.put(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(5, 10));
-        }
-        WriteableIngestDocument ingestDocument = new WriteableIngestDocument(new IngestDocument(sourceAndMetadata, ingestMetadata));
-
-        boolean changed = false;
-        Map<String, Object> otherSourceAndMetadata;
-        if (randomBoolean()) {
-            otherSourceAndMetadata = RandomDocumentPicks.randomSource(random());
-            otherSourceAndMetadata.put(VERSION.getFieldName(), TestIngestDocument.randomVersion());
-            changed = true;
-        } else {
-            otherSourceAndMetadata = new HashMap<>(sourceAndMetadata);
-        }
-        if (randomBoolean()) {
-            numFields = randomIntBetween(1, IngestDocument.Metadata.values().length);
-            for (int i = 0; i < numFields; i++) {
-                Tuple<String, Object> metadata = randomValueOtherThanMany(
-                    t -> t.v2().equals(sourceAndMetadata.get(t.v1())),
-                    TestIngestDocument::randomMetadata
-                );
-                otherSourceAndMetadata.put(metadata.v1(), metadata.v2());
-            }
-            changed = true;
-        }
-
-        Map<String, Object> otherIngestMetadata;
-        if (randomBoolean()) {
-            otherIngestMetadata = new HashMap<>();
-            numFields = randomIntBetween(1, 5);
-            for (int i = 0; i < numFields; i++) {
-                otherIngestMetadata.put(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(5, 10));
-            }
-            changed = true;
-        } else {
-            otherIngestMetadata = Collections.unmodifiableMap(ingestMetadata);
-        }
+    @Override
+    protected boolean assertToXContentEquivalence() {
+        return false;
+    }
 
-        WriteableIngestDocument otherIngestDocument = new WriteableIngestDocument(
-            new IngestDocument(otherSourceAndMetadata, otherIngestMetadata)
-        );
-        if (changed) {
-            assertThat(ingestDocument, not(equalTo(otherIngestDocument)));
-            assertThat(otherIngestDocument, not(equalTo(ingestDocument)));
-        } else {
-            assertThat(ingestDocument, equalTo(otherIngestDocument));
-            assertThat(otherIngestDocument, equalTo(ingestDocument));
-            assertThat(ingestDocument.hashCode(), equalTo(otherIngestDocument.hashCode()));
-            WriteableIngestDocument thirdIngestDocument = new WriteableIngestDocument(
-                new IngestDocument(Collections.unmodifiableMap(sourceAndMetadata), Collections.unmodifiableMap(ingestMetadata))
-            );
-            assertThat(thirdIngestDocument, equalTo(ingestDocument));
-            assertThat(ingestDocument, equalTo(thirdIngestDocument));
-            assertThat(ingestDocument.hashCode(), equalTo(thirdIngestDocument.hashCode()));
-        }
+    @Override
+    protected void assertEqualInstances(WriteableIngestDocument expectedInstance, WriteableIngestDocument newInstance) {
+        assertIngestDocument(expectedInstance.getIngestDocument(), newInstance.getIngestDocument());
     }
 
     public void testSerialization() throws IOException {
@@ -166,8 +107,7 @@ public class WriteableIngestDocumentTests extends AbstractXContentTestCase<Write
         sourceAndMetadata.putAll(toXContentSource);
         ingestDocument.getMetadata().keySet().forEach(k -> sourceAndMetadata.put(k, ingestDocument.getMetadata().get(k)));
         IngestDocument serializedIngestDocument = new IngestDocument(sourceAndMetadata, toXContentIngestMetadata);
-        // TODO(stu): is this test correct? Comparing against ingestDocument fails due to incorrectly failed byte array comparisons
-        assertThat(serializedIngestDocument, equalTo(serializedIngestDocument));
+        assertIngestDocument(writeableIngestDocument.getIngestDocument(), serializedIngestDocument);
     }
 
     public void testXContentHashSetSerialization() throws Exception {
@@ -189,7 +129,7 @@ public class WriteableIngestDocumentTests extends AbstractXContentTestCase<Write
         IngestDocument document = createRandomIngestDoc();
         WriteableIngestDocument wid = new WriteableIngestDocument(document);
 
-        assertThat(wid.getIngestDocument(), equalTo(document));
+        assertIngestDocument(wid.getIngestDocument(), document);
         assertThat(wid.getIngestDocument(), not(sameInstance(document)));
     }
 

+ 0 - 77
server/src/test/java/org/elasticsearch/ingest/IngestDocumentTests.java

@@ -8,7 +8,6 @@
 
 package org.elasticsearch.ingest;
 
-import org.elasticsearch.core.Tuple;
 import org.elasticsearch.test.ESTestCase;
 import org.hamcrest.Matchers;
 import org.junit.Before;
@@ -958,70 +957,6 @@ public class IngestDocumentTests extends ESTestCase {
         }
     }
 
-    public void testEqualsAndHashcode() throws Exception {
-        Map<String, Object> sourceAndMetadata = RandomDocumentPicks.randomSource(random());
-        int numFields = randomIntBetween(1, IngestDocument.Metadata.values().length);
-        for (int i = 0; i < numFields; i++) {
-            Tuple<String, Object> metadata = TestIngestDocument.randomMetadata();
-            sourceAndMetadata.put(metadata.v1(), metadata.v2());
-        }
-        sourceAndMetadata.putIfAbsent("_version", TestIngestDocument.randomVersion());
-        Map<String, Object> ingestMetadata = new HashMap<>();
-        numFields = randomIntBetween(1, 5);
-        for (int i = 0; i < numFields; i++) {
-            ingestMetadata.put(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(5, 10));
-        }
-        // this is testing equality so use the wire constructor
-        IngestDocument ingestDocument = new IngestDocument(sourceAndMetadata, ingestMetadata);
-
-        boolean changed = false;
-        Map<String, Object> otherSourceAndMetadata;
-        if (randomBoolean()) {
-            otherSourceAndMetadata = RandomDocumentPicks.randomSource(random());
-            otherSourceAndMetadata.putIfAbsent("_version", TestIngestDocument.randomVersion());
-            changed = true;
-        } else {
-            otherSourceAndMetadata = new HashMap<>(sourceAndMetadata);
-        }
-        if (randomBoolean()) {
-            numFields = randomIntBetween(1, IngestDocument.Metadata.values().length);
-            for (int i = 0; i < numFields; i++) {
-                Tuple<String, Object> metadata;
-                do {
-                    metadata = TestIngestDocument.randomMetadata();
-                } while (metadata.v2().equals(sourceAndMetadata.get(metadata.v1()))); // must actually be a change
-                otherSourceAndMetadata.put(metadata.v1(), metadata.v2());
-            }
-            changed = true;
-        }
-
-        Map<String, Object> otherIngestMetadata;
-        if (randomBoolean()) {
-            otherIngestMetadata = new HashMap<>();
-            numFields = randomIntBetween(1, 5);
-            for (int i = 0; i < numFields; i++) {
-                otherIngestMetadata.put(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(5, 10));
-            }
-            changed = true;
-        } else {
-            otherIngestMetadata = Map.copyOf(ingestMetadata);
-        }
-
-        IngestDocument otherIngestDocument = new IngestDocument(otherSourceAndMetadata, otherIngestMetadata);
-        if (changed) {
-            assertThat(ingestDocument, not(equalTo(otherIngestDocument)));
-            assertThat(otherIngestDocument, not(equalTo(ingestDocument)));
-        } else {
-            assertThat(ingestDocument, equalTo(otherIngestDocument));
-            assertThat(otherIngestDocument, equalTo(ingestDocument));
-            assertThat(ingestDocument.hashCode(), equalTo(otherIngestDocument.hashCode()));
-            IngestDocument thirdIngestDocument = new IngestDocument(Map.copyOf(sourceAndMetadata), Map.copyOf(ingestMetadata));
-            assertThat(thirdIngestDocument, equalTo(ingestDocument));
-            assertThat(ingestDocument, equalTo(thirdIngestDocument));
-            assertThat(ingestDocument.hashCode(), equalTo(thirdIngestDocument.hashCode()));
-        }
-    }
-
     public void testIngestMetadataTimestamp() throws Exception {
         long before = System.currentTimeMillis();
         IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
@@ -1169,16 +1104,4 @@ public class IngestDocumentTests extends ESTestCase {
         assertFalse(ingestDocument.updateIndexHistory(index1));
         assertThat(ingestDocument.getIndexHistory(), Matchers.contains(index1, index2));
     }
-
-    public void testEqualsAndHashCodeWithArray() {
-        // Test that equality still works when the ingest document uses primitive arrays,
-        // since normal .equals() methods would not work for Maps containing these arrays.
-        byte[] numbers = new byte[] { 0, 1, 2 };
-        ingestDocument.setFieldValue("some.nested.array", numbers);
-        IngestDocument copy = new IngestDocument(ingestDocument);
-        byte[] copiedNumbers = copy.getFieldValue("some.nested.array", byte[].class);
-        assertArrayEquals(numbers, copiedNumbers);
-        assertNotEquals(numbers, copiedNumbers);
-        assertThat(copy, equalTo(ingestDocument));
-    }
 }

+ 2 - 1
server/src/test/java/org/elasticsearch/ingest/PipelineProcessorTests.java

@@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.function.LongSupplier;
 
+import static org.elasticsearch.ingest.IngestDocumentMatcher.assertIngestDocument;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
@@ -60,7 +61,7 @@ public class PipelineProcessorTests extends ESTestCase {
         Map<String, Object> config = new HashMap<>();
         config.put("name", pipelineId);
         factory.create(Map.of(), null, null, config).execute(testIngestDocument, (result, e) -> {});
-        assertEquals(testIngestDocument, invoked.get());
+        assertIngestDocument(testIngestDocument, invoked.get());
     }
 
     public void testThrowsOnMissingPipeline() throws Exception {

+ 13 - 9
server/src/test/java/org/elasticsearch/ingest/TrackingResultProcessorTests.java

@@ -27,6 +27,7 @@ import java.util.Map;
 import static org.elasticsearch.ingest.CompoundProcessor.ON_FAILURE_MESSAGE_FIELD;
 import static org.elasticsearch.ingest.CompoundProcessor.ON_FAILURE_PROCESSOR_TAG_FIELD;
 import static org.elasticsearch.ingest.CompoundProcessor.ON_FAILURE_PROCESSOR_TYPE_FIELD;
+import static org.elasticsearch.ingest.IngestDocumentMatcher.assertIngestDocument;
 import static org.elasticsearch.ingest.PipelineProcessorTests.createIngestService;
 import static org.elasticsearch.ingest.TrackingResultProcessor.decorate;
 import static org.hamcrest.Matchers.containsString;
@@ -66,7 +67,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertThat(actualProcessor.getInvokedCounter(), equalTo(1));
         assertThat(resultList.size(), equalTo(1));
 
-        assertThat(resultList.get(0).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(0).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(0).getFailure(), nullValue());
         assertThat(resultList.get(0).getProcessorTag(), equalTo(expectedResult.getProcessorTag()));
     }
@@ -222,7 +223,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         );
         assertThat(testProcessor.getInvokedCounter(), equalTo(1));
         assertThat(resultList.size(), equalTo(1));
-        assertThat(resultList.get(0).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(0).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(0).getFailure(), sameInstance(exception));
         assertThat(resultList.get(0).getProcessorTag(), equalTo(expectedResult.getProcessorTag()));
     }
@@ -281,7 +282,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertFalse(resultList.get(2).getIngestDocument().hasField(key2));
         assertTrue(resultList.get(2).getIngestDocument().hasField(key3));
 
-        assertThat(resultList.get(2).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(2).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(2).getFailure(), nullValue());
         assertThat(resultList.get(2).getProcessorTag(), nullValue());
     }
@@ -335,7 +336,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertTrue(resultList.get(2).getIngestDocument().hasField(key2));
         assertFalse(resultList.get(2).getIngestDocument().hasField(key3));
 
-        assertThat(resultList.get(3).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(3).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(3).getFailure(), nullValue());
         assertThat(resultList.get(3).getProcessorTag(), nullValue());
     }
@@ -425,7 +426,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertTrue(resultList.get(3).getIngestDocument().hasField(key2));
         assertFalse(resultList.get(3).getIngestDocument().hasField(key3));
 
-        assertThat(resultList.get(4).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(4).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(4).getFailure(), nullValue());
         assertThat(resultList.get(4).getProcessorTag(), nullValue());
     }
@@ -511,7 +512,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertThat(resultList.get(2).getConditionalWithResult().v1(), equalTo(scriptName));
         assertThat(resultList.get(2).getConditionalWithResult().v2(), is(Boolean.FALSE));
 
-        assertThat(resultList.get(3).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(3).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(3).getFailure(), nullValue());
         assertThat(resultList.get(3).getProcessorTag(), nullValue());
     }
@@ -577,7 +578,7 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertTrue(resultList.get(3).getIngestDocument().hasField(key2));
         assertFalse(resultList.get(3).getIngestDocument().hasField(key3));
 
-        assertThat(resultList.get(4).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(4).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(4).getFailure(), nullValue());
         assertThat(resultList.get(4).getProcessorTag(), nullValue());
     }
@@ -710,14 +711,17 @@ public class TrackingResultProcessorTests extends ESTestCase {
         assertNull(resultList.get(0).getConditionalWithResult());
         assertThat(resultList.get(0).getType(), equalTo("pipeline"));
 
-        assertThat(resultList.get(1).getIngestDocument(), not(equalTo(expectedResult.getIngestDocument())));
+        assertThat(
+            resultList.get(1).getIngestDocument().getFieldValue(key1, Integer.class),
+            not(equalTo(expectedResult.getIngestDocument().getFieldValue(key1, Integer.class)))
+        );
         assertThat(resultList.get(1).getFailure(), nullValue());
         assertThat(resultList.get(1).getProcessorTag(), nullValue());
 
         assertNull(resultList.get(2).getConditionalWithResult());
         assertThat(resultList.get(2).getType(), equalTo("pipeline"));
 
-        assertThat(resultList.get(3).getIngestDocument(), equalTo(expectedResult.getIngestDocument()));
+        assertIngestDocument(resultList.get(3).getIngestDocument(), expectedResult.getIngestDocument());
         assertThat(resultList.get(3).getFailure(), nullValue());
         assertThat(resultList.get(3).getProcessorTag(), nullValue());
 

+ 22 - 7
test/framework/src/main/java/org/elasticsearch/ingest/IngestDocumentMatcher.java

@@ -12,17 +12,32 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
-public class IngestDocumentMatcher {
+public final class IngestDocumentMatcher {
+
+    private IngestDocumentMatcher() {
+        // utility class
+    }
+
     /**
      * Helper method to assert the equivalence between two IngestDocuments.
      *
-     * @param docA first document to compare
-     * @param docB second document to compare
+     * @param expected first document to compare
+     * @param actual second document to compare
      */
-    public static void assertIngestDocument(IngestDocument docA, IngestDocument docB) {
-        if ((deepEquals(docA.getIngestMetadata(), docB.getIngestMetadata(), true)
-            && deepEquals(docA.getSourceAndMetadata(), docB.getSourceAndMetadata(), false)) == false) {
-            throw new AssertionError("Expected [" + docA + "] but received [" + docB + "].");
+    public static void assertIngestDocument(IngestDocument expected, IngestDocument actual) {
+        // trivially true: if they're both null, then all is well
+        if (expected == null && actual == null) {
+            return;
+        }
+
+        // if only one is null, however, then that's not okay
+        if ((expected == null || actual == null)) {
+            throw new AssertionError("Expected [" + expected + "] but received [" + actual + "].");
+        }
+
+        if ((deepEquals(expected.getIngestMetadata(), actual.getIngestMetadata(), true)
+            && deepEquals(expected.getSourceAndMetadata(), actual.getSourceAndMetadata(), false)) == false) {
+            throw new AssertionError("Expected [" + expected + "] but received [" + actual + "].");
         }
     }
 

+ 28 - 18
test/framework/src/test/java/org/elasticsearch/ingest/IngestDocumentMatcherTests.java

@@ -10,9 +10,8 @@ package org.elasticsearch.ingest;
 
 import org.elasticsearch.test.ESTestCase;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import static org.elasticsearch.ingest.IngestDocumentMatcher.assertIngestDocument;
@@ -29,41 +28,52 @@ public class IngestDocumentMatcherTests extends ESTestCase {
 
     public void testDifferentLengthListData() {
         String rootKey = "foo";
-        IngestDocument document1 = TestIngestDocument.withDefaultVersion(Collections.singletonMap(rootKey, Arrays.asList("bar", "baz")));
-        IngestDocument document2 = TestIngestDocument.withDefaultVersion(Collections.singletonMap(rootKey, Collections.emptyList()));
+        IngestDocument document1 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, List.of("bar", "baz")));
+        IngestDocument document2 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, List.of()));
         assertThrowsOnComparision(document1, document2);
     }
 
     public void testDifferentNestedListFieldData() {
         String rootKey = "foo";
-        IngestDocument document1 = TestIngestDocument.withDefaultVersion(Collections.singletonMap(rootKey, Arrays.asList("bar", "baz")));
-        IngestDocument document2 = TestIngestDocument.withDefaultVersion(Collections.singletonMap(rootKey, Arrays.asList("bar", "blub")));
+        IngestDocument document1 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, List.of("bar", "baz")));
+        IngestDocument document2 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, List.of("bar", "blub")));
         assertThrowsOnComparision(document1, document2);
     }
 
     public void testDifferentNestedMapFieldData() {
         String rootKey = "foo";
-        IngestDocument document1 = TestIngestDocument.withDefaultVersion(
-            Collections.singletonMap(rootKey, Collections.singletonMap("bar", "baz"))
-        );
-        IngestDocument document2 = TestIngestDocument.withDefaultVersion(
-            Collections.singletonMap(rootKey, Collections.singletonMap("bar", "blub"))
-        );
+        IngestDocument document1 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, Map.of("bar", "baz")));
+        IngestDocument document2 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, Map.of("bar", "blub")));
         assertThrowsOnComparision(document1, document2);
     }
 
     public void testOnTypeConflict() {
         String rootKey = "foo";
-        IngestDocument document1 = TestIngestDocument.withDefaultVersion(
-            Collections.singletonMap(rootKey, Collections.singletonList("baz"))
-        );
-        IngestDocument document2 = TestIngestDocument.withDefaultVersion(
-            Collections.singletonMap(rootKey, Collections.singletonMap("blub", "blab"))
-        );
+        IngestDocument document1 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, List.of("baz")));
+        IngestDocument document2 = TestIngestDocument.withDefaultVersion(Map.of(rootKey, Map.of("blub", "blab")));
         assertThrowsOnComparision(document1, document2);
     }
 
+    public void testNestedMapArrayEquivalence() {
+        IngestDocument ingestDocument = TestIngestDocument.emptyIngestDocument();
+        // Test that equality still works when the ingest document uses primitive arrays,
+        // since normal .equals() methods would not work for Maps containing these arrays.
+        byte[] numbers = new byte[] { 0, 1, 2 };
+        ingestDocument.setFieldValue("some.nested.array", numbers);
+        IngestDocument copy = new IngestDocument(ingestDocument);
+        byte[] copiedNumbers = copy.getFieldValue("some.nested.array", byte[].class);
+        assertArrayEquals(numbers, copiedNumbers);
+        assertNotEquals(numbers, copiedNumbers);
+        assertIngestDocument(ingestDocument, copy);
+    }
+
+    public void testNullsAreEqual() {
+        assertIngestDocument(null, null);
+    }
+
     private static void assertThrowsOnComparision(IngestDocument document1, IngestDocument document2) {
+        expectThrows(AssertionError.class, () -> assertIngestDocument(document1, null));
+        expectThrows(AssertionError.class, () -> assertIngestDocument(null, document2));
         expectThrows(AssertionError.class, () -> assertIngestDocument(document1, document2));
         expectThrows(AssertionError.class, () -> assertIngestDocument(document2, document1));
     }