/** * Licensed 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.apache.aurora.common.zookeeper; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.JsonIOException; import org.apache.aurora.common.io.Codec; import org.apache.aurora.common.thrift.Endpoint; import org.apache.aurora.common.thrift.ServiceInstance; import org.apache.aurora.common.thrift.Status; import org.easymock.EasyMock; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.easymock.PowerMock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @RunWith(PowerMockRunner.class) @PrepareForTest(Gson.class) public class JsonCodecTest { private static final Codec<ServiceInstance> STANDARD_JSON_CODEC = new JsonCodec(); @Test public void testJsonCodecRoundtrip() throws Exception { Codec<ServiceInstance> codec = STANDARD_JSON_CODEC; ServiceInstance instance1 = new ServiceInstance( new Endpoint("foo", 1000), ImmutableMap.of("http", new Endpoint("foo", 8080)), Status.ALIVE) .setShard(0); byte[] data = ServerSets.serializeServiceInstance(instance1, codec); assertTrue(ServerSets.deserializeServiceInstance(data, codec).getServiceEndpoint().isSetPort()); assertTrue(ServerSets.deserializeServiceInstance(data, codec).isSetShard()); ServiceInstance instance2 = new ServiceInstance( new Endpoint("foo", 1000), ImmutableMap.of("http-admin1", new Endpoint("foo", 8080)), Status.ALIVE); data = ServerSets.serializeServiceInstance(instance2, codec); assertTrue(ServerSets.deserializeServiceInstance(data, codec).getServiceEndpoint().isSetPort()); assertFalse(ServerSets.deserializeServiceInstance(data, codec).isSetShard()); ServiceInstance instance3 = new ServiceInstance( new Endpoint("foo", 1000), ImmutableMap.<String, Endpoint>of(), Status.ALIVE); data = ServerSets.serializeServiceInstance(instance3, codec); assertTrue(ServerSets.deserializeServiceInstance(data, codec).getServiceEndpoint().isSetPort()); assertFalse(ServerSets.deserializeServiceInstance(data, codec).isSetShard()); } @Test public void testJsonCompatibility() throws IOException { ServiceInstance instance = new ServiceInstance( new Endpoint("foo", 1000), ImmutableMap.of("http", new Endpoint("foo", 8080)), Status.ALIVE).setShard(42); ByteArrayOutputStream results = new ByteArrayOutputStream(); STANDARD_JSON_CODEC.serialize(instance, results); assertEquals( "{\"serviceEndpoint\":{\"host\":\"foo\",\"port\":1000}," + "\"additionalEndpoints\":{\"http\":{\"host\":\"foo\",\"port\":8080}}," + "\"status\":\"ALIVE\"," + "\"shard\":42}", results.toString()); } @Test public void testInvalidSerialize() { // Gson is final so we need to call on PowerMock here. Gson gson = PowerMock.createMock(Gson.class); gson.toJson(EasyMock.isA(Object.class), EasyMock.isA(Appendable.class)); EasyMock.expectLastCall().andThrow(new JsonIOException("error")); PowerMock.replay(gson); ServiceInstance instance = new ServiceInstance(new Endpoint("foo", 1000), ImmutableMap.of(), Status.ALIVE); try { new JsonCodec(gson).serialize(instance, new ByteArrayOutputStream()); fail(); } catch (IOException e) { // Expected. } PowerMock.verify(gson); } @Test public void testDeserializeMinimal() throws IOException { String minimal = "{\"serviceEndpoint\":{\"host\":\"foo\",\"port\":1000},\"status\":\"ALIVE\"}"; ByteArrayInputStream source = new ByteArrayInputStream(minimal.getBytes(Charsets.UTF_8)); ServiceInstance actual = STANDARD_JSON_CODEC.deserialize(source); ServiceInstance expected = new ServiceInstance(new Endpoint("foo", 1000), ImmutableMap.of(), Status.ALIVE); assertEquals(expected, actual); } @Test public void testInvalidDeserialize() { // Not JSON. assertInvalidDeserialize(new byte[] {0xC, 0xA, 0xF, 0xE}); // No JSON object. assertInvalidDeserialize(""); assertInvalidDeserialize("[]"); // Missing required fields. assertInvalidDeserialize("{}"); assertInvalidDeserialize("{\"serviceEndpoint\":{\"host\":\"foo\",\"port\":1000}}"); assertInvalidDeserialize("{\"status\":\"ALIVE\"}"); } private void assertInvalidDeserialize(String data) { assertInvalidDeserialize(data.getBytes(Charsets.UTF_8)); } private void assertInvalidDeserialize(byte[] data) { try { STANDARD_JSON_CODEC.deserialize(new ByteArrayInputStream(data)); fail(); } catch (IOException e) { // Expected. } } }