1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.thrift.protocol; 20 21 import java.nio.ByteBuffer; 22 import java.util.Arrays; 23 import java.util.List; 24 25 import junit.framework.TestCase; 26 27 import org.apache.thrift.Fixtures; 28 import org.apache.thrift.TBase; 29 import org.apache.thrift.TDeserializer; 30 import org.apache.thrift.TException; 31 import org.apache.thrift.TSerializer; 32 import org.apache.thrift.transport.TMemoryBuffer; 33 34 import thrift.test.CompactProtoTestStruct; 35 import thrift.test.HolyMoley; 36 import thrift.test.Nesting; 37 import thrift.test.OneOfEach; 38 import thrift.test.Srv; 39 40 public abstract class ProtocolTestBase extends TestCase { 41 42 /** Does it make sense to call methods like writeI32 directly on your protocol? */ canBeUsedNaked()43 protected abstract boolean canBeUsedNaked(); 44 45 /** The protocol factory for the protocol being tested. */ getFactory()46 protected abstract TProtocolFactory getFactory(); 47 testDouble()48 public void testDouble() throws Exception { 49 if (canBeUsedNaked()) { 50 TMemoryBuffer buf = new TMemoryBuffer(1000); 51 TProtocol proto = getFactory().getProtocol(buf); 52 proto.writeDouble(123.456); 53 assertEquals(123.456, proto.readDouble()); 54 } 55 56 internalTestStructField(new StructFieldTestCase(TType.DOUBLE, (short)15) { 57 @Override 58 public void readMethod(TProtocol proto) throws TException { 59 assertEquals(123.456, proto.readDouble()); 60 } 61 62 @Override 63 public void writeMethod(TProtocol proto) throws TException { 64 proto.writeDouble(123.456); 65 } 66 }); 67 } 68 testSerialization()69 public void testSerialization() throws Exception { 70 internalTestSerialization(OneOfEach.class, Fixtures.oneOfEach); 71 internalTestSerialization(Nesting.class, Fixtures.nesting); 72 internalTestSerialization(HolyMoley.class, Fixtures.holyMoley); 73 internalTestSerialization(CompactProtoTestStruct.class, Fixtures.compactProtoTestStruct); 74 } 75 testBinary()76 public void testBinary() throws Exception { 77 for (byte[] b : Arrays.asList(new byte[0], 78 new byte[]{0,1,2,3,4,5,6,7,8,9,10}, 79 new byte[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14}, 80 new byte[]{0x5D}, 81 new byte[]{(byte)0xD5,(byte)0x5D}, 82 new byte[]{(byte)0xFF,(byte)0xD5,(byte)0x5D}, 83 new byte[128])) { 84 if (canBeUsedNaked()) { 85 internalTestNakedBinary(b); 86 } 87 internalTestBinaryField(b); 88 } 89 90 if (canBeUsedNaked()) { 91 byte[] data = {1, 2, 3, 4, 5, 6}; 92 93 TMemoryBuffer buf = new TMemoryBuffer(0); 94 TProtocol proto = getFactory().getProtocol(buf); 95 ByteBuffer bb = ByteBuffer.wrap(data); 96 bb.get(); 97 proto.writeBinary(bb.slice()); 98 assertEquals(ByteBuffer.wrap(data, 1, 5), proto.readBinary()); 99 } 100 } 101 testString()102 public void testString() throws Exception { 103 for (String s : Arrays.asList("", "short", "borderlinetiny", "a bit longer than the smallest possible")) { 104 if (canBeUsedNaked()) { 105 internalTestNakedString(s); 106 } 107 internalTestStringField(s); 108 } 109 } 110 testLong()111 public void testLong() throws Exception { 112 if (canBeUsedNaked()) { 113 internalTestNakedI64(0); 114 } 115 internalTestI64Field(0); 116 for (int i = 0; i < 62; i++) { 117 if (canBeUsedNaked()) { 118 internalTestNakedI64(1L << i); 119 internalTestNakedI64(-(1L << i)); 120 } 121 internalTestI64Field(1L << i); 122 internalTestI64Field(-(1L << i)); 123 } 124 } 125 testInt()126 public void testInt() throws Exception { 127 for (int i : Arrays.asList(0, 1, 7, 150, 15000, 31337, 0xffff, 0xffffff, -1, -7, -150, -15000, -0xffff, -0xffffff)) { 128 if (canBeUsedNaked()) { 129 internalTestNakedI32(i); 130 } 131 internalTestI32Field(i); 132 } 133 } 134 testShort()135 public void testShort() throws Exception { 136 for (int s : Arrays.asList(0, 1, 7, 150, 15000, 0x7fff, -1, -7, -150, -15000, -0x7fff)) { 137 if (canBeUsedNaked()) { 138 internalTestNakedI16((short)s); 139 } 140 internalTestI16Field((short)s); 141 } 142 } 143 testByte()144 public void testByte() throws Exception { 145 if (canBeUsedNaked()) { 146 internalTestNakedByte(); 147 } 148 for (int i = 0; i < 128; i++) { 149 internalTestByteField((byte)i); 150 internalTestByteField((byte)-i); 151 } 152 } 153 internalTestNakedByte()154 private void internalTestNakedByte() throws Exception { 155 TMemoryBuffer buf = new TMemoryBuffer(1000); 156 TProtocol proto = getFactory().getProtocol(buf); 157 proto.writeByte((byte)123); 158 assertEquals((byte) 123, proto.readByte()); 159 } 160 internalTestByteField(final byte b)161 private void internalTestByteField(final byte b) throws Exception { 162 internalTestStructField(new StructFieldTestCase(TType.BYTE, (short)15) { 163 public void writeMethod(TProtocol proto) throws TException { 164 proto.writeByte(b); 165 } 166 167 public void readMethod(TProtocol proto) throws TException { 168 assertEquals((byte)b, proto.readByte()); 169 } 170 }); 171 } 172 internalTestNakedI16(short n)173 private void internalTestNakedI16(short n) throws Exception { 174 TMemoryBuffer buf = new TMemoryBuffer(0); 175 TProtocol proto = getFactory().getProtocol(buf); 176 proto.writeI16(n); 177 assertEquals(n, proto.readI16()); 178 } 179 internalTestI16Field(final short n)180 private void internalTestI16Field(final short n) throws Exception { 181 internalTestStructField(new StructFieldTestCase(TType.I16, (short)15) { 182 public void writeMethod(TProtocol proto) throws TException { 183 proto.writeI16(n); 184 } 185 186 public void readMethod(TProtocol proto) throws TException { 187 assertEquals(n, proto.readI16()); 188 } 189 }); 190 } 191 internalTestNakedI32(int n)192 private void internalTestNakedI32(int n) throws Exception { 193 TMemoryBuffer buf = new TMemoryBuffer(0); 194 TProtocol proto = getFactory().getProtocol(buf); 195 proto.writeI32(n); 196 assertEquals(n, proto.readI32()); 197 } 198 internalTestI32Field(final int n)199 private void internalTestI32Field(final int n) throws Exception { 200 internalTestStructField(new StructFieldTestCase(TType.I32, (short)15) { 201 public void writeMethod(TProtocol proto) throws TException { 202 proto.writeI32(n); 203 } 204 205 public void readMethod(TProtocol proto) throws TException { 206 assertEquals(n, proto.readI32()); 207 } 208 }); 209 } 210 internalTestNakedI64(long n)211 private void internalTestNakedI64(long n) throws Exception { 212 TMemoryBuffer buf = new TMemoryBuffer(0); 213 TProtocol proto = getFactory().getProtocol(buf); 214 proto.writeI64(n); 215 assertEquals(n, proto.readI64()); 216 } 217 internalTestI64Field(final long n)218 private void internalTestI64Field(final long n) throws Exception { 219 internalTestStructField(new StructFieldTestCase(TType.I64, (short)15) { 220 public void writeMethod(TProtocol proto) throws TException { 221 proto.writeI64(n); 222 } 223 224 public void readMethod(TProtocol proto) throws TException { 225 assertEquals(n, proto.readI64()); 226 } 227 }); 228 } 229 internalTestNakedString(String str)230 private void internalTestNakedString(String str) throws Exception { 231 TMemoryBuffer buf = new TMemoryBuffer(0); 232 TProtocol proto = getFactory().getProtocol(buf); 233 proto.writeString(str); 234 assertEquals(str, proto.readString()); 235 } 236 internalTestStringField(final String str)237 private void internalTestStringField(final String str) throws Exception { 238 internalTestStructField(new StructFieldTestCase(TType.STRING, (short)15) { 239 public void writeMethod(TProtocol proto) throws TException { 240 proto.writeString(str); 241 } 242 243 public void readMethod(TProtocol proto) throws TException { 244 assertEquals(str, proto.readString()); 245 } 246 }); 247 } 248 internalTestNakedBinary(byte[] data)249 private void internalTestNakedBinary(byte[] data) throws Exception { 250 TMemoryBuffer buf = new TMemoryBuffer(0); 251 TProtocol proto = getFactory().getProtocol(buf); 252 proto.writeBinary(ByteBuffer.wrap(data)); 253 assertEquals(ByteBuffer.wrap(data), proto.readBinary()); 254 } 255 internalTestBinaryField(final byte[] data)256 private void internalTestBinaryField(final byte[] data) throws Exception { 257 internalTestStructField(new StructFieldTestCase(TType.STRING, (short)15) { 258 public void writeMethod(TProtocol proto) throws TException { 259 proto.writeBinary(ByteBuffer.wrap(data)); 260 } 261 262 public void readMethod(TProtocol proto) throws TException { 263 assertEquals(ByteBuffer.wrap(data), proto.readBinary()); 264 } 265 }); 266 } 267 internalTestSerialization(Class<T> klass, T expected)268 private <T extends TBase> void internalTestSerialization(Class<T> klass, T expected) throws Exception { 269 TMemoryBuffer buf = new TMemoryBuffer(0); 270 TBinaryProtocol binproto = new TBinaryProtocol(buf); 271 272 expected.write(binproto); 273 274 buf = new TMemoryBuffer(0); 275 TProtocol proto = getFactory().getProtocol(buf); 276 277 expected.write(proto); 278 System.out.println("Size in " + proto.getClass().getSimpleName() + ": " + buf.length()); 279 280 T actual = klass.newInstance(); 281 actual.read(proto); 282 assertEquals(expected, actual); 283 } 284 testMessage()285 public void testMessage() throws Exception { 286 List<TMessage> msgs = Arrays.asList(new TMessage[]{ 287 new TMessage("short message name", TMessageType.CALL, 0), 288 new TMessage("1", TMessageType.REPLY, 12345), 289 new TMessage("loooooooooooooooooooooooooooooooooong", TMessageType.EXCEPTION, 1 << 16), 290 new TMessage("Janky", TMessageType.CALL, 0), 291 }); 292 293 for (TMessage msg : msgs) { 294 TMemoryBuffer buf = new TMemoryBuffer(0); 295 TProtocol proto = getFactory().getProtocol(buf); 296 TMessage output = null; 297 298 proto.writeMessageBegin(msg); 299 proto.writeMessageEnd(); 300 301 output = proto.readMessageBegin(); 302 303 assertEquals(msg, output); 304 } 305 } 306 testServerRequest()307 public void testServerRequest() throws Exception { 308 Srv.Iface handler = new Srv.Iface() { 309 public int Janky(int i32arg) throws TException { 310 return i32arg * 2; 311 } 312 313 public int primitiveMethod() throws TException { 314 return 0; 315 } 316 317 public CompactProtoTestStruct structMethod() throws TException { 318 return null; 319 } 320 321 public void voidMethod() throws TException { 322 } 323 324 public void methodWithDefaultArgs(int something) throws TException { 325 } 326 327 @Override 328 public void onewayMethod() throws TException { 329 } 330 331 @Override 332 public boolean declaredExceptionMethod(boolean shouldThrow) throws TException { 333 return shouldThrow; 334 } 335 }; 336 337 Srv.Processor testProcessor = new Srv.Processor(handler); 338 339 TMemoryBuffer clientOutTrans = new TMemoryBuffer(0); 340 TProtocol clientOutProto = getFactory().getProtocol(clientOutTrans); 341 TMemoryBuffer clientInTrans = new TMemoryBuffer(0); 342 TProtocol clientInProto = getFactory().getProtocol(clientInTrans); 343 344 Srv.Client testClient = new Srv.Client(clientInProto, clientOutProto); 345 346 testClient.send_Janky(1); 347 // System.out.println(clientOutTrans.inspect()); 348 testProcessor.process(clientOutProto, clientInProto); 349 // System.out.println(clientInTrans.inspect()); 350 assertEquals(2, testClient.recv_Janky()); 351 } 352 testTDeserializer()353 public void testTDeserializer() throws TException { 354 TSerializer ser = new TSerializer(getFactory()); 355 byte[] bytes = ser.serialize(Fixtures.compactProtoTestStruct); 356 357 TDeserializer deser = new TDeserializer(getFactory()); 358 CompactProtoTestStruct cpts = new CompactProtoTestStruct(); 359 deser.deserialize(cpts, bytes); 360 361 assertEquals(Fixtures.compactProtoTestStruct, cpts); 362 } 363 364 // 365 // Helper methods 366 // 367 internalTestStructField(StructFieldTestCase testCase)368 private void internalTestStructField(StructFieldTestCase testCase) throws Exception { 369 TMemoryBuffer buf = new TMemoryBuffer(0); 370 TProtocol proto = getFactory().getProtocol(buf); 371 372 TField field = new TField("test_field", testCase.type_, testCase.id_); 373 proto.writeStructBegin(new TStruct("test_struct")); 374 proto.writeFieldBegin(field); 375 testCase.writeMethod(proto); 376 proto.writeFieldEnd(); 377 proto.writeStructEnd(); 378 379 proto.readStructBegin(); 380 TField readField = proto.readFieldBegin(); 381 assertEquals(testCase.id_, readField.id); 382 assertEquals(testCase.type_, readField.type); 383 testCase.readMethod(proto); 384 proto.readStructEnd(); 385 } 386 387 private static abstract class StructFieldTestCase { 388 byte type_; 389 short id_; StructFieldTestCase(byte type, short id)390 public StructFieldTestCase(byte type, short id) { 391 type_ = type; 392 id_ = id; 393 } 394 writeMethod(TProtocol proto)395 public abstract void writeMethod(TProtocol proto) throws TException; readMethod(TProtocol proto)396 public abstract void readMethod(TProtocol proto) throws TException; 397 } 398 399 private static final int NUM_TRIALS = 5; 400 private static final int NUM_REPS = 10000; 401 benchmark()402 protected void benchmark() throws Exception { 403 for (int trial = 0; trial < NUM_TRIALS; trial++) { 404 TSerializer ser = new TSerializer(getFactory()); 405 byte[] serialized = null; 406 long serStart = System.currentTimeMillis(); 407 for (int rep = 0; rep < NUM_REPS; rep++) { 408 serialized = ser.serialize(Fixtures.holyMoley); 409 } 410 long serEnd = System.currentTimeMillis(); 411 long serElapsed = serEnd - serStart; 412 System.out.println("Ser:\t" + serElapsed + "ms\t" 413 + ((double)serElapsed / NUM_REPS) + "ms per serialization"); 414 415 HolyMoley cpts = new HolyMoley(); 416 TDeserializer deser = new TDeserializer(getFactory()); 417 long deserStart = System.currentTimeMillis(); 418 for (int rep = 0; rep < NUM_REPS; rep++) { 419 deser.deserialize(cpts, serialized); 420 } 421 long deserEnd = System.currentTimeMillis(); 422 long deserElapsed = deserEnd - deserStart; 423 System.out.println("Des:\t" + deserElapsed + "ms\t" 424 + ((double)deserElapsed / NUM_REPS) + "ms per deserialization"); 425 } 426 } 427 } 428