diff options
Diffstat (limited to 'test')
96 files changed, 12096 insertions, 0 deletions
diff --git a/test/AllProtocolTests.cpp b/test/AllProtocolTests.cpp new file mode 100644 index 000000000..db29cccf8 --- /dev/null +++ b/test/AllProtocolTests.cpp @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <stdio.h> + +#include <protocol/TBinaryProtocol.h> +#include <protocol/TCompactProtocol.h> +#include <transport/TBufferTransports.h> +#include "AllProtocolTests.tcc" + +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; + +char errorMessage[ERR_LEN]; + +int main(int argc, char** argv) { + try { + testProtocol<TBinaryProtocol>("TBinaryProtocol"); + testProtocol<TCompactProtocol>("TCompactProtocol"); + } catch (TException e) { + printf("%s\n", e.what()); + return 1; + } + return 0; +} diff --git a/test/AllProtocolTests.tcc b/test/AllProtocolTests.tcc new file mode 100644 index 000000000..a5a31156f --- /dev/null +++ b/test/AllProtocolTests.tcc @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#ifndef _THRIFT_TEST_GENERICPROTOCOLTEST_TCC_ +#define _THRIFT_TEST_GENERICPROTOCOLTEST_TCC_ 1 + +#include <limits> + +#include <protocol/TBinaryProtocol.h> +#include <transport/TBufferTransports.h> +#include <Thrift.h> + +#include "GenericHelpers.h" + +using boost::shared_ptr; +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; + +#define ERR_LEN 512 +extern char errorMessage[ERR_LEN]; + +template <typename TProto, typename Val> +void testNaked(Val val) { + shared_ptr<TTransport> transport(new TMemoryBuffer()); + shared_ptr<TProtocol> protocol(new TProto(transport)); + + GenericIO::write(protocol, val); + Val out; + GenericIO::read(protocol, out); + if (out != val) { + snprintf(errorMessage, ERR_LEN, "Invalid naked test (type: %s)", ClassNames::getName<Val>()); + throw TException(errorMessage); + } +} + +template <typename TProto, TType type, typename Val> +void testField(const Val val) { + shared_ptr<TTransport> transport(new TMemoryBuffer()); + shared_ptr<TProtocol> protocol(new TProto(transport)); + + protocol->writeStructBegin("test_struct"); + protocol->writeFieldBegin("test_field", type, (int16_t)15); + + GenericIO::write(protocol, val); + + protocol->writeFieldEnd(); + protocol->writeStructEnd(); + + std::string name; + TType fieldType; + int16_t fieldId; + + protocol->readStructBegin(name); + protocol->readFieldBegin(name, fieldType, fieldId); + + if (fieldId != 15) { + snprintf(errorMessage, ERR_LEN, "Invalid ID (type: %s)", typeid(val).name()); + throw TException(errorMessage); + } + if (fieldType != type) { + snprintf(errorMessage, ERR_LEN, "Invalid Field Type (type: %s)", typeid(val).name()); + throw TException(errorMessage); + } + + Val out; + GenericIO::read(protocol, out); + + if (out != val) { + snprintf(errorMessage, ERR_LEN, "Invalid value read (type: %s)", typeid(val).name()); + throw TException(errorMessage); + } + + protocol->readFieldEnd(); + protocol->readStructEnd(); +} + +template <typename TProto> +void testMessage() { + struct TMessage { + const char* name; + TMessageType type; + int32_t seqid; + } messages[4] = { + {"short message name", T_CALL, 0}, + {"1", T_REPLY, 12345}, + {"loooooooooooooooooooooooooooooooooong", T_EXCEPTION, 1 << 16}, + {"Janky", T_CALL, 0} + }; + + for (int i = 0; i < 4; i++) { + shared_ptr<TTransport> transport(new TMemoryBuffer()); + shared_ptr<TProtocol> protocol(new TProto(transport)); + + protocol->writeMessageBegin(messages[i].name, + messages[i].type, + messages[i].seqid); + protocol->writeMessageEnd(); + + std::string name; + TMessageType type; + int32_t seqid; + + protocol->readMessageBegin(name, type, seqid); + if (name != messages[i].name || + type != messages[i].type || + seqid != messages[i].seqid) { + throw TException("readMessageBegin failed."); + } + } +} + +template <typename TProto> +void testProtocol(const char* protoname) { + try { + testNaked<TProto, int8_t>((int8_t)123); + + for (int32_t i = 0; i < 128; i++) { + testField<TProto, T_BYTE, int8_t>((int8_t)i); + testField<TProto, T_BYTE, int8_t>((int8_t)-i); + } + + testNaked<TProto, int16_t>((int16_t)0); + testNaked<TProto, int16_t>((int16_t)1); + testNaked<TProto, int16_t>((int16_t)15000); + testNaked<TProto, int16_t>((int16_t)0x7fff); + testNaked<TProto, int16_t>((int16_t)-1); + testNaked<TProto, int16_t>((int16_t)-15000); + testNaked<TProto, int16_t>((int16_t)-0x7fff); + testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::min()); + testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::max()); + + testField<TProto, T_I16, int16_t>((int16_t)0); + testField<TProto, T_I16, int16_t>((int16_t)1); + testField<TProto, T_I16, int16_t>((int16_t)7); + testField<TProto, T_I16, int16_t>((int16_t)150); + testField<TProto, T_I16, int16_t>((int16_t)15000); + testField<TProto, T_I16, int16_t>((int16_t)0x7fff); + testField<TProto, T_I16, int16_t>((int16_t)-1); + testField<TProto, T_I16, int16_t>((int16_t)-7); + testField<TProto, T_I16, int16_t>((int16_t)-150); + testField<TProto, T_I16, int16_t>((int16_t)-15000); + testField<TProto, T_I16, int16_t>((int16_t)-0x7fff); + + testNaked<TProto, int32_t>(0); + testNaked<TProto, int32_t>(1); + testNaked<TProto, int32_t>(15000); + testNaked<TProto, int32_t>(0xffff); + testNaked<TProto, int32_t>(-1); + testNaked<TProto, int32_t>(-15000); + testNaked<TProto, int32_t>(-0xffff); + testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::min()); + testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::max()); + + testField<TProto, T_I32, int32_t>(0); + testField<TProto, T_I32, int32_t>(1); + testField<TProto, T_I32, int32_t>(7); + testField<TProto, T_I32, int32_t>(150); + testField<TProto, T_I32, int32_t>(15000); + testField<TProto, T_I32, int32_t>(31337); + testField<TProto, T_I32, int32_t>(0xffff); + testField<TProto, T_I32, int32_t>(0xffffff); + testField<TProto, T_I32, int32_t>(-1); + testField<TProto, T_I32, int32_t>(-7); + testField<TProto, T_I32, int32_t>(-150); + testField<TProto, T_I32, int32_t>(-15000); + testField<TProto, T_I32, int32_t>(-0xffff); + testField<TProto, T_I32, int32_t>(-0xffffff); + testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min()); + testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max()); + testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min() + 10); + testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max() - 16); + testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::min()); + testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::max()); + + + testNaked<TProto, int64_t>(0); + for (int64_t i = 0; i < 62; i++) { + testNaked<TProto, int64_t>(1L << i); + testNaked<TProto, int64_t>(-(1L << i)); + } + + testField<TProto, T_I64, int64_t>(0); + for (int i = 0; i < 62; i++) { + testField<TProto, T_I64, int64_t>(1L << i); + testField<TProto, T_I64, int64_t>(-(1L << i)); + } + + testNaked<TProto, double>(123.456); + + testNaked<TProto, std::string>(""); + testNaked<TProto, std::string>("short"); + testNaked<TProto, std::string>("borderlinetiny"); + testNaked<TProto, std::string>("a bit longer than the smallest possible"); + testNaked<TProto, std::string>("\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA"); //kinda binary test + + testField<TProto, T_STRING, std::string>(""); + testField<TProto, T_STRING, std::string>("short"); + testField<TProto, T_STRING, std::string>("borderlinetiny"); + testField<TProto, T_STRING, std::string>("a bit longer than the smallest possible"); + + testMessage<TProto>(); + + printf("%s => OK\n", protoname); + } catch (TException e) { + snprintf(errorMessage, ERR_LEN, "%s => Test FAILED: %s", protoname, e.what()); + throw TException(errorMessage); + } +} + +#endif diff --git a/test/AnnotationTest.thrift b/test/AnnotationTest.thrift new file mode 100644 index 000000000..dcc41b0bf --- /dev/null +++ b/test/AnnotationTest.thrift @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +typedef list<i32> ( cpp.template = "std::list" ) int_linked_list + +struct foo { + 1: i32 bar; + 2: i32 baz; + 3: i32 qux; + 4: i32 bop; +} ( + cpp.type = "DenseFoo", + python.type = "DenseFoo", + java.final = "", +) diff --git a/test/Benchmark.cpp b/test/Benchmark.cpp new file mode 100644 index 000000000..d315fca73 --- /dev/null +++ b/test/Benchmark.cpp @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <iostream> +#include <cmath> +#include <transport/TBufferTransports.h> +#include <protocol/TBinaryProtocol.h> +#include <protocol/TJSONProtocol.h> +#include "gen-cpp/DebugProtoTest_types.h" +#include <time.h> +#include "../lib/cpp/src/protocol/TDebugProtocol.h" +#include <sys/time.h> + +class Timer { +public: + timeval vStart; + + Timer() { + gettimeofday(&vStart, 0); + } + void start() { + gettimeofday(&vStart, 0); + } + + double frame() { + timeval vEnd; + gettimeofday(&vEnd, 0); + double dstart = vStart.tv_sec + ((double)vStart.tv_usec / 1000000.0); + double dend = vEnd.tv_sec + ((double)vEnd.tv_usec / 1000000.0); + return dend - dstart; + } + +}; + +int main() { + using namespace std; + using namespace thrift::test::debug; + using namespace apache::thrift::transport; + using namespace apache::thrift::protocol; + using namespace boost; + + OneOfEach ooe; + ooe.im_true = true; + ooe.im_false = false; + ooe.a_bite = 0xd6; + ooe.integer16 = 27000; + ooe.integer32 = 1<<24; + ooe.integer64 = (uint64_t)6000 * 1000 * 1000; + ooe.double_precision = M_PI; + ooe.some_characters = "JSON THIS! \"\1"; + ooe.zomg_unicode = "\xd7\n\a\t"; + ooe.base64 = "\1\2\3\255"; + + shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer()); + + int num = 1000000; + + { + Timer timer; + + for (int i = 0; i < num; i ++) { + buf->resetBuffer(); + TBinaryProtocol prot(buf); + ooe.write(&prot); + } + cout << "Write: " << num / (1000 * timer.frame()) << " kHz" << endl; + } + + uint8_t* data; + uint32_t datasize; + + buf->getBuffer(&data, &datasize); + + { + + Timer timer; + + for (int i = 0; i < num; i ++) { + OneOfEach ooe2; + shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize)); + //buf2->resetBuffer(data, datasize); + TBinaryProtocol prot(buf2); + ooe2.read(&prot); + + //cout << apache::thrift::ThriftDebugString(ooe2) << endl << endl; + } + cout << " Read: " << num / (1000 * timer.frame()) << " kHz" << endl; + } + + + return 0; +} diff --git a/test/BrokenConstants.thrift b/test/BrokenConstants.thrift new file mode 100644 index 000000000..c5aab4abe --- /dev/null +++ b/test/BrokenConstants.thrift @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +const i64 myint = 68719476736 +const i64 broken = 9876543210987654321 // A little over 2^63 + +enum foo { + bar = 68719476736 +} diff --git a/test/ConstantsDemo.thrift b/test/ConstantsDemo.thrift new file mode 100644 index 000000000..7e97f02c8 --- /dev/null +++ b/test/ConstantsDemo.thrift @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace cpp yozone + +struct thing { + 1: i32 hello, + 2: i32 goodbye +} + +enum enumconstants { + ONE = 1, + TWO = 2 +} + +struct thing2 { + 1: enumconstants val = TWO +} + +typedef i32 myIntType +const myIntType myInt = 3 + +const map<enumconstants,string> GEN_ENUM_NAMES = {ONE : "HOWDY", TWO: PARTNER} + +const i32 hex_const = 0x0001F + +const i32 GEN_ME = -3523553 +const double GEn_DUB = 325.532 +const double GEn_DU = 085.2355 +const string GEN_STRING = "asldkjasfd" + +const map<i32,i32> GEN_MAP = { 35532 : 233, 43523 : 853 } +const list<i32> GEN_LIST = [ 235235, 23598352, 3253523 ] + +const map<i32, map<i32, i32>> GEN_MAPMAP = { 235 : { 532 : 53255, 235:235}} + +const map<string,i32> GEN_MAP2 = { "hello" : 233, "lkj98d" : 853, 'lkjsdf' : 098325 } + +const thing GEN_THING = { 'hello' : 325, 'goodbye' : 325352 } + +const map<i32,thing> GEN_WHAT = { 35 : { 'hello' : 325, 'goodbye' : 325352 } } + +const set<i32> GEN_SET = [ 235, 235, 53235 ] + +exception Blah { + 1: i32 bing } + +exception Gak {} + +service yowza { + void blingity(), + i32 blangity() throws (1: Blah hoot ) +} diff --git a/test/DebugProtoTest.cpp b/test/DebugProtoTest.cpp new file mode 100644 index 000000000..8c9aabec2 --- /dev/null +++ b/test/DebugProtoTest.cpp @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <iostream> +#include <cmath> +#include "gen-cpp/DebugProtoTest_types.h" +#include "../lib/cpp/src/protocol/TDebugProtocol.h" + +int main() { + using std::cout; + using std::endl; + using namespace thrift::test::debug; + + + OneOfEach ooe; + ooe.im_true = true; + ooe.im_false = false; + ooe.a_bite = 0xd6; + ooe.integer16 = 27000; + ooe.integer32 = 1<<24; + ooe.integer64 = (uint64_t)6000 * 1000 * 1000; + ooe.double_precision = M_PI; + ooe.some_characters = "Debug THIS!"; + ooe.zomg_unicode = "\xd7\n\a\t"; + + cout << apache::thrift::ThriftDebugString(ooe) << endl << endl; + + + Nesting n; + n.my_ooe = ooe; + n.my_ooe.integer16 = 16; + n.my_ooe.integer32 = 32; + n.my_ooe.integer64 = 64; + n.my_ooe.double_precision = (std::sqrt(5)+1)/2; + n.my_ooe.some_characters = ":R (me going \"rrrr\")"; + n.my_ooe.zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20" + "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e" + "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc"; + n.my_bonk.type = 31337; + n.my_bonk.message = "I am a bonk... xor!"; + + cout << apache::thrift::ThriftDebugString(n) << endl << endl; + + + HolyMoley hm; + + hm.big.push_back(ooe); + hm.big.push_back(n.my_ooe); + hm.big[0].a_bite = 0x22; + hm.big[1].a_bite = 0x33; + + std::vector<std::string> stage1; + stage1.push_back("and a one"); + stage1.push_back("and a two"); + hm.contain.insert(stage1); + stage1.clear(); + stage1.push_back("then a one, two"); + stage1.push_back("three!"); + stage1.push_back("FOUR!!"); + hm.contain.insert(stage1); + stage1.clear(); + hm.contain.insert(stage1); + + std::vector<Bonk> stage2; + hm.bonks["nothing"] = stage2; + stage2.resize(stage2.size()+1); + stage2.back().type = 1; + stage2.back().message = "Wait."; + stage2.resize(stage2.size()+1); + stage2.back().type = 2; + stage2.back().message = "What?"; + hm.bonks["something"] = stage2; + stage2.clear(); + stage2.resize(stage2.size()+1); + stage2.back().type = 3; + stage2.back().message = "quoth"; + stage2.resize(stage2.size()+1); + stage2.back().type = 4; + stage2.back().message = "the raven"; + stage2.resize(stage2.size()+1); + stage2.back().type = 5; + stage2.back().message = "nevermore"; + hm.bonks["poe"] = stage2; + + cout << apache::thrift::ThriftDebugString(hm) << endl << endl; + + + return 0; +} diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift new file mode 100644 index 000000000..d3d25802b --- /dev/null +++ b/test/DebugProtoTest.thrift @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace cpp thrift.test.debug +namespace java thrift.test + +struct Doubles { + 1: double nan, + 2: double inf, + 3: double neginf, + 4: double repeating, + 5: double big, + 6: double small, + 7: double zero, + 8: double negzero, +} + +struct OneOfEach { + 1: bool im_true, + 2: bool im_false, + 3: byte a_bite = 200, + 4: i16 integer16 = 33000, + 5: i32 integer32, + 6: i64 integer64 = 10000000000, + 7: double double_precision, + 8: string some_characters, + 9: string zomg_unicode, + 10: bool what_who, + 11: binary base64, + 12: list<byte> byte_list = [1, 2, 3], + 13: list<i16> i16_list = [1,2,3], + 14: list<i64> i64_list = [1,2,3] +} + +struct Bonk { + 1: i32 type, + 2: string message, +} + +struct Nesting { + 1: Bonk my_bonk, + 2: OneOfEach my_ooe, +} + +struct HolyMoley { + 1: list<OneOfEach> big, + 2: set<list<string>> contain, + 3: map<string,list<Bonk>> bonks, +} + +struct Backwards { + 2: i32 first_tag2, + 1: i32 second_tag1, +} + +struct Empty { +} + +struct Wrapper { + 1: Empty foo +} + +struct RandomStuff { + 1: i32 a, + 2: i32 b, + 3: i32 c, + 4: i32 d, + 5: list<i32> myintlist, + 6: map<i32,Wrapper> maps, + 7: i64 bigint, + 8: double triple, +} + +struct Base64 { + 1: i32 a, + 2: binary b1, + 3: binary b2, + 4: binary b3, + 5: binary b4, + 6: binary b5, + 7: binary b6, +} + +struct CompactProtoTestStruct { + // primitive fields + 1: byte a_byte; + 2: i16 a_i16; + 3: i32 a_i32; + 4: i64 a_i64; + 5: double a_double; + 6: string a_string; + 7: binary a_binary; + 8: bool true_field; + 9: bool false_field; + 10: Empty empty_struct_field; + + // primitives in lists + 11: list<byte> byte_list; + 12: list<i16> i16_list; + 13: list<i32> i32_list; + 14: list<i64> i64_list; + 15: list<double> double_list; + 16: list<string> string_list; + 17: list<binary> binary_list; + 18: list<bool> boolean_list; + 19: list<Empty> struct_list; + + // primitives in sets + 20: set<byte> byte_set; + 21: set<i16> i16_set; + 22: set<i32> i32_set; + 23: set<i64> i64_set; + 24: set<double> double_set; + 25: set<string> string_set; + 26: set<binary> binary_set; + 27: set<bool> boolean_set; + 28: set<Empty> struct_set; + + // maps + // primitives as keys + 29: map<byte, byte> byte_byte_map; + 30: map<i16, byte> i16_byte_map; + 31: map<i32, byte> i32_byte_map; + 32: map<i64, byte> i64_byte_map; + 33: map<double, byte> double_byte_map; + 34: map<string, byte> string_byte_map; + 35: map<binary, byte> binary_byte_map; + 36: map<bool, byte> boolean_byte_map; + // primitives as values + 37: map<byte, i16> byte_i16_map; + 38: map<byte, i32> byte_i32_map; + 39: map<byte, i64> byte_i64_map; + 40: map<byte, double> byte_double_map; + 41: map<byte, string> byte_string_map; + 42: map<byte, binary> byte_binary_map; + 43: map<byte, bool> byte_boolean_map; + // collections as keys + 44: map<list<byte>, byte> list_byte_map; + 45: map<set<byte>, byte> set_byte_map; + 46: map<map<byte,byte>, byte> map_byte_map; + // collections as values + 47: map<byte, map<byte,byte>> byte_map_map; + 48: map<byte, set<byte>> byte_set_map; + 49: map<byte, list<byte>> byte_list_map; +} + + +const CompactProtoTestStruct COMPACT_TEST = { + 'a_byte' : 127, + 'a_i16' : 32000, + 'a_i32' : 1000000000, + 'a_i64' : 0xffffffffff, + 'a_double' : 5.6789, + 'a_string' : "my string", +//'a_binary,' + 'true_field' : 1, + 'false_field' : 0, + 'empty_struct_field' : {}, + 'byte_list' : [-127, -1, 0, 1, 127], + 'i16_list' : [-1, 0, 1, 0x7fff], + 'i32_list' : [-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff], + 'i64_list' : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff], + 'double_list' : [0.1, 0.2, 0.3], + 'string_list' : ["first", "second", "third"], +//'binary_list,' + 'boolean_list' : [1, 1, 1, 0, 0, 0], + 'struct_list' : [{}, {}], + 'byte_set' : [-127, -1, 0, 1, 127], + 'i16_set' : [-1, 0, 1, 0x7fff], + 'i32_set' : [1, 2, 3], + 'i64_set' : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff], + 'double_set' : [0.1, 0.2, 0.3], + 'string_set' : ["first", "second", "third"], +//'binary_set,' + 'boolean_set' : [1, 0], + 'struct_set' : [{}], + 'byte_byte_map' : {1 : 2}, + 'i16_byte_map' : {1 : 1, -1 : 1, 0x7fff : 1}, + 'i32_byte_map' : {1 : 1, -1 : 1, 0x7fffffff : 1}, + 'i64_byte_map' : {0 : 1, 1 : 1, -1 : 1, 0x7fffffffffffffff : 1}, + 'double_byte_map' : {-1.1 : 1, 1.1 : 1}, + 'string_byte_map' : {"first" : 1, "second" : 2, "third" : 3, "" : 0}, +//'binary_byte_map,' + 'boolean_byte_map' : {1 : 1, 0 : 0}, + 'byte_i16_map' : {1 : 1, 2 : -1, 3 : 0x7fff}, + 'byte_i32_map' : {1 : 1, 2 : -1, 3 : 0x7fffffff}, + 'byte_i64_map' : {1 : 1, 2 : -1, 3 : 0x7fffffffffffffff}, + 'byte_double_map' : {1 : 0.1, 2 : -0.1, 3 : 1000000.1}, + 'byte_string_map' : {1 : "", 2 : "blah", 3 : "loooooooooooooong string"}, +//'byte_binary_map,' + 'byte_boolean_map' : {1 : 1, 2 : 0}, + 'list_byte_map' : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0}, + 'set_byte_map' : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0}, + 'map_byte_map' : {{1 : 1} : 1, {2 : 2} : 2, {} : 0}, + 'byte_map_map' : {0 : {}, 1 : {1 : 1}, 2 : {1 : 1, 2 : 2}}, + 'byte_set_map' : {0 : [], 1 : [1], 2 : [1, 2]}, + 'byte_list_map' : {0 : [], 1 : [1], 2 : [1, 2]}, +} + + + +service Srv { + i32 Janky(1: i32 arg); + + // return type only methods + + void voidMethod(); + i32 primitiveMethod(); + CompactProtoTestStruct structMethod(); +} + +service Inherited extends Srv { + i32 identity(1: i32 arg) +} + +service EmptyService {} + +// The only purpose of this thing is to increase the size of the generated code +// so that ZlibTest has more highly compressible data to play with. +struct BlowUp { + 1: map<list<i32>,set<map<i32,string>>> b1; + 2: map<list<i32>,set<map<i32,string>>> b2; + 3: map<list<i32>,set<map<i32,string>>> b3; + 4: map<list<i32>,set<map<i32,string>>> b4; +} + + +struct ReverseOrderStruct { + 4: string first; + 3: i16 second; + 2: i32 third; + 1: i64 fourth; +} + +service ReverseOrderService { + void myMethod(4: string first, 3: i16 second, 2: i32 third, 1: i64 fourth); +}
\ No newline at end of file diff --git a/test/DebugProtoTest_extras.cpp b/test/DebugProtoTest_extras.cpp new file mode 100644 index 000000000..e68c544bb --- /dev/null +++ b/test/DebugProtoTest_extras.cpp @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// Extra functions required for DebugProtoTest_types to work + +#include "gen-cpp/DebugProtoTest_types.h" + + +namespace thrift { namespace test { namespace debug { + +bool Empty::operator<(Empty const& other) const { + // It is empty, so all are equal. + return false; +} + +}}} diff --git a/test/DenseLinkingTest.thrift b/test/DenseLinkingTest.thrift new file mode 100644 index 000000000..cf61496aa --- /dev/null +++ b/test/DenseLinkingTest.thrift @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +/* +../compiler/cpp/thrift -gen cpp:dense DebugProtoTest.thrift +../compiler/cpp/thrift -gen cpp:dense DenseLinkingTest.thrift +g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ + DebugProtoTest.cpp gen-cpp/DebugProtoTest_types.cpp \ + gen-cpp/DenseLinkingTest_types.cpp \ + ../lib/cpp/.libs/libthrift.a -o DebugProtoTest +./DebugProtoTest +*/ + +/* +The idea of this test is that everything is structurally identical to DebugProtoTest. +If I messed up the naming of the reflection local typespecs, +then compiling this should give errors because of doubly defined symbols. +*/ + +namespace cpp thrift.test + +struct OneOfEachZZ { + 1: bool im_true, + 2: bool im_false, + 3: byte a_bite, + 4: i16 integer16, + 5: i32 integer32, + 6: i64 integer64, + 7: double double_precision, + 8: string some_characters, + 9: string zomg_unicode, + 10: bool what_who, +} + +struct BonkZZ { + 1: i32 type, + 2: string message, +} + +struct NestingZZ { + 1: BonkZZ my_bonk, + 2: OneOfEachZZ my_ooe, +} + +struct HolyMoleyZZ { + 1: list<OneOfEachZZ> big, + 2: set<list<string>> contain, + 3: map<string,list<BonkZZ>> bonks, +} + +struct BackwardsZZ { + 2: i32 first_tag2, + 1: i32 second_tag1, +} + +struct EmptyZZ { +} + +struct WrapperZZ { + 1: EmptyZZ foo +} + +struct RandomStuffZZ { + 1: i32 a, + 2: i32 b, + 3: i32 c, + 4: i32 d, + 5: list<i32> myintlist, + 6: map<i32,WrapperZZ> maps, + 7: i64 bigint, + 8: double triple, +} + +service Srv { + i32 Janky(1: i32 arg) +} diff --git a/test/DenseProtoTest.cpp b/test/DenseProtoTest.cpp new file mode 100644 index 000000000..99f78655f --- /dev/null +++ b/test/DenseProtoTest.cpp @@ -0,0 +1,384 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +/* +../compiler/cpp/thrift --gen cpp:dense DebugProtoTest.thrift +../compiler/cpp/thrift --gen cpp:dense OptionalRequiredTest.thrift +g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ + gen-cpp/OptionalRequiredTest_types.cpp \ + gen-cpp/DebugProtoTest_types.cpp \ + DenseProtoTest.cpp ../lib/cpp/.libs/libthrift.a -o DenseProtoTest +./DenseProtoTest +*/ + +// I do this to reach into the guts of TDenseProtocol. Sorry. +#define private public +#define inline + +#undef NDEBUG +#include <cstdlib> +#include <cassert> +#include <iostream> +#include <cmath> +#include <string> +#include "gen-cpp/DebugProtoTest_types.h" +#include "gen-cpp/OptionalRequiredTest_types.h" +#include <protocol/TDenseProtocol.h> +#include <transport/TBufferTransports.h> + + +// Can't use memcmp here. GCC is too smart. +bool my_memeq(const char* str1, const char* str2, int len) { + for (int i = 0; i < len; i++) { + if (str1[i] != str2[i]) { + return false; + } + } + return true; +} + + +int main() { + using std::string; + using std::cout; + using std::endl; + using boost::shared_ptr; + using namespace thrift::test::debug; + using namespace apache::thrift::transport; + using namespace apache::thrift::protocol; + + + OneOfEach ooe; + ooe.im_true = true; + ooe.im_false = false; + ooe.a_bite = 0xd6; + ooe.integer16 = 27000; + ooe.integer32 = 1<<24; + ooe.integer64 = (uint64_t)6000 * 1000 * 1000; + ooe.double_precision = M_PI; + ooe.some_characters = "Debug THIS!"; + ooe.zomg_unicode = "\xd7\n\a\t"; + + //cout << apache::thrift::ThriftDebugString(ooe) << endl << endl; + + + Nesting n; + n.my_ooe = ooe; + n.my_ooe.integer16 = 16; + n.my_ooe.integer32 = 32; + n.my_ooe.integer64 = 64; + n.my_ooe.double_precision = (std::sqrt(5)+1)/2; + n.my_ooe.some_characters = ":R (me going \"rrrr\")"; + n.my_ooe.zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20" + "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e" + "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc"; + n.my_bonk.type = 31337; + n.my_bonk.message = "I am a bonk... xor!"; + + //cout << apache::thrift::ThriftDebugString(n) << endl << endl; + + + HolyMoley hm; + + hm.big.push_back(ooe); + hm.big.push_back(n.my_ooe); + hm.big[0].a_bite = 0x22; + hm.big[1].a_bite = 0x33; + + std::vector<std::string> stage1; + stage1.push_back("and a one"); + stage1.push_back("and a two"); + hm.contain.insert(stage1); + stage1.clear(); + stage1.push_back("then a one, two"); + stage1.push_back("three!"); + stage1.push_back("FOUR!!"); + hm.contain.insert(stage1); + stage1.clear(); + hm.contain.insert(stage1); + + std::vector<Bonk> stage2; + hm.bonks["nothing"] = stage2; + stage2.resize(stage2.size()+1); + stage2.back().type = 1; + stage2.back().message = "Wait."; + stage2.resize(stage2.size()+1); + stage2.back().type = 2; + stage2.back().message = "What?"; + hm.bonks["something"] = stage2; + stage2.clear(); + stage2.resize(stage2.size()+1); + stage2.back().type = 3; + stage2.back().message = "quoth"; + stage2.resize(stage2.size()+1); + stage2.back().type = 4; + stage2.back().message = "the raven"; + stage2.resize(stage2.size()+1); + stage2.back().type = 5; + stage2.back().message = "nevermore"; + hm.bonks["poe"] = stage2; + + //cout << apache::thrift::ThriftDebugString(hm) << endl << endl; + + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); + shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); + proto->setTypeSpec(HolyMoley::local_reflection); + + hm.write(proto.get()); + HolyMoley hm2; + hm2.read(proto.get()); + + assert(hm == hm2); + + + // Let's test out the variable-length ints, shall we? + uint64_t vlq; + #define checkout(i, c) { \ + buffer->resetBuffer(); \ + proto->vlqWrite(i); \ + proto->getTransport()->flush(); \ + assert(my_memeq(buffer->getBufferAsString().data(), c, sizeof(c)-1)); \ + proto->vlqRead(vlq); \ + assert(vlq == i); \ + } + + checkout(0x00000000, "\x00"); + checkout(0x00000040, "\x40"); + checkout(0x0000007F, "\x7F"); + checkout(0x00000080, "\x81\x00"); + checkout(0x00002000, "\xC0\x00"); + checkout(0x00003FFF, "\xFF\x7F"); + checkout(0x00004000, "\x81\x80\x00"); + checkout(0x00100000, "\xC0\x80\x00"); + checkout(0x001FFFFF, "\xFF\xFF\x7F"); + checkout(0x00200000, "\x81\x80\x80\x00"); + checkout(0x08000000, "\xC0\x80\x80\x00"); + checkout(0x0FFFFFFF, "\xFF\xFF\xFF\x7F"); + checkout(0x10000000, "\x81\x80\x80\x80\x00"); + checkout(0x20000000, "\x82\x80\x80\x80\x00"); + checkout(0x1FFFFFFF, "\x81\xFF\xFF\xFF\x7F"); + checkout(0xFFFFFFFF, "\x8F\xFF\xFF\xFF\x7F"); + + checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00"); + checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00"); + checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00"); + checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00"); + checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00"); + checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F"); + checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00"); + checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + + // Test out the slow path with a TBufferedTransport. + shared_ptr<TBufferedTransport> buff_trans(new TBufferedTransport(buffer, 3)); + proto.reset(new TDenseProtocol(buff_trans)); + checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00"); + checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00"); + checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00"); + checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00"); + checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00"); + checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F"); + checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00"); + checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + + // Test optional stuff. + proto.reset(new TDenseProtocol(buffer)); + proto->setTypeSpec(ManyOpt::local_reflection); + ManyOpt mo1, mo2, mo3, mo4, mo5, mo6; + mo1.opt1 = 923759347; + mo1.opt2 = 392749274; + mo1.opt3 = 395739402; + mo1.def4 = 294730928; + mo1.opt5 = 394309218; + mo1.opt6 = 832194723; + mo1.__isset.opt1 = true; + mo1.__isset.opt2 = true; + mo1.__isset.opt3 = true; + mo1.__isset.def4 = true; + mo1.__isset.opt5 = true; + mo1.__isset.opt6 = true; + + mo1.write(proto.get()); + mo2.read(proto.get()); + + assert(mo2.__isset.opt1 == true); + assert(mo2.__isset.opt2 == true); + assert(mo2.__isset.opt3 == true); + assert(mo2.__isset.def4 == true); + assert(mo2.__isset.opt5 == true); + assert(mo2.__isset.opt6 == true); + + assert(mo1 == mo2); + + mo1.__isset.opt1 = false; + mo1.__isset.opt3 = false; + mo1.__isset.opt5 = false; + + mo1.write(proto.get()); + mo3.read(proto.get()); + + assert(mo3.__isset.opt1 == false); + assert(mo3.__isset.opt2 == true); + assert(mo3.__isset.opt3 == false); + assert(mo3.__isset.def4 == true); + assert(mo3.__isset.opt5 == false); + assert(mo3.__isset.opt6 == true); + + assert(mo1 == mo3); + + mo1.__isset.opt1 = true; + mo1.__isset.opt3 = true; + mo1.__isset.opt5 = true; + mo1.__isset.opt2 = false; + mo1.__isset.opt6 = false; + + mo1.write(proto.get()); + mo4.read(proto.get()); + + assert(mo4.__isset.opt1 == true); + assert(mo4.__isset.opt2 == false); + assert(mo4.__isset.opt3 == true); + assert(mo4.__isset.def4 == true); + assert(mo4.__isset.opt5 == true); + assert(mo4.__isset.opt6 == false); + + assert(mo1 == mo4); + + mo1.__isset.opt1 = false; + mo1.__isset.opt5 = false; + + mo1.write(proto.get()); + mo5.read(proto.get()); + + assert(mo5.__isset.opt1 == false); + assert(mo5.__isset.opt2 == false); + assert(mo5.__isset.opt3 == true); + assert(mo5.__isset.def4 == true); + assert(mo5.__isset.opt5 == false); + assert(mo5.__isset.opt6 == false); + + assert(mo1 == mo5); + + mo1.__isset.opt3 = false; + + mo1.write(proto.get()); + mo6.read(proto.get()); + + assert(mo6.__isset.opt1 == false); + assert(mo6.__isset.opt2 == false); + assert(mo6.__isset.opt3 == false); + assert(mo6.__isset.def4 == true); + assert(mo6.__isset.opt5 == false); + assert(mo6.__isset.opt6 == false); + + assert(mo1 == mo6); + + + // Test fingerprint checking stuff. + + { + // Default and required have the same fingerprint. + Tricky1 t1; + Tricky3 t3; + assert(string(Tricky1::ascii_fingerprint) == Tricky3::ascii_fingerprint); + proto->setTypeSpec(Tricky1::local_reflection); + t1.im_default = 227; + t1.write(proto.get()); + proto->setTypeSpec(Tricky3::local_reflection); + t3.read(proto.get()); + assert(t3.im_required == 227); + } + + { + // Optional changes things. + Tricky1 t1; + Tricky2 t2; + assert(string(Tricky1::ascii_fingerprint) != Tricky2::ascii_fingerprint); + proto->setTypeSpec(Tricky1::local_reflection); + t1.im_default = 227; + t1.write(proto.get()); + try { + proto->setTypeSpec(Tricky2::local_reflection); + t2.read(proto.get()); + assert(false); + } catch (TProtocolException& ex) { + buffer->resetBuffer(); + } + } + + { + // Holy cow. We can use the Tricky1 typespec with the Tricky2 structure. + Tricky1 t1; + Tricky2 t2; + proto->setTypeSpec(Tricky1::local_reflection); + t1.im_default = 227; + t1.write(proto.get()); + t2.read(proto.get()); + assert(t2.__isset.im_optional == true); + assert(t2.im_optional == 227); + } + + { + // And totally off the wall. + Tricky1 t1; + OneOfEach ooe2; + assert(string(Tricky1::ascii_fingerprint) != OneOfEach::ascii_fingerprint); + proto->setTypeSpec(Tricky1::local_reflection); + t1.im_default = 227; + t1.write(proto.get()); + try { + proto->setTypeSpec(OneOfEach::local_reflection); + ooe2.read(proto.get()); + assert(false); + } catch (TProtocolException& ex) { + buffer->resetBuffer(); + } + } + + // Okay, this is really off the wall. + // Just don't crash. + cout << "Starting fuzz test. This takes a while. (20 dots.)" << endl; + std::srand(12345); + for (int i = 0; i < 2000; i++) { + if (i % 100 == 0) { + cout << "."; + cout.flush(); + } + buffer->resetBuffer(); + // Make sure the fingerprint prefix is right. + buffer->write(Nesting::binary_fingerprint, 4); + for (int j = 0; j < 1024*1024; j++) { + uint8_t r = std::rand(); + buffer->write(&r, 1); + } + Nesting n; + proto->setTypeSpec(OneOfEach::local_reflection); + try { + n.read(proto.get()); + } catch (TProtocolException& ex) { + } catch (TTransportException& ex) { + } + } + cout << endl; + + return 0; +} diff --git a/test/DocTest.thrift b/test/DocTest.thrift new file mode 100644 index 000000000..cb355ae37 --- /dev/null +++ b/test/DocTest.thrift @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +/** + * Program doctext. + * + * Seriously, this is the documentation for this whole program. + */ + +namespace java thrift.test +namespace cpp thrift.test + +// C++ comment +/* c style comment */ + +# the new unix comment + +/** Some doc text goes here. Wow I am [nesting these] (no more nesting.) */ +enum Numberz +{ + + /** This is how to document a parameter */ + ONE = 1, + + /** And this is a doc for a parameter that has no specific value assigned */ + TWO, + + THREE, + FIVE = 5, + SIX, + EIGHT = 8 +} + +/** This is how you would do a typedef doc */ +typedef i64 UserId + +/** And this is where you would document a struct */ +struct Xtruct +{ + + /** And the members of a struct */ + 1: string string_thing + + /** doct text goes before a comma */ + 4: byte byte_thing, + + 9: i32 i32_thing, + 11: i64 i64_thing +} + +/** + * You can document constants now too. Yeehaw! + */ +const i32 INT32CONSTANT = 9853 +const i16 INT16CONSTANT = 1616 +/** Everyone get in on the docu-action! */ +const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} + +struct Xtruct2 +{ + 1: byte byte_thing, + 2: Xtruct struct_thing, + 3: i32 i32_thing +} + +/** Struct insanity */ +struct Insanity +{ + + /** This is doc for field 1 */ + 1: map<Numberz, UserId> userMap, + + /** And this is doc for field 2 */ + 2: list<Xtruct> xtructs +} + +exception Xception { + 1: i32 errorCode, + 2: string message +} + +exception Xception2 { + 1: i32 errorCode, + 2: Xtruct struct_thing +} + +/* C1 */ +/** Doc */ +/* C2 */ +/* C3 */ +struct EmptyStruct {} + +struct OneField { + 1: EmptyStruct field +} + +/** This is where you would document a Service */ +service ThriftTest +{ + + /** And this is how you would document functions in a service */ + void testVoid(), + string testString(1: string thing), + byte testByte(1: byte thing), + i32 testI32(1: i32 thing), + + /** Like this one */ + i64 testI64(1: i64 thing), + double testDouble(1: double thing), + Xtruct testStruct(1: Xtruct thing), + Xtruct2 testNest(1: Xtruct2 thing), + map<i32,i32> testMap(1: map<i32,i32> thing), + set<i32> testSet(1: set<i32> thing), + list<i32> testList(1: list<i32> thing), + + /** This is an example of a function with params documented */ + Numberz testEnum( + + /** This param is a thing */ + 1: Numberz thing + + ), + + UserId testTypedef(1: UserId thing), + + map<i32,map<i32,i32>> testMapMap(1: i32 hello), + + /* So you think you've got this all worked, out eh? */ + map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument), + +} + +/// This style of Doxy-comment doesn't work. +typedef i32 SorryNoGo + +/** + * This is a trivial example of a multiline docstring. + */ +typedef i32 TrivialMultiLine + +/** + * This is the cannonical example + * of a multiline docstring. + */ +typedef i32 StandardMultiLine + +/** + * The last line is non-blank. + * I said non-blank! */ +typedef i32 LastLine + +/** Both the first line + * are non blank. ;-) + * and the last line */ +typedef i32 FirstAndLastLine + +/** + * INDENTED TITLE + * The text is less indented. + */ +typedef i32 IndentedTitle + +/** First line indented. + * Unfortunately, this does not get indented. + */ +typedef i32 FirstLineIndent + + +/** + * void code_in_comment() { + * printf("hooray code!"); + * } + */ +typedef i32 CodeInComment + + /** + * Indented Docstring. + * This whole docstring is indented. + * This line is indented further. + */ +typedef i32 IndentedDocstring + +/** Irregular docstring. + * We will have to punt + * on this thing */ +typedef i32 Irregular1 + +/** + * note the space + * before these lines +* but not this + * one + */ +typedef i32 Irregular2 + +/** +* Flush against +* the left. +*/ +typedef i32 Flush + +/** + No stars in this one. + It should still work fine, though. + Including indenting. + */ +typedef i32 NoStars + +/** Trailing whitespace +Sloppy trailing whitespace +is truncated. */ +typedef i32 TrailingWhitespace + +/** + * This is a big one. + * + * We'll have some blank lines in it. + * + * void as_well_as(some code) { + * puts("YEEHAW!"); + * } + */ +typedef i32 BigDog + +/** +* +* +*/ +typedef i32 TotallyDegenerate + +/* THE END */ diff --git a/test/FastbinaryTest.py b/test/FastbinaryTest.py new file mode 100755 index 000000000..7f6efae60 --- /dev/null +++ b/test/FastbinaryTest.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +r""" +thrift --gen py DebugProtoTest.thrift +./FastbinaryTest.py +""" + +# TODO(dreiss): Test error cases. Check for memory leaks. + +import sys +sys.path.append('./gen-py') + +import math +from DebugProtoTest import Srv +from DebugProtoTest.ttypes import * +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + +import timeit +from cStringIO import StringIO +from copy import deepcopy +from pprint import pprint + +class TDevNullTransport(TTransport.TTransportBase): + def __init__(self): + pass + def isOpen(self): + return True + +ooe1 = OneOfEach() +ooe1.im_true = True; +ooe1.im_false = False; +ooe1.a_bite = 0xd6; +ooe1.integer16 = 27000; +ooe1.integer32 = 1<<24; +ooe1.integer64 = 6000 * 1000 * 1000; +ooe1.double_precision = math.pi; +ooe1.some_characters = "Debug THIS!"; +ooe1.zomg_unicode = "\xd7\n\a\t"; + +ooe2 = OneOfEach(); +ooe2.integer16 = 16; +ooe2.integer32 = 32; +ooe2.integer64 = 64; +ooe2.double_precision = (math.sqrt(5)+1)/2; +ooe2.some_characters = ":R (me going \"rrrr\")"; +ooe2.zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"\ + "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\ + "\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\ + "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\ + "\xc7\x83\xe2\x80\xbc"; + +hm = HolyMoley({"big":[], "contain":set(), "bonks":{}}) +hm.big.append(ooe1) +hm.big.append(ooe2) +hm.big[0].a_bite = 0x22; +hm.big[1].a_bite = 0x22; + +hm.contain.add(("and a one", "and a two")) +hm.contain.add(("then a one, two", "three!", "FOUR!")) +hm.contain.add(()) + +hm.bonks["nothing"] = []; +hm.bonks["something"] = [ + Bonk({"type":1, "message":"Wait."}), + Bonk({"type":2, "message":"What?"}), +] +hm.bonks["poe"] = [ + Bonk({"type":3, "message":"quoth"}), + Bonk({"type":4, "message":"the raven"}), + Bonk({"type":5, "message":"nevermore"}), +] + +rs = RandomStuff() +rs.a = 1 +rs.b = 2 +rs.c = 3 +rs.myintlist = range(20) +rs.maps = {1:Wrapper({"foo":Empty()}),2:Wrapper({"foo":Empty()})} +rs.bigint = 124523452435L +rs.triple = 3.14 + +# make sure this splits two buffers in a buffered protocol +rshuge = RandomStuff() +rshuge.myintlist=range(10000) + +my_zero = Srv.Janky_result({"arg":5}) + +def checkWrite(o): + trans_fast = TTransport.TMemoryBuffer() + trans_slow = TTransport.TMemoryBuffer() + prot_fast = TBinaryProtocol.TBinaryProtocolAccelerated(trans_fast) + prot_slow = TBinaryProtocol.TBinaryProtocol(trans_slow) + + o.write(prot_fast) + o.write(prot_slow) + ORIG = trans_slow.getvalue() + MINE = trans_fast.getvalue() + if ORIG != MINE: + print "mine: %s\norig: %s" % (repr(MINE), repr(ORIG)) + +def checkRead(o): + prot = TBinaryProtocol.TBinaryProtocol(TTransport.TMemoryBuffer()) + o.write(prot) + + slow_version_binary = prot.trans.getvalue() + + prot = TBinaryProtocol.TBinaryProtocolAccelerated( + TTransport.TMemoryBuffer(slow_version_binary)) + c = o.__class__() + c.read(prot) + if c != o: + print "copy: " + pprint(eval(repr(c))) + print "orig: " + pprint(eval(repr(o))) + + prot = TBinaryProtocol.TBinaryProtocolAccelerated( + TTransport.TBufferedTransport( + TTransport.TMemoryBuffer(slow_version_binary))) + c = o.__class__() + c.read(prot) + if c != o: + print "copy: " + pprint(eval(repr(c))) + print "orig: " + pprint(eval(repr(o))) + + +def doTest(): + checkWrite(hm) + no_set = deepcopy(hm) + no_set.contain = set() + checkRead(no_set) + checkWrite(rs) + checkRead(rs) + checkWrite(rshuge) + checkRead(rshuge) + checkWrite(my_zero) + checkRead(my_zero) + checkRead(Backwards({"first_tag2":4, "second_tag1":2})) + + # One case where the serialized form changes, but only superficially. + o = Backwards({"first_tag2":4, "second_tag1":2}) + trans_fast = TTransport.TMemoryBuffer() + trans_slow = TTransport.TMemoryBuffer() + prot_fast = TBinaryProtocol.TBinaryProtocolAccelerated(trans_fast) + prot_slow = TBinaryProtocol.TBinaryProtocol(trans_slow) + + o.write(prot_fast) + o.write(prot_slow) + ORIG = trans_slow.getvalue() + MINE = trans_fast.getvalue() + if ORIG == MINE: + print "That shouldn't happen." + + + prot = TBinaryProtocol.TBinaryProtocolAccelerated(TTransport.TMemoryBuffer()) + o.write(prot) + prot = TBinaryProtocol.TBinaryProtocol( + TTransport.TMemoryBuffer( + prot.trans.getvalue())) + c = o.__class__() + c.read(prot) + if c != o: + print "copy: " + pprint(eval(repr(c))) + print "orig: " + pprint(eval(repr(o))) + + + +def doBenchmark(): + + iters = 25000 + + setup = """ +from __main__ import hm, rs, TDevNullTransport +from thrift.protocol import TBinaryProtocol +trans = TDevNullTransport() +prot = TBinaryProtocol.TBinaryProtocol%s(trans) +""" + + setup_fast = setup % "Accelerated" + setup_slow = setup % "" + + print "Starting Benchmarks" + + print "HolyMoley Standard = %f" % \ + timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters) + print "HolyMoley Acceler. = %f" % \ + timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters) + + print "FastStruct Standard = %f" % \ + timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters) + print "FastStruct Acceler. = %f" % \ + timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters) + + + +doTest() +doBenchmark() + diff --git a/test/GenericHelpers.h b/test/GenericHelpers.h new file mode 100644 index 000000000..d661d8ba3 --- /dev/null +++ b/test/GenericHelpers.h @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#ifndef _THRIFT_TEST_GENERICHELPERS_H_ +#define _THRIFT_TEST_GENERICHELPERS_H_ 1 + +#include <protocol/TBinaryProtocol.h> +#include <transport/TBufferTransports.h> +#include <Thrift.h> + +using boost::shared_ptr; +using namespace apache::thrift::protocol; + +/* ClassName Helper for cleaner exceptions */ +class ClassNames { + public: + template <typename T> + static const char* getName() { return "Unknown type"; } +}; + +template <> const char* ClassNames::getName<int8_t>() { return "byte"; } +template <> const char* ClassNames::getName<int16_t>() { return "short"; } +template <> const char* ClassNames::getName<int32_t>() { return "int"; } +template <> const char* ClassNames::getName<int64_t>() { return "long"; } +template <> const char* ClassNames::getName<double>() { return "double"; } +template <> const char* ClassNames::getName<std::string>() { return "string"; } + +/* Generic Protocol I/O function for tests */ +class GenericIO { + public: + + /* Write functions */ + + static uint32_t write(shared_ptr<TProtocol> proto, const int8_t& val) { + return proto->writeByte(val); + } + + static uint32_t write(shared_ptr<TProtocol> proto, const int16_t& val) { + return proto->writeI16(val); + } + + static uint32_t write(shared_ptr<TProtocol> proto, const int32_t& val) { + return proto->writeI32(val); + } + + static uint32_t write(shared_ptr<TProtocol> proto, const double& val) { + return proto->writeDouble(val); + } + + static uint32_t write(shared_ptr<TProtocol> proto, const int64_t& val) { + return proto->writeI64(val); + } + + static uint32_t write(shared_ptr<TProtocol> proto, const std::string& val) { + return proto->writeString(val); + } + + /* Read functions */ + + static uint32_t read(shared_ptr<TProtocol> proto, int8_t& val) { + return proto->readByte(val); + } + + static uint32_t read(shared_ptr<TProtocol> proto, int16_t& val) { + return proto->readI16(val); + } + + static uint32_t read(shared_ptr<TProtocol> proto, int32_t& val) { + return proto->readI32(val); + } + + static uint32_t read(shared_ptr<TProtocol> proto, int64_t& val) { + return proto->readI64(val); + } + + static uint32_t read(shared_ptr<TProtocol> proto, double& val) { + return proto->readDouble(val); + } + + static uint32_t read(shared_ptr<TProtocol> proto, std::string& val) { + return proto->readString(val); + } + +}; + +#endif diff --git a/test/JSONProtoTest.cpp b/test/JSONProtoTest.cpp new file mode 100644 index 000000000..668135691 --- /dev/null +++ b/test/JSONProtoTest.cpp @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <iostream> +#include <cmath> +#include <transport/TBufferTransports.h> +#include <protocol/TJSONProtocol.h> +#include "gen-cpp/DebugProtoTest_types.h" + +int main() { + using std::cout; + using std::endl; + using namespace thrift::test::debug; + using apache::thrift::transport::TMemoryBuffer; + using apache::thrift::protocol::TJSONProtocol; + + OneOfEach ooe; + ooe.im_true = true; + ooe.im_false = false; + ooe.a_bite = 0xd6; + ooe.integer16 = 27000; + ooe.integer32 = 1<<24; + ooe.integer64 = (uint64_t)6000 * 1000 * 1000; + ooe.double_precision = M_PI; + ooe.some_characters = "JSON THIS! \"\1"; + ooe.zomg_unicode = "\xd7\n\a\t"; + ooe.base64 = "\1\2\3\255"; + cout << apache::thrift::ThriftJSONString(ooe) << endl << endl; + + + Nesting n; + n.my_ooe = ooe; + n.my_ooe.integer16 = 16; + n.my_ooe.integer32 = 32; + n.my_ooe.integer64 = 64; + n.my_ooe.double_precision = (std::sqrt(5)+1)/2; + n.my_ooe.some_characters = ":R (me going \"rrrr\")"; + n.my_ooe.zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20" + "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e" + "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc"; + n.my_bonk.type = 31337; + n.my_bonk.message = "I am a bonk... xor!"; + + cout << apache::thrift::ThriftJSONString(n) << endl << endl; + + + HolyMoley hm; + + hm.big.push_back(ooe); + hm.big.push_back(n.my_ooe); + hm.big[0].a_bite = 0x22; + hm.big[1].a_bite = 0x33; + + std::vector<std::string> stage1; + stage1.push_back("and a one"); + stage1.push_back("and a two"); + hm.contain.insert(stage1); + stage1.clear(); + stage1.push_back("then a one, two"); + stage1.push_back("three!"); + stage1.push_back("FOUR!!"); + hm.contain.insert(stage1); + stage1.clear(); + hm.contain.insert(stage1); + + std::vector<Bonk> stage2; + hm.bonks["nothing"] = stage2; + stage2.resize(stage2.size()+1); + stage2.back().type = 1; + stage2.back().message = "Wait."; + stage2.resize(stage2.size()+1); + stage2.back().type = 2; + stage2.back().message = "What?"; + hm.bonks["something"] = stage2; + stage2.clear(); + stage2.resize(stage2.size()+1); + stage2.back().type = 3; + stage2.back().message = "quoth"; + stage2.resize(stage2.size()+1); + stage2.back().type = 4; + stage2.back().message = "the raven"; + stage2.resize(stage2.size()+1); + stage2.back().type = 5; + stage2.back().message = "nevermore"; + hm.bonks["poe"] = stage2; + + cout << apache::thrift::ThriftJSONString(hm) << endl << endl; + + boost::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); + boost::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer)); + + + cout << "Testing ooe" << endl; + + ooe.write(proto.get()); + OneOfEach ooe2; + ooe2.read(proto.get()); + + assert(ooe == ooe2); + + + cout << "Testing hm" << endl; + + hm.write(proto.get()); + HolyMoley hm2; + hm2.read(proto.get()); + + assert(hm == hm2); + + hm2.big[0].a_bite = 0xFF; + + assert(hm != hm2); + + Doubles dub; + dub.nan = HUGE_VAL/HUGE_VAL; + dub.inf = HUGE_VAL; + dub.neginf = -HUGE_VAL; + dub.repeating = 10.0/3.0; + dub.big = 1E+305; + dub.small = 1E-305; + dub.zero = 0.0; + dub.negzero = -0.0; + cout << apache::thrift::ThriftJSONString(dub) << endl << endl; + + cout << "Testing base" << endl; + + Base64 base; + base.a = 123; + base.b1 = "1"; + base.b2 = "12"; + base.b3 = "123"; + base.b4 = "1234"; + base.b5 = "12345"; + base.b6 = "123456"; + + base.write(proto.get()); + Base64 base2; + base2.read(proto.get()); + + assert(base == base2); + + return 0; +} diff --git a/test/JavaBeansTest.thrift b/test/JavaBeansTest.thrift new file mode 100644 index 000000000..02bf98d63 --- /dev/null +++ b/test/JavaBeansTest.thrift @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace java thrift.test + +struct OneOfEachBeans { + 1: bool boolean_field, + 2: byte a_bite, + 3: i16 integer16, + 4: i32 integer32, + 5: i64 integer64, + 6: double double_precision, + 7: string some_characters, + 8: binary base64, + 9: list<byte> byte_list, + 10: list<i16> i16_list, + 11: list<i64> i64_list +} diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 000000000..1226935de --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,178 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +SUBDIRS = + +if WITH_PYTHON +SUBDIRS += py +endif + +if WITH_RUBY +SUBDIRS += rb +endif + +noinst_LTLIBRARIES = libtestgencpp.la +libtestgencpp_la_SOURCES = \ + gen-cpp/DebugProtoTest_types.cpp \ + gen-cpp/OptionalRequiredTest_types.cpp \ + gen-cpp/DebugProtoTest_types.cpp \ + gen-cpp/ThriftTest_types.cpp \ + gen-cpp/DebugProtoTest_types.h \ + gen-cpp/OptionalRequiredTest_types.h \ + gen-cpp/ThriftTest_types.h \ + ThriftTest_extras.cpp \ + DebugProtoTest_extras.cpp + +ThriftTest_extras.o: gen-cpp/ThriftTest_types.h +DebugProtoTest_extras.o: gen-cpp/DebugProtoTest_types.h + +libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la + +noinst_PROGRAMS = Benchmark + +Benchmark_SOURCES = \ + Benchmark.cpp + +Benchmark_LDADD = libtestgencpp.la + +check_PROGRAMS = \ + TFDTransportTest \ + TPipedTransportTest \ + DebugProtoTest \ + JSONProtoTest \ + OptionalRequiredTest \ + AllProtocolsTest \ + UnitTests + +TESTS = \ + $(check_PROGRAMS) + +UnitTests_SOURCES = \ + UnitTestMain.cpp \ + TMemoryBufferTest.cpp \ + TBufferBaseTest.cpp + +UnitTests_LDADD = libtestgencpp.la + +# +# TFDTransportTest +# +TFDTransportTest_SOURCES = \ + TFDTransportTest.cpp + +TFDTransportTest_LDADD = \ + $(top_builddir)/lib/cpp/libthrift.la + + +# +# TPipedTransportTest +# +TPipedTransportTest_SOURCES = \ + TPipedTransportTest.cpp + +TPipedTransportTest_LDADD = \ + $(top_builddir)/lib/cpp/libthrift.la + +# +# AllProtocolsTest +# +AllProtocolsTest_SOURCES = \ + AllProtocolTests.cpp \ + AllProtocolTests.tcc \ + GenericHelpers.h + +AllProtocolsTest_LDADD = libtestgencpp.la + +# +# DebugProtoTest +# +DebugProtoTest_SOURCES = \ + DebugProtoTest.cpp + +DebugProtoTest_LDADD = libtestgencpp.la + + +# +# JSONProtoTest +# +JSONProtoTest_SOURCES = \ + JSONProtoTest.cpp + +JSONProtoTest_LDADD = libtestgencpp.la + +# +# OptionalRequiredTest +# +OptionalRequiredTest_SOURCES = \ + OptionalRequiredTest.cpp + +OptionalRequiredTest_LDADD = libtestgencpp.la + + +# +# Common thrift code generation rules +# +THRIFT = $(top_builddir)/compiler/cpp/thrift + +gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h: DebugProtoTest.thrift + $(THRIFT) --gen cpp:dense $< + +gen-cpp/OptionalRequiredTest_types.cpp gen-cpp/OptionalRequiredTest_types.h: OptionalRequiredTest.thrift + $(THRIFT) --gen cpp:dense $< + +gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp: StressTest.thrift + $(THRIFT) --gen cpp:dense $< + +gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h: ThriftTest.thrift + $(THRIFT) --gen cpp:dense $< + +INCLUDES = \ + -I$(top_srcdir)/lib/cpp/src + +AM_CPPFLAGS = $(BOOST_CPPFLAGS) + +clean-local: + $(RM) -r gen-cpp + +EXTRA_DIST = \ + cpp \ + threads \ + csharp \ + py \ + rb \ + perl \ + php \ + erl \ + hs \ + ocaml \ + AnnotationTest.thrift \ + BrokenConstants.thrift \ + ConstantsDemo.thrift \ + DebugProtoTest.thrift \ + DenseLinkingTest.thrift \ + DocTest.thrift \ + JavaBeansTest.thrift \ + ManyTypedefs.thrift \ + OptionalRequiredTest.thrift \ + SmallTest.thrift \ + StressTest.thrift \ + ThriftTest.thrift \ + ZlibTest.cpp \ + DenseProtoTest.cpp \ + FastbinaryTest.py diff --git a/test/ManyTypedefs.thrift b/test/ManyTypedefs.thrift new file mode 100644 index 000000000..d194b63c2 --- /dev/null +++ b/test/ManyTypedefs.thrift @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// This is to make sure you don't mess something up when you change typedef code. +// Generate it with the old and new thrift and make sure they are the same. +/* +rm -rf gen-* orig-* +mkdir old new +thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift +mv gen-* old +../compiler/cpp/thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift +mv gen-* new +diff -ur old new +rm -rf old new +# There should be no output. +*/ + +typedef i32 int32 +typedef list<map<int32, string>> biglist + +struct struct1 { + 1: int32 myint; + 2: biglist mylist; +} + +exception exception1 { + 1: biglist alist; + 2: struct1 mystruct; +} + +service AService { + struct1 method1(1: int32 myint) throws (1: exception1 exn); + biglist method2(); +} diff --git a/test/OptionalRequiredTest.cpp b/test/OptionalRequiredTest.cpp new file mode 100644 index 000000000..5743ce303 --- /dev/null +++ b/test/OptionalRequiredTest.cpp @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <cassert> +#include <map> +#include <iostream> +#include <protocol/TDebugProtocol.h> +#include <protocol/TBinaryProtocol.h> +#include <transport/TBufferTransports.h> +#include "gen-cpp/OptionalRequiredTest_types.h" + +using std::cout; +using std::endl; +using std::map; +using std::string; +using namespace thrift::test; +using namespace apache::thrift; +using namespace apache::thrift::transport; +using namespace apache::thrift::protocol; + + +/* +template<typename Struct> +void trywrite(const Struct& s, bool should_work) { + bool worked; + try { + TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer)); + s.write(&protocol); + worked = true; + } catch (TProtocolException & ex) { + worked = false; + } + assert(worked == should_work); +} +*/ + +template <typename Struct1, typename Struct2> +void write_to_read(const Struct1 & w, Struct2 & r) { + TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer)); + w.write(&protocol); + r.read(&protocol); +} + + +int main() { + + cout << "This old school struct should have three fields." << endl; + { + OldSchool o; + cout << ThriftDebugString(o) << endl; + } + cout << endl; + + cout << "Setting a value before setting isset." << endl; + { + Simple s; + cout << ThriftDebugString(s) << endl; + s.im_optional = 10; + cout << ThriftDebugString(s) << endl; + s.__isset.im_optional = true; + cout << ThriftDebugString(s) << endl; + } + cout << endl; + + cout << "Setting isset before setting a value." << endl; + { + Simple s; + cout << ThriftDebugString(s) << endl; + s.__isset.im_optional = true; + cout << ThriftDebugString(s) << endl; + s.im_optional = 10; + cout << ThriftDebugString(s) << endl; + } + cout << endl; + + // Write-to-read with optional fields. + { + Simple s1, s2, s3; + s1.im_optional = 10; + assert(!s1.__isset.im_default); + //assert(!s1.__isset.im_required); // Compile error. + assert(!s1.__isset.im_optional); + + write_to_read(s1, s2); + + assert( s2.__isset.im_default); + //assert( s2.__isset.im_required); // Compile error. + assert(!s2.__isset.im_optional); + assert(s3.im_optional == 0); + + s1.__isset.im_optional = true; + write_to_read(s1, s3); + + assert( s3.__isset.im_default); + //assert( s3.__isset.im_required); // Compile error. + assert( s3.__isset.im_optional); + assert(s3.im_optional == 10); + } + + // Writing between optional and default. + { + Tricky1 t1; + Tricky2 t2; + + t2.im_optional = 10; + write_to_read(t2, t1); + write_to_read(t1, t2); + assert(!t1.__isset.im_default); + assert( t2.__isset.im_optional); + assert(t1.im_default == t2.im_optional); + assert(t1.im_default == 0); + } + + // Writing between default and required. + { + Tricky1 t1; + Tricky3 t3; + write_to_read(t1, t3); + write_to_read(t3, t1); + assert(t1.__isset.im_default); + } + + // Writing between optional and required. + { + Tricky2 t2; + Tricky3 t3; + t2.__isset.im_optional = true; + write_to_read(t2, t3); + write_to_read(t3, t2); + } + + // Mu-hu-ha-ha-ha! + { + Tricky2 t2; + Tricky3 t3; + try { + write_to_read(t2, t3); + abort(); + } + catch (TProtocolException& ex) {} + + write_to_read(t3, t2); + assert(t2.__isset.im_optional); + } + + cout << "Complex struct, simple test." << endl; + { + Complex c; + cout << ThriftDebugString(c) << endl; + } + + + { + Tricky1 t1; + Tricky2 t2; + // Compile error. + //(void)(t1 == t2); + } + + { + OldSchool o1, o2, o3; + assert(o1 == o2); + o1.im_int = o2.im_int = 10; + assert(o1 == o2); + o1.__isset.im_int = true; + o2.__isset.im_int = false; + assert(o1 == o2); + o1.im_int = 20; + o1.__isset.im_int = false; + assert(o1 != o2); + o1.im_int = 10; + assert(o1 == o2); + o1.im_str = o2.im_str = "foo"; + assert(o1 == o2); + o1.__isset.im_str = o2.__isset.im_str = true; + assert(o1 == o2); + map<int32_t,string> mymap; + mymap[1] = "bar"; + mymap[2] = "baz"; + o1.im_big.push_back(map<int32_t,string>()); + assert(o1 != o2); + o2.im_big.push_back(map<int32_t,string>()); + assert(o1 == o2); + o2.im_big.push_back(mymap); + assert(o1 != o2); + o1.im_big.push_back(mymap); + assert(o1 == o2); + + TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer)); + o1.write(&protocol); + + o1.im_big.push_back(mymap); + mymap[3] = "qux"; + o2.im_big.push_back(mymap); + assert(o1 != o2); + o1.im_big.back()[3] = "qux"; + assert(o1 == o2); + + o3.read(&protocol); + o3.im_big.push_back(mymap); + assert(o1 == o3); + + //cout << ThriftDebugString(o3) << endl; + } + + { + Tricky2 t1, t2; + assert(t1.__isset.im_optional == false); + assert(t2.__isset.im_optional == false); + assert(t1 == t2); + t1.im_optional = 5; + assert(t1 == t2); + t2.im_optional = 5; + assert(t1 == t2); + t1.__isset.im_optional = true; + assert(t1 != t2); + t2.__isset.im_optional = true; + assert(t1 == t2); + t1.im_optional = 10; + assert(t1 != t2); + t2.__isset.im_optional = false; + assert(t1 != t2); + } + + return 0; +} diff --git a/test/OptionalRequiredTest.thrift b/test/OptionalRequiredTest.thrift new file mode 100644 index 000000000..f7d1fd6a1 --- /dev/null +++ b/test/OptionalRequiredTest.thrift @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace cpp thrift.test +namespace java thrift.test + +struct OldSchool { + 1: i16 im_int; + 2: string im_str; + 3: list<map<i32,string>> im_big; +} + +struct Simple { + 1: /* :) */ i16 im_default; + 2: required i16 im_required; + 3: optional i16 im_optional; +} + +struct Tricky1 { + 1: /* :) */ i16 im_default; +} + +struct Tricky2 { + 1: optional i16 im_optional; +} + +struct Tricky3 { + 1: required i16 im_required; +} + +struct Complex { + 1: i16 cp_default; + 2: required i16 cp_required; + 3: optional i16 cp_optional; + 4: map<i16,Simple> the_map; + 5: required Simple req_simp; + 6: optional Simple opt_simp; +} + +struct ManyOpt { + 1: optional i32 opt1; + 2: optional i32 opt2; + 3: optional i32 opt3; + 4: i32 def4; + 5: optional i32 opt5; + 6: optional i32 opt6; +} + +struct JavaTestHelper { + 1: required i32 req_int; + 2: optional i32 opt_int; + 3: required string req_obj; + 4: optional string opt_obj; + 5: required binary req_bin; + 6: optional binary opt_bin; +} diff --git a/test/SmallTest.thrift b/test/SmallTest.thrift new file mode 100644 index 000000000..d0821c7ff --- /dev/null +++ b/test/SmallTest.thrift @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + + +namespace rb TestNamespace + +struct Goodbyez { + 1: i32 val = 325; +} + +senum Thinger { + "ASDFKJ", + "r32)*F#@", + "ASDFLJASDF" +} + +struct BoolPasser { + 1: bool value = 1 +} + +struct Hello { + 1: i32 simple = 53, + 2: map<i32,i32> complex = {23:532, 6243:632, 2355:532}, + 3: map<i32, map<i32,i32>> complexer, + 4: string words = "words", + 5: Goodbyez thinz = {'val' : 36632} +} + +const map<i32,map<i32,i32>> CMAP = { 235: {235:235}, 53:{53:53} } +const i32 CINT = 325; +const Hello WHOA = {'simple' : 532} + +exception Goodbye { + 1: i32 simple, + 2: map<i32,i32> complex, + 3: map<i32, map<i32,i32>> complexer, +} + +service SmallService { + Thinger testThinger(1:Thinger bootz), + Hello testMe(1:i32 hello=64, 2: Hello wonk) throws (1: Goodbye g), + void testVoid() throws (1: Goodbye g), + i32 testI32(1:i32 boo) +} diff --git a/test/StressTest.thrift b/test/StressTest.thrift new file mode 100644 index 000000000..87c6e4761 --- /dev/null +++ b/test/StressTest.thrift @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace cpp test.stress + +service Service { + + void echoVoid(), + byte echoByte(1: byte arg), + i32 echoI32(1: i32 arg), + i64 echoI64(1: i64 arg), + string echoString(1: string arg), + list<byte> echoList(1: list<byte> arg), + set<byte> echoSet(1: set<byte> arg), + map<byte, byte> echoMap(1: map<byte, byte> arg), +} + diff --git a/test/TBufferBaseTest.cpp b/test/TBufferBaseTest.cpp new file mode 100644 index 000000000..da3ce8567 --- /dev/null +++ b/test/TBufferBaseTest.cpp @@ -0,0 +1,639 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <algorithm> +#include <boost/foreach.hpp> +#include <boost/test/unit_test.hpp> +#include <transport/TBufferTransports.h> +#include <transport/TShortReadTransport.h> + +using std::string; +using boost::shared_ptr; +using apache::thrift::transport::TMemoryBuffer; +using apache::thrift::transport::TBufferedTransport; +using apache::thrift::transport::TFramedTransport; +using apache::thrift::transport::test::TShortReadTransport; + +#define foreach BOOST_FOREACH + +// Shamelessly copied from ZlibTransport. TODO: refactor. +unsigned int dist[][5000] = { + { 1<<15 }, + + { + 5,13,9,1,8,9,11,13,18,48,24,13,21,13,5,11,35,2,4,20,17,72,27,14,15,4,7,26, + 12,1,14,9,2,16,29,41,7,24,4,27,14,4,1,4,25,3,6,34,10,8,50,2,14,13,55,29,3, + 43,53,49,14,4,10,32,27,48,1,3,1,11,5,17,16,51,17,30,15,11,9,2,2,11,52,12,2, + 13,94,1,19,1,38,2,8,43,8,33,7,30,8,17,22,2,15,14,12,34,2,12,6,37,29,74,3, + 165,16,11,17,5,14,3,10,7,37,11,24,7,1,3,12,37,8,9,34,17,12,8,21,13,37,1,4, + 30,14,78,4,15,2,40,37,17,12,36,82,14,4,1,4,7,17,11,16,88,77,2,3,15,3,34,11, + 5,79,22,34,8,4,4,40,22,24,28,9,13,3,34,27,9,16,39,16,39,13,2,4,3,41,26,10,4, + 33,4,7,12,5,6,3,10,30,8,21,16,58,19,9,0,47,7,13,11,19,15,7,53,57,2,13,28,22, + 3,16,9,25,33,12,40,7,12,64,7,14,24,44,9,2,14,11,2,58,1,26,30,11,9,5,24,7,9, + 94,2,10,21,5,5,4,5,6,179,9,18,2,7,13,31,41,17,4,36,3,21,6,26,8,15,18,44,27, + 11,9,25,7,0,14,2,12,20,23,13,2,163,9,5,15,65,2,14,6,8,98,11,15,14,34,2,3,10, + 22,9,92,7,10,32,67,13,3,4,35,8,2,1,5,0,26,381,7,27,8,2,16,93,4,19,5,8,25,9, + 31,14,4,21,5,3,9,22,56,4,18,3,11,18,6,4,3,40,12,16,110,8,35,14,1,18,40,9,12, + 14,3,11,7,57,13,18,116,53,19,22,7,16,11,5,8,21,16,1,75,21,20,1,28,2,6,1,7, + 19,38,5,6,9,9,4,1,7,55,36,62,5,4,4,24,15,1,12,35,48,20,5,17,1,5,26,15,4,54, + 13,5,5,15,5,19,32,29,31,7,6,40,7,80,11,18,8,128,48,6,12,84,13,4,7,2,13,9,16, + 17,3,254,1,4,181,8,44,7,6,24,27,9,23,14,34,16,22,25,10,3,3,4,4,12,2,12,6,7, + 13,58,13,6,11,19,53,11,66,18,19,10,4,13,2,5,49,58,1,67,7,21,64,14,11,14,8,3, + 26,33,91,31,20,7,9,42,39,4,3,55,11,10,0,7,4,75,8,12,0,27,3,8,9,0,12,12,23, + 28,23,20,4,13,30,2,22,20,19,30,6,22,2,6,4,24,7,19,55,86,5,33,2,161,6,7,1,62, + 13,3,72,12,12,9,7,12,10,5,10,29,1,5,22,13,13,5,2,12,3,7,14,18,2,3,46,21,17, + 15,19,3,27,5,16,45,31,10,8,17,18,18,3,7,24,6,55,9,3,6,12,10,12,8,91,9,4,4,4, + 27,29,16,5,7,22,43,28,11,14,8,11,28,109,55,71,40,3,8,22,26,15,44,3,25,29,5, + 3,32,17,12,3,29,27,25,15,11,8,40,39,38,17,3,9,11,2,32,11,6,20,48,75,27,3,7, + 54,12,95,12,7,24,23,2,13,8,15,16,5,12,4,17,7,19,88,2,6,13,115,45,12,21,2,86, + 74,9,7,5,16,32,16,2,21,18,6,34,5,18,260,7,12,16,44,19,92,31,7,8,2,9,0,0,15, + 8,38,4,8,20,18,2,83,3,3,4,9,5,3,10,3,5,29,15,7,11,8,48,17,23,2,17,4,11,22, + 21,64,8,8,4,19,95,0,17,28,9,11,20,71,5,11,18,12,13,45,49,4,1,33,32,23,13,5, + 52,2,2,16,3,4,7,12,2,1,12,6,24,1,22,155,21,3,45,4,12,44,26,5,40,36,9,9,8,20, + 35,31,3,2,32,50,10,8,37,2,75,35,22,15,192,8,11,23,1,4,29,6,8,8,5,12,18,32,4, + 7,12,2,0,0,9,5,48,11,35,3,1,123,6,29,8,11,8,23,51,16,6,63,12,2,5,4,14,2,15, + 7,14,3,2,7,17,32,8,8,10,1,23,62,2,49,6,49,47,23,3,20,7,11,39,10,24,6,15,5,5, + 11,8,16,36,8,13,20,3,10,44,7,52,7,10,36,6,15,10,5,11,4,14,19,17,10,12,3,6, + 23,4,13,94,70,7,36,7,38,7,28,8,4,15,3,19,4,33,39,21,109,4,80,6,40,4,432,4,4, + 7,8,3,31,8,28,37,34,10,2,21,5,22,0,7,36,14,12,6,24,1,21,5,9,2,29,20,54,113, + 13,31,39,27,6,0,27,4,5,2,43,7,8,57,8,62,7,9,12,22,90,30,6,19,7,10,20,6,5,58, + 32,30,41,4,10,25,13,3,8,7,10,2,9,6,151,44,16,12,16,20,8,3,18,11,17,4,10,45, + 15,8,56,38,52,25,40,14,4,17,15,8,2,19,7,8,26,30,2,3,180,8,26,17,38,35,5,16, + 28,5,15,56,13,14,18,9,15,83,27,3,9,4,11,8,27,27,44,10,12,8,3,48,14,7,9,4,4, + 8,4,5,9,122,8,14,12,19,17,21,4,29,63,21,17,10,12,18,47,10,10,53,4,18,16,4,8, + 118,9,5,12,9,11,9,3,12,32,3,23,2,15,3,3,30,3,17,235,15,22,9,299,14,17,1,5, + 16,8,3,7,3,13,2,7,6,4,8,66,2,13,6,15,16,47,3,36,5,7,10,24,1,9,9,8,13,16,26, + 12,7,24,21,18,49,23,39,10,41,4,13,4,27,11,12,12,19,4,147,8,10,9,40,21,2,83, + 10,5,6,11,25,9,50,57,40,12,12,21,1,3,24,23,9,3,9,13,2,3,12,57,8,11,13,15,26, + 15,10,47,36,4,25,1,5,8,5,4,0,12,49,5,19,4,6,16,14,6,10,69,10,33,29,7,8,61, + 12,4,0,3,7,6,3,16,29,27,38,4,21,0,24,3,2,1,19,16,22,2,8,138,11,7,7,3,12,22, + 3,16,5,7,3,53,9,10,32,14,5,7,3,6,22,9,59,26,8,7,58,5,16,11,55,7,4,11,146,91, + 8,13,18,14,6,8,8,31,26,22,6,11,30,11,30,15,18,31,3,48,17,7,6,4,9,2,25,3,35, + 13,13,7,8,4,31,10,8,10,4,3,45,10,23,2,7,259,17,21,13,14,3,26,3,8,27,4,18,9, + 66,7,12,5,8,17,4,23,55,41,51,2,32,26,66,4,21,14,12,65,16,22,17,5,14,2,29,24, + 7,3,36,2,43,53,86,5,28,4,58,13,49,121,6,2,73,2,1,47,4,2,27,10,35,28,27,10, + 17,10,56,7,10,14,28,20,24,40,7,4,7,3,10,11,32,6,6,3,15,11,54,573,2,3,6,2,3, + 14,64,4,16,12,16,42,10,26,4,6,11,69,18,27,2,2,17,22,9,13,22,11,6,1,15,49,3, + 14,1 + }, + + { + 11,11,11,15,47,1,3,1,23,5,8,18,3,23,15,21,1,7,19,10,26,1,17,11,31,21,41,18, + 34,4,9,58,19,3,3,36,5,18,13,3,14,4,9,10,4,19,56,15,3,5,3,11,27,9,4,10,13,4, + 11,6,9,2,18,3,10,19,11,4,53,4,2,2,3,4,58,16,3,0,5,30,2,11,93,10,2,14,10,6,2, + 115,2,25,16,22,38,101,4,18,13,2,145,51,45,15,14,15,13,20,7,24,5,13,14,30,40, + 10,4,107,12,24,14,39,12,6,13,20,7,7,11,5,18,18,45,22,6,39,3,2,1,51,9,11,4, + 13,9,38,44,8,11,9,15,19,9,23,17,17,17,13,9,9,1,10,4,18,6,2,9,5,27,32,72,8, + 37,9,4,10,30,17,20,15,17,66,10,4,73,35,37,6,4,16,117,45,13,4,75,5,24,65,10, + 4,9,4,13,46,5,26,29,10,4,4,52,3,13,18,63,6,14,9,24,277,9,88,2,48,27,123,14, + 61,7,5,10,8,7,90,3,10,3,3,48,17,13,10,18,33,2,19,36,6,21,1,16,12,5,6,2,16, + 15,29,88,28,2,15,6,11,4,6,11,3,3,4,18,9,53,5,4,3,33,8,9,8,6,7,36,9,62,14,2, + 1,10,1,16,7,32,7,23,20,11,10,23,2,1,0,9,16,40,2,81,5,22,8,5,4,37,51,37,10, + 19,57,11,2,92,31,6,39,10,13,16,8,20,6,9,3,10,18,25,23,12,30,6,2,26,7,64,18, + 6,30,12,13,27,7,10,5,3,33,24,99,4,23,4,1,27,7,27,49,8,20,16,3,4,13,9,22,67, + 28,3,10,16,3,2,10,4,8,1,8,19,3,85,6,21,1,9,16,2,30,10,33,12,4,9,3,1,60,38,6, + 24,32,3,14,3,40,8,34,115,5,9,27,5,96,3,40,6,15,5,8,22,112,5,5,25,17,58,2,7, + 36,21,52,1,3,95,12,21,4,11,8,59,24,5,21,4,9,15,8,7,21,3,26,5,11,6,7,17,65, + 14,11,10,2,17,5,12,22,4,4,2,21,8,112,3,34,63,35,2,25,1,2,15,65,23,0,3,5,15, + 26,27,9,5,48,11,15,4,9,5,33,20,15,1,18,19,11,24,40,10,21,74,6,6,32,30,40,5, + 4,7,44,10,25,46,16,12,5,40,7,18,5,18,9,12,8,4,25,5,6,36,4,43,8,9,12,35,17,4, + 8,9,11,27,5,10,17,40,8,12,4,18,9,18,12,20,25,39,42,1,24,13,22,15,7,112,35,3, + 7,17,33,2,5,5,19,8,4,12,24,14,13,2,1,13,6,5,19,11,7,57,0,19,6,117,48,14,8, + 10,51,17,12,14,2,5,8,9,15,4,48,53,13,22,4,25,12,11,19,45,5,2,6,54,22,9,15,9, + 13,2,7,11,29,82,16,46,4,26,14,26,40,22,4,26,6,18,13,4,4,20,3,3,7,12,17,8,9, + 23,6,20,7,25,23,19,5,15,6,23,15,11,19,11,3,17,59,8,18,41,4,54,23,44,75,13, + 20,6,11,2,3,1,13,10,3,7,12,3,4,7,8,30,6,6,7,3,32,9,5,28,6,114,42,13,36,27, + 59,6,93,13,74,8,69,140,3,1,17,48,105,6,11,5,15,1,10,10,14,8,53,0,8,24,60,2, + 6,35,2,12,32,47,16,17,75,2,5,4,37,28,10,5,9,57,4,59,5,12,13,7,90,5,11,5,24, + 22,13,30,1,2,10,9,6,19,3,18,47,2,5,7,9,35,15,3,6,1,21,14,14,18,14,9,12,8,73, + 6,19,3,32,9,14,17,17,5,55,23,6,16,28,3,11,48,4,6,6,6,12,16,30,10,30,27,51, + 18,29,2,3,15,1,76,0,16,33,4,27,3,62,4,10,2,4,8,15,9,41,26,22,2,4,20,4,49,0, + 8,1,57,13,12,39,3,63,10,19,34,35,2,7,8,29,72,4,10,0,77,8,6,7,9,15,21,9,4,1, + 20,23,1,9,18,9,15,36,4,7,6,15,5,7,7,40,2,9,22,2,3,20,4,12,34,13,6,18,15,1, + 38,20,12,7,16,3,19,85,12,16,18,16,2,17,1,13,8,6,12,15,97,17,12,9,3,21,15,12, + 23,44,81,26,30,2,5,17,6,6,0,22,42,19,6,19,41,14,36,7,3,56,7,9,3,2,6,9,69,3, + 15,4,30,28,29,7,9,15,17,17,6,1,6,153,9,33,5,12,14,16,28,3,8,7,14,12,4,6,36, + 9,24,13,13,4,2,9,15,19,9,53,7,13,4,150,17,9,2,6,12,7,3,5,58,19,58,28,8,14,3, + 20,3,0,32,56,7,5,4,27,1,68,4,29,13,5,58,2,9,65,41,27,16,15,12,14,2,10,9,24, + 3,2,9,2,2,3,14,32,10,22,3,13,11,4,6,39,17,0,10,5,5,10,35,16,19,14,1,8,63,19, + 14,8,56,10,2,12,6,12,6,7,16,2,9,9,12,20,73,25,13,21,17,24,5,32,8,12,25,8,14, + 16,5,23,3,7,6,3,11,24,6,30,4,21,13,28,4,6,29,15,5,17,6,26,8,15,8,3,7,7,50, + 11,30,6,2,28,56,16,24,25,23,24,89,31,31,12,7,22,4,10,17,3,3,8,11,13,5,3,27, + 1,12,1,14,8,10,29,2,5,2,2,20,10,0,31,10,21,1,48,3,5,43,4,5,18,13,5,18,25,34, + 18,3,5,22,16,3,4,20,3,9,3,25,6,6,44,21,3,12,7,5,42,3,2,14,4,36,5,3,45,51,15, + 9,11,28,9,7,6,6,12,26,5,14,10,11,42,55,13,21,4,28,6,7,23,27,11,1,41,36,0,32, + 15,26,2,3,23,32,11,2,15,7,29,26,144,33,20,12,7,21,10,7,11,65,46,10,13,20,32, + 4,4,5,19,2,19,15,49,41,1,75,10,11,25,1,2,45,11,8,27,18,10,60,28,29,12,30,19, + 16,4,24,11,19,27,17,49,18,7,40,13,19,22,8,55,12,11,3,6,5,11,8,10,22,5,9,9, + 25,7,17,7,64,1,24,2,12,17,44,4,12,27,21,11,10,7,47,5,9,13,12,38,27,21,7,29, + 7,1,17,3,3,5,48,62,10,3,11,17,15,15,6,3,8,10,8,18,19,13,3,9,7,6,44,9,10,4, + 43,8,6,6,14,20,38,24,2,4,5,5,7,5,9,39,8,44,40,9,19,7,3,15,25,2,37,18,15,9,5, + 8,32,10,5,18,4,7,46,20,17,23,4,11,16,18,31,11,3,11,1,14,1,25,4,27,13,13,39, + 14,6,6,35,6,16,13,11,122,21,15,20,24,10,5,152,15,39,5,20,16,9,14,7,53,6,3,8, + 19,63,32,6,2,3,20,1,19,5,13,42,15,4,6,68,31,46,11,38,10,24,5,5,8,9,12,3,35, + 46,26,16,2,8,4,74,16,44,4,5,1,16,4,14,23,16,69,15,42,31,14,7,7,6,97,14,40,1, + 8,7,34,9,39,19,13,15,10,21,18,10,5,15,38,7,5,12,7,20,15,4,11,6,14,5,17,7,39, + 35,36,18,20,26,22,4,2,36,21,64,0,5,9,10,6,4,1,7,3,1,3,3,4,10,20,90,2,22,48, + 16,23,2,33,40,1,21,21,17,20,8,8,12,4,83,14,48,4,21,3,9,27,5,11,40,15,9,3,16, + 17,9,11,4,24,31,17,3,4,2,11,1,8,4,8,6,41,17,4,13,3,7,17,8,27,5,13,6,10,7,13, + 12,18,13,60,18,3,8,1,12,125,2,7,16,2,11,2,4,7,26,5,9,14,14,16,8,14,7,14,6,9, + 13,9,6,4,26,35,49,36,55,3,9,6,40,26,23,31,19,41,2,10,31,6,54,5,69,16,7,8,16, + 1,5,7,4,22,7,7,5,4,48,11,13,3,98,4,11,19,4,2,14,7,34,7,10,3,2,12,7,6,2,5,118 + }, +}; + +uint8_t data[1<<15]; +string data_str; +void init_data() { + static bool initted = false; + if (initted) return; + initted = true; + + // Repeatability. Kind of. + std::srand(42); + for (int i = 0; i < (int)(sizeof(data)/sizeof(data[0])); ++i) { + data[i] = (uint8_t)rand(); + } + + data_str.assign((char*)data, sizeof(data)); +} + + +BOOST_AUTO_TEST_SUITE( TBufferBaseTest ) + +BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_GetBuffer ) { + init_data(); + + for (int d1 = 0; d1 < 3; d1++) { + TMemoryBuffer buffer(16); + int offset = 0; + int index = 0; + + while (offset < 1<<15) { + buffer.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + string output = buffer.getBufferAsString(); + BOOST_CHECK_EQUAL(data_str, output); + } +} + +BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read ) { + init_data(); + + for (int d1 = 0; d1 < 3; d1++) { + for (int d2 = 0; d2 < 3; d2++) { + TMemoryBuffer buffer(16); + uint8_t data_out[1<<15]; + int offset; + int index; + + offset = 0; + index = 0; + while (offset < 1<<15) { + buffer.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + offset = 0; + index = 0; + while (offset < 1<<15) { + unsigned int got = buffer.read(&data_out[offset], dist[d2][index]); + BOOST_CHECK_EQUAL(got, dist[d2][index]); + offset += dist[d2][index]; + index++; + } + + BOOST_CHECK(!memcmp(data, data_out, sizeof(data))); + } + } +} + +BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_ReadString ) { + init_data(); + + for (int d1 = 0; d1 < 3; d1++) { + for (int d2 = 0; d2 < 3; d2++) { + TMemoryBuffer buffer(16); + string output; + int offset; + int index; + + offset = 0; + index = 0; + while (offset < 1<<15) { + buffer.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + offset = 0; + index = 0; + while (offset < 1<<15) { + unsigned int got = buffer.readAppendToString(output, dist[d2][index]); + BOOST_CHECK_EQUAL(got, dist[d2][index]); + offset += dist[d2][index]; + index++; + } + + BOOST_CHECK_EQUAL(output, data_str); + } + } +} + +BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read_Multi1 ) { + init_data(); + + // Do shorter writes and reads so we don't align to power-of-two boundaries. + + for (int d1 = 0; d1 < 3; d1++) { + for (int d2 = 0; d2 < 3; d2++) { + TMemoryBuffer buffer(16); + uint8_t data_out[1<<15]; + int offset; + int index; + + for (int iter = 0; iter < 6; iter++) { + offset = 0; + index = 0; + while (offset < (1<<15)-42) { + buffer.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + offset = 0; + index = 0; + while (offset < (1<<15)-42) { + buffer.read(&data_out[offset], dist[d2][index]); + offset += dist[d2][index]; + index++; + } + + BOOST_CHECK(!memcmp(data, data_out, (1<<15)-42)); + + // Pull out the extra data. + buffer.read(data_out, 42); + } + } + } +} + +BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read_Multi2 ) { + init_data(); + + // Do shorter writes and reads so we don't align to power-of-two boundaries. + // Pull the buffer out of the loop so its state gets worked harder. + TMemoryBuffer buffer(16); + + for (int d1 = 0; d1 < 3; d1++) { + for (int d2 = 0; d2 < 3; d2++) { + uint8_t data_out[1<<15]; + int offset; + int index; + + for (int iter = 0; iter < 6; iter++) { + offset = 0; + index = 0; + while (offset < (1<<15)-42) { + buffer.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + offset = 0; + index = 0; + while (offset < (1<<15)-42) { + buffer.read(&data_out[offset], dist[d2][index]); + offset += dist[d2][index]; + index++; + } + + BOOST_CHECK(!memcmp(data, data_out, (1<<15)-42)); + + // Pull out the extra data. + buffer.read(data_out, 42); + } + } + } +} + +BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read_Incomplete ) { + init_data(); + + // Do shorter writes and reads so we don't align to power-of-two boundaries. + // Pull the buffer out of the loop so its state gets worked harder. + + for (int d1 = 0; d1 < 3; d1++) { + for (int d2 = 0; d2 < 3; d2++) { + TMemoryBuffer buffer(16); + uint8_t data_out[1<<13]; + + int write_offset = 0; + int write_index = 0; + unsigned int to_write = (1<<14)-42; + while (to_write > 0) { + int write_amt = std::min(dist[d1][write_index], to_write); + buffer.write(&data[write_offset], write_amt); + write_offset += write_amt; + write_index++; + to_write -= write_amt; + } + + int read_offset = 0; + int read_index = 0; + unsigned int to_read = (1<<13)-42; + while (to_read > 0) { + int read_amt = std::min(dist[d2][read_index], to_read); + int got = buffer.read(&data_out[read_offset], read_amt); + BOOST_CHECK_EQUAL(got, read_amt); + read_offset += read_amt; + read_index++; + to_read -= read_amt; + } + + BOOST_CHECK(!memcmp(data, data_out, (1<<13)-42)); + + int second_offset = write_offset; + int second_index = write_index-1; + unsigned int to_second = (1<<14)+42; + while (to_second > 0) { + int second_amt = std::min(dist[d1][second_index], to_second); + //printf("%d\n", second_amt); + buffer.write(&data[second_offset], second_amt); + second_offset += second_amt; + second_index++; + to_second -= second_amt; + } + + string output = buffer.getBufferAsString(); + BOOST_CHECK_EQUAL(data_str.substr((1<<13)-42), output); + } + } +} + +BOOST_AUTO_TEST_CASE( test_BufferedTransport_Write ) { + init_data(); + + int sizes[] = { + 12, 15, 16, 17, 20, + 501, 512, 523, + 2000, 2048, 2096, + 1<<14, 1<<17, + }; + + foreach (int size, sizes) { + for (int d1 = 0; d1 < 3; d1++) { + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16)); + TBufferedTransport trans(buffer, size); + + int offset = 0; + int index = 0; + while (offset < 1<<15) { + trans.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + trans.flush(); + + string output = buffer->getBufferAsString(); + BOOST_CHECK_EQUAL(data_str, output); + } + } +} + +BOOST_AUTO_TEST_CASE( test_BufferedTransport_Read_Full ) { + init_data(); + + int sizes[] = { + 12, 15, 16, 17, 20, + 501, 512, 523, + 2000, 2048, 2096, + 1<<14, 1<<17, + }; + + foreach (int size, sizes) { + for (int d1 = 0; d1 < 3; d1++) { + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(data, sizeof(data))); + TBufferedTransport trans(buffer, size); + uint8_t data_out[1<<15]; + + int offset = 0; + int index = 0; + while (offset < 1<<15) { + // Note: this doesn't work with "read" because TBufferedTransport + // doesn't try loop over reads, so we get short reads. We don't + // check the return value, so that messes us up. + trans.readAll(&data_out[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + BOOST_CHECK(!memcmp(data, data_out, sizeof(data))); + } + } +} + +BOOST_AUTO_TEST_CASE( test_BufferedTransport_Read_Short ) { + init_data(); + + int sizes[] = { + 12, 15, 16, 17, 20, + 501, 512, 523, + 2000, 2048, 2096, + 1<<14, 1<<17, + }; + + foreach (int size, sizes) { + for (int d1 = 0; d1 < 3; d1++) { + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(data, sizeof(data))); + shared_ptr<TShortReadTransport> tshort(new TShortReadTransport(buffer, 0.125)); + TBufferedTransport trans(buffer, size); + uint8_t data_out[1<<15]; + + int offset = 0; + int index = 0; + while (offset < 1<<15) { + // Note: this doesn't work with "read" because TBufferedTransport + // doesn't try loop over reads, so we get short reads. We don't + // check the return value, so that messes us up. + trans.readAll(&data_out[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + BOOST_CHECK(!memcmp(data, data_out, sizeof(data))); + } + } +} + +BOOST_AUTO_TEST_CASE( test_FramedTransport_Write ) { + init_data(); + + int sizes[] = { + 12, 15, 16, 17, 20, + 501, 512, 523, + 2000, 2048, 2096, + 1<<14, 1<<17, + }; + + foreach (int size, sizes) { + for (int d1 = 0; d1 < 3; d1++) { + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16)); + TFramedTransport trans(buffer, size); + + int offset = 0; + int index = 0; + while (offset < 1<<15) { + trans.write(&data[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + trans.flush(); + + int32_t frame_size = -1; + buffer->read(reinterpret_cast<uint8_t*>(&frame_size), sizeof(frame_size)); + frame_size = (int32_t)ntohl((uint32_t)frame_size); + BOOST_CHECK_EQUAL(frame_size, 1<<15); + BOOST_CHECK_EQUAL(data_str.size(), (unsigned int)frame_size); + string output = buffer->getBufferAsString(); + BOOST_CHECK_EQUAL(data_str, output); + } + } +} + +BOOST_AUTO_TEST_CASE( test_FramedTransport_Read ) { + init_data(); + + for (int d1 = 0; d1 < 3; d1++) { + uint8_t data_out[1<<15]; + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); + TFramedTransport trans(buffer); + int32_t length = sizeof(data); + length = (int32_t)htonl((uint32_t)length); + buffer->write(reinterpret_cast<uint8_t*>(&length), sizeof(length)); + buffer->write(data, sizeof(data)); + + int offset = 0; + int index = 0; + while (offset < 1<<15) { + // This should work with read because we have one huge frame. + trans.read(&data_out[offset], dist[d1][index]); + offset += dist[d1][index]; + index++; + } + + BOOST_CHECK(!memcmp(data, data_out, sizeof(data))); + } +} + +BOOST_AUTO_TEST_CASE( test_FramedTransport_Write_Read ) { + init_data(); + + int sizes[] = { + 12, 15, 16, 17, 20, + 501, 512, 523, + 2000, 2048, 2096, + 1<<14, 1<<17, + }; + + int probs[] = { 1, 2, 4, 8, 16, 32, }; + + foreach (int size, sizes) { + foreach (int prob, probs) { + for (int d1 = 0; d1 < 3; d1++) { + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16)); + TFramedTransport trans(buffer, size); + uint8_t data_out[1<<15]; + std::vector<int> flush_sizes; + + int write_offset = 0; + int write_index = 0; + int flush_size = 0; + while (write_offset < 1<<15) { + trans.write(&data[write_offset], dist[d1][write_index]); + write_offset += dist[d1][write_index]; + flush_size += dist[d1][write_index]; + write_index++; + if (flush_size > 0 && rand()%prob == 0) { + flush_sizes.push_back(flush_size); + flush_size = 0; + trans.flush(); + } + } + if (flush_size != 0) { + flush_sizes.push_back(flush_size); + flush_size = 0; + trans.flush(); + } + + int read_offset = 0; + int read_index = 0; + foreach (int fsize, flush_sizes) { + // We are exploiting an implementation detail of TFramedTransport. + // The read buffer starts empty and it will never do more than one + // readFrame per read, so we should always get exactly one frame. + int got = trans.read(&data_out[read_offset], 1<<15); + BOOST_CHECK_EQUAL(got, fsize); + read_offset += got; + read_index++; + } + + BOOST_CHECK_EQUAL((unsigned int)read_offset, sizeof(data)); + BOOST_CHECK(!memcmp(data, data_out, sizeof(data))); + } + } + } +} + +BOOST_AUTO_TEST_CASE( test_FramedTransport_Empty_Flush ) { + init_data(); + + string output1("\x00\x00\x00\x01""a", 5); + string output2("\x00\x00\x00\x01""a\x00\x00\x00\x02""bc", 11); + + shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); + TFramedTransport trans(buffer); + + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), ""); + trans.flush(); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), ""); + trans.flush(); + trans.flush(); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), ""); + trans.write((const uint8_t*)"a", 1); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), ""); + trans.flush(); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output1); + trans.flush(); + trans.flush(); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output1); + trans.write((const uint8_t*)"bc", 2); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output1); + trans.flush(); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output2); + trans.flush(); + trans.flush(); + BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/TFDTransportTest.cpp b/test/TFDTransportTest.cpp new file mode 100644 index 000000000..1ec538e3a --- /dev/null +++ b/test/TFDTransportTest.cpp @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <cstdlib> +#include <stdexcept> +#include <Thrift.h> +#include <transport/TFDTransport.h> +using apache::thrift::transport::TTransportException; +using apache::thrift::transport::TFDTransport; + +class DummyException : std::exception { +}; + +int main() { + { + TFDTransport t(256, TFDTransport::NO_CLOSE_ON_DESTROY); + } + + try { + { + TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY); + } + std::abort(); + } catch (TTransportException) { + } + + try { + { + TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY); + throw DummyException(); + } + std::abort(); + } catch (TTransportException&) { + abort(); + } catch (DummyException&) { + } + + return 0; + +} diff --git a/test/TMemoryBufferTest.cpp b/test/TMemoryBufferTest.cpp new file mode 100644 index 000000000..49bd10b5d --- /dev/null +++ b/test/TMemoryBufferTest.cpp @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <boost/test/unit_test.hpp> +#include <iostream> +#include <climits> +#include <cassert> +#include <transport/TBufferTransports.h> +#include <protocol/TBinaryProtocol.h> +#include "gen-cpp/ThriftTest_types.h" + +BOOST_AUTO_TEST_SUITE( TMemoryBufferTest ) + +BOOST_AUTO_TEST_CASE( test_roundtrip ) { + using apache::thrift::transport::TMemoryBuffer; + using apache::thrift::protocol::TBinaryProtocol; + using boost::shared_ptr; + + shared_ptr<TMemoryBuffer> strBuffer(new TMemoryBuffer()); + shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(strBuffer)); + + thrift::test::Xtruct a; + a.i32_thing = 10; + a.i64_thing = 30; + a.string_thing ="holla back a"; + + a.write(binaryProtcol.get()); + std::string serialized = strBuffer->getBufferAsString(); + + shared_ptr<TMemoryBuffer> strBuffer2(new TMemoryBuffer()); + shared_ptr<TBinaryProtocol> binaryProtcol2(new TBinaryProtocol(strBuffer2)); + + strBuffer2->resetBuffer((uint8_t*)serialized.data(), serialized.length()); + thrift::test::Xtruct a2; + a2.read(binaryProtcol2.get()); + + assert(a == a2); + } + +BOOST_AUTO_TEST_CASE( test_copy ) + { + using apache::thrift::transport::TMemoryBuffer; + using std::string; + using std::cout; + using std::endl; + + string* str1 = new string("abcd1234"); + const char* data1 = str1->data(); + TMemoryBuffer buf((uint8_t*)str1->data(), str1->length(), TMemoryBuffer::COPY); + delete str1; + string* str2 = new string("plsreuse"); + bool obj_reuse = (str1 == str2); + bool dat_reuse = (data1 == str2->data()); + cout << "Object reuse: " << obj_reuse << " Data reuse: " << dat_reuse + << ((obj_reuse && dat_reuse) ? " YAY!" : "") << endl; + delete str2; + + string str3 = "wxyz", str4 = "6789"; + buf.readAppendToString(str3, 4); + buf.readAppendToString(str4, INT_MAX); + + assert(str3 == "wxyzabcd"); + assert(str4 == "67891234"); + } + +BOOST_AUTO_TEST_CASE( test_exceptions ) + { + using apache::thrift::transport::TTransportException; + using apache::thrift::transport::TMemoryBuffer; + using std::string; + + char data[] = "foo\0bar"; + + TMemoryBuffer buf1((uint8_t*)data, 7, TMemoryBuffer::OBSERVE); + string str = buf1.getBufferAsString(); + assert(str.length() == 7); + buf1.resetBuffer(); + try { + buf1.write((const uint8_t*)"foo", 3); + assert(false); + } catch (TTransportException& ex) {} + + TMemoryBuffer buf2((uint8_t*)data, 7, TMemoryBuffer::COPY); + try { + buf2.write((const uint8_t*)"bar", 3); + } catch (TTransportException& ex) { + assert(false); + } + } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/TPipedTransportTest.cpp b/test/TPipedTransportTest.cpp new file mode 100644 index 000000000..5708fd21c --- /dev/null +++ b/test/TPipedTransportTest.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <cstdlib> +#include <stdexcept> +#include <Thrift.h> +#include <transport/TTransportUtils.h> +#include <transport/TBufferTransports.h> +using namespace std; +using boost::shared_ptr; +using apache::thrift::transport::TTransportException; +using apache::thrift::transport::TPipedTransport; +using apache::thrift::transport::TMemoryBuffer; + +int main() { + shared_ptr<TMemoryBuffer> underlying(new TMemoryBuffer); + shared_ptr<TMemoryBuffer> pipe(new TMemoryBuffer); + shared_ptr<TPipedTransport> trans(new TPipedTransport(underlying, pipe)); + + uint8_t buffer[4]; + + underlying->write((uint8_t*)"abcd", 4); + trans->readAll(buffer, 2); + assert( string((char*)buffer, 2) == "ab" ); + trans->readEnd(); + assert( pipe->getBufferAsString() == "ab" ); + pipe->resetBuffer(); + underlying->write((uint8_t*)"ef", 2); + trans->readAll(buffer, 2); + assert( string((char*)buffer, 2) == "cd" ); + trans->readAll(buffer, 2); + assert( string((char*)buffer, 2) == "ef" ); + trans->readEnd(); + assert( pipe->getBufferAsString() == "cdef" ); + + return 0; + +} diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift new file mode 100644 index 000000000..3517640a6 --- /dev/null +++ b/test/ThriftTest.thrift @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace java thrift.test +namespace cpp thrift.test +namespace rb Thrift.Test +namespace perl ThriftTest +namespace csharp Thrift.Test + +enum Numberz +{ + ONE = 1, + TWO, + THREE, + FIVE = 5, + SIX, + EIGHT = 8 +} + +typedef i64 UserId + +struct Bonk +{ + 1: string message, + 2: i32 type +} + +struct Bools { + 1: bool im_true, + 2: bool im_false, +} + +struct Xtruct +{ + 1: string string_thing, + 4: byte byte_thing, + 9: i32 i32_thing, + 11: i64 i64_thing +} + +struct Xtruct2 +{ + 1: byte byte_thing, + 2: Xtruct struct_thing, + 3: i32 i32_thing +} + +struct Xtruct3 +{ + 1: string string_thing, + 4: i32 changed, + 9: i32 i32_thing, + 11: i64 i64_thing +} + + +struct Insanity +{ + 1: map<Numberz, UserId> userMap, + 2: list<Xtruct> xtructs +} + +struct CrazyNesting { + 1: string string_field, + 2: optional set<Insanity> set_field, + 3: required list< map<set<i32>,map<i32,set<list<map<Insanity,string>>>>>> list_field +} + +exception Xception { + 1: i32 errorCode, + 2: string message +} + +exception Xception2 { + 1: i32 errorCode, + 2: Xtruct struct_thing +} + +struct EmptyStruct {} + +struct OneField { + 1: EmptyStruct field +} + +service ThriftTest +{ + void testVoid(), + string testString(1: string thing), + byte testByte(1: byte thing), + i32 testI32(1: i32 thing), + i64 testI64(1: i64 thing), + double testDouble(1: double thing), + Xtruct testStruct(1: Xtruct thing), + Xtruct2 testNest(1: Xtruct2 thing), + map<i32,i32> testMap(1: map<i32,i32> thing), + set<i32> testSet(1: set<i32> thing), + list<i32> testList(1: list<i32> thing), + Numberz testEnum(1: Numberz thing), + UserId testTypedef(1: UserId thing), + + map<i32,map<i32,i32>> testMapMap(1: i32 hello), + + /* So you think you've got this all worked, out eh? */ + map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument), + + /* Multiple parameters */ + Xtruct testMulti(1: byte arg0, 2: i32 arg1, 3: i64 arg2, 4: map<i16, string> arg3, 5: Numberz arg4, 6: UserId arg5), + + /* Exception specifier */ + + void testException(1: string arg) throws(1: Xception err1), + + /* Multiple exceptions specifier */ + + Xtruct testMultiException(1: string arg0, 2: string arg1) throws(1: Xception err1, 2: Xception2 err2) + + /* Test oneway void */ + oneway void testOneway(1:i32 secondsToSleep) +} + +service SecondService +{ + void blahBlah() +} + +struct VersioningTestV1 { + 1: i32 begin_in_both, + 3: string old_string, + 12: i32 end_in_both +} + +struct VersioningTestV2 { + 1: i32 begin_in_both, + + 2: i32 newint, + 3: byte newbyte, + 4: i16 newshort, + 5: i64 newlong, + 6: double newdouble + 7: Bonk newstruct, + 8: list<i32> newlist, + 9: set<i32> newset, + 10: map<i32, i32> newmap, + 11: string newstring, + 12: i32 end_in_both +} + +struct ListTypeVersioningV1 { + 1: list<i32> myints; + 2: string hello; +} + +struct ListTypeVersioningV2 { + 1: list<string> strings; + 2: string hello; +} diff --git a/test/ThriftTest_extras.cpp b/test/ThriftTest_extras.cpp new file mode 100644 index 000000000..b78f27635 --- /dev/null +++ b/test/ThriftTest_extras.cpp @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// Extra functions required for ThriftTest_types to work + +#include <protocol/TDebugProtocol.h> +#include "gen-cpp/ThriftTest_types.h" + + +namespace thrift { namespace test { + +bool Insanity::operator<(thrift::test::Insanity const& other) const { + using apache::thrift::ThriftDebugString; + return ThriftDebugString(*this) < ThriftDebugString(other); +} + +}} diff --git a/test/UnitTestMain.cpp b/test/UnitTestMain.cpp new file mode 100644 index 000000000..d90c54f48 --- /dev/null +++ b/test/UnitTestMain.cpp @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#define BOOST_TEST_MODULE thrift +#include <boost/test/included/unit_test.hpp> diff --git a/test/ZlibTest.cpp b/test/ZlibTest.cpp new file mode 100644 index 000000000..45d3ecc4b --- /dev/null +++ b/test/ZlibTest.cpp @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +/* +thrift --gen cpp DebugProtoTest.thrift +g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ + ZlibTest.cpp \ + ../lib/cpp/.libs/libthriftz.a ../lib/cpp/.libs/libthrift.a \ + -lz -o ZlibTest +./ZlibTest +*/ + +#include <cstddef> +#include <cassert> +#include <fstream> +#include <iostream> +#include <transport/TBufferTransports.h> +#include <transport/TZlibTransport.h> + + +// Distributions of reads and writes meant to approximate a real load, +// mixing up small and large while also hitting various boundary conditions. +// Generated by Python: int(random.lognormvariate(2.5, 1)) +unsigned int dist[][5000] = { + { 1<<15 }, + + { + 5,13,9,1,8,9,11,13,18,48,24,13,21,13,5,11,35,2,4,20,17,72,27,14,15,4,7,26, + 12,1,14,9,2,16,29,41,7,24,4,27,14,4,1,4,25,3,6,34,10,8,50,2,14,13,55,29,3, + 43,53,49,14,4,10,32,27,48,1,3,1,11,5,17,16,51,17,30,15,11,9,2,2,11,52,12,2, + 13,94,1,19,1,38,2,8,43,8,33,7,30,8,17,22,2,15,14,12,34,2,12,6,37,29,74,3, + 165,16,11,17,5,14,3,10,7,37,11,24,7,1,3,12,37,8,9,34,17,12,8,21,13,37,1,4, + 30,14,78,4,15,2,40,37,17,12,36,82,14,4,1,4,7,17,11,16,88,77,2,3,15,3,34,11, + 5,79,22,34,8,4,4,40,22,24,28,9,13,3,34,27,9,16,39,16,39,13,2,4,3,41,26,10,4, + 33,4,7,12,5,6,3,10,30,8,21,16,58,19,9,0,47,7,13,11,19,15,7,53,57,2,13,28,22, + 3,16,9,25,33,12,40,7,12,64,7,14,24,44,9,2,14,11,2,58,1,26,30,11,9,5,24,7,9, + 94,2,10,21,5,5,4,5,6,179,9,18,2,7,13,31,41,17,4,36,3,21,6,26,8,15,18,44,27, + 11,9,25,7,0,14,2,12,20,23,13,2,163,9,5,15,65,2,14,6,8,98,11,15,14,34,2,3,10, + 22,9,92,7,10,32,67,13,3,4,35,8,2,1,5,0,26,381,7,27,8,2,16,93,4,19,5,8,25,9, + 31,14,4,21,5,3,9,22,56,4,18,3,11,18,6,4,3,40,12,16,110,8,35,14,1,18,40,9,12, + 14,3,11,7,57,13,18,116,53,19,22,7,16,11,5,8,21,16,1,75,21,20,1,28,2,6,1,7, + 19,38,5,6,9,9,4,1,7,55,36,62,5,4,4,24,15,1,12,35,48,20,5,17,1,5,26,15,4,54, + 13,5,5,15,5,19,32,29,31,7,6,40,7,80,11,18,8,128,48,6,12,84,13,4,7,2,13,9,16, + 17,3,254,1,4,181,8,44,7,6,24,27,9,23,14,34,16,22,25,10,3,3,4,4,12,2,12,6,7, + 13,58,13,6,11,19,53,11,66,18,19,10,4,13,2,5,49,58,1,67,7,21,64,14,11,14,8,3, + 26,33,91,31,20,7,9,42,39,4,3,55,11,10,0,7,4,75,8,12,0,27,3,8,9,0,12,12,23, + 28,23,20,4,13,30,2,22,20,19,30,6,22,2,6,4,24,7,19,55,86,5,33,2,161,6,7,1,62, + 13,3,72,12,12,9,7,12,10,5,10,29,1,5,22,13,13,5,2,12,3,7,14,18,2,3,46,21,17, + 15,19,3,27,5,16,45,31,10,8,17,18,18,3,7,24,6,55,9,3,6,12,10,12,8,91,9,4,4,4, + 27,29,16,5,7,22,43,28,11,14,8,11,28,109,55,71,40,3,8,22,26,15,44,3,25,29,5, + 3,32,17,12,3,29,27,25,15,11,8,40,39,38,17,3,9,11,2,32,11,6,20,48,75,27,3,7, + 54,12,95,12,7,24,23,2,13,8,15,16,5,12,4,17,7,19,88,2,6,13,115,45,12,21,2,86, + 74,9,7,5,16,32,16,2,21,18,6,34,5,18,260,7,12,16,44,19,92,31,7,8,2,9,0,0,15, + 8,38,4,8,20,18,2,83,3,3,4,9,5,3,10,3,5,29,15,7,11,8,48,17,23,2,17,4,11,22, + 21,64,8,8,4,19,95,0,17,28,9,11,20,71,5,11,18,12,13,45,49,4,1,33,32,23,13,5, + 52,2,2,16,3,4,7,12,2,1,12,6,24,1,22,155,21,3,45,4,12,44,26,5,40,36,9,9,8,20, + 35,31,3,2,32,50,10,8,37,2,75,35,22,15,192,8,11,23,1,4,29,6,8,8,5,12,18,32,4, + 7,12,2,0,0,9,5,48,11,35,3,1,123,6,29,8,11,8,23,51,16,6,63,12,2,5,4,14,2,15, + 7,14,3,2,7,17,32,8,8,10,1,23,62,2,49,6,49,47,23,3,20,7,11,39,10,24,6,15,5,5, + 11,8,16,36,8,13,20,3,10,44,7,52,7,10,36,6,15,10,5,11,4,14,19,17,10,12,3,6, + 23,4,13,94,70,7,36,7,38,7,28,8,4,15,3,19,4,33,39,21,109,4,80,6,40,4,432,4,4, + 7,8,3,31,8,28,37,34,10,2,21,5,22,0,7,36,14,12,6,24,1,21,5,9,2,29,20,54,113, + 13,31,39,27,6,0,27,4,5,2,43,7,8,57,8,62,7,9,12,22,90,30,6,19,7,10,20,6,5,58, + 32,30,41,4,10,25,13,3,8,7,10,2,9,6,151,44,16,12,16,20,8,3,18,11,17,4,10,45, + 15,8,56,38,52,25,40,14,4,17,15,8,2,19,7,8,26,30,2,3,180,8,26,17,38,35,5,16, + 28,5,15,56,13,14,18,9,15,83,27,3,9,4,11,8,27,27,44,10,12,8,3,48,14,7,9,4,4, + 8,4,5,9,122,8,14,12,19,17,21,4,29,63,21,17,10,12,18,47,10,10,53,4,18,16,4,8, + 118,9,5,12,9,11,9,3,12,32,3,23,2,15,3,3,30,3,17,235,15,22,9,299,14,17,1,5, + 16,8,3,7,3,13,2,7,6,4,8,66,2,13,6,15,16,47,3,36,5,7,10,24,1,9,9,8,13,16,26, + 12,7,24,21,18,49,23,39,10,41,4,13,4,27,11,12,12,19,4,147,8,10,9,40,21,2,83, + 10,5,6,11,25,9,50,57,40,12,12,21,1,3,24,23,9,3,9,13,2,3,12,57,8,11,13,15,26, + 15,10,47,36,4,25,1,5,8,5,4,0,12,49,5,19,4,6,16,14,6,10,69,10,33,29,7,8,61, + 12,4,0,3,7,6,3,16,29,27,38,4,21,0,24,3,2,1,19,16,22,2,8,138,11,7,7,3,12,22, + 3,16,5,7,3,53,9,10,32,14,5,7,3,6,22,9,59,26,8,7,58,5,16,11,55,7,4,11,146,91, + 8,13,18,14,6,8,8,31,26,22,6,11,30,11,30,15,18,31,3,48,17,7,6,4,9,2,25,3,35, + 13,13,7,8,4,31,10,8,10,4,3,45,10,23,2,7,259,17,21,13,14,3,26,3,8,27,4,18,9, + 66,7,12,5,8,17,4,23,55,41,51,2,32,26,66,4,21,14,12,65,16,22,17,5,14,2,29,24, + 7,3,36,2,43,53,86,5,28,4,58,13,49,121,6,2,73,2,1,47,4,2,27,10,35,28,27,10, + 17,10,56,7,10,14,28,20,24,40,7,4,7,3,10,11,32,6,6,3,15,11,54,573,2,3,6,2,3, + 14,64,4,16,12,16,42,10,26,4,6,11,69,18,27,2,2,17,22,9,13,22,11,6,1,15,49,3, + 14,1 + }, + + { + 11,11,11,15,47,1,3,1,23,5,8,18,3,23,15,21,1,7,19,10,26,1,17,11,31,21,41,18, + 34,4,9,58,19,3,3,36,5,18,13,3,14,4,9,10,4,19,56,15,3,5,3,11,27,9,4,10,13,4, + 11,6,9,2,18,3,10,19,11,4,53,4,2,2,3,4,58,16,3,0,5,30,2,11,93,10,2,14,10,6,2, + 115,2,25,16,22,38,101,4,18,13,2,145,51,45,15,14,15,13,20,7,24,5,13,14,30,40, + 10,4,107,12,24,14,39,12,6,13,20,7,7,11,5,18,18,45,22,6,39,3,2,1,51,9,11,4, + 13,9,38,44,8,11,9,15,19,9,23,17,17,17,13,9,9,1,10,4,18,6,2,9,5,27,32,72,8, + 37,9,4,10,30,17,20,15,17,66,10,4,73,35,37,6,4,16,117,45,13,4,75,5,24,65,10, + 4,9,4,13,46,5,26,29,10,4,4,52,3,13,18,63,6,14,9,24,277,9,88,2,48,27,123,14, + 61,7,5,10,8,7,90,3,10,3,3,48,17,13,10,18,33,2,19,36,6,21,1,16,12,5,6,2,16, + 15,29,88,28,2,15,6,11,4,6,11,3,3,4,18,9,53,5,4,3,33,8,9,8,6,7,36,9,62,14,2, + 1,10,1,16,7,32,7,23,20,11,10,23,2,1,0,9,16,40,2,81,5,22,8,5,4,37,51,37,10, + 19,57,11,2,92,31,6,39,10,13,16,8,20,6,9,3,10,18,25,23,12,30,6,2,26,7,64,18, + 6,30,12,13,27,7,10,5,3,33,24,99,4,23,4,1,27,7,27,49,8,20,16,3,4,13,9,22,67, + 28,3,10,16,3,2,10,4,8,1,8,19,3,85,6,21,1,9,16,2,30,10,33,12,4,9,3,1,60,38,6, + 24,32,3,14,3,40,8,34,115,5,9,27,5,96,3,40,6,15,5,8,22,112,5,5,25,17,58,2,7, + 36,21,52,1,3,95,12,21,4,11,8,59,24,5,21,4,9,15,8,7,21,3,26,5,11,6,7,17,65, + 14,11,10,2,17,5,12,22,4,4,2,21,8,112,3,34,63,35,2,25,1,2,15,65,23,0,3,5,15, + 26,27,9,5,48,11,15,4,9,5,33,20,15,1,18,19,11,24,40,10,21,74,6,6,32,30,40,5, + 4,7,44,10,25,46,16,12,5,40,7,18,5,18,9,12,8,4,25,5,6,36,4,43,8,9,12,35,17,4, + 8,9,11,27,5,10,17,40,8,12,4,18,9,18,12,20,25,39,42,1,24,13,22,15,7,112,35,3, + 7,17,33,2,5,5,19,8,4,12,24,14,13,2,1,13,6,5,19,11,7,57,0,19,6,117,48,14,8, + 10,51,17,12,14,2,5,8,9,15,4,48,53,13,22,4,25,12,11,19,45,5,2,6,54,22,9,15,9, + 13,2,7,11,29,82,16,46,4,26,14,26,40,22,4,26,6,18,13,4,4,20,3,3,7,12,17,8,9, + 23,6,20,7,25,23,19,5,15,6,23,15,11,19,11,3,17,59,8,18,41,4,54,23,44,75,13, + 20,6,11,2,3,1,13,10,3,7,12,3,4,7,8,30,6,6,7,3,32,9,5,28,6,114,42,13,36,27, + 59,6,93,13,74,8,69,140,3,1,17,48,105,6,11,5,15,1,10,10,14,8,53,0,8,24,60,2, + 6,35,2,12,32,47,16,17,75,2,5,4,37,28,10,5,9,57,4,59,5,12,13,7,90,5,11,5,24, + 22,13,30,1,2,10,9,6,19,3,18,47,2,5,7,9,35,15,3,6,1,21,14,14,18,14,9,12,8,73, + 6,19,3,32,9,14,17,17,5,55,23,6,16,28,3,11,48,4,6,6,6,12,16,30,10,30,27,51, + 18,29,2,3,15,1,76,0,16,33,4,27,3,62,4,10,2,4,8,15,9,41,26,22,2,4,20,4,49,0, + 8,1,57,13,12,39,3,63,10,19,34,35,2,7,8,29,72,4,10,0,77,8,6,7,9,15,21,9,4,1, + 20,23,1,9,18,9,15,36,4,7,6,15,5,7,7,40,2,9,22,2,3,20,4,12,34,13,6,18,15,1, + 38,20,12,7,16,3,19,85,12,16,18,16,2,17,1,13,8,6,12,15,97,17,12,9,3,21,15,12, + 23,44,81,26,30,2,5,17,6,6,0,22,42,19,6,19,41,14,36,7,3,56,7,9,3,2,6,9,69,3, + 15,4,30,28,29,7,9,15,17,17,6,1,6,153,9,33,5,12,14,16,28,3,8,7,14,12,4,6,36, + 9,24,13,13,4,2,9,15,19,9,53,7,13,4,150,17,9,2,6,12,7,3,5,58,19,58,28,8,14,3, + 20,3,0,32,56,7,5,4,27,1,68,4,29,13,5,58,2,9,65,41,27,16,15,12,14,2,10,9,24, + 3,2,9,2,2,3,14,32,10,22,3,13,11,4,6,39,17,0,10,5,5,10,35,16,19,14,1,8,63,19, + 14,8,56,10,2,12,6,12,6,7,16,2,9,9,12,20,73,25,13,21,17,24,5,32,8,12,25,8,14, + 16,5,23,3,7,6,3,11,24,6,30,4,21,13,28,4,6,29,15,5,17,6,26,8,15,8,3,7,7,50, + 11,30,6,2,28,56,16,24,25,23,24,89,31,31,12,7,22,4,10,17,3,3,8,11,13,5,3,27, + 1,12,1,14,8,10,29,2,5,2,2,20,10,0,31,10,21,1,48,3,5,43,4,5,18,13,5,18,25,34, + 18,3,5,22,16,3,4,20,3,9,3,25,6,6,44,21,3,12,7,5,42,3,2,14,4,36,5,3,45,51,15, + 9,11,28,9,7,6,6,12,26,5,14,10,11,42,55,13,21,4,28,6,7,23,27,11,1,41,36,0,32, + 15,26,2,3,23,32,11,2,15,7,29,26,144,33,20,12,7,21,10,7,11,65,46,10,13,20,32, + 4,4,5,19,2,19,15,49,41,1,75,10,11,25,1,2,45,11,8,27,18,10,60,28,29,12,30,19, + 16,4,24,11,19,27,17,49,18,7,40,13,19,22,8,55,12,11,3,6,5,11,8,10,22,5,9,9, + 25,7,17,7,64,1,24,2,12,17,44,4,12,27,21,11,10,7,47,5,9,13,12,38,27,21,7,29, + 7,1,17,3,3,5,48,62,10,3,11,17,15,15,6,3,8,10,8,18,19,13,3,9,7,6,44,9,10,4, + 43,8,6,6,14,20,38,24,2,4,5,5,7,5,9,39,8,44,40,9,19,7,3,15,25,2,37,18,15,9,5, + 8,32,10,5,18,4,7,46,20,17,23,4,11,16,18,31,11,3,11,1,14,1,25,4,27,13,13,39, + 14,6,6,35,6,16,13,11,122,21,15,20,24,10,5,152,15,39,5,20,16,9,14,7,53,6,3,8, + 19,63,32,6,2,3,20,1,19,5,13,42,15,4,6,68,31,46,11,38,10,24,5,5,8,9,12,3,35, + 46,26,16,2,8,4,74,16,44,4,5,1,16,4,14,23,16,69,15,42,31,14,7,7,6,97,14,40,1, + 8,7,34,9,39,19,13,15,10,21,18,10,5,15,38,7,5,12,7,20,15,4,11,6,14,5,17,7,39, + 35,36,18,20,26,22,4,2,36,21,64,0,5,9,10,6,4,1,7,3,1,3,3,4,10,20,90,2,22,48, + 16,23,2,33,40,1,21,21,17,20,8,8,12,4,83,14,48,4,21,3,9,27,5,11,40,15,9,3,16, + 17,9,11,4,24,31,17,3,4,2,11,1,8,4,8,6,41,17,4,13,3,7,17,8,27,5,13,6,10,7,13, + 12,18,13,60,18,3,8,1,12,125,2,7,16,2,11,2,4,7,26,5,9,14,14,16,8,14,7,14,6,9, + 13,9,6,4,26,35,49,36,55,3,9,6,40,26,23,31,19,41,2,10,31,6,54,5,69,16,7,8,16, + 1,5,7,4,22,7,7,5,4,48,11,13,3,98,4,11,19,4,2,14,7,34,7,10,3,2,12,7,6,2,5,118 + }, +}; + + +int main() { + using namespace std; + using namespace boost; + using namespace apache::thrift::transport; + + char *file_names[] = { + // Highly compressible. + "./gen-cpp/DebugProtoTest_types.cpp", + // Uncompressible. + "/dev/urandom", + // Null-terminated. + NULL, + }; + + + for (char** fnamep = &file_names[0]; *fnamep != NULL; fnamep++) { + ifstream file(*fnamep); + char buf[32*1024]; + file.read(buf, sizeof(buf)); + vector<uint8_t> content(buf, buf+file.gcount()); + vector<uint8_t> mirror; + file.close(); + + assert(content.size() == 32*1024); + + // Let's just start with the big dog! + { + mirror.clear(); + shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer()); + shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false)); + zlib_trans->write(&content[0], content.size()); + zlib_trans->flush(); + mirror.resize(content.size()); + uint32_t got = zlib_trans->read(&mirror[0], mirror.size()); + assert(got == content.size()); + assert(mirror == content); + zlib_trans->verifyChecksum(); + } + + // This one is tricky. I separate the last byte of the stream out + // into a separate crbuf_. The last byte is part of the checksum, + // so the entire read goes fine, but when I go to verify the checksum + // it isn't there. The original implementation complained that + // the stream was not complete. I'm about to go fix that. + // It worked. Awesome. + { + mirror.clear(); + shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer()); + shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false)); + zlib_trans->write(&content[0], content.size()); + zlib_trans->flush(); + string tmp_buf; + membuf->appendBufferToString(tmp_buf); + zlib_trans.reset(new TZlibTransport(membuf, false, + TZlibTransport::DEFAULT_URBUF_SIZE, + tmp_buf.length()-1)); + mirror.resize(content.size()); + uint32_t got = zlib_trans->read(&mirror[0], mirror.size()); + assert(got == content.size()); + assert(mirror == content); + zlib_trans->verifyChecksum(); + } + + // Make sure we still get that "not complete" error if + // it really isn't complete. + { + mirror.clear(); + shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer()); + shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false)); + zlib_trans->write(&content[0], content.size()); + zlib_trans->flush(); + string tmp_buf; + membuf->appendBufferToString(tmp_buf); + tmp_buf.erase(tmp_buf.length() - 1); + membuf->resetFromString(tmp_buf); + mirror.resize(content.size()); + uint32_t got = zlib_trans->read(&mirror[0], mirror.size()); + assert(got == content.size()); + assert(mirror == content); + try { + zlib_trans->verifyChecksum(); + assert(false); + } catch (TTransportException& ex) { + assert(ex.getType() == TTransportException::CORRUPTED_DATA); + } + } + + // Try it with a mix of read/write sizes. + for (int d1 = 0; d1 < 3; d1++) { + for (int d2 = 0; d2 < 3; d2++) { + mirror.clear(); + shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer()); + shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false)); + int idx; + unsigned int tot; + + idx = 0; + tot = 0; + while (tot < content.size()) { + zlib_trans->write(&content[tot], dist[d1][idx]); + tot += dist[d1][idx]; + idx++; + } + + zlib_trans->flush(); + mirror.resize(content.size()); + + idx = 0; + tot = 0; + while (tot < mirror.size()) { + uint32_t got = zlib_trans->read(&mirror[tot], dist[d2][idx]); + assert(got == dist[d2][idx]); + tot += dist[d2][idx]; + idx++; + } + + assert(mirror == content); + zlib_trans->verifyChecksum(); + } + } + + // Verify checksum checking. + { + mirror.clear(); + shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer()); + shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false)); + zlib_trans->write(&content[0], content.size()); + zlib_trans->flush(); + string tmp_buf; + membuf->appendBufferToString(tmp_buf); + tmp_buf[57]++; + membuf->resetFromString(tmp_buf); + mirror.resize(content.size()); + try { + zlib_trans->read(&mirror[0], mirror.size()); + zlib_trans->verifyChecksum(); + assert(false); + } catch (TZlibTransportException& ex) { + assert(ex.getType() == TTransportException::INTERNAL_ERROR); + } + } + } + + return 0; +} diff --git a/test/cpp/Stress-test.mk b/test/cpp/Stress-test.mk new file mode 100644 index 000000000..1a753b3a1 --- /dev/null +++ b/test/cpp/Stress-test.mk @@ -0,0 +1,71 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +ifndef thrift_home +thrift_home=../.. +endif #thrift_home + +target: all + +ifndef boost_home +#boost_home=../../../../../thirdparty/boost_1_33_1 +boost_home=/usr/local/include/boost-1_33_1 +endif #boost_home +target: all + +include_paths = $(thrift_home)/lib/cpp/src \ + $(thrift_home)/lib/cpp \ + $(thrift_home)/ \ + $(boost_home) + +include_flags = $(patsubst %,-I%, $(include_paths)) + +# Tools +ifndef THRIFT +THRIFT = ../../compiler/cpp/thrift +endif # THRIFT + +CC = g++ +LD = g++ + +# Compiler flags +DCFL = -Wall -O3 -g -I./gen-cpp $(include_flags) -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent +CFL = -Wall -O3 -I./gen-cpp $(include_flags) -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent + +all: stress-test stress-test-nb + +debug: stress-test-debug stress-test-debug-nb + +stubs: ../StressTest.thrift + $(THRIFT) --gen cpp --gen php ../StressTest.thrift + +stress-test-debug-nb: stubs + g++ -o stress-test-nb $(DCFL) src/nb-main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp + +stress-test-nb: stubs + g++ -o stress-test-nb $(CFL) src/nb-main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp + +stress-test-debug: stubs + g++ -o stress-test $(DCFL) src/main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp + +stress-test: stubs + g++ -o stress-test $(CFL) src/main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp + +clean: + rm -fr stress-test stress-test-nb gen-cpp diff --git a/test/cpp/Thrift-test.mk b/test/cpp/Thrift-test.mk new file mode 100644 index 000000000..fb3e38bc6 --- /dev/null +++ b/test/cpp/Thrift-test.mk @@ -0,0 +1,78 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +# Makefile for Thrift test project. +# Default target is everything + +ifndef thrift_home +thrift_home=../.. +endif #thrift_home + +target: all + +ifndef boost_home +#boost_home=../../../../../thirdparty/boost_1_33_1 +boost_home=/usr/local/include/boost-1_33_1 +endif #boost_home +target: all + +include_paths = $(thrift_home)/lib/cpp/src \ + $(boost_home) + +include_flags = $(patsubst %,-I%, $(include_paths)) + +# Tools +ifndef THRIFT +THRIFT = ../../compiler/cpp/thrift +endif # THRIFT + +CC = g++ +LD = g++ + +# Compiler flags +DCFL = -Wall -O3 -g -I. -I./gen-cpp $(include_flags) -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent +LFL = -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent +CCFL = -Wall -O3 -I. -I./gen-cpp $(include_flags) +CFL = $(CCFL) $(LFL) + +all: server client + +debug: server-debug client-debug + +stubs: ../ThriftTest.thrift + $(THRIFT) --gen cpp ../ThriftTest.thrift + +server-debug: stubs + g++ -o TestServer $(DCFL) src/TestServer.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp + +client-debug: stubs + g++ -o TestClient $(DCFL) src/TestClient.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp + +server: stubs + g++ -o TestServer $(CFL) src/TestServer.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp + +client: stubs + g++ -o TestClient $(CFL) src/TestClient.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp + +small: + $(THRIFT) --gen cpp ../SmallTest.thrift + g++ -c $(CCFL) ./gen-cpp/SmallService.cpp ./gen-cpp/SmallTest_types.cpp + +clean: + rm -fr *.o TestServer TestClient gen-cpp diff --git a/test/cpp/realloc/Makefile b/test/cpp/realloc/Makefile new file mode 100644 index 000000000..f89bbb3c5 --- /dev/null +++ b/test/cpp/realloc/Makefile @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +# This probably should not go into "make check", because it is an experiment, +# not a test. Specifically, it is meant to determine how likely realloc is +# to avoid a copy. This is poorly documented. + +run: realloc_test + for it in 1 4 64 ; do \ + for nb in 1 8 64 512 ; do \ + for mins in 64 512 ; do \ + for maxs in 2048 262144 ; do \ + for db in 8 64 ; do \ + ./realloc_test $$nb $$mins $$maxs $$db $$it \ + ; done \ + ; done \ + ; done \ + ; done \ + ; done \ + > raw_stats + +CFLAGS = -Wall -g -std=c99 +LDLIBS = -ldl +realloc_test: realloc_test.c diff --git a/test/cpp/realloc/realloc_test.c b/test/cpp/realloc/realloc_test.c new file mode 100644 index 000000000..f9763adf4 --- /dev/null +++ b/test/cpp/realloc/realloc_test.c @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <dlfcn.h> + +int copies; +int non_copies; + +void *realloc(void *ptr, size_t size) { + static void *(*real_realloc)(void*, size_t) = NULL; + if (real_realloc == NULL) { + real_realloc = (void* (*) (void*, size_t)) dlsym(RTLD_NEXT, "realloc"); + } + + void *ret_ptr = (*real_realloc)(ptr, size); + + if (ret_ptr == ptr) { + non_copies++; + } else { + copies++; + } + + return ret_ptr; +} + + +struct TMemoryBuffer { + void* ptr; + int size; +}; + +int main(int argc, char *argv[]) { + int num_buffers; + int init_size; + int max_size; + int doublings; + int iterations; + + if (argc < 6 || + argc > 7 || + (num_buffers = atoi(argv[1])) == 0 || + (init_size = atoi(argv[2])) == 0 || + (max_size = atoi(argv[3])) == 0 || + init_size > max_size || + (iterations = atoi(argv[4])) == 0 || + (doublings = atoi(argv[5])) == 0 || + (argc == 7 && atoi(argv[6]) == 0)) { + fprintf(stderr, "usage: realloc_test <num_buffers> <init_size> <max_size> <doublings> <iterations> [seed]\n"); + exit(EXIT_FAILURE); + } + + for ( int i = 0 ; i < argc ; i++ ) { + printf("%s ", argv[i]); + } + printf("\n"); + + if (argc == 7) { + srand(atoi(argv[6])); + } else { + srand(time(NULL)); + } + + struct TMemoryBuffer* buffers = calloc(num_buffers, sizeof(*buffers)); + if (buffers == NULL) abort(); + + for ( int i = 0 ; i < num_buffers ; i++ ) { + buffers[i].size = max_size; + } + + while (iterations --> 0) { + for ( int i = 0 ; i < doublings * num_buffers ; i++ ) { + struct TMemoryBuffer* buf = &buffers[rand() % num_buffers]; + buf->size *= 2; + if (buf->size <= max_size) { + buf->ptr = realloc(buf->ptr, buf->size); + } else { + free(buf->ptr); + buf->size = init_size; + buf->ptr = malloc(buf->size); + } + if (buf->ptr == NULL) abort(); + } + } + + printf("Non-copied %d/%d (%.2f%%)\n", non_copies, copies + non_copies, 100.0 * non_copies / (copies + non_copies)); + return 0; +} diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp new file mode 100644 index 000000000..5ddfa0601 --- /dev/null +++ b/test/cpp/src/TestClient.cpp @@ -0,0 +1,497 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <protocol/TBinaryProtocol.h> +#include <transport/TTransportUtils.h> +#include <transport/TSocket.h> + +#include <boost/shared_ptr.hpp> +#include "ThriftTest.h" + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +using namespace boost; +using namespace std; +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace thrift::test; + +//extern uint32_t g_socket_syscalls; + +// Current time, microseconds since the epoch +uint64_t now() +{ + long long ret; + struct timeval tv; + + gettimeofday(&tv, NULL); + ret = tv.tv_sec; + ret = ret*1000*1000 + tv.tv_usec; + return ret; +} + +int main(int argc, char** argv) { + string host = "localhost"; + int port = 9090; + int numTests = 1; + bool framed = false; + + for (int i = 0; i < argc; ++i) { + if (strcmp(argv[i], "-h") == 0) { + char* pch = strtok(argv[++i], ":"); + if (pch != NULL) { + host = string(pch); + } + pch = strtok(NULL, ":"); + if (pch != NULL) { + port = atoi(pch); + } + } else if (strcmp(argv[i], "-n") == 0) { + numTests = atoi(argv[++i]); + } else if (strcmp(argv[i], "-f") == 0) { + framed = true; + } + } + + + shared_ptr<TTransport> transport; + + shared_ptr<TSocket> socket(new TSocket(host, port)); + + if (framed) { + shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket)); + transport = framedSocket; + } else { + shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket)); + transport = bufferedSocket; + } + + shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport)); + ThriftTestClient testClient(protocol); + + uint64_t time_min = 0; + uint64_t time_max = 0; + uint64_t time_tot = 0; + + int test = 0; + for (test = 0; test < numTests; ++test) { + + try { + transport->open(); + } catch (TTransportException& ttx) { + printf("Connect failed: %s\n", ttx.what()); + continue; + } + + /** + * CONNECT TEST + */ + printf("Test #%d, connect %s:%d\n", test+1, host.c_str(), port); + + uint64_t start = now(); + + /** + * VOID TEST + */ + try { + printf("testVoid()"); + testClient.testVoid(); + printf(" = void\n"); + } catch (TApplicationException tax) { + printf("%s\n", tax.what()); + } + + /** + * STRING TEST + */ + printf("testString(\"Test\")"); + string s; + testClient.testString(s, "Test"); + printf(" = \"%s\"\n", s.c_str()); + + /** + * BYTE TEST + */ + printf("testByte(1)"); + uint8_t u8 = testClient.testByte(1); + printf(" = %d\n", (int)u8); + + /** + * I32 TEST + */ + printf("testI32(-1)"); + int32_t i32 = testClient.testI32(-1); + printf(" = %d\n", i32); + + /** + * I64 TEST + */ + printf("testI64(-34359738368)"); + int64_t i64 = testClient.testI64(-34359738368LL); + printf(" = %"PRId64"\n", i64); + + /** + * DOUBLE TEST + */ + printf("testDouble(-5.2098523)"); + double dub = testClient.testDouble(-5.2098523); + printf(" = %lf\n", dub); + + /** + * STRUCT TEST + */ + printf("testStruct({\"Zero\", 1, -3, -5})"); + Xtruct out; + out.string_thing = "Zero"; + out.byte_thing = 1; + out.i32_thing = -3; + out.i64_thing = -5; + Xtruct in; + testClient.testStruct(in, out); + printf(" = {\"%s\", %d, %d, %"PRId64"}\n", + in.string_thing.c_str(), + (int)in.byte_thing, + in.i32_thing, + in.i64_thing); + + /** + * NESTED STRUCT TEST + */ + printf("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); + Xtruct2 out2; + out2.byte_thing = 1; + out2.struct_thing = out; + out2.i32_thing = 5; + Xtruct2 in2; + testClient.testNest(in2, out2); + in = in2.struct_thing; + printf(" = {%d, {\"%s\", %d, %d, %"PRId64"}, %d}\n", + in2.byte_thing, + in.string_thing.c_str(), + (int)in.byte_thing, + in.i32_thing, + in.i64_thing, + in2.i32_thing); + + /** + * MAP TEST + */ + map<int32_t,int32_t> mapout; + for (int32_t i = 0; i < 5; ++i) { + mapout.insert(make_pair(i, i-10)); + } + printf("testMap({"); + map<int32_t, int32_t>::const_iterator m_iter; + bool first = true; + for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d => %d", m_iter->first, m_iter->second); + } + printf("})"); + map<int32_t,int32_t> mapin; + testClient.testMap(mapin, mapout); + printf(" = {"); + first = true; + for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d => %d", m_iter->first, m_iter->second); + } + printf("}\n"); + + /** + * SET TEST + */ + set<int32_t> setout; + for (int32_t i = -2; i < 3; ++i) { + setout.insert(i); + } + printf("testSet({"); + set<int32_t>::const_iterator s_iter; + first = true; + for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *s_iter); + } + printf("})"); + set<int32_t> setin; + testClient.testSet(setin, setout); + printf(" = {"); + first = true; + for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *s_iter); + } + printf("}\n"); + + /** + * LIST TEST + */ + vector<int32_t> listout; + for (int32_t i = -2; i < 3; ++i) { + listout.push_back(i); + } + printf("testList({"); + vector<int32_t>::const_iterator l_iter; + first = true; + for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *l_iter); + } + printf("})"); + vector<int32_t> listin; + testClient.testList(listin, listout); + printf(" = {"); + first = true; + for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *l_iter); + } + printf("}\n"); + + /** + * ENUM TEST + */ + printf("testEnum(ONE)"); + Numberz ret = testClient.testEnum(ONE); + printf(" = %d\n", ret); + + printf("testEnum(TWO)"); + ret = testClient.testEnum(TWO); + printf(" = %d\n", ret); + + printf("testEnum(THREE)"); + ret = testClient.testEnum(THREE); + printf(" = %d\n", ret); + + printf("testEnum(FIVE)"); + ret = testClient.testEnum(FIVE); + printf(" = %d\n", ret); + + printf("testEnum(EIGHT)"); + ret = testClient.testEnum(EIGHT); + printf(" = %d\n", ret); + + /** + * TYPEDEF TEST + */ + printf("testTypedef(309858235082523)"); + UserId uid = testClient.testTypedef(309858235082523LL); + printf(" = %"PRId64"\n", uid); + + /** + * NESTED MAP TEST + */ + printf("testMapMap(1)"); + map<int32_t, map<int32_t, int32_t> > mm; + testClient.testMapMap(mm, 1); + printf(" = {"); + map<int32_t, map<int32_t, int32_t> >::const_iterator mi; + for (mi = mm.begin(); mi != mm.end(); ++mi) { + printf("%d => {", mi->first); + map<int32_t, int32_t>::const_iterator mi2; + for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) { + printf("%d => %d, ", mi2->first, mi2->second); + } + printf("}, "); + } + printf("}\n"); + + /** + * INSANITY TEST + */ + Insanity insane; + insane.userMap.insert(make_pair(FIVE, 5000)); + Xtruct truck; + truck.string_thing = "Truck"; + truck.byte_thing = 8; + truck.i32_thing = 8; + truck.i64_thing = 8; + insane.xtructs.push_back(truck); + printf("testInsanity()"); + map<UserId, map<Numberz,Insanity> > whoa; + testClient.testInsanity(whoa, insane); + printf(" = {"); + map<UserId, map<Numberz,Insanity> >::const_iterator i_iter; + for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) { + printf("%"PRId64" => {", i_iter->first); + map<Numberz,Insanity>::const_iterator i2_iter; + for (i2_iter = i_iter->second.begin(); + i2_iter != i_iter->second.end(); + ++i2_iter) { + printf("%d => {", i2_iter->first); + map<Numberz, UserId> userMap = i2_iter->second.userMap; + map<Numberz, UserId>::const_iterator um; + printf("{"); + for (um = userMap.begin(); um != userMap.end(); ++um) { + printf("%d => %"PRId64", ", um->first, um->second); + } + printf("}, "); + + vector<Xtruct> xtructs = i2_iter->second.xtructs; + vector<Xtruct>::const_iterator x; + printf("{"); + for (x = xtructs.begin(); x != xtructs.end(); ++x) { + printf("{\"%s\", %d, %d, %"PRId64"}, ", + x->string_thing.c_str(), + (int)x->byte_thing, + x->i32_thing, + x->i64_thing); + } + printf("}"); + + printf("}, "); + } + printf("}, "); + } + printf("}\n"); + + /* test exception */ + + try { + printf("testClient.testException(\"Xception\") =>"); + testClient.testException("Xception"); + printf(" void\nFAILURE\n"); + + } catch(Xception& e) { + printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); + } + + try { + printf("testClient.testException(\"success\") =>"); + testClient.testException("success"); + printf(" void\n"); + } catch(...) { + printf(" exception\nFAILURE\n"); + } + + /* test multi exception */ + + try { + printf("testClient.testMultiException(\"Xception\", \"test 1\") =>"); + Xtruct result; + testClient.testMultiException(result, "Xception", "test 1"); + printf(" result\nFAILURE\n"); + } catch(Xception& e) { + printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); + } + + try { + printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>"); + Xtruct result; + testClient.testMultiException(result, "Xception2", "test 2"); + printf(" result\nFAILURE\n"); + + } catch(Xception2& e) { + printf(" {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str()); + } + + try { + printf("testClient.testMultiException(\"success\", \"test 3\") =>"); + Xtruct result; + testClient.testMultiException(result, "success", "test 3"); + printf(" {{\"%s\"}}\n", result.string_thing.c_str()); + } catch(...) { + printf(" exception\nFAILURE\n"); + } + + /* test oneway void */ + { + printf("testClient.testOneway(3) =>"); + uint64_t startOneway = now(); + testClient.testOneway(3); + uint64_t elapsed = now() - startOneway; + if (elapsed > 200 * 1000) { // 0.2 seconds + printf(" FAILURE - took %.2f ms\n", (double)elapsed/1000.0); + } else { + printf(" success - took %.2f ms\n", (double)elapsed/1000.0); + } + } + + /** + * redo a simple test after the oneway to make sure we aren't "off by one" -- + * if the server treated oneway void like normal void, this next test will + * fail since it will get the void confirmation rather than the correct + * result. In this circumstance, the client will throw the exception: + * + * TApplicationException: Wrong method namea + */ + /** + * I32 TEST + */ + printf("re-test testI32(-1)"); + i32 = testClient.testI32(-1); + printf(" = %d\n", i32); + + + uint64_t stop = now(); + uint64_t tot = stop-start; + + printf("Total time: %"PRIu64" us\n", stop-start); + + time_tot += tot; + if (time_min == 0 || tot < time_min) { + time_min = tot; + } + if (tot > time_max) { + time_max = tot; + } + + transport->close(); + } + + // printf("\nSocket syscalls: %u", g_socket_syscalls); + printf("\nAll tests done.\n"); + + uint64_t time_avg = time_tot / numTests; + + printf("Min time: %"PRIu64" us\n", time_min); + printf("Max time: %"PRIu64" us\n", time_max); + printf("Avg time: %"PRIu64" us\n", time_avg); + + return 0; +} diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp new file mode 100644 index 000000000..83454dcaf --- /dev/null +++ b/test/cpp/src/TestServer.cpp @@ -0,0 +1,424 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <concurrency/ThreadManager.h> +#include <concurrency/PosixThreadFactory.h> +#include <protocol/TBinaryProtocol.h> +#include <server/TSimpleServer.h> +#include <server/TThreadedServer.h> +#include <server/TThreadPoolServer.h> +#include <server/TNonblockingServer.h> +#include <transport/TServerSocket.h> +#include <transport/TTransportUtils.h> +#include "ThriftTest.h" + +#include <iostream> +#include <stdexcept> +#include <sstream> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +using namespace std; +using namespace boost; + +using namespace apache::thrift; +using namespace apache::thrift::concurrency; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; + +using namespace thrift::test; + +class TestHandler : public ThriftTestIf { + public: + TestHandler() {} + + void testVoid() { + printf("testVoid()\n"); + } + + void testString(string& out, const string &thing) { + printf("testString(\"%s\")\n", thing.c_str()); + out = thing; + } + + int8_t testByte(const int8_t thing) { + printf("testByte(%d)\n", (int)thing); + return thing; + } + + int32_t testI32(const int32_t thing) { + printf("testI32(%d)\n", thing); + return thing; + } + + int64_t testI64(const int64_t thing) { + printf("testI64(%"PRId64")\n", thing); + return thing; + } + + double testDouble(const double thing) { + printf("testDouble(%lf)\n", thing); + return thing; + } + + void testStruct(Xtruct& out, const Xtruct &thing) { + printf("testStruct({\"%s\", %d, %d, %"PRId64"})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing); + out = thing; + } + + void testNest(Xtruct2& out, const Xtruct2& nest) { + const Xtruct &thing = nest.struct_thing; + printf("testNest({%d, {\"%s\", %d, %d, %"PRId64"}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing); + out = nest; + } + + void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) { + printf("testMap({"); + map<int32_t, int32_t>::const_iterator m_iter; + bool first = true; + for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d => %d", m_iter->first, m_iter->second); + } + printf("})\n"); + out = thing; + } + + void testSet(set<int32_t> &out, const set<int32_t> &thing) { + printf("testSet({"); + set<int32_t>::const_iterator s_iter; + bool first = true; + for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *s_iter); + } + printf("})\n"); + out = thing; + } + + void testList(vector<int32_t> &out, const vector<int32_t> &thing) { + printf("testList({"); + vector<int32_t>::const_iterator l_iter; + bool first = true; + for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) { + if (first) { + first = false; + } else { + printf(", "); + } + printf("%d", *l_iter); + } + printf("})\n"); + out = thing; + } + + Numberz testEnum(const Numberz thing) { + printf("testEnum(%d)\n", thing); + return thing; + } + + UserId testTypedef(const UserId thing) { + printf("testTypedef(%"PRId64")\n", thing); + return thing; + } + + void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) { + printf("testMapMap(%d)\n", hello); + + map<int32_t,int32_t> pos; + map<int32_t,int32_t> neg; + for (int i = 1; i < 5; i++) { + pos.insert(make_pair(i,i)); + neg.insert(make_pair(-i,-i)); + } + + mapmap.insert(make_pair(4, pos)); + mapmap.insert(make_pair(-4, neg)); + + } + + void testInsanity(map<UserId, map<Numberz,Insanity> > &insane, const Insanity &argument) { + printf("testInsanity()\n"); + + Xtruct hello; + hello.string_thing = "Hello2"; + hello.byte_thing = 2; + hello.i32_thing = 2; + hello.i64_thing = 2; + + Xtruct goodbye; + goodbye.string_thing = "Goodbye4"; + goodbye.byte_thing = 4; + goodbye.i32_thing = 4; + goodbye.i64_thing = 4; + + Insanity crazy; + crazy.userMap.insert(make_pair(EIGHT, 8)); + crazy.xtructs.push_back(goodbye); + + Insanity looney; + crazy.userMap.insert(make_pair(FIVE, 5)); + crazy.xtructs.push_back(hello); + + map<Numberz, Insanity> first_map; + map<Numberz, Insanity> second_map; + + first_map.insert(make_pair(TWO, crazy)); + first_map.insert(make_pair(THREE, crazy)); + + second_map.insert(make_pair(SIX, looney)); + + insane.insert(make_pair(1, first_map)); + insane.insert(make_pair(2, second_map)); + + printf("return"); + printf(" = {"); + map<UserId, map<Numberz,Insanity> >::const_iterator i_iter; + for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) { + printf("%"PRId64" => {", i_iter->first); + map<Numberz,Insanity>::const_iterator i2_iter; + for (i2_iter = i_iter->second.begin(); + i2_iter != i_iter->second.end(); + ++i2_iter) { + printf("%d => {", i2_iter->first); + map<Numberz, UserId> userMap = i2_iter->second.userMap; + map<Numberz, UserId>::const_iterator um; + printf("{"); + for (um = userMap.begin(); um != userMap.end(); ++um) { + printf("%d => %"PRId64", ", um->first, um->second); + } + printf("}, "); + + vector<Xtruct> xtructs = i2_iter->second.xtructs; + vector<Xtruct>::const_iterator x; + printf("{"); + for (x = xtructs.begin(); x != xtructs.end(); ++x) { + printf("{\"%s\", %d, %d, %"PRId64"}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing); + } + printf("}"); + + printf("}, "); + } + printf("}, "); + } + printf("}\n"); + + + } + + void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string> &arg3, const Numberz arg4, const UserId arg5) { + printf("testMulti()\n"); + + hello.string_thing = "Hello2"; + hello.byte_thing = arg0; + hello.i32_thing = arg1; + hello.i64_thing = (int64_t)arg2; + } + + void testException(const std::string &arg) + throw(Xception, apache::thrift::TException) + { + printf("testException(%s)\n", arg.c_str()); + if (arg.compare("Xception") == 0) { + Xception e; + e.errorCode = 1001; + e.message = arg; + throw e; + } else if (arg.compare("ApplicationException") == 0) { + apache::thrift::TException e; + throw e; + } else { + Xtruct result; + result.string_thing = arg; + return; + } + } + + void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) { + + printf("testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str()); + + if (arg0.compare("Xception") == 0) { + Xception e; + e.errorCode = 1001; + e.message = "This is an Xception"; + throw e; + } else if (arg0.compare("Xception2") == 0) { + Xception2 e; + e.errorCode = 2002; + e.struct_thing.string_thing = "This is an Xception2"; + throw e; + } else { + result.string_thing = arg1; + return; + } + } + + void testOneway(int sleepFor) { + printf("testOneway(%d): Sleeping...\n", sleepFor); + sleep(sleepFor); + printf("testOneway(%d): done sleeping!\n", sleepFor); + } +}; + +int main(int argc, char **argv) { + + int port = 9090; + string serverType = "simple"; + string protocolType = "binary"; + size_t workerCount = 4; + + ostringstream usage; + + usage << + argv[0] << " [--port=<port number>] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>]" << endl << + + "\t\tserver-type\t\ttype of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\". Default is " << serverType << endl << + + "\t\tprotocol-type\t\ttype of protocol, \"binary\", \"ascii\", or \"xml\". Default is " << protocolType << endl << + + "\t\tworkers\t\tNumber of thread pools workers. Only valid for thread-pool server type. Default is " << workerCount << endl; + + map<string, string> args; + + for (int ix = 1; ix < argc; ix++) { + string arg(argv[ix]); + if (arg.compare(0,2, "--") == 0) { + size_t end = arg.find_first_of("=", 2); + if (end != string::npos) { + args[string(arg, 2, end - 2)] = string(arg, end + 1); + } else { + args[string(arg, 2)] = "true"; + } + } else { + throw invalid_argument("Unexcepted command line token: "+arg); + } + } + + try { + + if (!args["port"].empty()) { + port = atoi(args["port"].c_str()); + } + + if (!args["server-type"].empty()) { + serverType = args["server-type"]; + if (serverType == "simple") { + } else if (serverType == "thread-pool") { + } else if (serverType == "threaded") { + } else if (serverType == "nonblocking") { + } else { + throw invalid_argument("Unknown server type "+serverType); + } + } + + if (!args["protocol-type"].empty()) { + protocolType = args["protocol-type"]; + if (protocolType == "binary") { + } else if (protocolType == "ascii") { + throw invalid_argument("ASCII protocol not supported"); + } else if (protocolType == "xml") { + throw invalid_argument("XML protocol not supported"); + } else { + throw invalid_argument("Unknown protocol type "+protocolType); + } + } + + if (!args["workers"].empty()) { + workerCount = atoi(args["workers"].c_str()); + } + } catch (exception& e) { + cerr << e.what() << endl; + cerr << usage; + } + + // Dispatcher + shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); + + shared_ptr<TestHandler> testHandler(new TestHandler()); + + shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler)); + + // Transport + shared_ptr<TServerSocket> serverSocket(new TServerSocket(port)); + + // Factory + shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); + + if (serverType == "simple") { + + // Server + TSimpleServer simpleServer(testProcessor, + serverSocket, + transportFactory, + protocolFactory); + + printf("Starting the server on port %d...\n", port); + simpleServer.serve(); + + } else if (serverType == "thread-pool") { + + shared_ptr<ThreadManager> threadManager = + ThreadManager::newSimpleThreadManager(workerCount); + + shared_ptr<PosixThreadFactory> threadFactory = + shared_ptr<PosixThreadFactory>(new PosixThreadFactory()); + + threadManager->threadFactory(threadFactory); + + threadManager->start(); + + TThreadPoolServer threadPoolServer(testProcessor, + serverSocket, + transportFactory, + protocolFactory, + threadManager); + + printf("Starting the server on port %d...\n", port); + threadPoolServer.serve(); + + } else if (serverType == "threaded") { + + TThreadedServer threadedServer(testProcessor, + serverSocket, + transportFactory, + protocolFactory); + + printf("Starting the server on port %d...\n", port); + threadedServer.serve(); + + } else if (serverType == "nonblocking") { + TNonblockingServer nonblockingServer(testProcessor, port); + printf("Starting the nonblocking server on port %d...\n", port); + nonblockingServer.serve(); + } + + printf("done.\n"); + return 0; +} diff --git a/test/cpp/src/main.cpp b/test/cpp/src/main.cpp new file mode 100644 index 000000000..46ee950d8 --- /dev/null +++ b/test/cpp/src/main.cpp @@ -0,0 +1,509 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <concurrency/ThreadManager.h> +#include <concurrency/PosixThreadFactory.h> +#include <concurrency/Monitor.h> +#include <concurrency/Util.h> +#include <concurrency/Mutex.h> +#include <protocol/TBinaryProtocol.h> +#include <server/TSimpleServer.h> +#include <server/TThreadPoolServer.h> +#include <server/TThreadedServer.h> +#include <transport/TServerSocket.h> +#include <transport/TSocket.h> +#include <transport/TTransportUtils.h> +#include <transport/TFileTransport.h> +#include <TLogging.h> + +#include "Service.h" + +#include <iostream> +#include <set> +#include <stdexcept> +#include <sstream> + +#include <map> +#include <ext/hash_map> +using __gnu_cxx::hash_map; +using __gnu_cxx::hash; + +using namespace std; +using namespace boost; + +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; + +using namespace test::stress; + +struct eqstr { + bool operator()(const char* s1, const char* s2) const { + return strcmp(s1, s2) == 0; + } +}; + +struct ltstr { + bool operator()(const char* s1, const char* s2) const { + return strcmp(s1, s2) < 0; + } +}; + + +// typedef hash_map<const char*, int, hash<const char*>, eqstr> count_map; +typedef map<const char*, int, ltstr> count_map; + +class Server : public ServiceIf { + public: + Server() {} + + void count(const char* method) { + Guard m(lock_); + int ct = counts_[method]; + counts_[method] = ++ct; + } + + void echoVoid() { + count("echoVoid"); + return; + } + + count_map getCount() { + Guard m(lock_); + return counts_; + } + + int8_t echoByte(const int8_t arg) {return arg;} + int32_t echoI32(const int32_t arg) {return arg;} + int64_t echoI64(const int64_t arg) {return arg;} + void echoString(string& out, const string &arg) { + if (arg != "hello") { + T_ERROR_ABORT("WRONG STRING!!!!"); + } + out = arg; + } + void echoList(vector<int8_t> &out, const vector<int8_t> &arg) { out = arg; } + void echoSet(set<int8_t> &out, const set<int8_t> &arg) { out = arg; } + void echoMap(map<int8_t, int8_t> &out, const map<int8_t, int8_t> &arg) { out = arg; } + +private: + count_map counts_; + Mutex lock_; + +}; + +class ClientThread: public Runnable { +public: + + ClientThread(shared_ptr<TTransport>transport, shared_ptr<ServiceClient> client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) : + _transport(transport), + _client(client), + _monitor(monitor), + _workerCount(workerCount), + _loopCount(loopCount), + _loopType(loopType) + {} + + void run() { + + // Wait for all worker threads to start + + {Synchronized s(_monitor); + while(_workerCount == 0) { + _monitor.wait(); + } + } + + _startTime = Util::currentTime(); + + _transport->open(); + + switch(_loopType) { + case T_VOID: loopEchoVoid(); break; + case T_BYTE: loopEchoByte(); break; + case T_I32: loopEchoI32(); break; + case T_I64: loopEchoI64(); break; + case T_STRING: loopEchoString(); break; + default: cerr << "Unexpected loop type" << _loopType << endl; break; + } + + _endTime = Util::currentTime(); + + _transport->close(); + + _done = true; + + {Synchronized s(_monitor); + + _workerCount--; + + if (_workerCount == 0) { + + _monitor.notify(); + } + } + } + + void loopEchoVoid() { + for (size_t ix = 0; ix < _loopCount; ix++) { + _client->echoVoid(); + } + } + + void loopEchoByte() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int8_t arg = 1; + int8_t result; + result =_client->echoByte(arg); + assert(result == arg); + } + } + + void loopEchoI32() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int32_t arg = 1; + int32_t result; + result =_client->echoI32(arg); + assert(result == arg); + } + } + + void loopEchoI64() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int64_t arg = 1; + int64_t result; + result =_client->echoI64(arg); + assert(result == arg); + } + } + + void loopEchoString() { + for (size_t ix = 0; ix < _loopCount; ix++) { + string arg = "hello"; + string result; + _client->echoString(result, arg); + assert(result == arg); + } + } + + shared_ptr<TTransport> _transport; + shared_ptr<ServiceClient> _client; + Monitor& _monitor; + size_t& _workerCount; + size_t _loopCount; + TType _loopType; + long long _startTime; + long long _endTime; + bool _done; + Monitor _sleep; +}; + + +int main(int argc, char **argv) { + + int port = 9091; + string serverType = "thread-pool"; + string protocolType = "binary"; + size_t workerCount = 4; + size_t clientCount = 20; + size_t loopCount = 50000; + TType loopType = T_VOID; + string callName = "echoVoid"; + bool runServer = true; + bool logRequests = false; + string requestLogPath = "./requestlog.tlog"; + bool replayRequests = false; + + ostringstream usage; + + usage << + argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl << + "\tclients Number of client threads to create - 0 implies no clients, i.e. server only. Default is " << clientCount << endl << + "\thelp Prints this help text." << endl << + "\tcall Service method to call. Default is " << callName << endl << + "\tloop The number of remote thrift calls each client makes. Default is " << loopCount << endl << + "\tport The port the server and clients should bind to for thrift network connections. Default is " << port << endl << + "\tserver Run the Thrift server in this process. Default is " << runServer << endl << + "\tserver-type Type of server, \"simple\" or \"thread-pool\". Default is " << serverType << endl << + "\tprotocol-type Type of protocol, \"binary\", \"ascii\", or \"xml\". Default is " << protocolType << endl << + "\tlog-request Log all request to ./requestlog.tlog. Default is " << logRequests << endl << + "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl << + "\tworkers Number of thread pools workers. Only valid for thread-pool server type. Default is " << workerCount << endl; + + + map<string, string> args; + + for (int ix = 1; ix < argc; ix++) { + + string arg(argv[ix]); + + if (arg.compare(0,2, "--") == 0) { + + size_t end = arg.find_first_of("=", 2); + + string key = string(arg, 2, end - 2); + + if (end != string::npos) { + args[key] = string(arg, end + 1); + } else { + args[key] = "true"; + } + } else { + throw invalid_argument("Unexcepted command line token: "+arg); + } + } + + try { + + if (!args["clients"].empty()) { + clientCount = atoi(args["clients"].c_str()); + } + + if (!args["help"].empty()) { + cerr << usage.str(); + return 0; + } + + if (!args["loop"].empty()) { + loopCount = atoi(args["loop"].c_str()); + } + + if (!args["call"].empty()) { + callName = args["call"]; + } + + if (!args["port"].empty()) { + port = atoi(args["port"].c_str()); + } + + if (!args["server"].empty()) { + runServer = args["server"] == "true"; + } + + if (!args["log-request"].empty()) { + logRequests = args["log-request"] == "true"; + } + + if (!args["replay-request"].empty()) { + replayRequests = args["replay-request"] == "true"; + } + + if (!args["server-type"].empty()) { + serverType = args["server-type"]; + + if (serverType == "simple") { + + } else if (serverType == "thread-pool") { + + } else if (serverType == "threaded") { + + } else { + + throw invalid_argument("Unknown server type "+serverType); + } + } + + if (!args["workers"].empty()) { + workerCount = atoi(args["workers"].c_str()); + } + + } catch(exception& e) { + cerr << e.what() << endl; + cerr << usage; + } + + shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory()); + + // Dispatcher + shared_ptr<Server> serviceHandler(new Server()); + + if (replayRequests) { + shared_ptr<Server> serviceHandler(new Server()); + shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Transports + shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + fileTransport->seekToEnd(); + + // Protocol Factory + shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); + + TFileProcessor fileProcessor(serviceProcessor, + protocolFactory, + fileTransport); + + fileProcessor.process(0, true); + exit(0); + } + + + if (runServer) { + + shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Transport + shared_ptr<TServerSocket> serverSocket(new TServerSocket(port)); + + // Transport Factory + shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); + + // Protocol Factory + shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); + + if (logRequests) { + // initialize the log file + shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + + transportFactory = + shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport)); + } + + shared_ptr<Thread> serverThread; + + if (serverType == "simple") { + + serverThread = threadFactory->newThread(shared_ptr<TServer>(new TSimpleServer(serviceProcessor, serverSocket, transportFactory, protocolFactory))); + + } else if (serverType == "threaded") { + + serverThread = threadFactory->newThread(shared_ptr<TServer>(new TThreadedServer(serviceProcessor, serverSocket, transportFactory, protocolFactory))); + + } else if (serverType == "thread-pool") { + + shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount); + + threadManager->threadFactory(threadFactory); + threadManager->start(); + serverThread = threadFactory->newThread(shared_ptr<TServer>(new TThreadPoolServer(serviceProcessor, serverSocket, transportFactory, protocolFactory, threadManager))); + } + + cerr << "Starting the server on port " << port << endl; + + serverThread->start(); + + // If we aren't running clients, just wait forever for external clients + + if (clientCount == 0) { + serverThread->join(); + } + } + + if (clientCount > 0) { + + Monitor monitor; + + size_t threadCount = 0; + + set<shared_ptr<Thread> > clientThreads; + + if (callName == "echoVoid") { loopType = T_VOID;} + else if (callName == "echoByte") { loopType = T_BYTE;} + else if (callName == "echoI32") { loopType = T_I32;} + else if (callName == "echoI64") { loopType = T_I64;} + else if (callName == "echoString") { loopType = T_STRING;} + else {throw invalid_argument("Unknown service call "+callName);} + + for (size_t ix = 0; ix < clientCount; ix++) { + + shared_ptr<TSocket> socket(new TSocket("127.0.01", port)); + shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048)); + shared_ptr<TProtocol> protocol(new TBinaryProtocol(bufferedSocket)); + shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol)); + + clientThreads.insert(threadFactory->newThread(shared_ptr<ClientThread>(new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType)))); + } + + for (std::set<shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) { + (*thread)->start(); + } + + long long time00; + long long time01; + + {Synchronized s(monitor); + threadCount = clientCount; + + cerr << "Launch "<< clientCount << " client threads" << endl; + + time00 = Util::currentTime(); + + monitor.notifyAll(); + + while(threadCount > 0) { + monitor.wait(); + } + + time01 = Util::currentTime(); + } + + long long firstTime = 9223372036854775807LL; + long long lastTime = 0; + + double averageTime = 0; + long long minTime = 9223372036854775807LL; + long long maxTime = 0; + + for (set<shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) { + + shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable()); + + long long delta = client->_endTime - client->_startTime; + + assert(delta > 0); + + if (client->_startTime < firstTime) { + firstTime = client->_startTime; + } + + if (client->_endTime > lastTime) { + lastTime = client->_endTime; + } + + if (delta < minTime) { + minTime = delta; + } + + if (delta > maxTime) { + maxTime = delta; + } + + averageTime+= delta; + } + + averageTime /= clientCount; + + + cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl; + + count_map count = serviceHandler->getCount(); + count_map::iterator iter; + for (iter = count.begin(); iter != count.end(); ++iter) { + printf("%s => %d\n", iter->first, iter->second); + } + cerr << "done." << endl; + } + + return 0; +} diff --git a/test/cpp/src/nb-main.cpp b/test/cpp/src/nb-main.cpp new file mode 100644 index 000000000..8c74a815d --- /dev/null +++ b/test/cpp/src/nb-main.cpp @@ -0,0 +1,502 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +#include <concurrency/ThreadManager.h> +#include <concurrency/PosixThreadFactory.h> +#include <concurrency/Monitor.h> +#include <concurrency/Util.h> +#include <concurrency/Mutex.h> +#include <protocol/TBinaryProtocol.h> +#include <server/TSimpleServer.h> +#include <server/TThreadPoolServer.h> +#include <server/TThreadedServer.h> +#include <server/TNonblockingServer.h> +#include <transport/TServerSocket.h> +#include <transport/TSocket.h> +#include <transport/TTransportUtils.h> +#include <transport/TFileTransport.h> +#include <TLogging.h> + +#include "Service.h" + +#include <unistd.h> +#include <boost/shared_ptr.hpp> + +#include <iostream> +#include <set> +#include <stdexcept> +#include <sstream> + +#include <map> +#include <ext/hash_map> +using __gnu_cxx::hash_map; +using __gnu_cxx::hash; + +using namespace std; +using namespace boost; + +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; + +using namespace test::stress; + +struct eqstr { + bool operator()(const char* s1, const char* s2) const { + return strcmp(s1, s2) == 0; + } +}; + +struct ltstr { + bool operator()(const char* s1, const char* s2) const { + return strcmp(s1, s2) < 0; + } +}; + + +// typedef hash_map<const char*, int, hash<const char*>, eqstr> count_map; +typedef map<const char*, int, ltstr> count_map; + +class Server : public ServiceIf { + public: + Server() {} + + void count(const char* method) { + Guard m(lock_); + int ct = counts_[method]; + counts_[method] = ++ct; + } + + void echoVoid() { + count("echoVoid"); + // Sleep to simulate work + usleep(5000); + return; + } + + count_map getCount() { + Guard m(lock_); + return counts_; + } + + int8_t echoByte(const int8_t arg) {return arg;} + int32_t echoI32(const int32_t arg) {return arg;} + int64_t echoI64(const int64_t arg) {return arg;} + void echoString(string& out, const string &arg) { + if (arg != "hello") { + T_ERROR_ABORT("WRONG STRING!!!!"); + } + out = arg; + } + void echoList(vector<int8_t> &out, const vector<int8_t> &arg) { out = arg; } + void echoSet(set<int8_t> &out, const set<int8_t> &arg) { out = arg; } + void echoMap(map<int8_t, int8_t> &out, const map<int8_t, int8_t> &arg) { out = arg; } + +private: + count_map counts_; + Mutex lock_; + +}; + +class ClientThread: public Runnable { +public: + + ClientThread(shared_ptr<TTransport>transport, shared_ptr<ServiceClient> client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) : + _transport(transport), + _client(client), + _monitor(monitor), + _workerCount(workerCount), + _loopCount(loopCount), + _loopType(loopType) + {} + + void run() { + + // Wait for all worker threads to start + + {Synchronized s(_monitor); + while(_workerCount == 0) { + _monitor.wait(); + } + } + + _startTime = Util::currentTime(); + + _transport->open(); + + switch(_loopType) { + case T_VOID: loopEchoVoid(); break; + case T_BYTE: loopEchoByte(); break; + case T_I32: loopEchoI32(); break; + case T_I64: loopEchoI64(); break; + case T_STRING: loopEchoString(); break; + default: cerr << "Unexpected loop type" << _loopType << endl; break; + } + + _endTime = Util::currentTime(); + + _transport->close(); + + _done = true; + + {Synchronized s(_monitor); + + _workerCount--; + + if (_workerCount == 0) { + + _monitor.notify(); + } + } + } + + void loopEchoVoid() { + for (size_t ix = 0; ix < _loopCount; ix++) { + _client->echoVoid(); + } + } + + void loopEchoByte() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int8_t arg = 1; + int8_t result; + result =_client->echoByte(arg); + assert(result == arg); + } + } + + void loopEchoI32() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int32_t arg = 1; + int32_t result; + result =_client->echoI32(arg); + assert(result == arg); + } + } + + void loopEchoI64() { + for (size_t ix = 0; ix < _loopCount; ix++) { + int64_t arg = 1; + int64_t result; + result =_client->echoI64(arg); + assert(result == arg); + } + } + + void loopEchoString() { + for (size_t ix = 0; ix < _loopCount; ix++) { + string arg = "hello"; + string result; + _client->echoString(result, arg); + assert(result == arg); + } + } + + shared_ptr<TTransport> _transport; + shared_ptr<ServiceClient> _client; + Monitor& _monitor; + size_t& _workerCount; + size_t _loopCount; + TType _loopType; + long long _startTime; + long long _endTime; + bool _done; + Monitor _sleep; +}; + + +int main(int argc, char **argv) { + + int port = 9091; + string serverType = "simple"; + string protocolType = "binary"; + size_t workerCount = 4; + size_t clientCount = 20; + size_t loopCount = 50000; + TType loopType = T_VOID; + string callName = "echoVoid"; + bool runServer = true; + bool logRequests = false; + string requestLogPath = "./requestlog.tlog"; + bool replayRequests = false; + + ostringstream usage; + + usage << + argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl << + "\tclients Number of client threads to create - 0 implies no clients, i.e. server only. Default is " << clientCount << endl << + "\thelp Prints this help text." << endl << + "\tcall Service method to call. Default is " << callName << endl << + "\tloop The number of remote thrift calls each client makes. Default is " << loopCount << endl << + "\tport The port the server and clients should bind to for thrift network connections. Default is " << port << endl << + "\tserver Run the Thrift server in this process. Default is " << runServer << endl << + "\tserver-type Type of server, \"simple\" or \"thread-pool\". Default is " << serverType << endl << + "\tprotocol-type Type of protocol, \"binary\", \"ascii\", or \"xml\". Default is " << protocolType << endl << + "\tlog-request Log all request to ./requestlog.tlog. Default is " << logRequests << endl << + "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl << + "\tworkers Number of thread pools workers. Only valid for thread-pool server type. Default is " << workerCount << endl; + + + map<string, string> args; + + for (int ix = 1; ix < argc; ix++) { + + string arg(argv[ix]); + + if (arg.compare(0,2, "--") == 0) { + + size_t end = arg.find_first_of("=", 2); + + string key = string(arg, 2, end - 2); + + if (end != string::npos) { + args[key] = string(arg, end + 1); + } else { + args[key] = "true"; + } + } else { + throw invalid_argument("Unexcepted command line token: "+arg); + } + } + + try { + + if (!args["clients"].empty()) { + clientCount = atoi(args["clients"].c_str()); + } + + if (!args["help"].empty()) { + cerr << usage.str(); + return 0; + } + + if (!args["loop"].empty()) { + loopCount = atoi(args["loop"].c_str()); + } + + if (!args["call"].empty()) { + callName = args["call"]; + } + + if (!args["port"].empty()) { + port = atoi(args["port"].c_str()); + } + + if (!args["server"].empty()) { + runServer = args["server"] == "true"; + } + + if (!args["log-request"].empty()) { + logRequests = args["log-request"] == "true"; + } + + if (!args["replay-request"].empty()) { + replayRequests = args["replay-request"] == "true"; + } + + if (!args["server-type"].empty()) { + serverType = args["server-type"]; + } + + if (!args["workers"].empty()) { + workerCount = atoi(args["workers"].c_str()); + } + + } catch(exception& e) { + cerr << e.what() << endl; + cerr << usage; + } + + shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory()); + + // Dispatcher + shared_ptr<Server> serviceHandler(new Server()); + + if (replayRequests) { + shared_ptr<Server> serviceHandler(new Server()); + shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Transports + shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + fileTransport->seekToEnd(); + + // Protocol Factory + shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); + + TFileProcessor fileProcessor(serviceProcessor, + protocolFactory, + fileTransport); + + fileProcessor.process(0, true); + exit(0); + } + + + if (runServer) { + + shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler)); + + // Protocol Factory + shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); + + // Transport Factory + shared_ptr<TTransportFactory> transportFactory; + + if (logRequests) { + // initialize the log file + shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath)); + fileTransport->setChunkSize(2 * 1024 * 1024); + fileTransport->setMaxEventSize(1024 * 16); + + transportFactory = + shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport)); + } + + shared_ptr<Thread> serverThread; + shared_ptr<Thread> serverThread2; + + if (serverType == "simple") { + + serverThread = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port))); + serverThread2 = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port+1))); + + } else if (serverType == "thread-pool") { + + shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount); + + threadManager->threadFactory(threadFactory); + threadManager->start(); + serverThread = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port, threadManager))); + serverThread2 = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port+1, threadManager))); + } + + cerr << "Starting the server on port " << port << " and " << (port + 1) << endl; + serverThread->start(); + serverThread2->start(); + + // If we aren't running clients, just wait forever for external clients + + if (clientCount == 0) { + serverThread->join(); + serverThread2->join(); + } + } + sleep(1); + + if (clientCount > 0) { + + Monitor monitor; + + size_t threadCount = 0; + + set<shared_ptr<Thread> > clientThreads; + + if (callName == "echoVoid") { loopType = T_VOID;} + else if (callName == "echoByte") { loopType = T_BYTE;} + else if (callName == "echoI32") { loopType = T_I32;} + else if (callName == "echoI64") { loopType = T_I64;} + else if (callName == "echoString") { loopType = T_STRING;} + else {throw invalid_argument("Unknown service call "+callName);} + + for (size_t ix = 0; ix < clientCount; ix++) { + + shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port + (ix % 2))); + shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket)); + shared_ptr<TProtocol> protocol(new TBinaryProtocol(framedSocket)); + shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol)); + + clientThreads.insert(threadFactory->newThread(shared_ptr<ClientThread>(new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType)))); + } + + for (std::set<shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) { + (*thread)->start(); + } + + long long time00; + long long time01; + + {Synchronized s(monitor); + threadCount = clientCount; + + cerr << "Launch "<< clientCount << " client threads" << endl; + + time00 = Util::currentTime(); + + monitor.notifyAll(); + + while(threadCount > 0) { + monitor.wait(); + } + + time01 = Util::currentTime(); + } + + long long firstTime = 9223372036854775807LL; + long long lastTime = 0; + + double averageTime = 0; + long long minTime = 9223372036854775807LL; + long long maxTime = 0; + + for (set<shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) { + + shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable()); + + long long delta = client->_endTime - client->_startTime; + + assert(delta > 0); + + if (client->_startTime < firstTime) { + firstTime = client->_startTime; + } + + if (client->_endTime > lastTime) { + lastTime = client->_endTime; + } + + if (delta < minTime) { + minTime = delta; + } + + if (delta > maxTime) { + maxTime = delta; + } + + averageTime+= delta; + } + + averageTime /= clientCount; + + + cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl; + + count_map count = serviceHandler->getCount(); + count_map::iterator iter; + for (iter = count.begin(); iter != count.end(); ++iter) { + printf("%s => %d\n", iter->first, iter->second); + } + cerr << "done." << endl; + } + + return 0; +} diff --git a/test/csharp/CSharpClient.cs b/test/csharp/CSharpClient.cs new file mode 100644 index 000000000..641d5c9bb --- /dev/null +++ b/test/csharp/CSharpClient.cs @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +using System; +using Thrift; +using Thrift.Protocol; +using Thrift.Server; +using Thrift.Transport; + + +namespace CSharpTutorial +{ + public class CSharpClient + { + public static void Main() + { + try + { + TTransport transport = new TSocket("localhost", 9090); + TProtocol protocol = new TBinaryProtocol(transport); + Calculator.Client client = new Calculator.Client(protocol); + + transport.Open(); + + client.ping(); + Console.WriteLine("ping()"); + + int sum = client.add(1, 1); + Console.WriteLine("1+1={0}", sum); + + Work work = new Work(); + + work.op = Operation.DIVIDE; + work.num1 = 1; + work.num2 = 0; + try + { + int quotient = client.calculate(1, work); + Console.WriteLine("Whoa we can divide by 0"); + } + catch (InvalidOperation io) + { + Console.WriteLine("Invalid operation: " + io.why); + } + + work.op = Operation.SUBTRACT; + work.num1 = 15; + work.num2 = 10; + try + { + int diff = client.calculate(1, work); + Console.WriteLine("15-10={0}", diff); + } + catch (InvalidOperation io) + { + Console.WriteLine("Invalid operation: " + io.why); + } + + SharedStruct log = client.getStruct(1); + Console.WriteLine("Check log: {0}", log.value); + + transport.Close(); + } + catch (TApplicationException x) + { + Console.WriteLine(x.StackTrace); + } + + } + } +} diff --git a/test/csharp/CSharpServer.cs b/test/csharp/CSharpServer.cs new file mode 100644 index 000000000..f9ab8fd28 --- /dev/null +++ b/test/csharp/CSharpServer.cs @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +using System; +using System.Collections.Generic; +using Thrift.Server; +using Thrift.Transport; + +namespace CSharpTutorial +{ + public class CalculatorHandler : Calculator.Iface + { + Dictionary<int, SharedStruct> log; + + public CalculatorHandler() + { + log = new Dictionary<int, SharedStruct>(); + } + + public void ping() + { + Console.WriteLine("ping()"); + } + + public int add(int n1, int n2) + { + Console.WriteLine("add({0},{1})", n1, n2); + return n1 + n2; + } + + public int calculate(int logid, Work work) + { + Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.op, work.num1, work.num2); + int val = 0; + switch (work.op) + { + case Operation.ADD: + val = work.num1 + work.num2; + break; + + case Operation.SUBTRACT: + val = work.num1 - work.num2; + break; + + case Operation.MULTIPLY: + val = work.num1 * work.num2; + break; + + case Operation.DIVIDE: + if (work.num2 == 0) + { + InvalidOperation io = new InvalidOperation(); + io.what = (int)work.op; + io.why = "Cannot divide by 0"; + throw io; + } + val = work.num1 / work.num2; + break; + + default: + { + InvalidOperation io = new InvalidOperation(); + io.what = (int)work.op; + io.why = "Unknown operation"; + throw io; + } + } + + SharedStruct entry = new SharedStruct(); + entry.key = logid; + entry.value = val.ToString(); + log[logid] = entry; + + return val; + } + + public SharedStruct getStruct(int key) + { + Console.WriteLine("getStruct({0})", key); + return log[key]; + } + + public void zip() + { + Console.WriteLine("zip()"); + } + } + + public class CSharpServer + { + public static void Main() + { + try + { + CalculatorHandler handler = new CalculatorHandler(); + Calculator.Processor processor = new Calculator.Processor(handler); + TServerTransport serverTransport = new TServerSocket(9090); + TServer server = new TSimpleServer(processor, serverTransport); + + // Use this for a multithreaded server + // server = new TThreadPoolServer(processor, serverTransport); + + Console.WriteLine("Starting the server..."); + server.Serve(); + } + catch (Exception x) + { + Console.WriteLine(x.StackTrace); + } + Console.WriteLine("done."); + } + } +} diff --git a/test/csharp/ThriftTest/Program.cs b/test/csharp/ThriftTest/Program.cs new file mode 100644 index 000000000..4c63ca478 --- /dev/null +++ b/test/csharp/ThriftTest/Program.cs @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// Distributed under the Thrift Software License +// +// See accompanying file LICENSE or visit the Thrift site at: +// http://developers.facebook.com/thrift/ + +using System; +using Thrift.Transport; +using Thrift.Protocol; +using Thrift.Test; //generated code + +namespace Test +{ + class Program + { + static void Main(string[] args) + { + if (args.Length == 0) + { + Console.WriteLine("must provide 'server' or 'client' arg"); + return; + } + + string[] subArgs = new string[args.Length - 1]; + for(int i = 1; i < args.Length; i++) + { + subArgs[i-1] = args[i]; + } + if (args[0] == "client") + { + TestClient.Execute(subArgs); + } + else if (args[0] == "server") + { + TestServer.Execute(subArgs); + } + else + { + Console.WriteLine("first argument must be 'server' or 'client'"); + } + } + } +} diff --git a/test/csharp/ThriftTest/Properties/AssemblyInfo.cs b/test/csharp/ThriftTest/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..504ca8de7 --- /dev/null +++ b/test/csharp/ThriftTest/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ThriftTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ThriftTest")] +[assembly: AssemblyCopyright("Copyright © 2009 The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f41b193b-f1ab-48ee-8843-f88e43084e26")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/csharp/ThriftTest/TestClient.cs b/test/csharp/ThriftTest/TestClient.cs new file mode 100644 index 000000000..2d278b7f1 --- /dev/null +++ b/test/csharp/ThriftTest/TestClient.cs @@ -0,0 +1,425 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using Thrift.Collections; +using Thrift.Protocol; +using Thrift.Transport; +using Thrift.Test; + +namespace Test +{ + public class TestClient + { + private static int numIterations = 1; + + public static void Execute(string[] args) + { + try + { + string host = "localhost"; + int port = 9090; + string url = null; + int numThreads = 1; + bool buffered = false; + + try + { + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-h") + { + string[] hostport = args[++i].Split(':'); + host = hostport[0]; + if (hostport.Length > 1) + { + port = Convert.ToInt32(hostport[1]); + } + } + else if (args[i] == "-u") + { + url = args[++i]; + } + else if (args[i] == "-n") + { + numIterations = Convert.ToInt32(args[++i]); + } + else if (args[i] == "-b" || args[i] == "-buffered") + { + buffered = true; + Console.WriteLine("Using buffered sockets"); + } + else if (args[i] == "-t") + { + numThreads = Convert.ToInt32(args[++i]); + } + } + } + catch (Exception e) + { + Console.WriteLine(e.StackTrace); + } + + + + //issue tests on separate threads simultaneously + Thread[] threads = new Thread[numThreads]; + DateTime start = DateTime.Now; + for (int test = 0; test < numThreads; test++) + { + Thread t = new Thread(new ParameterizedThreadStart(ClientThread)); + threads[test] = t; + TSocket socket = new TSocket(host, port); + if (buffered) + { + TBufferedTransport buffer = new TBufferedTransport(socket); + t.Start(buffer); + } + else + { + t.Start(socket); + } + } + + for (int test = 0; test < numThreads; test++) + { + threads[test].Join(); + } + Console.Write("Total time: " + (DateTime.Now - start)); + } + catch (Exception outerEx) + { + Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace); + } + + Console.WriteLine(); + Console.WriteLine(); + } + + public static void ClientThread(object obj) + { + TTransport transport = (TTransport)obj; + for (int i = 0; i < numIterations; i++) + { + ClientTest(transport); + } + transport.Close(); + } + + public static void ClientTest(TTransport transport) + { + TBinaryProtocol binaryProtocol = new TBinaryProtocol(transport); + + ThriftTest.Client client = new ThriftTest.Client(binaryProtocol); + try + { + if (!transport.IsOpen) + { + transport.Open(); + } + } + catch (TTransportException ttx) + { + Console.WriteLine("Connect failed: " + ttx.Message); + return; + } + + long start = DateTime.Now.ToFileTime(); + + Console.Write("testVoid()"); + client.testVoid(); + Console.WriteLine(" = void"); + + Console.Write("testString(\"Test\")"); + string s = client.testString("Test"); + Console.WriteLine(" = \"" + s + "\""); + + Console.Write("testByte(1)"); + byte i8 = client.testByte((byte)1); + Console.WriteLine(" = " + i8); + + Console.Write("testI32(-1)"); + int i32 = client.testI32(-1); + Console.WriteLine(" = " + i32); + + Console.Write("testI64(-34359738368)"); + long i64 = client.testI64(-34359738368); + Console.WriteLine(" = " + i64); + + Console.Write("testDouble(5.325098235)"); + double dub = client.testDouble(5.325098235); + Console.WriteLine(" = " + dub); + + Console.Write("testStruct({\"Zero\", 1, -3, -5})"); + Xtruct o = new Xtruct(); + o.String_thing = "Zero"; + o.Byte_thing = (byte)1; + o.I32_thing = -3; + o.I64_thing = -5; + Xtruct i = client.testStruct(o); + Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}"); + + Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})"); + Xtruct2 o2 = new Xtruct2(); + o2.Byte_thing = (byte)1; + o2.Struct_thing = o; + o2.I32_thing = 5; + Xtruct2 i2 = client.testNest(o2); + i = i2.Struct_thing; + Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}"); + + Dictionary<int, int> mapout = new Dictionary<int, int>(); + for (int j = 0; j < 5; j++) + { + mapout[j] = j - 10; + } + Console.Write("testMap({"); + bool first = true; + foreach (int key in mapout.Keys) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(key + " => " + mapout[key]); + } + Console.Write("})"); + + Dictionary<int, int> mapin = client.testMap(mapout); + + Console.Write(" = {"); + first = true; + foreach (int key in mapin.Keys) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(key + " => " + mapin[key]); + } + Console.WriteLine("}"); + + List<int> listout = new List<int>(); + for (int j = -2; j < 3; j++) + { + listout.Add(j); + } + Console.Write("testList({"); + first = true; + foreach (int j in listout) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.Write("})"); + + List<int> listin = client.testList(listout); + + Console.Write(" = {"); + first = true; + foreach (int j in listin) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.WriteLine("}"); + + //set + THashSet<int> setout = new THashSet<int>(); + for (int j = -2; j < 3; j++) + { + setout.Add(j); + } + Console.Write("testSet({"); + first = true; + foreach (int j in setout) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.Write("})"); + + THashSet<int> setin = client.testSet(setout); + + Console.Write(" = {"); + first = true; + foreach (int j in setin) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.WriteLine("}"); + + + Console.Write("testEnum(ONE)"); + Numberz ret = client.testEnum(Numberz.ONE); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(TWO)"); + ret = client.testEnum(Numberz.TWO); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(THREE)"); + ret = client.testEnum(Numberz.THREE); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(FIVE)"); + ret = client.testEnum(Numberz.FIVE); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(EIGHT)"); + ret = client.testEnum(Numberz.EIGHT); + Console.WriteLine(" = " + ret); + + Console.Write("testTypedef(309858235082523)"); + long uid = client.testTypedef(309858235082523L); + Console.WriteLine(" = " + uid); + + Console.Write("testMapMap(1)"); + Dictionary<int, Dictionary<int, int>> mm = client.testMapMap(1); + Console.Write(" = {"); + foreach (int key in mm.Keys) + { + Console.Write(key + " => {"); + Dictionary<int, int> m2 = mm[key]; + foreach (int k2 in m2.Keys) + { + Console.Write(k2 + " => " + m2[k2] + ", "); + } + Console.Write("}, "); + } + Console.WriteLine("}"); + + Insanity insane = new Insanity(); + insane.UserMap = new Dictionary<Numberz, long>(); + insane.UserMap[Numberz.FIVE] = 5000L; + Xtruct truck = new Xtruct(); + truck.String_thing = "Truck"; + truck.Byte_thing = (byte)8; + truck.I32_thing = 8; + truck.I64_thing = 8; + insane.Xtructs = new List<Xtruct>(); + insane.Xtructs.Add(truck); + Console.Write("testInsanity()"); + Dictionary<long, Dictionary<Numberz, Insanity>> whoa = client.testInsanity(insane); + Console.Write(" = {"); + foreach (long key in whoa.Keys) + { + Dictionary<Numberz, Insanity> val = whoa[key]; + Console.Write(key + " => {"); + + foreach (Numberz k2 in val.Keys) + { + Insanity v2 = val[k2]; + + Console.Write(k2 + " => {"); + Dictionary<Numberz, long> userMap = v2.UserMap; + + Console.Write("{"); + if (userMap != null) + { + foreach (Numberz k3 in userMap.Keys) + { + Console.Write(k3 + " => " + userMap[k3] + ", "); + } + } + else + { + Console.Write("null"); + } + Console.Write("}, "); + + List<Xtruct> xtructs = v2.Xtructs; + + Console.Write("{"); + if (xtructs != null) + { + foreach (Xtruct x in xtructs) + { + Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, "); + } + } + else + { + Console.Write("null"); + } + Console.Write("}"); + + Console.Write("}, "); + } + Console.Write("}, "); + } + Console.WriteLine("}"); + + + byte arg0 = 1; + int arg1 = 2; + long arg2 = long.MaxValue; + Dictionary<short, string> multiDict = new Dictionary<short, string>(); + multiDict[1] = "one"; + Numberz arg4 = Numberz.FIVE; + long arg5 = 5000000; + Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")"); + Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5); + Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing + + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n"); + + Console.WriteLine("Test Oneway(1)"); + client.testOneway(1); + } + } +} diff --git a/test/csharp/ThriftTest/TestServer.cs b/test/csharp/ThriftTest/TestServer.cs new file mode 100644 index 000000000..e37064040 --- /dev/null +++ b/test/csharp/ThriftTest/TestServer.cs @@ -0,0 +1,348 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// Distributed under the Thrift Software License +// +// See accompanying file LICENSE or visit the Thrift site at: +// http://developers.facebook.com/thrift/ +using System; +using System.Collections.Generic; +using Thrift.Collections; +using Thrift.Test; //generated code +using Thrift.Transport; +using Thrift.Protocol; +using Thrift.Server; + +namespace Test +{ + public class TestServer + { + public class TestHandler : ThriftTest.Iface + { + public TServer server; + + public TestHandler() { } + + public void testVoid() + { + Console.WriteLine("testVoid()"); + } + + public string testString(string thing) + { + Console.WriteLine("teststring(\"" + thing + "\")"); + return thing; + } + + public byte testByte(byte thing) + { + Console.WriteLine("testByte(" + thing + ")"); + return thing; + } + + public int testI32(int thing) + { + Console.WriteLine("testI32(" + thing + ")"); + return thing; + } + + public long testI64(long thing) + { + Console.WriteLine("testI64(" + thing + ")"); + return thing; + } + + public double testDouble(double thing) + { + Console.WriteLine("testDouble(" + thing + ")"); + return thing; + } + + public Xtruct testStruct(Xtruct thing) + { + Console.WriteLine("testStruct({" + + "\"" + thing.String_thing + "\", " + + thing.Byte_thing + ", " + + thing.I32_thing + ", " + + thing.I64_thing + "})"); + return thing; + } + + public Xtruct2 testNest(Xtruct2 nest) + { + Xtruct thing = nest.Struct_thing; + Console.WriteLine("testNest({" + + nest.Byte_thing + ", {" + + "\"" + thing.String_thing + "\", " + + thing.Byte_thing + ", " + + thing.I32_thing + ", " + + thing.I64_thing + "}, " + + nest.I32_thing + "})"); + return nest; + } + + public Dictionary<int, int> testMap(Dictionary<int, int> thing) + { + Console.WriteLine("testMap({"); + bool first = true; + foreach (int key in thing.Keys) + { + if (first) + { + first = false; + } + else + { + Console.WriteLine(", "); + } + Console.WriteLine(key + " => " + thing[key]); + } + Console.WriteLine("})"); + return thing; + } + + public THashSet<int> testSet(THashSet<int> thing) + { + Console.WriteLine("testSet({"); + bool first = true; + foreach (int elem in thing) + { + if (first) + { + first = false; + } + else + { + Console.WriteLine(", "); + } + Console.WriteLine(elem); + } + Console.WriteLine("})"); + return thing; + } + + public List<int> testList(List<int> thing) + { + Console.WriteLine("testList({"); + bool first = true; + foreach (int elem in thing) + { + if (first) + { + first = false; + } + else + { + Console.WriteLine(", "); + } + Console.WriteLine(elem); + } + Console.WriteLine("})"); + return thing; + } + + public Numberz testEnum(Numberz thing) + { + Console.WriteLine("testEnum(" + thing + ")"); + return thing; + } + + public long testTypedef(long thing) + { + Console.WriteLine("testTypedef(" + thing + ")"); + return thing; + } + + public Dictionary<int, Dictionary<int, int>> testMapMap(int hello) + { + Console.WriteLine("testMapMap(" + hello + ")"); + Dictionary<int, Dictionary<int, int>> mapmap = + new Dictionary<int, Dictionary<int, int>>(); + + Dictionary<int, int> pos = new Dictionary<int, int>(); + Dictionary<int, int> neg = new Dictionary<int, int>(); + for (int i = 1; i < 5; i++) + { + pos[i] = i; + neg[-i] = -i; + } + + mapmap[4] = pos; + mapmap[-4] = neg; + + return mapmap; + } + + public Dictionary<long, Dictionary<Numberz, Insanity>> testInsanity(Insanity argument) + { + Console.WriteLine("testInsanity()"); + + Xtruct hello = new Xtruct(); + hello.String_thing = "Hello2"; + hello.Byte_thing = 2; + hello.I32_thing = 2; + hello.I64_thing = 2; + + Xtruct goodbye = new Xtruct(); + goodbye.String_thing = "Goodbye4"; + goodbye.Byte_thing = (byte)4; + goodbye.I32_thing = 4; + goodbye.I64_thing = (long)4; + + Insanity crazy = new Insanity(); + crazy.UserMap = new Dictionary<Numberz, long>(); + crazy.UserMap[Numberz.EIGHT] = (long)8; + crazy.Xtructs = new List<Xtruct>(); + crazy.Xtructs.Add(goodbye); + + Insanity looney = new Insanity(); + crazy.UserMap[Numberz.FIVE] = (long)5; + crazy.Xtructs.Add(hello); + + Dictionary<Numberz, Insanity> first_map = new Dictionary<Numberz, Insanity>(); + Dictionary<Numberz, Insanity> second_map = new Dictionary<Numberz, Insanity>(); ; + + first_map[Numberz.TWO] = crazy; + first_map[Numberz.THREE] = crazy; + + second_map[Numberz.SIX] = looney; + + Dictionary<long, Dictionary<Numberz, Insanity>> insane = + new Dictionary<long, Dictionary<Numberz, Insanity>>(); + insane[(long)1] = first_map; + insane[(long)2] = second_map; + + return insane; + } + + public Xtruct testMulti(byte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5) + { + Console.WriteLine("testMulti()"); + + Xtruct hello = new Xtruct(); ; + hello.String_thing = "Hello2"; + hello.Byte_thing = arg0; + hello.I32_thing = arg1; + hello.I64_thing = arg2; + return hello; + } + + public void testException(string arg) + { + Console.WriteLine("testException(" + arg + ")"); + if (arg == "Xception") + { + Xception x = new Xception(); + x.ErrorCode = 1001; + x.Message = "This is an Xception"; + throw x; + } + return; + } + + public Xtruct testMultiException(string arg0, string arg1) + { + Console.WriteLine("testMultiException(" + arg0 + ", " + arg1 + ")"); + if (arg0 == "Xception") + { + Xception x = new Xception(); + x.ErrorCode = 1001; + x.Message = "This is an Xception"; + throw x; + } + else if (arg0 == "Xception2") + { + Xception2 x = new Xception2(); + x.ErrorCode = 2002; + x.Struct_thing = new Xtruct(); + x.Struct_thing.String_thing = "This is an Xception2"; + throw x; + } + + Xtruct result = new Xtruct(); + result.String_thing = arg1; + return result; + } + + public void testStop() + { + if (server != null) + { + server.Stop(); + } + } + + public void testOneway(int arg) + { + Console.WriteLine("testOneway(" + arg + "), sleeping..."); + System.Threading.Thread.Sleep(arg * 1000); + Console.WriteLine("testOneway finished"); + } + + } // class TestHandler + + public static void Execute(string[] args) + { + try + { + bool useBufferedSockets = false; + int port = 9090; + if (args.Length > 0) + { + port = int.Parse(args[0]); + + if (args.Length > 1) + { + bool.TryParse(args[1], out useBufferedSockets); + } + } + + // Processor + TestHandler testHandler = new TestHandler(); + ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler); + + // Transport + TServerSocket tServerSocket = new TServerSocket(port, 0, useBufferedSockets); + + TServer serverEngine; + + // Simple Server + serverEngine = new TSimpleServer(testProcessor, tServerSocket); + + // ThreadPool Server + // serverEngine = new TThreadPoolServer(testProcessor, tServerSocket); + + // Threaded Server + // serverEngine = new TThreadedServer(testProcessor, tServerSocket); + + testHandler.server = serverEngine; + + // Run it + Console.WriteLine("Starting the server on port " + port + (useBufferedSockets ? " with buffered socket" : "") + "..."); + serverEngine.Serve(); + + } + catch (Exception x) + { + Console.Error.Write(x); + } + Console.WriteLine("done."); + } + } +} diff --git a/test/csharp/ThriftTest/ThriftTest.csproj b/test/csharp/ThriftTest/ThriftTest.csproj new file mode 100644 index 000000000..3f427fd77 --- /dev/null +++ b/test/csharp/ThriftTest/ThriftTest.csproj @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.21022</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ThriftTest</RootNamespace> + <AssemblyName>ThriftTest</AssemblyName> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <PublishUrl>publish\</PublishUrl> + <Install>true</Install> + <InstallFrom>Disk</InstallFrom> + <UpdateEnabled>false</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.%2a</ApplicationVersion> + <IsWebBootstrapper>false</IsWebBootstrapper> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + <SccProjectName>SAK</SccProjectName> + <SccLocalPath>SAK</SccLocalPath> + <SccAuxPath>SAK</SccAuxPath> + <SccProvider>SAK</SccProvider> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="ThriftImpl, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>.\ThriftImpl.dll</HintPath> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="TestClient.cs" /> + <Compile Include="TestServer.cs" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include="Microsoft.Net.Framework.2.0"> + <Visible>False</Visible> + <ProductName>.NET Framework 2.0 %28x86%29</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.0"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.0 %28x86%29</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1"> + <Visible>False</Visible> + <ProductName>Windows Installer 3.1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\lib\csharp\src\Thrift.csproj"> + <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project> + <Name>Thrift</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <PropertyGroup> + <PreBuildEvent>rmdir /s /q $(ProjectDir)gen-csharp +del /f /q $(ProjectDir)ThriftImpl.dll + +$(ProjectDir)\..\..\..\compiler\cpp\thrift.exe -csharp -o $(ProjectDir) $(ProjectDir)\..\..\ThriftTest.thrift + +cd $(ProjectDir) + +$(MSBuildToolsPath)\Csc.exe /t:library /out:.\ThriftImpl.dll /recurse:.\gen-csharp\* /reference:$(ProjectDir)..\..\..\lib\csharp\src\bin\Debug\Thrift.dll</PreBuildEvent> + </PropertyGroup> +</Project> diff --git a/test/csharp/ThriftTest/maketest.sh b/test/csharp/ThriftTest/maketest.sh new file mode 100755 index 000000000..5580de802 --- /dev/null +++ b/test/csharp/ThriftTest/maketest.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +../../../compiler/cpp/thrift --gen csharp -o . ../../ThriftTest.thrift +gmcs /t:library /out:./ThriftImpl.dll /recurse:./gen-csharp/* /reference:../../../lib/csharp/Thrift.dll diff --git a/test/erl/Makefile b/test/erl/Makefile new file mode 100644 index 000000000..17e30da6f --- /dev/null +++ b/test/erl/Makefile @@ -0,0 +1,66 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +GENDIR=gen +GEN_INCLUDEDIR=$(GENDIR)/include +GEN_SRCDIR=$(GENDIR)/src +GEN_TARGETDIR=$(GENDIR)/ebin + +INCLUDEDIR=include +TARGETDIR=ebin +SRCDIR=src + +ALL_INCLUDEDIR=$(GEN_INCLUDEDIR) $(INCLUDEDIR) ../../lib/erl/include +INCLUDEFLAGS=$(patsubst %,-I%, ${ALL_INCLUDEDIR}) + +MODULES = stress_server test_server test_disklog test_membuffer + +INCLUDES = +TARGETS = $(patsubst %,${TARGETDIR}/%.beam,${MODULES}) +HEADERS = $(patsubst %,${INCLUDEDIR}/%.hrl,${INCLUDES}) + +all: ${GEN_TARGETDIR}/ ${TARGETS} + +TEST_RPCFILE = ../ThriftTest.thrift +STRESS_RPCFILE = ../StressTest.thrift +THRIFT = ../../compiler/cpp/thrift + +${GENDIR}/: ${RPCFILE} + rm -rf ${GENDIR} + ${THRIFT} --gen erl ${TEST_RPCFILE} + ${THRIFT} --gen erl ${STRESS_RPCFILE} + mkdir -p ${GEN_INCLUDEDIR} + mkdir -p ${GEN_SRCDIR} + mkdir -p ${GEN_TARGETDIR} + mv -t ${GEN_INCLUDEDIR} gen-erl/*.hrl + mv -t ${GEN_SRCDIR} gen-erl/*.erl + rm -rf gen-erl + +${GEN_TARGETDIR}/: ${GENDIR}/ + rm -rf ${GEN_TARGETDIR} + mkdir -p ${GEN_TARGETDIR} + erlc ${INCLUDEFLAGS} -o ${GEN_TARGETDIR} ${GEN_SRCDIR}/*.erl + +$(TARGETS): ${TARGETDIR}/%.beam: ${SRCDIR}/%.erl ${GEN_INCLUDEDIR}/ ${HEADERS} + mkdir -p ${TARGETDIR} + erlc ${INCLUDEFLAGS} -o ${TARGETDIR} $< + +clean: + rm -f ${TARGETDIR}/*.beam + rm -rf ${GENDIR} diff --git a/test/erl/src/stress_server.erl b/test/erl/src/stress_server.erl new file mode 100644 index 000000000..35fff0693 --- /dev/null +++ b/test/erl/src/stress_server.erl @@ -0,0 +1,64 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF 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. +%% + +-module(stress_server). + + +-export([start_link/1, + + handle_function/2, + + echoVoid/0, + echoByte/1, + echoI32/1, + echoI64/1, + echoString/1, + echoList/1, + echoSet/1, + echoMap/1 + ]). + +start_link(Port) -> + thrift_server:start_link(Port, service_thrift, ?MODULE). + + +handle_function(Function, Args) -> + case apply(?MODULE, Function, tuple_to_list(Args)) of + ok -> + ok; + Else -> {reply, Else} + end. + + +echoVoid() -> + ok. +echoByte(X) -> + X. +echoI32(X) -> + X. +echoI64(X) -> + X. +echoString(X) -> + X. +echoList(X) -> + X. +echoSet(X) -> + X. +echoMap(X) -> + X. diff --git a/test/erl/src/test_disklog.erl b/test/erl/src/test_disklog.erl new file mode 100644 index 000000000..7b0be72db --- /dev/null +++ b/test/erl/src/test_disklog.erl @@ -0,0 +1,81 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF 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. +%% + +-module(test_disklog). + +-compile(export_all). + +t() -> + {ok, TransportFactory} = + thrift_disk_log_transport:new_transport_factory( + test_disklog, + [{file, "/tmp/test_log"}, + {size, {1024*1024, 10}}]), + {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory( + TransportFactory, []), + {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift), + + io:format("Client started~n"), + + % We have to make oneway calls into this client only since otherwise it will try + % to read from the disklog and go boom. + {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]), + io:format("Call written~n"), + + % Use the send_call method to write a non-oneway call into the log + ok = thrift_client:send_call(Client, testString, [<<"hello world">>]), + io:format("Non-oneway call sent~n"), + + ok = thrift_client:close(Client), + io:format("Client closed~n"), + + ok. + + + +t_base64() -> + {ok, TransportFactory} = + thrift_disk_log_transport:new_transport_factory( + test_disklog, + [{file, "/tmp/test_b64_log"}, + {size, {1024*1024, 10}}]), + {ok, B64Factory} = + thrift_base64_transport:new_transport_factory(TransportFactory), + {ok, BufFactory} = + thrift_buffered_transport:new_transport_factory(B64Factory), + {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory( + BufFactory, []), + {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift), + + io:format("Client started~n"), + + % We have to make oneway calls into this client only since otherwise it will try + % to read from the disklog and go boom. + {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]), + io:format("Call written~n"), + + % Use the send_call method to write a non-oneway call into the log + ok = thrift_client:send_call(Client, testString, [<<"hello world">>]), + io:format("Non-oneway call sent~n"), + + ok = thrift_client:close(Client), + io:format("Client closed~n"), + + ok. + diff --git a/test/erl/src/test_membuffer.erl b/test/erl/src/test_membuffer.erl new file mode 100644 index 000000000..7bd23a0f1 --- /dev/null +++ b/test/erl/src/test_membuffer.erl @@ -0,0 +1,81 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF 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. +%% + +-module(test_membuffer). +-export([t/0]). + +-include("thriftTest_types.hrl"). + +test_data() -> + #xtruct{string_thing = <<"foobar">>, + byte_thing = 123, + i32_thing = 1234567, + i64_thing = 12345678900}. + +t1() -> + {ok, Transport} = thrift_memory_buffer:new(), + {ok, Protocol} = thrift_binary_protocol:new(Transport), + TestData = test_data(), + ok = thrift_protocol:write(Protocol, + {{struct, element(2, thriftTest_types:struct_info('xtruct'))}, + TestData}), + {ok, Result} = thrift_protocol:read(Protocol, + {struct, element(2, thriftTest_types:struct_info('xtruct'))}, + 'xtruct'), + + Result = TestData. + + +t2() -> + {ok, Transport} = thrift_memory_buffer:new(), + {ok, Protocol} = thrift_binary_protocol:new(Transport), + TestData = test_data(), + ok = thrift_protocol:write(Protocol, + {{struct, element(2, thriftTest_types:struct_info('xtruct'))}, + TestData}), + {ok, Result} = thrift_protocol:read(Protocol, + {struct, element(2, thriftTest_types:struct_info('xtruct3'))}, + 'xtruct3'), + + Result = #xtruct3{string_thing = TestData#xtruct.string_thing, + changed = undefined, + i32_thing = TestData#xtruct.i32_thing, + i64_thing = TestData#xtruct.i64_thing}. + + +t3() -> + {ok, Transport} = thrift_memory_buffer:new(), + {ok, Protocol} = thrift_binary_protocol:new(Transport), + TestData = #bools{im_true = true, im_false = false}, + ok = thrift_protocol:write(Protocol, + {{struct, element(2, thriftTest_types:struct_info('bools'))}, + TestData}), + {ok, Result} = thrift_protocol:read(Protocol, + {struct, element(2, thriftTest_types:struct_info('bools'))}, + 'bools'), + + true = TestData#bools.im_true =:= Result#bools.im_true, + true = TestData#bools.im_false =:= Result#bools.im_false. + + +t() -> + t1(), + t2(), + t3(). + diff --git a/test/erl/src/test_server.erl b/test/erl/src/test_server.erl new file mode 100644 index 000000000..cd439ccdf --- /dev/null +++ b/test/erl/src/test_server.erl @@ -0,0 +1,174 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF 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. +%% + +-module(test_server). + +-export([start_link/1, handle_function/2]). + +-include("thriftTest_types.hrl"). + +start_link(Port) -> + thrift_server:start_link(Port, thriftTest_thrift, ?MODULE). + + +handle_function(testVoid, {}) -> + io:format("testVoid~n"), + ok; + +handle_function(testString, {S}) when is_binary(S) -> + io:format("testString: ~p~n", [S]), + {reply, S}; + +handle_function(testByte, {I8}) when is_integer(I8) -> + io:format("testByte: ~p~n", [I8]), + {reply, I8}; + +handle_function(testI32, {I32}) when is_integer(I32) -> + io:format("testI32: ~p~n", [I32]), + {reply, I32}; + +handle_function(testI64, {I64}) when is_integer(I64) -> + io:format("testI64: ~p~n", [I64]), + {reply, I64}; + +handle_function(testDouble, {Double}) when is_float(Double) -> + io:format("testDouble: ~p~n", [Double]), + {reply, Double}; + +handle_function(testStruct, + {Struct = #xtruct{string_thing = String, + byte_thing = Byte, + i32_thing = I32, + i64_thing = I64}}) +when is_binary(String), + is_integer(Byte), + is_integer(I32), + is_integer(I64) -> + io:format("testStruct: ~p~n", [Struct]), + {reply, Struct}; + +handle_function(testNest, + {Nest}) when is_record(Nest, xtruct2), + is_record(Nest#xtruct2.struct_thing, xtruct) -> + io:format("testNest: ~p~n", [Nest]), + {reply, Nest}; + +handle_function(testMap, {Map}) -> + io:format("testMap: ~p~n", [dict:to_list(Map)]), + {reply, Map}; + +handle_function(testSet, {Set}) -> + true = sets:is_set(Set), + io:format("testSet: ~p~n", [sets:to_list(Set)]), + {reply, Set}; + +handle_function(testList, {List}) when is_list(List) -> + io:format("testList: ~p~n", [List]), + {reply, List}; + +handle_function(testEnum, {Enum}) when is_integer(Enum) -> + io:format("testEnum: ~p~n", [Enum]), + {reply, Enum}; + +handle_function(testTypedef, {UserID}) when is_integer(UserID) -> + io:format("testTypedef: ~p~n", [UserID]), + {reply, UserID}; + +handle_function(testMapMap, {Hello}) -> + io:format("testMapMap: ~p~n", [Hello]), + + PosList = [{I, I} || I <- lists:seq(1, 5)], + NegList = [{-I, -I} || I <- lists:seq(1, 5)], + + MapMap = dict:from_list([{4, dict:from_list(PosList)}, + {-4, dict:from_list(NegList)}]), + {reply, MapMap}; + +handle_function(testInsanity, {Insanity}) when is_record(Insanity, insanity) -> + Hello = #xtruct{string_thing = <<"Hello2">>, + byte_thing = 2, + i32_thing = 2, + i64_thing = 2}, + + Goodbye = #xtruct{string_thing = <<"Goodbye4">>, + byte_thing = 4, + i32_thing = 4, + i64_thing = 4}, + Crazy = #insanity{ + userMap = dict:from_list([{?thriftTest_EIGHT, 8}]), + xtructs = [Goodbye] + }, + + Looney = #insanity{ + userMap = dict:from_list([{?thriftTest_FIVE, 5}]), + xtructs = [Hello] + }, + + FirstMap = dict:from_list([{?thriftTest_TWO, Crazy}, + {?thriftTest_THREE, Crazy}]), + + SecondMap = dict:from_list([{?thriftTest_SIX, Looney}]), + + Insane = dict:from_list([{1, FirstMap}, + {2, SecondMap}]), + + io:format("Return = ~p~n", [Insane]), + + {reply, Insane}; + +handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5}) + when is_integer(Arg0), + is_integer(Arg1), + is_integer(Arg2), + is_integer(Arg4), + is_integer(Arg5) -> + + io:format("testMulti(~p)~n", [Args]), + {reply, #xtruct{string_thing = <<"Hello2">>, + byte_thing = Arg0, + i32_thing = Arg1, + i64_thing = Arg2}}; + +handle_function(testException, {String}) when is_binary(String) -> + io:format("testException(~p)~n", [String]), + case String of + <<"Xception">> -> + throw(#xception{errorCode = 1001, + message = <<"This is an Xception">>}); + _ -> + ok + end; + +handle_function(testMultiException, {Arg0, Arg1}) -> + io:format("testMultiException(~p, ~p)~n", [Arg0, Arg1]), + case Arg0 of + <<"Xception">> -> + throw(#xception{errorCode = 1001, + message = <<"This is an Xception">>}); + <<"Xception2">> -> + throw(#xception2{errorCode = 2002, + struct_thing = + #xtruct{string_thing = <<"This is an Xception2">>}}); + _ -> + {reply, #xtruct{string_thing = Arg1}} + end; + +handle_function(testOneway, {Seconds}) -> + timer:sleep(1000 * Seconds), + ok. diff --git a/test/hs/Client.hs b/test/hs/Client.hs new file mode 100644 index 000000000..c5e4d9074 --- /dev/null +++ b/test/hs/Client.hs @@ -0,0 +1,58 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF 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. +-- + +module Client where + +import ThriftTest_Client +import ThriftTest_Types +import qualified Data.Map as Map +import qualified Data.Set as Set +import Control.Monad +import Control.Exception as CE + +import Network + +import Thrift +import Thrift.Transport.Handle +import Thrift.Protocol.Binary + + +serverAddress = ("127.0.0.1", PortNumber 9090) + +main = do to <- hOpen serverAddress + let p = BinaryProtocol to + let ps = (p,p) + print =<< testString ps "bya" + print =<< testByte ps 8 + print =<< testByte ps (-8) + print =<< testI32 ps 32 + print =<< testI32 ps (-32) + print =<< testI64 ps 64 + print =<< testI64 ps (-64) + print =<< testDouble ps 3.14 + print =<< testDouble ps (-3.14) + print =<< testMap ps (Map.fromList [(1,1),(2,2),(3,3)]) + print =<< testList ps [1,2,3,4,5] + print =<< testSet ps (Set.fromList [1,2,3,4,5]) + print =<< testStruct ps (Xtruct (Just "hi") (Just 4) (Just 5) Nothing) + CE.catch (testException ps "e" >> print "bad") (\e -> print (e :: Xception)) + CE.catch (testMultiException ps "e" "e2" >> print "ok") (\e -> print (e :: Xception)) + CE.catch (CE.catch (testMultiException ps "e" "e2">> print "bad") (\e -> print (e :: Xception2))) (\(e :: SomeException) -> print "ok") + tClose to + diff --git a/test/hs/Server.hs b/test/hs/Server.hs new file mode 100644 index 000000000..0ca9d9fea --- /dev/null +++ b/test/hs/Server.hs @@ -0,0 +1,57 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF 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. +-- + +module Server where + +import ThriftTest +import ThriftTest_Iface +import Data.Map as Map +import Control.Exception +import ThriftTest_Types + +import Thrift +import Thrift.Server + + +data TestHandler = TestHandler +instance ThriftTest_Iface TestHandler where + testVoid a = return () + testString a (Just s) = do print s; return s + testByte a (Just x) = do print x; return x + testI32 a (Just x) = do print x; return x + testI64 a (Just x) = do print x; return x + testDouble a (Just x) = do print x; return x + testStruct a (Just x) = do print x; return x + testNest a (Just x) = do print x; return x + testMap a (Just x) = do print x; return x + testSet a (Just x) = do print x; return x + testList a (Just x) = do print x; return x + testEnum a (Just x) = do print x; return x + testTypedef a (Just x) = do print x; return x + testMapMap a (Just x) = return (Map.fromList [(1,Map.fromList [(2,2)])]) + testInsanity a (Just x) = return (Map.fromList [(1,Map.fromList [(ONE,x)])]) + testMulti a a1 a2 a3 a4 a5 a6 = return (Xtruct Nothing Nothing Nothing Nothing) + testException a c = throw (Xception (Just 1) (Just "bya")) + testMultiException a c1 c2 = throw (Xception (Just 1) (Just "xyz")) + testOneway a (Just i) = do print i + + +main = do (runBasicServer TestHandler process 9090) + `Control.Exception.catch` + (\(TransportExn s t) -> print s) diff --git a/test/hs/runclient.sh b/test/hs/runclient.sh new file mode 100644 index 000000000..b93bbb147 --- /dev/null +++ b/test/hs/runclient.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +if [ -z $BASE ]; then + BASE=../.. +fi + +ghci -fglasgow-exts -i$BASE/lib/hs/src -i$BASE/test/hs/gen-hs Client.hs diff --git a/test/hs/runserver.sh b/test/hs/runserver.sh new file mode 100644 index 000000000..b23301b48 --- /dev/null +++ b/test/hs/runserver.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +if [ -z $BASE ]; then + BASE=../.. +fi + +printf "Starting server... " +ghc -fglasgow-exts -i$BASE/lib/hs/src -i$BASE/test/hs/gen-hs Server.hs -e "putStrLn \"ready.\" >> Server.main" diff --git a/test/ocaml/Makefile b/test/ocaml/Makefile new file mode 100644 index 000000000..a543ce587 --- /dev/null +++ b/test/ocaml/Makefile @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +all: + cd client; make; cd ..; cd server; make +clean: + cd client; make clean; cd ..; cd server; make clean + diff --git a/test/ocaml/client/Makefile b/test/ocaml/client/Makefile new file mode 100644 index 000000000..806ed20a9 --- /dev/null +++ b/test/ocaml/client/Makefile @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestClient.ml +RESULT = tc +INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/" +LIBS = unix thrift +all: nc +OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile +include $(OCAMLMAKEFILE) diff --git a/test/ocaml/client/TestClient.ml b/test/ocaml/client/TestClient.ml new file mode 100644 index 000000000..91783ae42 --- /dev/null +++ b/test/ocaml/client/TestClient.ml @@ -0,0 +1,82 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF 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. +*) + +open Thrift;; +open ThriftTest_types;; + +let s = new TSocket.t "127.0.0.1" 9090;; +let p = new TBinaryProtocol.t s;; +let c = new ThriftTest.client p p;; +let sod = function + Some v -> v + | None -> raise Thrift_error;; + +s#opn; +print_string (c#testString "bya"); +print_char '\n'; +print_int (c#testByte 8); +print_char '\n'; +print_int (c#testByte (-8)); +print_char '\n'; +print_int (c#testI32 32); +print_char '\n'; +print_string (Int64.to_string (c#testI64 64L)); +print_char '\n'; +print_float (c#testDouble 3.14); +print_char '\n'; + +let l = [1;2;3;4] in + if l = (c#testList l) then print_string "list ok\n" else print_string "list fail\n";; +let h = Hashtbl.create 5 in +let a = Hashtbl.add h in + for i=1 to 10 do + a i (10*i) + done; + let r = c#testMap h in + for i=1 to 10 do + try + let g = Hashtbl.find r i in + print_int i; + print_char ' '; + print_int g; + print_char '\n' + with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n") + done;; + +let s = Hashtbl.create 5 in +let a = Hashtbl.add s in + for i = 1 to 10 do + a i true + done; + let r = c#testSet s in + for i = 1 to 10 do + try + let g = Hashtbl.find r i in + print_int i; + print_char '\n' + with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n") + done;; +try + c#testException "Xception" +with Xception _ -> print_string "testException ok\n";; +try + ignore(c#testMultiException "Xception" "bya") +with Xception e -> Printf.printf "%d %s\n" (sod e#get_errorCode) (sod e#get_message);; + + diff --git a/test/ocaml/server/Makefile b/test/ocaml/server/Makefile new file mode 100644 index 000000000..44dcac761 --- /dev/null +++ b/test/ocaml/server/Makefile @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestServer.ml +RESULT = ts +INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/" +LIBS = thrift +THREADS = yes +all: nc +OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile +include $(OCAMLMAKEFILE) diff --git a/test/ocaml/server/TestServer.ml b/test/ocaml/server/TestServer.ml new file mode 100644 index 000000000..3f5c9ee15 --- /dev/null +++ b/test/ocaml/server/TestServer.ml @@ -0,0 +1,136 @@ +(* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF 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. +*) + +open Thrift +open ThriftTest_types + +let p = Printf.printf;; +exception Die;; +let sod = function + Some v -> v + | None -> raise Die;; + + +class test_handler = +object (self) + inherit ThriftTest.iface + method testVoid = p "testVoid()\n" + method testString x = p "testString(%s)\n" (sod x); (sod x) + method testByte x = p "testByte(%d)\n" (sod x); (sod x) + method testI32 x = p "testI32(%d)\n" (sod x); (sod x) + method testI64 x = p "testI64(%s)\n" (Int64.to_string (sod x)); (sod x) + method testDouble x = p "testDouble(%f)\n" (sod x); (sod x) + method testStruct x = p "testStruct(---)\n"; (sod x) + method testNest x = p "testNest(---)\n"; (sod x) + method testMap x = p "testMap(---)\n"; (sod x) + method testSet x = p "testSet(---)\n"; (sod x) + method testList x = p "testList(---)\n"; (sod x) + method testEnum x = p "testEnum(---)\n"; (sod x) + method testTypedef x = p "testTypedef(---)\n"; (sod x) + method testMapMap x = p "testMapMap(%d)\n" (sod x); + let mm = Hashtbl.create 3 in + let pos = Hashtbl.create 7 in + let neg = Hashtbl.create 7 in + for i=1 to 4 do + Hashtbl.add pos i i; + Hashtbl.add neg (-i) (-i); + done; + Hashtbl.add mm 4 pos; + Hashtbl.add mm (-4) neg; + mm + method testInsanity x = p "testInsanity()\n"; + p "testinsanity()\n"; + let hello = new xtruct in + let goodbye = new xtruct in + let crazy = new insanity in + let looney = new insanity in + let cumap = Hashtbl.create 7 in + let insane = Hashtbl.create 7 in + let firstmap = Hashtbl.create 7 in + let secondmap = Hashtbl.create 7 in + hello#set_string_thing "Hello2"; + hello#set_byte_thing 2; + hello#set_i32_thing 2; + hello#set_i64_thing 2L; + goodbye#set_string_thing "Goodbye4"; + goodbye#set_byte_thing 4; + goodbye#set_i32_thing 4; + goodbye#set_i64_thing 4L; + Hashtbl.add cumap Numberz.EIGHT 8L; + Hashtbl.add cumap Numberz.FIVE 5L; + crazy#set_userMap cumap; + crazy#set_xtructs [goodbye; hello]; + Hashtbl.add firstmap Numberz.TWO crazy; + Hashtbl.add firstmap Numberz.THREE crazy; + Hashtbl.add secondmap Numberz.SIX looney; + Hashtbl.add insane 1L firstmap; + Hashtbl.add insane 2L secondmap; + insane + method testMulti a0 a1 a2 a3 a4 a5 = + p "testMulti()\n"; + let hello = new xtruct in + hello#set_string_thing "Hello2"; + hello#set_byte_thing (sod a0); + hello#set_i32_thing (sod a1); + hello#set_i64_thing (sod a2); + hello + method testException s = + p "testException(%S)\n" (sod s); + if (sod s) = "Xception" then + let x = new xception in + x#set_errorCode 1001; + x#set_message "This is an Xception"; + raise (Xception x) + else () + method testMultiException a0 a1 = + p "testMultiException(%S, %S)\n" (sod a0) (sod a1); + if (sod a0) = "Xception" then + let x = new xception in + x#set_errorCode 1001; + x#set_message "This is an Xception"; + raise (Xception x) + else (if (sod a0) = "Xception2" then + let x = new xception2 in + let s = new xtruct in + x#set_errorCode 2002; + s#set_string_thing "This as an Xception2"; + x#set_struct_thing s; + raise (Xception2 x) + else ()); + let res = new xtruct in + res#set_string_thing (sod a1); + res + method testOneway i = + Unix.sleep (sod i) +end;; + +let h = new test_handler in +let proc = new ThriftTest.processor h in +let port = 9090 in +let pf = new TBinaryProtocol.factory in +let server = new TThreadedServer.t + proc + (new TServerSocket.t port) + (new Transport.factory) + pf + pf +in + server#serve + + diff --git a/test/perl/Makefile b/test/perl/Makefile new file mode 100644 index 000000000..e2d81d452 --- /dev/null +++ b/test/perl/Makefile @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +# Default target is everything +target: all + +# Tools +THRIFT = ../../compiler/cpp/thrift + +all: ../ThriftTest.thrift + $(THRIFT) --gen perl ../ThriftTest.thrift + +clean: + $(RM) -r gen-perl diff --git a/test/perl/TestClient.pl b/test/perl/TestClient.pl new file mode 100644 index 000000000..af80d4694 --- /dev/null +++ b/test/perl/TestClient.pl @@ -0,0 +1,338 @@ +#!/usr/bin/env perl + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require 5.6.0; +use strict; +use warnings; +use Data::Dumper; +use Time::HiRes qw(gettimeofday); + +use lib '../../lib/perl/lib'; +use lib 'gen-perl'; + +use Thrift; +use Thrift::BinaryProtocol; +use Thrift::Socket; +use Thrift::BufferedTransport; + +use ThriftTest::ThriftTest; +use ThriftTest::Types; + +$|++; + +my $host = 'localhost'; +my $port = 9090; + + +my $socket = new Thrift::Socket($host, $port); + +my $bufferedSocket = new Thrift::BufferedTransport($socket, 1024, 1024); +my $transport = $bufferedSocket; +my $protocol = new Thrift::BinaryProtocol($transport); +my $testClient = new ThriftTest::ThriftTestClient($protocol); + +eval{ +$transport->open(); +}; if($@){ + die(Dumper($@)); +} +my $start = gettimeofday(); + +# +# VOID TEST +# +print("testVoid()"); +$testClient->testVoid(); +print(" = void\n"); + +# +# STRING TEST +# +print("testString(\"Test\")"); +my $s = $testClient->testString("Test"); +print(" = \"$s\"\n"); + +# +# BYTE TEST +# +print("testByte(1)"); +my $u8 = $testClient->testByte(1); +print(" = $u8\n"); + +# +# I32 TEST +# +print("testI32(-1)"); +my $i32 = $testClient->testI32(-1); +print(" = $i32\n"); + +# +#I64 TEST +# +print("testI64(-34359738368)"); +my $i64 = $testClient->testI64(-34359738368); +print(" = $i64\n"); + +# +# DOUBLE TEST +# +print("testDouble(-852.234234234)"); +my $dub = $testClient->testDouble(-852.234234234); +print(" = $dub\n"); + +# +# STRUCT TEST +# +print("testStruct({\"Zero\", 1, -3, -5})"); +my $out = new ThriftTest::Xtruct(); +$out->string_thing("Zero"); +$out->byte_thing(1); +$out->i32_thing(-3); +$out->i64_thing(-5); +my $in = $testClient->testStruct($out); +print(" = {\"".$in->string_thing."\", ". + $in->byte_thing.", ". + $in->i32_thing.", ". + $in->i64_thing."}\n"); + +# +# NESTED STRUCT TEST +# +print("testNest({1, {\"Zero\", 1, -3, -5}, 5}"); +my $out2 = new ThriftTest::Xtruct2(); +$out2->byte_thing(1); +$out2->struct_thing($out); +$out2->i32_thing(5); +my $in2 = $testClient->testNest($out2); +$in = $in2->struct_thing; +print(" = {".$in2->byte_thing.", {\"". + $in->string_thing."\", ". + $in->byte_thing.", ". + $in->i32_thing.", ". + $in->i64_thing."}, ". + $in2->i32_thing."}\n"); + +# +# MAP TEST +# +my $mapout = {}; +for (my $i = 0; $i < 5; ++$i) { + $mapout->{$i} = $i-10; +} +print("testMap({"); +my $first = 1; +while( my($key,$val) = each %$mapout) { + if ($first) { + $first = 0; + } else { + print(", "); + } + print("$key => $val"); +} +print("})"); + + +my $mapin = $testClient->testMap($mapout); +print(" = {"); + +$first = 1; +while( my($key,$val) = each %$mapin){ + if ($first) { + $first = 0; + } else { + print(", "); + } + print("$key => $val"); +} +print("}\n"); + +# +# SET TEST +# +my $setout = []; +for (my $i = -2; $i < 3; ++$i) { + push(@$setout, $i); +} + +print("testSet({".join(",",@$setout)."})"); + +my $setin = $testClient->testSet($setout); + +print(" = {".join(",",@$setout)."}\n"); + +# +# LIST TEST +# +my $listout = []; +for (my $i = -2; $i < 3; ++$i) { + push(@$listout, $i); +} + +print("testList({".join(",",@$listout)."})"); + +my $listin = $testClient->testList($listout); + +print(" = {".join(",",@$listin)."}\n"); + +# +# ENUM TEST +# +print("testEnum(ONE)"); +my $ret = $testClient->testEnum(ThriftTest::Numberz::ONE); +print(" = $ret\n"); + +print("testEnum(TWO)"); +$ret = $testClient->testEnum(ThriftTest::Numberz::TWO); +print(" = $ret\n"); + +print("testEnum(THREE)"); +$ret = $testClient->testEnum(ThriftTest::Numberz::THREE); +print(" = $ret\n"); + +print("testEnum(FIVE)"); +$ret = $testClient->testEnum(ThriftTest::Numberz::FIVE); +print(" = $ret\n"); + +print("testEnum(EIGHT)"); +$ret = $testClient->testEnum(ThriftTest::Numberz::EIGHT); +print(" = $ret\n"); + +# +# TYPEDEF TEST +# +print("testTypedef(309858235082523)"); +my $uid = $testClient->testTypedef(309858235082523); +print(" = $uid\n"); + +# +# NESTED MAP TEST +# +print("testMapMap(1)"); +my $mm = $testClient->testMapMap(1); +print(" = {"); +while( my ($key,$val) = each %$mm) { + print("$key => {"); + while( my($k2,$v2) = each %$val) { + print("$k2 => $v2, "); + } + print("}, "); +} +print("}\n"); + +# +# INSANITY TEST +# +my $insane = new ThriftTest::Insanity(); +$insane->{userMap}->{ThriftTest::Numberz::FIVE} = 5000; +my $truck = new ThriftTest::Xtruct(); +$truck->string_thing("Truck"); +$truck->byte_thing(8); +$truck->i32_thing(8); +$truck->i64_thing(8); +push(@{$insane->{xtructs}}, $truck); + +print("testInsanity()"); +my $whoa = $testClient->testInsanity($insane); +print(" = {"); +while( my ($key,$val) = each %$whoa) { + print("$key => {"); + while( my($k2,$v2) = each %$val) { + print("$k2 => {"); + my $userMap = $v2->{userMap}; + print("{"); + if (ref($userMap) eq "HASH") { + while( my($k3,$v3) = each %$userMap) { + print("$k3 => $v3, "); + } + } + print("}, "); + + my $xtructs = $v2->{xtructs}; + print("{"); + if (ref($xtructs) eq "ARRAY") { + foreach my $x (@$xtructs) { + print("{\"".$x->{string_thing}."\", ". + $x->{byte_thing}.", ".$x->{i32_thing}.", ".$x->{i64_thing}."}, "); + } + } + print("}"); + + print("}, "); + } + print("}, "); +} +print("}\n"); + +# +# EXCEPTION TEST +# +print("testException('Xception')"); +eval { + $testClient->testException('Xception'); + print(" void\nFAILURE\n"); +}; if($@ && $@->UNIVERSAL::isa('ThriftTest::Xception')) { + print(' caught xception '.$@->{errorCode}.': '.$@->{message}."\n"); +} + + +# +# Normal tests done. +# +my $stop = gettimeofday(); +my $elp = sprintf("%d",1000*($stop - $start), 0); +print("Total time: $elp ms\n"); + +# +# Extraneous "I don't trust PHP to pack/unpack integer" tests +# + +# Max I32 +my $num = 2**30 + 2**30 - 1; +my $num2 = $testClient->testI32($num); +if ($num != $num2) { + print "Missed max32 $num = $num2\n"; +} + +# Min I32 +$num = 0 - 2**31; +$num2 = $testClient->testI32($num); +if ($num != $num2) { + print "Missed min32 $num = $num2\n"; +} + +# Max Number I can get out of my perl +$num = 2**40; +$num2 = $testClient->testI64($num); +if ($num != $num2) { + print "Missed max64 $num = $num2\n"; +} + +# Max Number I can get out of my perl +$num = 0 - 2**40; +$num2 = $testClient->testI64($num); +if ($num != $num2) { + print "Missed min64 $num = $num2\n"; +} + +$transport->close(); + + + diff --git a/test/php/Makefile b/test/php/Makefile new file mode 100644 index 000000000..aa35c6e93 --- /dev/null +++ b/test/php/Makefile @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +# Default target is everything +target: all + +# Tools +THRIFT = ../../compiler/cpp/thrift + +all: normal inline + +normal: stubs + +inline: stubs-inline + +stubs: ../ThriftTest.thrift + $(THRIFT) --gen php ../ThriftTest.thrift + +stubs-inline: ../ThriftTest.thrift + $(THRIFT) --gen php:inlined ../ThriftTest.thrift + +clean: + $(RM) -r gen-php gen-phpi diff --git a/test/php/TestClient.php b/test/php/TestClient.php new file mode 100644 index 000000000..6d640dac3 --- /dev/null +++ b/test/php/TestClient.php @@ -0,0 +1,398 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +<?php + +if (!isset($GEN_DIR)) { + $GEN_DIR = 'gen-php'; +} +if (!isset($MODE)) { + $MODE = 'normal'; +} + +/** Set the Thrift root */ +$GLOBALS['THRIFT_ROOT'] = '../../lib/php/src'; + +/** Include the Thrift base */ +require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php'; + +/** Include the binary protocol */ +require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php'; + +/** Include the socket layer */ +require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocketPool.php'; + +/** Include the socket layer */ +require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php'; + +echo '==============================='."\n"; +echo ' SAFE TO IGNORE THESE IN TEST'."\n"; +echo '==============================='."\n"; + +/** Include the generated code */ +require_once $GEN_DIR.'/ThriftTest.php'; +require_once $GEN_DIR.'/ThriftTest_types.php'; + +echo '==============================='."\n"; +echo ' END OF SAFE ERRORS SECTION'."\n"; +echo '==============================='."\n\n"; + +$host = 'localhost'; +$port = 9090; + +if ($argc > 1) { + $host = $argv[0]; +} + +if ($argc > 2) { + $host = $argv[1]; +} + +$hosts = array('localhost'); + +$socket = new TSocket($host, $port); +$socket = new TSocketPool($hosts, $port); +$socket->setDebug(TRUE); + +if ($MODE == 'inline') { + $transport = $socket; + $testClient = new ThriftTestClient($transport); +} else { + $bufferedSocket = new TBufferedTransport($socket, 1024, 1024); + $transport = $bufferedSocket; + $protocol = new TBinaryProtocol($transport); + $testClient = new ThriftTestClient($protocol); +} + +$transport->open(); + +$start = microtime(true); + +/** + * VOID TEST + */ +print_r("testVoid()"); +$testClient->testVoid(); +print_r(" = void\n"); + +/** + * STRING TEST + */ +print_r("testString(\"Test\")"); +$s = $testClient->testString("Test"); +print_r(" = \"$s\"\n"); + +/** + * BYTE TEST + */ +print_r("testByte(1)"); +$u8 = $testClient->testByte(1); +print_r(" = $u8\n"); + +/** + * I32 TEST + */ +print_r("testI32(-1)"); +$i32 = $testClient->testI32(-1); +print_r(" = $i32\n"); + +/** + * I64 TEST + */ +print_r("testI64(-34359738368)"); +$i64 = $testClient->testI64(-34359738368); +print_r(" = $i64\n"); + +/** + * DOUBLE TEST + */ +print_r("testDouble(-852.234234234)"); +$dub = $testClient->testDouble(-852.234234234); +print_r(" = $dub\n"); + +/** + * STRUCT TEST + */ +print_r("testStruct({\"Zero\", 1, -3, -5})"); +$out = new Xtruct(); +$out->string_thing = "Zero"; +$out->byte_thing = 1; +$out->i32_thing = -3; +$out->i64_thing = -5; +$in = $testClient->testStruct($out); +print_r(" = {\"".$in->string_thing."\", ". + $in->byte_thing.", ". + $in->i32_thing.", ". + $in->i64_thing."}\n"); + +/** + * NESTED STRUCT TEST + */ +print_r("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); +$out2 = new Xtruct2(); +$out2->byte_thing = 1; +$out2->struct_thing = $out; +$out2->i32_thing = 5; +$in2 = $testClient->testNest($out2); +$in = $in2->struct_thing; +print_r(" = {".$in2->byte_thing.", {\"". + $in->string_thing."\", ". + $in->byte_thing.", ". + $in->i32_thing.", ". + $in->i64_thing."}, ". + $in2->i32_thing."}\n"); + +/** + * MAP TEST + */ +$mapout = array(); +for ($i = 0; $i < 5; ++$i) { + $mapout[$i] = $i-10; +} +print_r("testMap({"); +$first = true; +foreach ($mapout as $key => $val) { + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r("$key => $val"); +} +print_r("})"); + +$mapin = $testClient->testMap($mapout); +print_r(" = {"); +$first = true; +foreach ($mapin as $key => $val) { + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r("$key => $val"); +} +print_r("}\n"); + +/** + * SET TEST + */ +$setout = array();; +for ($i = -2; $i < 3; ++$i) { + $setout []= $i; +} +print_r("testSet({"); +$first = true; +foreach ($setout as $val) { + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r($val); +} +print_r("})"); +$setin = $testClient->testSet($setout); +print_r(" = {"); +$first = true; +foreach ($setin as $val) { + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r($val); +} +print_r("}\n"); + +/** + * LIST TEST + */ +$listout = array(); +for ($i = -2; $i < 3; ++$i) { + $listout []= $i; +} +print_r("testList({"); +$first = true; +foreach ($listout as $val) { + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r($val); +} +print_r("})"); +$listin = $testClient->testList($listout); +print_r(" = {"); +$first = true; +foreach ($listin as $val) { + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r($val); +} +print_r("}\n"); + +/** + * ENUM TEST + */ +print_r("testEnum(ONE)"); +$ret = $testClient->testEnum(Numberz::ONE); +print_r(" = $ret\n"); + +print_r("testEnum(TWO)"); +$ret = $testClient->testEnum(Numberz::TWO); +print_r(" = $ret\n"); + +print_r("testEnum(THREE)"); +$ret = $testClient->testEnum(Numberz::THREE); +print_r(" = $ret\n"); + +print_r("testEnum(FIVE)"); +$ret = $testClient->testEnum(Numberz::FIVE); +print_r(" = $ret\n"); + +print_r("testEnum(EIGHT)"); +$ret = $testClient->testEnum(Numberz::EIGHT); +print_r(" = $ret\n"); + +/** + * TYPEDEF TEST + */ +print_r("testTypedef(309858235082523)"); +$uid = $testClient->testTypedef(309858235082523); +print_r(" = $uid\n"); + +/** + * NESTED MAP TEST + */ +print_r("testMapMap(1)"); +$mm = $testClient->testMapMap(1); +print_r(" = {"); +foreach ($mm as $key => $val) { + print_r("$key => {"); + foreach ($val as $k2 => $v2) { + print_r("$k2 => $v2, "); + } + print_r("}, "); +} +print_r("}\n"); + +/** + * INSANITY TEST + */ +$insane = new Insanity(); +$insane->userMap[Numberz::FIVE] = 5000; +$truck = new Xtruct(); +$truck->string_thing = "Truck"; +$truck->byte_thing = 8; +$truck->i32_thing = 8; +$truck->i64_thing = 8; +$insane->xtructs []= $truck; +print_r("testInsanity()"); +$whoa = $testClient->testInsanity($insane); +print_r(" = {"); +foreach ($whoa as $key => $val) { + print_r("$key => {"); + foreach ($val as $k2 => $v2) { + print_r("$k2 => {"); + $userMap = $v2->userMap; + print_r("{"); + if (is_array($usermap)) { + foreach ($userMap as $k3 => $v3) { + print_r("$k3 => $v3, "); + } + } + print_r("}, "); + + $xtructs = $v2->xtructs; + print_r("{"); + if (is_array($xtructs)) { + foreach ($xtructs as $x) { + print_r("{\"".$x->string_thing."\", ". + $x->byte_thing.", ".$x->i32_thing.", ".$x->i64_thing."}, "); + } + } + print_r("}"); + + print_r("}, "); + } + print_r("}, "); +} +print_r("}\n"); + +/** + * EXCEPTION TEST + */ +print_r("testException('Xception')"); +try { + $testClient->testException('Xception'); + print_r(" void\nFAILURE\n"); +} catch (Xception $x) { + print_r(' caught xception '.$x->errorCode.': '.$x->message."\n"); +} + + +/** + * Normal tests done. + */ + +$stop = microtime(true); +$elp = round(1000*($stop - $start), 0); +print_r("Total time: $elp ms\n"); + +/** + * Extraneous "I don't trust PHP to pack/unpack integer" tests + */ + +// Max I32 +$num = pow(2, 30) + (pow(2, 30) - 1); +$num2 = $testClient->testI32($num); +if ($num != $num2) { + print "Missed $num = $num2\n"; +} + +// Min I32 +$num = 0 - pow(2, 31); +$num2 = $testClient->testI32($num); +if ($num != $num2) { + print "Missed $num = $num2\n"; +} + +// Max I64 +$num = pow(2, 62) + (pow(2, 62) - 1); +$num2 = $testClient->testI64($num); +if ($num != $num2) { + print "Missed $num = $num2\n"; +} + +// Min I64 +$num = 0 - pow(2, 63); +$num2 = $testClient->testI64($num); +if ($num != $num2) { + print "Missed $num = $num2\n"; +} + +$transport->close(); +return; + +?> diff --git a/test/php/TestInline.php b/test/php/TestInline.php new file mode 100644 index 000000000..7066c461f --- /dev/null +++ b/test/php/TestInline.php @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +<?php +$GEN_DIR = 'gen-phpi'; +$MODE = 'inline'; +include_once('TestClient.php'); +?> diff --git a/test/py/Makefile.am b/test/py/Makefile.am new file mode 100644 index 000000000..63b7a890b --- /dev/null +++ b/test/py/Makefile.am @@ -0,0 +1,48 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +THRIFT = $(top_srcdir)/compiler/cpp/thrift + +py_unit_tests = \ + SerializationTest.py \ + TestEof.py \ + TestSyntax.py \ + RunClientServer.py + +thrift_gen = \ + gen-py/ThriftTest/__init__.py \ + gen-py/DebugProtoTest/__init__.py + +helper_scripts= \ + TestClient.py \ + TestServer.py + +check_SCRIPTS= \ + $(thrift_gen) \ + $(py_unit_tests) \ + $(helper_scripts) + +TESTS= $(py_unit_tests) + + +gen-py/%/__init__.py: ../%.thrift + $(THRIFT) --gen py $< + +clean-local: + $(RM) -r gen-py diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py new file mode 100755 index 000000000..2bd6094dd --- /dev/null +++ b/test/py/RunClientServer.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import time +import subprocess +import sys +import os +import signal + +def relfile(fname): + return os.path.join(os.path.dirname(__file__), fname) + +FRAMED = ["TNonblockingServer"] + +def runTest(server_class): + print "Testing ", server_class + serverproc = subprocess.Popen([sys.executable, relfile("TestServer.py"), server_class]) + time.sleep(0.25) + try: + argv = [sys.executable, relfile("TestClient.py")] + if server_class in FRAMED: + argv.append('--framed') + if server_class == 'THttpServer': + argv.append('--http=/') + ret = subprocess.call(argv) + if ret != 0: + raise Exception("subprocess failed") + finally: + # fixme: should check that server didn't die + os.kill(serverproc.pid, signal.SIGKILL) + + # wait for shutdown + time.sleep(1) + +map(runTest, [ + "TSimpleServer", + "TThreadedServer", + "TThreadPoolServer", + "TForkingServer", + "TNonblockingServer", + "THttpServer", + ]) diff --git a/test/py/SerializationTest.py b/test/py/SerializationTest.py new file mode 100755 index 000000000..52bedd5e3 --- /dev/null +++ b/test/py/SerializationTest.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import sys, glob +sys.path.insert(0, './gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) + +from ThriftTest.ttypes import * +from thrift.transport import TTransport +from thrift.transport import TSocket +from thrift.protocol import TBinaryProtocol +import unittest +import time + +class AbstractTest(unittest.TestCase): + + def setUp(self): + self.v1obj = VersioningTestV1( + begin_in_both=12345, + old_string='aaa', + end_in_both=54321, + ) + + self.v2obj = VersioningTestV2( + begin_in_both=12345, + newint=1, + newbyte=2, + newshort=3, + newlong=4, + newdouble=5.0, + newstruct=Bonk(message="Hello!", type=123), + newlist=[7,8,9], + newset=[42,1,8], + newmap={1:2,2:3}, + newstring="Hola!", + end_in_both=54321, + ) + + def _serialize(self, obj): + trans = TTransport.TMemoryBuffer() + prot = self.protocol_factory.getProtocol(trans) + obj.write(prot) + return trans.getvalue() + + def _deserialize(self, objtype, data): + prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data)) + ret = objtype() + ret.read(prot) + return ret + + def testForwards(self): + obj = self._deserialize(VersioningTestV2, self._serialize(self.v1obj)) + self.assertEquals(obj.begin_in_both, self.v1obj.begin_in_both) + self.assertEquals(obj.end_in_both, self.v1obj.end_in_both) + + def testBackwards(self): + obj = self._deserialize(VersioningTestV1, self._serialize(self.v2obj)) + self.assertEquals(obj.begin_in_both, self.v2obj.begin_in_both) + self.assertEquals(obj.end_in_both, self.v2obj.end_in_both) + + +class NormalBinaryTest(AbstractTest): + protocol_factory = TBinaryProtocol.TBinaryProtocolFactory() + +class AcceleratedBinaryTest(AbstractTest): + protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory() + + +class AcceleratedFramedTest(unittest.TestCase): + def testSplit(self): + """Test FramedTransport and BinaryProtocolAccelerated + + Tests that TBinaryProtocolAccelerated and TFramedTransport + play nicely together when a read spans a frame""" + + protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory() + bigstring = "".join(chr(byte) for byte in range(ord("a"), ord("z")+1)) + + databuf = TTransport.TMemoryBuffer() + prot = protocol_factory.getProtocol(databuf) + prot.writeI32(42) + prot.writeString(bigstring) + prot.writeI16(24) + data = databuf.getvalue() + cutpoint = len(data)/2 + parts = [ data[:cutpoint], data[cutpoint:] ] + + framed_buffer = TTransport.TMemoryBuffer() + framed_writer = TTransport.TFramedTransport(framed_buffer) + for part in parts: + framed_writer.write(part) + framed_writer.flush() + self.assertEquals(len(framed_buffer.getvalue()), len(data) + 8) + + # Recreate framed_buffer so we can read from it. + framed_buffer = TTransport.TMemoryBuffer(framed_buffer.getvalue()) + framed_reader = TTransport.TFramedTransport(framed_buffer) + prot = protocol_factory.getProtocol(framed_reader) + self.assertEqual(prot.readI32(), 42) + self.assertEqual(prot.readString(), bigstring) + self.assertEqual(prot.readI16(), 24) + + + +def suite(): + suite = unittest.TestSuite() + loader = unittest.TestLoader() + + suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest)) + suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest)) + suite.addTest(loader.loadTestsFromTestCase(AcceleratedFramedTest)) + return suite + +if __name__ == "__main__": + unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/test/py/TestClient.py b/test/py/TestClient.py new file mode 100755 index 000000000..64e5e872b --- /dev/null +++ b/test/py/TestClient.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import sys, glob +sys.path.insert(0, './gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) + +from ThriftTest import ThriftTest +from ThriftTest.ttypes import * +from thrift.transport import TTransport +from thrift.transport import TSocket +from thrift.transport import THttpClient +from thrift.protocol import TBinaryProtocol +import unittest +import time +from optparse import OptionParser + + +parser = OptionParser() +parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090) +parser.add_option("--port", type="int", dest="port", + help="connect to server at port") +parser.add_option("--host", type="string", dest="host", + help="connect to server") +parser.add_option("--framed", action="store_true", dest="framed", + help="use framed transport") +parser.add_option("--http", dest="http_path", + help="Use the HTTP transport with the specified path") +parser.add_option('-v', '--verbose', action="store_const", + dest="verbose", const=2, + help="verbose output") +parser.add_option('-q', '--quiet', action="store_const", + dest="verbose", const=0, + help="minimal output") + +options, args = parser.parse_args() + +class AbstractTest(unittest.TestCase): + def setUp(self): + if options.http_path: + self.transport = THttpClient.THttpClient( + options.host, options.port, options.http_path) + else: + socket = TSocket.TSocket(options.host, options.port) + + # frame or buffer depending upon args + if options.framed: + self.transport = TTransport.TFramedTransport(socket) + else: + self.transport = TTransport.TBufferedTransport(socket) + + self.transport.open() + + protocol = self.protocol_factory.getProtocol(self.transport) + self.client = ThriftTest.Client(protocol) + + def tearDown(self): + # Close! + self.transport.close() + + def testVoid(self): + self.client.testVoid() + + def testString(self): + self.assertEqual(self.client.testString('Python'), 'Python') + + def testByte(self): + self.assertEqual(self.client.testByte(63), 63) + + def testI32(self): + self.assertEqual(self.client.testI32(-1), -1) + self.assertEqual(self.client.testI32(0), 0) + + def testI64(self): + self.assertEqual(self.client.testI64(-34359738368), -34359738368) + + def testDouble(self): + self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235) + + def testStruct(self): + x = Xtruct() + x.string_thing = "Zero" + x.byte_thing = 1 + x.i32_thing = -3 + x.i64_thing = -5 + y = self.client.testStruct(x) + + self.assertEqual(y.string_thing, "Zero") + self.assertEqual(y.byte_thing, 1) + self.assertEqual(y.i32_thing, -3) + self.assertEqual(y.i64_thing, -5) + + def testException(self): + self.client.testException('Safe') + try: + self.client.testException('Xception') + self.fail("should have gotten exception") + except Xception, x: + self.assertEqual(x.errorCode, 1001) + self.assertEqual(x.message, 'Xception') + + try: + self.client.testException("throw_undeclared") + self.fail("should have thrown exception") + except Exception: # type is undefined + pass + + def testOneway(self): + start = time.time() + self.client.testOneway(0.5) + end = time.time() + self.assertTrue(end - start < 0.2, + "oneway sleep took %f sec" % (end - start)) + +class NormalBinaryTest(AbstractTest): + protocol_factory = TBinaryProtocol.TBinaryProtocolFactory() + +class AcceleratedBinaryTest(AbstractTest): + protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory() + +def suite(): + suite = unittest.TestSuite() + loader = unittest.TestLoader() + + suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest)) + suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest)) + return suite + +class OwnArgsTestProgram(unittest.TestProgram): + def parseArgs(self, argv): + if args: + self.testNames = args + else: + self.testNames = (self.defaultTest,) + self.createTests() + +if __name__ == "__main__": + OwnArgsTestProgram(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/test/py/TestEof.py b/test/py/TestEof.py new file mode 100755 index 000000000..7d64289d0 --- /dev/null +++ b/test/py/TestEof.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import sys, glob +sys.path.insert(0, './gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) + +from ThriftTest import ThriftTest +from ThriftTest.ttypes import * +from thrift.transport import TTransport +from thrift.transport import TSocket +from thrift.protocol import TBinaryProtocol +import unittest +import time + +class TestEof(unittest.TestCase): + + def setUp(self): + trans = TTransport.TMemoryBuffer() + prot = TBinaryProtocol.TBinaryProtocol(trans) + + x = Xtruct() + x.string_thing = "Zero" + x.byte_thing = 0 + + x.write(prot) + + x = Xtruct() + x.string_thing = "One" + x.byte_thing = 1 + + x.write(prot) + + self.data = trans.getvalue() + + def testTransportReadAll(self): + """Test that readAll on any type of transport throws an EOFError""" + trans = TTransport.TMemoryBuffer(self.data) + trans.readAll(1) + + try: + trans.readAll(10000) + except EOFError: + return + + self.fail("Should have gotten EOFError") + + def eofTestHelper(self, pfactory): + trans = TTransport.TMemoryBuffer(self.data) + prot = pfactory.getProtocol(trans) + + x = Xtruct() + x.read(prot) + self.assertEqual(x.string_thing, "Zero") + self.assertEqual(x.byte_thing, 0) + + x = Xtruct() + x.read(prot) + self.assertEqual(x.string_thing, "One") + self.assertEqual(x.byte_thing, 1) + + try: + x = Xtruct() + x.read(prot) + except EOFError: + return + + self.fail("Should have gotten EOFError") + + def eofTestHelperStress(self, pfactory): + """Teest the ability of TBinaryProtocol to deal with the removal of every byte in the file""" + # TODO: we should make sure this covers more of the code paths + + for i in xrange(0, len(self.data) + 1): + trans = TTransport.TMemoryBuffer(self.data[0:i]) + prot = pfactory.getProtocol(trans) + try: + x = Xtruct() + x.read(prot) + x.read(prot) + x.read(prot) + except EOFError: + continue + self.fail("Should have gotten an EOFError") + + def testBinaryProtocolEof(self): + """Test that TBinaryProtocol throws an EOFError when it reaches the end of the stream""" + self.eofTestHelper(TBinaryProtocol.TBinaryProtocolFactory()) + self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolFactory()) + + def testBinaryProtocolAcceleratedEof(self): + """Test that TBinaryProtocolAccelerated throws an EOFError when it reaches the end of the stream""" + self.eofTestHelper(TBinaryProtocol.TBinaryProtocolAcceleratedFactory()) + self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolAcceleratedFactory()) + +def suite(): + suite = unittest.TestSuite() + loader = unittest.TestLoader() + suite.addTest(loader.loadTestsFromTestCase(TestEof)) + return suite + +if __name__ == "__main__": + unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/test/py/TestServer.py b/test/py/TestServer.py new file mode 100755 index 000000000..3d379eaeb --- /dev/null +++ b/test/py/TestServer.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import sys, glob, time +sys.path.insert(0, './gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) + +from ThriftTest import ThriftTest +from ThriftTest.ttypes import * +from thrift.transport import TTransport +from thrift.transport import TSocket +from thrift.protocol import TBinaryProtocol +from thrift.server import TServer, TNonblockingServer, THttpServer + +class TestHandler: + + def testVoid(self): + print 'testVoid()' + + def testString(self, str): + print 'testString(%s)' % str + return str + + def testByte(self, byte): + print 'testByte(%d)' % byte + return byte + + def testI16(self, i16): + print 'testI16(%d)' % i16 + return i16 + + def testI32(self, i32): + print 'testI32(%d)' % i32 + return i32 + + def testI64(self, i64): + print 'testI64(%d)' % i64 + return i64 + + def testDouble(self, dub): + print 'testDouble(%f)' % dub + return dub + + def testStruct(self, thing): + print 'testStruct({%s, %d, %d, %d})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing) + return thing + + def testException(self, str): + print 'testException(%s)' % str + if str == 'Xception': + x = Xception() + x.errorCode = 1001 + x.message = str + raise x + elif str == "throw_undeclared": + raise ValueError("foo") + + def testOneway(self, seconds): + print 'testOneway(%d) => sleeping...' % seconds + time.sleep(seconds) + print 'done sleeping' + + def testNest(self, thing): + return thing + + def testMap(self, thing): + return thing + + def testSet(self, thing): + return thing + + def testList(self, thing): + return thing + + def testEnum(self, thing): + return thing + + def testTypedef(self, thing): + return thing + +pfactory = TBinaryProtocol.TBinaryProtocolFactory() +handler = TestHandler() +processor = ThriftTest.Processor(handler) + +if sys.argv[1] == "THttpServer": + server = THttpServer.THttpServer(processor, ('', 9090), pfactory) +else: + transport = TSocket.TServerSocket(9090) + tfactory = TTransport.TBufferedTransportFactory() + + if sys.argv[1] == "TNonblockingServer": + server = TNonblockingServer.TNonblockingServer(processor, transport) + else: + ServerClass = getattr(TServer, sys.argv[1]) + server = ServerClass(processor, transport, tfactory, pfactory) + +server.serve() diff --git a/test/py/TestSocket.py b/test/py/TestSocket.py new file mode 100755 index 000000000..2f7353fb1 --- /dev/null +++ b/test/py/TestSocket.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import sys, glob +sys.path.insert(0, './gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) + +from ThriftTest import ThriftTest +from ThriftTest.ttypes import * +from thrift.transport import TTransport +from thrift.transport import TSocket +from thrift.protocol import TBinaryProtocol +import unittest +import time +import socket +import random +from optparse import OptionParser + +class TimeoutTest(unittest.TestCase): + def setUp(self): + for i in xrange(50): + try: + # find a port we can use + self.listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.port = random.randint(10000, 30000) + self.listen_sock.bind(('localhost', self.port)) + self.listen_sock.listen(5) + break + except: + if i == 49: + raise + + def testConnectTimeout(self): + starttime = time.time() + + try: + leaky = [] + for i in xrange(100): + socket = TSocket.TSocket('localhost', self.port) + socket.setTimeout(10) + socket.open() + leaky.append(socket) + except: + self.assert_(time.time() - starttime < 5.0) + + def testWriteTimeout(self): + starttime = time.time() + + try: + socket = TSocket.TSocket('localhost', self.port) + socket.setTimeout(10) + socket.open() + lsock = self.listen_sock.accept() + while True: + socket.write("hi" * 100) + + except: + self.assert_(time.time() - starttime < 5.0) + +suite = unittest.TestSuite() +loader = unittest.TestLoader() + +suite.addTest(loader.loadTestsFromTestCase(TimeoutTest)) + +testRunner = unittest.TextTestRunner(verbosity=2) +testRunner.run(suite) diff --git a/test/py/TestSyntax.py b/test/py/TestSyntax.py new file mode 100755 index 000000000..df67d4851 --- /dev/null +++ b/test/py/TestSyntax.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +import sys, glob +sys.path.insert(0, './gen-py') +sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) + +# Just import these generated files to make sure they are syntactically valid +from DebugProtoTest import EmptyService +from DebugProtoTest import Inherited diff --git a/test/py/explicit_module/runtest.sh b/test/py/explicit_module/runtest.sh new file mode 100755 index 000000000..2e5a4f1be --- /dev/null +++ b/test/py/explicit_module/runtest.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +rm -rf gen-py +../../../compiler/cpp/thrift --gen py test1.thrift || exit 1 +../../../compiler/cpp/thrift --gen py test2.thrift || exit 1 +PYTHONPATH=./gen-py python -c 'import foo.bar.baz' || exit 1 +PYTHONPATH=./gen-py python -c 'import test2' || exit 1 +PYTHONPATH=./gen-py python -c 'import test1' &>/dev/null && exit 1 # Should fail. +cp -r gen-py simple +../../../compiler/cpp/thrift -r --gen py test2.thrift || exit 1 +PYTHONPATH=./gen-py python -c 'import test2' || exit 1 +diff -ur simple gen-py > thediffs +file thediffs | grep -s -q empty || exit 1 +rm -rf simple thediffs +echo 'All tests pass!' diff --git a/test/py/explicit_module/test1.thrift b/test/py/explicit_module/test1.thrift new file mode 100644 index 000000000..ec600d7d4 --- /dev/null +++ b/test/py/explicit_module/test1.thrift @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +namespace py foo.bar.baz + +struct astruct { + 1: i32 how_unoriginal; +} diff --git a/test/py/explicit_module/test2.thrift b/test/py/explicit_module/test2.thrift new file mode 100644 index 000000000..68f9da4dd --- /dev/null +++ b/test/py/explicit_module/test2.thrift @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +include "test1.thrift" + +struct another { + 1: test1.astruct something; +} diff --git a/test/rb/Makefile.am b/test/rb/Makefile.am new file mode 100644 index 000000000..a6f431c8e --- /dev/null +++ b/test/rb/Makefile.am @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +THRIFT = $(top_srcdir)/compiler/cpp/thrift + +stubs: ../ThriftTest.thrift ../SmallTest.thrift + $(THRIFT) --gen rb ../ThriftTest.thrift + $(THRIFT) --gen rb ../SmallTest.thrift + +check: stubs + $(RUBY) test_suite.rb + diff --git a/test/rb/benchmarks/protocol_benchmark.rb b/test/rb/benchmarks/protocol_benchmark.rb new file mode 100644 index 000000000..05a8ee534 --- /dev/null +++ b/test/rb/benchmarks/protocol_benchmark.rb @@ -0,0 +1,174 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb lib]) +$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb ext]) + +require 'thrift' + +require 'benchmark' +require 'rubygems' +require 'set' +require 'pp' + +# require 'ruby-debug' +# require 'ruby-prof' + +require File.join(File.dirname(__FILE__), '../fixtures/structs') + +transport1 = Thrift::MemoryBuffer.new +ruby_binary_protocol = Thrift::BinaryProtocol.new(transport1) + +transport2 = Thrift::MemoryBuffer.new +c_fast_binary_protocol = Thrift::BinaryProtocolAccelerated.new(transport2) + + +ooe = Fixtures::Structs::OneOfEach.new +ooe.im_true = true +ooe.im_false = false +ooe.a_bite = -42 +ooe.integer16 = 27000 +ooe.integer32 = 1<<24 +ooe.integer64 = 6000 * 1000 * 1000 +ooe.double_precision = Math::PI +ooe.some_characters = "Debug THIS!" +ooe.zomg_unicode = "\xd7\n\a\t" + +n1 = Fixtures::Structs::Nested1.new +n1.a_list = [] +n1.a_list << ooe << ooe << ooe << ooe +n1.i32_map = {} +n1.i32_map[1234] = ooe +n1.i32_map[46345] = ooe +n1.i32_map[-34264] = ooe +n1.i64_map = {} +n1.i64_map[43534986783945] = ooe +n1.i64_map[-32434639875122] = ooe +n1.dbl_map = {} +n1.dbl_map[324.65469834] = ooe +n1.dbl_map[-9458672340.4986798345112] = ooe +n1.str_map = {} +n1.str_map['sdoperuix'] = ooe +n1.str_map['pwoerxclmn'] = ooe + +n2 = Fixtures::Structs::Nested2.new +n2.a_list = [] +n2.a_list << n1 << n1 << n1 << n1 << n1 +n2.i32_map = {} +n2.i32_map[398345] = n1 +n2.i32_map[-2345] = n1 +n2.i32_map[12312] = n1 +n2.i64_map = {} +n2.i64_map[2349843765934] = n1 +n2.i64_map[-123234985495] = n1 +n2.i64_map[0] = n1 +n2.dbl_map = {} +n2.dbl_map[23345345.38927834] = n1 +n2.dbl_map[-1232349.5489345] = n1 +n2.dbl_map[-234984574.23498725] = n1 +n2.str_map = {} +n2.str_map[''] = n1 +n2.str_map['sdflkertpioux'] = n1 +n2.str_map['sdfwepwdcjpoi'] = n1 + +n3 = Fixtures::Structs::Nested3.new +n3.a_list = [] +n3.a_list << n2 << n2 << n2 << n2 << n2 +n3.i32_map = {} +n3.i32_map[398345] = n2 +n3.i32_map[-2345] = n2 +n3.i32_map[12312] = n2 +n3.i64_map = {} +n3.i64_map[2349843765934] = n2 +n3.i64_map[-123234985495] = n2 +n3.i64_map[0] = n2 +n3.dbl_map = {} +n3.dbl_map[23345345.38927834] = n2 +n3.dbl_map[-1232349.5489345] = n2 +n3.dbl_map[-234984574.23498725] = n2 +n3.str_map = {} +n3.str_map[''] = n2 +n3.str_map['sdflkertpioux'] = n2 +n3.str_map['sdfwepwdcjpoi'] = n2 + +n4 = Fixtures::Structs::Nested4.new +n4.a_list = [] +n4.a_list << n3 +n4.i32_map = {} +n4.i32_map[-2345] = n3 +n4.i64_map = {} +n4.i64_map[2349843765934] = n3 +n4.dbl_map = {} +n4.dbl_map[-1232349.5489345] = n3 +n4.str_map = {} +n4.str_map[''] = n3 + + +# prof = RubyProf.profile do +# n4.write(c_fast_binary_protocol) +# Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol) +# end +# +# printer = RubyProf::GraphHtmlPrinter.new(prof) +# printer.print(STDOUT, :min_percent=>0) + +Benchmark.bmbm do |x| + x.report("ruby write large (1MB) structure once") do + n4.write(ruby_binary_protocol) + end + + x.report("ruby read large (1MB) structure once") do + Fixtures::Structs::Nested4.new.read(ruby_binary_protocol) + end + + x.report("c write large (1MB) structure once") do + n4.write(c_fast_binary_protocol) + end + + x.report("c read large (1MB) structure once") do + Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol) + end + + + + x.report("ruby write 10_000 small structures") do + 10_000.times do + ooe.write(ruby_binary_protocol) + end + end + + x.report("ruby read 10_000 small structures") do + 10_000.times do + Fixtures::Structs::OneOfEach.new.read(ruby_binary_protocol) + end + end + + x.report("c write 10_000 small structures") do + 10_000.times do + ooe.write(c_fast_binary_protocol) + end + end + + x.report("c read 10_000 small structures") do + 10_000.times do + Fixtures::Structs::OneOfEach.new.read(c_fast_binary_protocol) + end + end + +end diff --git a/test/rb/core/test_backwards_compatability.rb b/test/rb/core/test_backwards_compatability.rb new file mode 100644 index 000000000..0577515d3 --- /dev/null +++ b/test/rb/core/test_backwards_compatability.rb @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') + +require 'thrift' + +class TestThriftException < Test::Unit::TestCase + def test_has_accessible_message + msg = "hi there thrift" + assert_equal msg, Thrift::Exception.new(msg).message + end +end + diff --git a/test/rb/core/test_exceptions.rb b/test/rb/core/test_exceptions.rb new file mode 100644 index 000000000..f41587a7b --- /dev/null +++ b/test/rb/core/test_exceptions.rb @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') + +require 'thrift' + +class TestException < Test::Unit::TestCase + def test_has_accessible_message + msg = "hi there thrift" + assert_equal msg, Thrift::Exception.new(msg).message + end +end + diff --git a/test/rb/core/transport/test_transport.rb b/test/rb/core/transport/test_transport.rb new file mode 100644 index 000000000..52755c1da --- /dev/null +++ b/test/rb/core/transport/test_transport.rb @@ -0,0 +1,70 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../../test_helper') + +require 'thrift' + +class DummyTransport < Thrift::BaseTransport + def initialize(data) + @data = data + end + + def read(size) + @data.slice!(0, size) + end +end + +# TTransport is basically an abstract class, but isn't raising NotImplementedError +class TestThriftTransport < Test::Unit::TestCase + def setup + @trans = Thrift::BaseTransport.new + end + + def test_open? + assert_nil @trans.open? + end + + def test_open + assert_nil @trans.open + end + + def test_close + assert_nil @trans.close + end + + # TODO: + # This doesn't necessarily test he right thing. + # It _looks_ like read isn't guarenteed to return the length + # you ask for and read_all is. This means our test needs to check + # for blocking. -- Kevin Clark 3/27/08 + def test_read_all + # Implements read + t = DummyTransport.new("hello") + assert_equal "hello", t.read_all(5) + end + + def test_write + assert_nil @trans.write(5) # arbitrary value + end + + def test_flush + assert_nil @trans.flush + end +end diff --git a/test/rb/fixtures/structs.rb b/test/rb/fixtures/structs.rb new file mode 100644 index 000000000..ebbeb0a7d --- /dev/null +++ b/test/rb/fixtures/structs.rb @@ -0,0 +1,298 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require 'thrift' + +module Fixtures + module Structs + class OneBool + include Thrift::Struct + attr_accessor :bool + FIELDS = { + 1 => {:type => Thrift::Types::BOOL, :name => 'bool'} + } + + def validate + end + end + + class OneByte + include Thrift::Struct + attr_accessor :byte + FIELDS = { + 1 => {:type => Thrift::Types::BYTE, :name => 'byte'} + } + + def validate + end + end + + class OneI16 + include Thrift::Struct + attr_accessor :i16 + FIELDS = { + 1 => {:type => Thrift::Types::I16, :name => 'i16'} + } + + def validate + end + end + + class OneI32 + include Thrift::Struct + attr_accessor :i32 + FIELDS = { + 1 => {:type => Thrift::Types::I32, :name => 'i32'} + } + + def validate + end + end + + class OneI64 + include Thrift::Struct + attr_accessor :i64 + FIELDS = { + 1 => {:type => Thrift::Types::I64, :name => 'i64'} + } + + def validate + end + end + + class OneDouble + include Thrift::Struct + attr_accessor :double + FIELDS = { + 1 => {:type => Thrift::Types::DOUBLE, :name => 'double'} + } + + def validate + end + end + + class OneString + include Thrift::Struct + attr_accessor :string + FIELDS = { + 1 => {:type => Thrift::Types::STRING, :name => 'string'} + } + + def validate + end + end + + class OneMap + include Thrift::Struct + attr_accessor :map + FIELDS = { + 1 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRING}} + } + + def validate + end + end + + class NestedMap + include Thrift::Struct + attr_accessor :map + FIELDS = { + 0 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::I32}}} + } + + def validate + end + end + + class OneList + include Thrift::Struct + attr_accessor :list + FIELDS = { + 1 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::STRING}} + } + + def validate + end + end + + class NestedList + include Thrift::Struct + attr_accessor :list + FIELDS = { + 0 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::LIST, :element => { :type => Thrift::Types::I32 } } } + } + + def validate + end + end + + class OneSet + include Thrift::Struct + attr_accessor :set + FIELDS = { + 1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::STRING}} + } + + def validate + end + end + + class NestedSet + include Thrift::Struct + attr_accessor :set + FIELDS = { + 1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::SET, :element => { :type => Thrift::Types::STRING } }} + } + + def validate + end + end + + # struct OneOfEach { + # 1: bool im_true, + # 2: bool im_false, + # 3: byte a_bite, + # 4: i16 integer16, + # 5: i32 integer32, + # 6: i64 integer64, + # 7: double double_precision, + # 8: string some_characters, + # 9: string zomg_unicode, + # 10: bool what_who, + # 11: binary base64, + # } + class OneOfEach + include Thrift::Struct + attr_accessor :im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64 + FIELDS = { + 1 => {:type => Thrift::Types::BOOL, :name => 'im_true'}, + 2 => {:type => Thrift::Types::BOOL, :name => 'im_false'}, + 3 => {:type => Thrift::Types::BYTE, :name => 'a_bite'}, + 4 => {:type => Thrift::Types::I16, :name => 'integer16'}, + 5 => {:type => Thrift::Types::I32, :name => 'integer32'}, + 6 => {:type => Thrift::Types::I64, :name => 'integer64'}, + 7 => {:type => Thrift::Types::DOUBLE, :name => 'double_precision'}, + 8 => {:type => Thrift::Types::STRING, :name => 'some_characters'}, + 9 => {:type => Thrift::Types::STRING, :name => 'zomg_unicode'}, + 10 => {:type => Thrift::Types::BOOL, :name => 'what_who'}, + 11 => {:type => Thrift::Types::STRING, :name => 'base64'} + } + + # Added for assert_equal + def ==(other) + [:im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64].each do |f| + var = "@#{f}" + return false if instance_variable_get(var) != other.instance_variable_get(var) + end + true + end + + def validate + end + end + + # struct Nested1 { + # 1: list<OneOfEach> a_list + # 2: map<i32, OneOfEach> i32_map + # 3: map<i64, OneOfEach> i64_map + # 4: map<double, OneOfEach> dbl_map + # 5: map<string, OneOfEach> str_map + # } + class Nested1 + include Thrift::Struct + attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map + FIELDS = { + 1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}, + 2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}, + 3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}, + 4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}, + 5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}} + } + + def validate + end + end + + # struct Nested2 { + # 1: list<Nested1> a_list + # 2: map<i32, Nested1> i32_map + # 3: map<i64, Nested1> i64_map + # 4: map<double, Nested1> dbl_map + # 5: map<string, Nested1> str_map + # } + class Nested2 + include Thrift::Struct + attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map + FIELDS = { + 1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested1}}, + 2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}}, + 3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}}, + 4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}}, + 5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}} + } + + def validate + end + end + + # struct Nested3 { + # 1: list<Nested2> a_list + # 2: map<i32, Nested2> i32_map + # 3: map<i64, Nested2> i64_map + # 4: map<double, Nested2> dbl_map + # 5: map<string, Nested2> str_map + # } + class Nested3 + include Thrift::Struct + attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map + FIELDS = { + 1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested2}}, + 2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}}, + 3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}}, + 4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}}, + 5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}} + } + + def validate + end + end + + # struct Nested4 { + # 1: list<Nested3> a_list + # 2: map<i32, Nested3> i32_map + # 3: map<i64, Nested3> i64_map + # 4: map<double, Nested3> dbl_map + # 5: map<string, Nested3> str_map + # } + class Nested4 + include Thrift::Struct + attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map + FIELDS = { + 1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested3}}, + 2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}}, + 3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}}, + 4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}}, + 5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}} + } + + def validate + end + end + end +end diff --git a/test/rb/generation/test_enum.rb b/test/rb/generation/test_enum.rb new file mode 100644 index 000000000..7d3f08ba5 --- /dev/null +++ b/test/rb/generation/test_enum.rb @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') +require 'thrift_test' + +class TestEnumGeneration < Test::Unit::TestCase + include Thrift::Test + def test_enum_valid_values + assert_equal(Numberz::VALID_VALUES, Set.new([Numberz::ONE, Numberz::TWO, Numberz::THREE, Numberz::FIVE, Numberz::SIX, Numberz::EIGHT])) + end +end
\ No newline at end of file diff --git a/test/rb/generation/test_struct.rb b/test/rb/generation/test_struct.rb new file mode 100644 index 000000000..3bd4fc9bb --- /dev/null +++ b/test/rb/generation/test_struct.rb @@ -0,0 +1,48 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') +require 'small_service' + +class TestStructGeneration < Test::Unit::TestCase + + def test_default_values + hello = TestNamespace::Hello.new + + assert_kind_of(TestNamespace::Hello, hello) + assert_nil(hello.complexer) + + assert_equal(hello.simple, 53) + assert_equal(hello.words, 'words') + + assert_kind_of(TestNamespace::Goodbyez, hello.thinz) + assert_equal(hello.thinz.val, 36632) + + assert_kind_of(Hash, hello.complex) + assert_equal(hello.complex, { 6243 => 632, 2355 => 532, 23 => 532}) + + bool_passer = TestNamespace::BoolPasser.new(:value => false) + assert_equal false, bool_passer.value + end + + def test_goodbyez + assert_equal(TestNamespace::Goodbyez.new.val, 325) + end + +end diff --git a/test/rb/integration/accelerated_buffered_client.rb b/test/rb/integration/accelerated_buffered_client.rb new file mode 100644 index 000000000..7cec1df51 --- /dev/null +++ b/test/rb/integration/accelerated_buffered_client.rb @@ -0,0 +1,163 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') + +require 'thrift' +require 'ThriftTest' + +class AcceleratedBufferedClientTest < Test::Unit::TestCase + def setup + unless @socket + @socket = Thrift::Socket.new('localhost', 9090) + @protocol = Thrift::BinaryProtocolAccelerated.new(Thrift::BufferedTransport.new(@socket)) + @client = Thrift::Test::ThriftTest::Client.new(@protocol) + @socket.open + end + end + + def test_string + assert_equal(@client.testString('string'), 'string') + end + + def test_byte + val = 8 + assert_equal(@client.testByte(val), val) + assert_equal(@client.testByte(-val), -val) + end + + def test_i32 + val = 32 + assert_equal(@client.testI32(val), val) + assert_equal(@client.testI32(-val), -val) + end + + def test_i64 + val = 64 + assert_equal(@client.testI64(val), val) + assert_equal(@client.testI64(-val), -val) + end + + def test_double + val = 3.14 + assert_equal(@client.testDouble(val), val) + assert_equal(@client.testDouble(-val), -val) + assert_kind_of(Float, @client.testDouble(val)) + end + + def test_map + val = {1 => 1, 2 => 2, 3 => 3} + assert_equal(@client.testMap(val), val) + assert_kind_of(Hash, @client.testMap(val)) + end + + def test_list + val = [1,2,3,4,5] + assert_equal(@client.testList(val), val) + assert_kind_of(Array, @client.testList(val)) + end + + def test_enum + val = Thrift::Test::Numberz::SIX + ret = @client.testEnum(val) + + assert_equal(ret, 6) + assert_kind_of(Fixnum, ret) + end + + def test_typedef + #UserId testTypedef(1: UserId thing), + true + end + + def test_set + val = Set.new([1,2,3]) + assert_equal(@client.testSet(val), val) + assert_kind_of(Set, @client.testSet(val)) + end + + def get_struct + Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 }) + end + + def test_struct + ret = @client.testStruct(get_struct) + + assert_nil(ret.byte_thing, nil) + assert_nil(ret.i64_thing, nil) + assert_equal(ret.string_thing, 'hi!') + assert_equal(ret.i32_thing, 4) + assert_kind_of(Thrift::Test::Xtruct, ret) + end + + def test_nest + struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10}) + + ret = @client.testNest(struct2) + + assert_nil(ret.struct_thing.byte_thing, nil) + assert_nil(ret.struct_thing.i64_thing, nil) + assert_equal(ret.struct_thing.string_thing, 'hi!') + assert_equal(ret.struct_thing.i32_thing, 4) + assert_equal(ret.i32_thing, 10) + + assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing) + assert_kind_of(Thrift::Test::Xtruct2, ret) + end + + def test_insane + insane = Thrift::Test::Insanity.new({ + 'userMap' => { Thrift::Test::Numberz::ONE => 44 }, + 'xtructs' => [get_struct, + Thrift::Test::Xtruct.new({ + 'string_thing' => 'hi again', + 'i32_thing' => 12 + }) + ] + }) + + ret = @client.testInsanity(insane) + + assert_not_nil(ret[44]) + assert_not_nil(ret[44][1]) + + struct = ret[44][1] + + assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44) + assert_equal(struct.xtructs[1].string_thing, 'hi again') + assert_equal(struct.xtructs[1].i32_thing, 12) + + assert_kind_of(Hash, struct.userMap) + assert_kind_of(Array, struct.xtructs) + assert_kind_of(Thrift::Test::Insanity, struct) + end + + def test_map_map + ret = @client.testMapMap(4) + assert_kind_of(Hash, ret) + assert_equal(ret, { 4 => { 4 => 4}}) + end + + def test_exception + assert_raise Thrift::Test::Xception do + @client.testException('foo') + end + end +end + diff --git a/test/rb/integration/accelerated_buffered_server.rb b/test/rb/integration/accelerated_buffered_server.rb new file mode 100644 index 000000000..1ca66e543 --- /dev/null +++ b/test/rb/integration/accelerated_buffered_server.rb @@ -0,0 +1,65 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +$:.push File.dirname(__FILE__) + '/../gen-rb' +$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/lib') +$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/ext') + +require 'thrift' +require 'ThriftTest' + +class SimpleHandler + [:testString, :testByte, :testI32, :testI64, :testDouble, + :testStruct, :testMap, :testSet, :testList, :testNest, + :testEnum, :testTypedef].each do |meth| + + define_method(meth) do |thing| + thing + end + + end + + def testInsanity(thing) + num, uid = thing.userMap.find { true } + return {uid => {num => thing}} + end + + def testMapMap(thing) + return {thing => {thing => thing}} + end + + def testEnum(thing) + return thing + end + + def testTypedef(thing) + return thing + end + + def testException(thing) + raise Thrift::Test::Xception, :message => 'error' + end +end + +@handler = SimpleHandler.new +@processor = Thrift::Test::ThriftTest::Processor.new(@handler) +@transport = Thrift::ServerSocket.new(9090) +@server = Thrift::ThreadedServer.new(@processor, @transport, Thrift::BufferedTransportFactory.new, Thrift::BinaryProtocolAcceleratedFactory.new) + +@server.serve diff --git a/test/rb/integration/buffered_client.rb b/test/rb/integration/buffered_client.rb new file mode 100644 index 000000000..1a925ccf4 --- /dev/null +++ b/test/rb/integration/buffered_client.rb @@ -0,0 +1,163 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') + +require 'thrift' +require 'ThriftTest' + +class BufferedClientTest < Test::Unit::TestCase + def setup + unless @socket + @socket = Thrift::Socket.new('localhost', 9090) + @protocol = Thrift::BinaryProtocol.new(Thrift::BufferedTransport.new(@socket)) + @client = Thrift::Test::ThriftTest::Client.new(@protocol) + @socket.open + end + end + + def test_string + assert_equal(@client.testString('string'), 'string') + end + + def test_byte + val = 8 + assert_equal(@client.testByte(val), val) + assert_equal(@client.testByte(-val), -val) + end + + def test_i32 + val = 32 + assert_equal(@client.testI32(val), val) + assert_equal(@client.testI32(-val), -val) + end + + def test_i64 + val = 64 + assert_equal(@client.testI64(val), val) + assert_equal(@client.testI64(-val), -val) + end + + def test_double + val = 3.14 + assert_equal(@client.testDouble(val), val) + assert_equal(@client.testDouble(-val), -val) + assert_kind_of(Float, @client.testDouble(val)) + end + + def test_map + val = {1 => 1, 2 => 2, 3 => 3} + assert_equal(@client.testMap(val), val) + assert_kind_of(Hash, @client.testMap(val)) + end + + def test_list + val = [1,2,3,4,5] + assert_equal(@client.testList(val), val) + assert_kind_of(Array, @client.testList(val)) + end + + def test_enum + val = Thrift::Test::Numberz::SIX + ret = @client.testEnum(val) + + assert_equal(ret, 6) + assert_kind_of(Fixnum, ret) + end + + def test_typedef + #UserId testTypedef(1: UserId thing), + true + end + + def test_set + val = Set.new([1,2,3]) + assert_equal(@client.testSet(val), val) + assert_kind_of(Set, @client.testSet(val)) + end + + def get_struct + Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 }) + end + + def test_struct + ret = @client.testStruct(get_struct) + + assert_nil(ret.byte_thing, nil) + assert_nil(ret.i64_thing, nil) + assert_equal(ret.string_thing, 'hi!') + assert_equal(ret.i32_thing, 4) + assert_kind_of(Thrift::Test::Xtruct, ret) + end + + def test_nest + struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10}) + + ret = @client.testNest(struct2) + + assert_nil(ret.struct_thing.byte_thing, nil) + assert_nil(ret.struct_thing.i64_thing, nil) + assert_equal(ret.struct_thing.string_thing, 'hi!') + assert_equal(ret.struct_thing.i32_thing, 4) + assert_equal(ret.i32_thing, 10) + + assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing) + assert_kind_of(Thrift::Test::Xtruct2, ret) + end + + def test_insane + insane = Thrift::Test::Insanity.new({ + 'userMap' => { Thrift::Test::Numberz::ONE => 44 }, + 'xtructs' => [get_struct, + Thrift::Test::Xtruct.new({ + 'string_thing' => 'hi again', + 'i32_thing' => 12 + }) + ] + }) + + ret = @client.testInsanity(insane) + + assert_not_nil(ret[44]) + assert_not_nil(ret[44][1]) + + struct = ret[44][1] + + assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44) + assert_equal(struct.xtructs[1].string_thing, 'hi again') + assert_equal(struct.xtructs[1].i32_thing, 12) + + assert_kind_of(Hash, struct.userMap) + assert_kind_of(Array, struct.xtructs) + assert_kind_of(Thrift::Test::Insanity, struct) + end + + def test_map_map + ret = @client.testMapMap(4) + assert_kind_of(Hash, ret) + assert_equal(ret, { 4 => { 4 => 4}}) + end + + def test_exception + assert_raise Thrift::Test::Xception do + @client.testException('foo') + end + end +end + diff --git a/test/rb/integration/simple_client.rb b/test/rb/integration/simple_client.rb new file mode 100644 index 000000000..1064822ac --- /dev/null +++ b/test/rb/integration/simple_client.rb @@ -0,0 +1,163 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') + +require 'thrift' +require 'ThriftTest' + +class SimpleClientTest < Test::Unit::TestCase + def setup + unless @socket + @socket = Thrift::Socket.new('localhost', 9090) + @protocol = Thrift::BinaryProtocol.new(@socket) + @client = Thrift::Test::ThriftTest::Client.new(@protocol) + @socket.open + end + end + + def test_string + assert_equal(@client.testString('string'), 'string') + end + + def test_byte + val = 8 + assert_equal(@client.testByte(val), val) + assert_equal(@client.testByte(-val), -val) + end + + def test_i32 + val = 32 + assert_equal(@client.testI32(val), val) + assert_equal(@client.testI32(-val), -val) + end + + def test_i64 + val = 64 + assert_equal(@client.testI64(val), val) + assert_equal(@client.testI64(-val), -val) + end + + def test_double + val = 3.14 + assert_equal(@client.testDouble(val), val) + assert_equal(@client.testDouble(-val), -val) + assert_kind_of(Float, @client.testDouble(val)) + end + + def test_map + val = {1 => 1, 2 => 2, 3 => 3} + assert_equal(@client.testMap(val), val) + assert_kind_of(Hash, @client.testMap(val)) + end + + def test_list + val = [1,2,3,4,5] + assert_equal(@client.testList(val), val) + assert_kind_of(Array, @client.testList(val)) + end + + def test_enum + val = Thrift::Test::Numberz::SIX + ret = @client.testEnum(val) + + assert_equal(ret, 6) + assert_kind_of(Fixnum, ret) + end + + def test_typedef + #UserId testTypedef(1: UserId thing), + true + end + + def test_set + val = Set.new([1,2,3]) + assert_equal(@client.testSet(val), val) + assert_kind_of(Set, @client.testSet(val)) + end + + def get_struct + Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 }) + end + + def test_struct + ret = @client.testStruct(get_struct) + + assert_nil(ret.byte_thing, nil) + assert_nil(ret.i64_thing, nil) + assert_equal(ret.string_thing, 'hi!') + assert_equal(ret.i32_thing, 4) + assert_kind_of(Thrift::Test::Xtruct, ret) + end + + def test_nest + struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10}) + + ret = @client.testNest(struct2) + + assert_nil(ret.struct_thing.byte_thing, nil) + assert_nil(ret.struct_thing.i64_thing, nil) + assert_equal(ret.struct_thing.string_thing, 'hi!') + assert_equal(ret.struct_thing.i32_thing, 4) + assert_equal(ret.i32_thing, 10) + + assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing) + assert_kind_of(Thrift::Test::Xtruct2, ret) + end + + def test_insane + insane = Thrift::Test::Insanity.new({ + 'userMap' => { Thrift::Test::Numberz::ONE => 44 }, + 'xtructs' => [get_struct, + Thrift::Test::Xtruct.new({ + 'string_thing' => 'hi again', + 'i32_thing' => 12 + }) + ] + }) + + ret = @client.testInsanity(insane) + + assert_not_nil(ret[44]) + assert_not_nil(ret[44][1]) + + struct = ret[44][1] + + assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44) + assert_equal(struct.xtructs[1].string_thing, 'hi again') + assert_equal(struct.xtructs[1].i32_thing, 12) + + assert_kind_of(Hash, struct.userMap) + assert_kind_of(Array, struct.xtructs) + assert_kind_of(Thrift::Test::Insanity, struct) + end + + def test_map_map + ret = @client.testMapMap(4) + assert_kind_of(Hash, ret) + assert_equal(ret, { 4 => { 4 => 4}}) + end + + def test_exception + assert_raise Thrift::Test::Xception do + @client.testException('foo') + end + end +end + diff --git a/test/rb/integration/simple_server.rb b/test/rb/integration/simple_server.rb new file mode 100644 index 000000000..3518d2e14 --- /dev/null +++ b/test/rb/integration/simple_server.rb @@ -0,0 +1,64 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +$:.push File.dirname(__FILE__) + '/../gen-rb' +$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/lib') + +require 'thrift' +require 'ThriftTest' + +class SimpleHandler + [:testString, :testByte, :testI32, :testI64, :testDouble, + :testStruct, :testMap, :testSet, :testList, :testNest, + :testEnum, :testTypedef].each do |meth| + + define_method(meth) do |thing| + thing + end + + end + + def testInsanity(thing) + num, uid = thing.userMap.find { true } + return {uid => {num => thing}} + end + + def testMapMap(thing) + return {thing => {thing => thing}} + end + + def testEnum(thing) + return thing + end + + def testTypedef(thing) + return thing + end + + def testException(thing) + raise Thrift::Test::Xception, :message => 'error' + end +end + +@handler = SimpleHandler.new +@processor = Thrift::Test::ThriftTest::Processor.new(@handler) +@transport = Thrift::ServerSocket.new(9090) +@server = Thrift::ThreadedServer.new(@processor, @transport) + +@server.serve diff --git a/test/rb/integration/test_simple_handler.rb b/test/rb/integration/test_simple_handler.rb new file mode 100644 index 000000000..c34aa7e51 --- /dev/null +++ b/test/rb/integration/test_simple_handler.rb @@ -0,0 +1,211 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +require File.join(File.dirname(__FILE__), '../test_helper') + +require 'thrift' +require 'ThriftTest' + +class TestHandler + [:testString, :testByte, :testI32, :testI64, :testDouble, + :testStruct, :testMap, :testSet, :testList, :testNest, + :testEnum, :testTypedef].each do |meth| + + define_method(meth) do |thing| + thing + end + + end + + def testInsanity(thing) + num, uid = thing.userMap.find { true } + return {uid => {num => thing}} + end + + def testMapMap(thing) + return {thing => {thing => thing}} + end + + def testEnum(thing) + return thing + end + + def testTypedef(thing) + return thing + end + + def testException(thing) + raise Thrift::Test::Xception, :message => 'error' + end + +end +class TestThrift < Test::Unit::TestCase + + @@INIT = nil + + def setup + if @@INIT.nil? + # Initialize the server + @handler = TestHandler.new() + @processor = Thrift::Test::ThriftTest::Processor.new(@handler) + @transport = Thrift::ServerSocket.new(9090) + @server = Thrift::ThreadedServer.new(@processor, @transport) + + @thread = Thread.new { @server.serve } + + # And the Client + @socket = Thrift::Socket.new('localhost', 9090) + @protocol = Thrift::BinaryProtocol.new(@socket) + @client = Thrift::Test::ThriftTest::Client.new(@protocol) + @socket.open + end + end + + def test_string + assert_equal(@client.testString('string'), 'string') + end + + def test_byte + val = 8 + assert_equal(@client.testByte(val), val) + assert_equal(@client.testByte(-val), -val) + end + + def test_i32 + val = 32 + assert_equal(@client.testI32(val), val) + assert_equal(@client.testI32(-val), -val) + end + + def test_i64 + val = 64 + assert_equal(@client.testI64(val), val) + assert_equal(@client.testI64(-val), -val) + end + + def test_double + val = 3.14 + assert_equal(@client.testDouble(val), val) + assert_equal(@client.testDouble(-val), -val) + assert_kind_of(Float, @client.testDouble(val)) + end + + def test_map + val = {1 => 1, 2 => 2, 3 => 3} + assert_equal(@client.testMap(val), val) + assert_kind_of(Hash, @client.testMap(val)) + end + + def test_list + val = [1,2,3,4,5] + assert_equal(@client.testList(val), val) + assert_kind_of(Array, @client.testList(val)) + end + + def test_enum + val = Thrift::Test::Numberz::SIX + ret = @client.testEnum(val) + + assert_equal(ret, 6) + assert_kind_of(Fixnum, ret) + end + + def test_typedef + #UserId testTypedef(1: UserId thing), + true + end + + def test_set + val = Set.new([1, 2, 3]) + assert_equal(val, @client.testSet(val)) + assert_kind_of(Set, @client.testSet(val)) + end + + def get_struct + Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 }) + end + + def test_struct + ret = @client.testStruct(get_struct) + + assert_nil(ret.byte_thing, nil) + assert_nil(ret.i64_thing, nil) + assert_equal(ret.string_thing, 'hi!') + assert_equal(ret.i32_thing, 4) + assert_kind_of(Thrift::Test::Xtruct, ret) + end + + def test_nest + struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10}) + + ret = @client.testNest(struct2) + + assert_nil(ret.struct_thing.byte_thing, nil) + assert_nil(ret.struct_thing.i64_thing, nil) + assert_equal(ret.struct_thing.string_thing, 'hi!') + assert_equal(ret.struct_thing.i32_thing, 4) + assert_equal(ret.i32_thing, 10) + + assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing) + assert_kind_of(Thrift::Test::Xtruct2, ret) + end + + def test_insane + insane = Thrift::Test::Insanity.new({ + 'userMap' => { Thrift::Test::Numberz::ONE => 44 }, + 'xtructs' => [get_struct, + Thrift::Test::Xtruct.new({ + 'string_thing' => 'hi again', + 'i32_thing' => 12 + }) + ] + }) + + ret = @client.testInsanity(insane) + + assert_not_nil(ret[44]) + assert_not_nil(ret[44][1]) + + struct = ret[44][1] + + assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44) + assert_equal(struct.xtructs[1].string_thing, 'hi again') + assert_equal(struct.xtructs[1].i32_thing, 12) + + assert_kind_of(Hash, struct.userMap) + assert_kind_of(Array, struct.xtructs) + assert_kind_of(Thrift::Test::Insanity, struct) + end + + def test_map_map + ret = @client.testMapMap(4) + assert_kind_of(Hash, ret) + assert_equal(ret, { 4 => { 4 => 4}}) + end + + def test_exception + assert_raise Thrift::Test::Xception do + @client.testException('foo') + end + end + + def teardown + end + +end diff --git a/test/rb/test_helper.rb b/test/rb/test_helper.rb new file mode 100644 index 000000000..c1ed779ef --- /dev/null +++ b/test/rb/test_helper.rb @@ -0,0 +1,35 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +$:.unshift File.dirname(__FILE__) + '/gen-rb' +$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/lib') +$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/ext') + +require 'test/unit' + +module Thrift + module Struct + def ==(other) + return false unless other.is_a? self.class + self.class.const_get(:FIELDS).collect {|fid, data| data[:name] }.all? do |field| + send(field) == other.send(field) + end + end + end +end diff --git a/test/rb/test_suite.rb b/test/rb/test_suite.rb new file mode 100644 index 000000000..b157c2c50 --- /dev/null +++ b/test/rb/test_suite.rb @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +Dir["{core,generation}/**/*.rb"].each {|f| require f }
\ No newline at end of file diff --git a/test/threads/Makefile b/test/threads/Makefile new file mode 100644 index 000000000..14f1a5890 --- /dev/null +++ b/test/threads/Makefile @@ -0,0 +1,63 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. +# + +# Default target is everything + +ifndef thrift_home +thrift_home=../../ +endif #thrift_home + +target: all + +ifndef boost_home +boost_home=/usr/local/include/boost-1_33_1 +endif #boost_home +target: all + +include_paths = $(thrift_home)/lib/cpp/src \ + $(boost_home) + +include_flags = $(patsubst %,-I%, $(include_paths)) + +# Tools +ifndef THRIFT +THRIFT = ../../compiler/cpp/thrift +endif # THRIFT + +CC = g++ +LD = g++ + +# Compiler flags +LFL = -L$(thrift_home)/lib/cpp/.libs -lthrift +CCFL = -Wall -O3 -g -I./gen-cpp $(include_flags) +CFL = $(CCFL) $(LFL) + +all: server client + +stubs: ThreadsTest.thrift + $(THRIFT) --gen cpp --gen py ThreadsTest.thrift + +server: stubs + g++ -o ThreadsServer $(CFL) ThreadsServer.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp + +client: stubs + g++ -o ThreadsClient $(CFL) ThreadsClient.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp + +clean: + $(RM) -r *.o ThreadsServer ThreadsClient gen-cpp gen-py diff --git a/test/threads/ThreadsClient.cpp b/test/threads/ThreadsClient.cpp new file mode 100644 index 000000000..85274a632 --- /dev/null +++ b/test/threads/ThreadsClient.cpp @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// This autogenerated skeleton file illustrates how to build a server. +// You should copy it to another filename to avoid overwriting it. + +#include "ThreadsTest.h" +#include <protocol/TBinaryProtocol.h> +#include <server/TThreadPoolServer.h> +#include <transport/TSocket.h> +#include <transport/TTransportUtils.h> +#include <thrift/concurrency/Monitor.h> +#include <thrift/concurrency/ThreadManager.h> +#include <thrift/concurrency/PosixThreadFactory.h> + +using boost::shared_ptr; +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; + +int main(int argc, char **argv) { + int port = 9090; + std::string host = "localhost"; + + shared_ptr<TTransport> transport(new TSocket(host, port)); + shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); + + transport->open(); + + ThreadsTestClient client(protocol); + int val; + val = client.threadOne(5); + fprintf(stderr, "%d\n", val); + val = client.stop(); + fprintf(stderr, "%d\n", val); + val = client.threadTwo(5); + fprintf(stderr, "%d\n", val); + + transport->close(); + + fprintf(stderr, "done.\n"); + + return 0; +} + diff --git a/test/threads/ThreadsServer.cpp b/test/threads/ThreadsServer.cpp new file mode 100644 index 000000000..8734ee893 --- /dev/null +++ b/test/threads/ThreadsServer.cpp @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +// This autogenerated skeleton file illustrates how to build a server. +// You should copy it to another filename to avoid overwriting it. + +#include "ThreadsTest.h" +#include <protocol/TBinaryProtocol.h> +#include <server/TThreadPoolServer.h> +#include <server/TThreadedServer.h> +#include <transport/TServerSocket.h> +#include <transport/TTransportUtils.h> +#include <thrift/concurrency/Monitor.h> +#include <thrift/concurrency/ThreadManager.h> +#include <thrift/concurrency/PosixThreadFactory.h> + +using boost::shared_ptr; +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; + + +class ThreadsTestHandler : virtual public ThreadsTestIf { + public: + ThreadsTestHandler() { + // Your initialization goes here + } + + int32_t threadOne(const int32_t sleep) { + // Your implementation goes here + printf("threadOne\n"); + go2sleep(1, sleep); + return 1; + } + + int32_t threadTwo(const int32_t sleep) { + // Your implementation goes here + printf("threadTwo\n"); + go2sleep(2, sleep); + return 1; + } + + int32_t threadThree(const int32_t sleep) { + // Your implementation goes here + printf("threadThree\n"); + go2sleep(3, sleep); + return 1; + } + + int32_t threadFour(const int32_t sleep) { + // Your implementation goes here + printf("threadFour\n"); + go2sleep(4, sleep); + return 1; + } + + int32_t stop() { + printf("stop\n"); + server_->stop(); + return 1; + } + + void setServer(boost::shared_ptr<TServer> server) { + server_ = server; + } + +protected: + void go2sleep(int thread, int seconds) { + Monitor m; + for (int i = 0; i < seconds; ++i) { + fprintf(stderr, "Thread %d: sleep %d\n", thread, i); + try { + m.wait(1000); + } catch(TimedOutException& e) { + } + } + fprintf(stderr, "THREAD %d DONE\n", thread); + } + +private: + boost::shared_ptr<TServer> server_; + +}; + +int main(int argc, char **argv) { + int port = 9090; + shared_ptr<ThreadsTestHandler> handler(new ThreadsTestHandler()); + shared_ptr<TProcessor> processor(new ThreadsTestProcessor(handler)); + shared_ptr<TServerTransport> serverTransport(new TServerSocket(port)); + shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); + shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); + + /* + shared_ptr<ThreadManager> threadManager = + ThreadManager::newSimpleThreadManager(10); + shared_ptr<PosixThreadFactory> threadFactory = + shared_ptr<PosixThreadFactory>(new PosixThreadFactory()); + threadManager->threadFactory(threadFactory); + threadManager->start(); + + shared_ptr<TServer> server = + shared_ptr<TServer>(new TThreadPoolServer(processor, + serverTransport, + transportFactory, + protocolFactory, + threadManager)); + */ + + shared_ptr<TServer> server = + shared_ptr<TServer>(new TThreadedServer(processor, + serverTransport, + transportFactory, + protocolFactory)); + + handler->setServer(server); + + server->serve(); + + fprintf(stderr, "done.\n"); + + return 0; +} + diff --git a/test/threads/ThreadsTest.thrift b/test/threads/ThreadsTest.thrift new file mode 100644 index 000000000..caa934605 --- /dev/null +++ b/test/threads/ThreadsTest.thrift @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +service ThreadsTest { + i32 threadOne(1: i32 sleep=15), + i32 threadTwo(2: i32 sleep=15), + i32 threadThree(3: i32 sleep=15), + i32 threadFour(4: i32 sleep=15) + + i32 stop(); + +} |