/* * 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.test; import org.elasticsearch.cluster.Diff; import org.elasticsearch.cluster.Diffable; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.io.stream.Writeable.Reader; import java.io.IOException; import java.util.function.Function; import java.util.function.Supplier; import static org.elasticsearch.test.AbstractWireSerializingTestCase.NUMBER_OF_TEST_RUNS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; /** * Utilities that simplify testing of diffable classes */ public final class DiffableTestUtils { protected static final int NUMBER_OF_DIFF_TEST_RUNS = NUMBER_OF_TEST_RUNS; private DiffableTestUtils() { } /** * Asserts that changes are applied correctly, i.e. that applying diffs to localInstance produces that object * equal but not the same as the remoteChanges instance. */ public static <T extends Diffable<T>> T assertDiffApplication(T remoteChanges, T localInstance, Diff<T> diffs) { T localChanges = diffs.apply(localInstance); assertEquals(remoteChanges, localChanges); assertEquals(remoteChanges.hashCode(), localChanges.hashCode()); assertNotSame(remoteChanges, localChanges); return localChanges; } /** * Simulates sending diffs over the wire */ public static <T extends Writeable> T copyInstance(T diffs, NamedWriteableRegistry namedWriteableRegistry, Reader<T> reader) throws IOException { try (BytesStreamOutput output = new BytesStreamOutput()) { diffs.writeTo(output); try (StreamInput in = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), namedWriteableRegistry)) { return reader.read(in); } } } /** * Tests making random changes to an object, calculating diffs for these changes, sending this * diffs over the wire and appling these diffs on the other side. */ public static <T extends Diffable<T>> void testDiffableSerialization(Supplier<T> testInstance, Function<T, T> modifier, NamedWriteableRegistry namedWriteableRegistry, Reader<T> reader, Reader<Diff<T>> diffReader) throws IOException { T remoteInstance = testInstance.get(); T localInstance = assertSerialization(remoteInstance, namedWriteableRegistry, reader); for (int runs = 0; runs < NUMBER_OF_DIFF_TEST_RUNS; runs++) { T remoteChanges = modifier.apply(remoteInstance); Diff<T> remoteDiffs = remoteChanges.diff(remoteInstance); Diff<T> localDiffs = copyInstance(remoteDiffs, namedWriteableRegistry, diffReader); localInstance = assertDiffApplication(remoteChanges, localInstance, localDiffs); remoteInstance = remoteChanges; } } /** * Asserts that testInstance can be correctly. */ public static <T extends Writeable> T assertSerialization(T testInstance, NamedWriteableRegistry namedWriteableRegistry, Reader<T> reader) throws IOException { T deserializedInstance = copyInstance(testInstance, namedWriteableRegistry, reader); assertEquals(testInstance, deserializedInstance); assertEquals(testInstance.hashCode(), deserializedInstance.hashCode()); assertNotSame(testInstance, deserializedInstance); return deserializedInstance; } }