]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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? */ | |
43 | protected abstract boolean canBeUsedNaked(); | |
44 | ||
45 | /** The protocol factory for the protocol being tested. */ | |
46 | protected abstract TProtocolFactory getFactory(); | |
47 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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_; | |
390 | public StructFieldTestCase(byte type, short id) { | |
391 | type_ = type; | |
392 | id_ = id; | |
393 | } | |
394 | ||
395 | public abstract void writeMethod(TProtocol proto) throws TException; | |
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 | ||
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 | } |