/* * 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.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteable; 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.Collections; import static org.hamcrest.Matchers.equalTo; public abstract class AbstractWireSerializingTestCase<T extends Writeable> extends ESTestCase { protected static final int NUMBER_OF_TEST_RUNS = 20; /** * Creates a random test instance to use in the tests. This method will be * called multiple times during test execution and should return a different * random instance each time it is called. */ protected abstract T createTestInstance(); /** * Returns a {@link Reader} that can be used to de-serialize the instance */ protected abstract Reader<T> instanceReader(); /** * Tests that the equals and hashcode methods are consistent and copied * versions of the instance have are equal. */ public void testEqualsAndHashcode() throws IOException { for (int runs = 0; runs < NUMBER_OF_TEST_RUNS; runs++) { T firstInstance = createTestInstance(); assertFalse("instance is equal to null", firstInstance.equals(null)); assertFalse("instance is equal to incompatible type", firstInstance.equals("")); assertEquals("instance is not equal to self", firstInstance, firstInstance); assertThat("same instance's hashcode returns different values if called multiple times", firstInstance.hashCode(), equalTo(firstInstance.hashCode())); T secondInstance = copyInstance(firstInstance); assertEquals("instance is not equal to self", secondInstance, secondInstance); assertEquals("instance is not equal to its copy", firstInstance, secondInstance); assertEquals("equals is not symmetric", secondInstance, firstInstance); assertThat("instance copy's hashcode is different from original hashcode", secondInstance.hashCode(), equalTo(firstInstance.hashCode())); T thirdInstance = copyInstance(secondInstance); assertEquals("instance is not equal to self", thirdInstance, thirdInstance); assertEquals("instance is not equal to its copy", secondInstance, thirdInstance); assertThat("instance copy's hashcode is different from original hashcode", secondInstance.hashCode(), equalTo(thirdInstance.hashCode())); assertEquals("equals is not transitive", firstInstance, thirdInstance); assertThat("instance copy's hashcode is different from original hashcode", firstInstance.hashCode(), equalTo(thirdInstance.hashCode())); assertEquals("equals is not symmetric", thirdInstance, secondInstance); assertEquals("equals is not symmetric", thirdInstance, firstInstance); } } /** * Test serialization and deserialization of the test instance. */ public void testSerialization() throws IOException { for (int runs = 0; runs < NUMBER_OF_TEST_RUNS; runs++) { T testInstance = createTestInstance(); assertSerialization(testInstance); } } /** * Serialize the given instance and asserts that both are equal */ protected T assertSerialization(T testInstance) throws IOException { T deserializedInstance = copyInstance(testInstance); assertEquals(testInstance, deserializedInstance); assertEquals(testInstance.hashCode(), deserializedInstance.hashCode()); assertNotSame(testInstance, deserializedInstance); return deserializedInstance; } protected T copyInstance(T instance) throws IOException { try (BytesStreamOutput output = new BytesStreamOutput()) { instance.writeTo(output); try (StreamInput in = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), getNamedWriteableRegistry())) { return instanceReader().read(in); } } } /** * Get the {@link NamedWriteableRegistry} to use when de-serializing the object. * * Override this method if you need to register {@link NamedWriteable}s for the test object to de-serialize. * * By default this will return a {@link NamedWriteableRegistry} with no registered {@link NamedWriteable}s */ protected NamedWriteableRegistry getNamedWriteableRegistry() { return new NamedWriteableRegistry(Collections.emptyList()); } }