THRIFT-892 - refactor erlang library to build using rebar, move tests into lib/erl/test directory and run several via make check
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1137870 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/erl/Makefile.am b/lib/erl/Makefile.am
index 0722f12..fd780a2 100644
--- a/lib/erl/Makefile.am
+++ b/lib/erl/Makefile.am
@@ -17,7 +17,23 @@
# under the License.
#
-SUBDIRS = src
+THRIFT = ../../compiler/cpp/thrift
+#THRIFT_FILES = ../../test/ThriftTest.thrift \
+# ../../test/Stress.thrift
+THRIFT_FILES = $(wildcard ../../test/*.thrift) \
+ $(wildcard test/*.thrift)
+
+.generated: $(THRIFT_FILES)
+ for f in $(THRIFT_FILES) ; do \
+ $(THRIFT) --gen erl -out test $$f ; \
+ done ; \
+ touch .generated
+
+all: .generated
+ ./rebar compile
+
+check: .generated
+ ./rebar eunit
install: all
mkdir -p $(DESTDIR)$(ERLANG_INSTALL_LIB_DIR_thrift) ; \
@@ -31,10 +47,36 @@
uninstall:
rm -rf $(DESTDIR)$(ERLANG_INSTALL_LIB_DIR_thrift)
+clean:
+ rm .generated
+ ./rebar clean
maintainer-clean-local:
+ rm -f test/secondService_* \
+ test/aService_* \
+ test/serviceForExceptionWithAMap_* \
+ test/annotationTest_* \
+ test/service_* \
+ test/constantsDemo_* \
+ test/smallService_* \
+ test/smallTest_* \
+ test/debugProtoTest_* \
+ test/srv_* \
+ test/denseLinkingTest_* \
+ test/stressTest_* \
+ test/docTest_* \
+ test/emptyService_* \
+ test/inherited_* \
+ test/javaBeansTest_* \
+ test/thrift1151_* \
+ test/javaBeansTest_* \
+ test/manyTypedefs_* \
+ test/thriftTest_* \
+ test/optionalRequiredTest_* \
+ test/yowza_* \
+ test/reverseOrderService_*
rm -rf ebin
-EXTRA_DIST = include src
+EXTRA_DIST = include src rebar rebar.config
MAINTAINERCLEANFILES = Makefile.in
diff --git a/lib/erl/rebar b/lib/erl/rebar
new file mode 100755
index 0000000..53419ea
--- /dev/null
+++ b/lib/erl/rebar
Binary files differ
diff --git a/lib/erl/rebar.config b/lib/erl/rebar.config
new file mode 100644
index 0000000..7eb26b2
--- /dev/null
+++ b/lib/erl/rebar.config
@@ -0,0 +1,3 @@
+{erl_opts, [debug_info]}.
+% {pre_hooks, [{compile, "./scripts/rebar-pre-compile"},
+% {clean, "./scripts/rebar-clean"}]}.
diff --git a/lib/erl/src/Makefile.am b/lib/erl/src/Makefile.am
deleted file mode 100644
index 9d6fcdb..0000000
--- a/lib/erl/src/Makefile.am
+++ /dev/null
@@ -1,83 +0,0 @@
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-
-APP_NAME=$(PACKAGE_NAME)
-VSN=$(PACKAGE_VERSION)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-ERL_FLAGS =
-ERL_INCLUDE = -I../include
-ERL_BEHAV_PATH = -pz ../ebin
-ERL_COMPILE_FLAGS = $(ERL_INCLUDE) $(ERL_BEHAV_PATH)
-
-EBIN ?= ../ebin
-ESRC ?= .
-EMULATOR = beam
-
-ERLC_WFLAGS = -W
-ERLC = erlc $(ERLC_WFLAGS) $(ERLC_FLAGS)
-ERL = erl -boot start_clean
-
-$(EBIN)/%.beam: $(ESRC)/%.erl
- @echo " ERLC $<"
- @$(ERLC) $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
-
-.erl.beam:
- $(ERLC) $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = $(shell find . -name \*.erl | sed 's:^\./::' | sed 's/\.erl//')
-MODULES_STRING_LIST = $(shell find . -name \*.erl | sed 's:^\./::' | sed 's/\.erl/,/')
-BEHAV_MODULES = $(shell find . -name \*.erl | xargs grep -l behaviour_info | sed 's:^\./::' | sed 's/\.erl//')
-
-ERL_FILES= $(MODULES:%=%.erl)
-DOC_FILES=$(ERL_FILES)
-
-APP_FILE= $(APP_NAME).app
-APP_SRC= $(APP_FILE).src
-APP_TARGET= $(EBIN)/$(APP_FILE)
-
-BEAMS= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-BEHAV_BEAMS= $(BEHAV_MODULES:%=$(EBIN)/%.$(EMULATOR))
-TARGET_FILES= $(BEHAV_BEAMS) $(BEAMS) $(APP_TARGET) $(APPUP_TARGET)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-all debug opt: $(EBIN) $(TARGET_FILES)
-
-# Note: In the open-source build clean must not destroy the preloaded
-# beam files.
-clean:
- rm -f $(TARGET_FILES)
- rm -f *~
- rm -f core
- rm -rf $(EBIN)
- rm -rf *html
-
-$(EBIN):
- mkdir $(EBIN)
-
-dialyzer: $(TARGET_FILES)
- dialyzer --src -r . $(ERL_INCLUDE)
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-$(APP_TARGET): $(APP_SRC) $(BEAMS)
- sed -e 's;%VSN%;$(VSN);' \
- -e 's;%APP_NAME%;$(APP_NAME);' \
- -e 's;%MODULES%;%MODULES%$(MODULES_STRING_LIST);' \
- $< > $<".tmp"
- sed -e 's/%MODULES%\(.*\),/\1/' \
- $<".tmp" > $@
- rm $<".tmp"
diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src.in
similarity index 96%
rename from lib/erl/src/thrift.app.src
rename to lib/erl/src/thrift.app.src.in
index ebe38d3..176c4c1 100644
--- a/lib/erl/src/thrift.app.src
+++ b/lib/erl/src/thrift.app.src.in
@@ -17,17 +17,16 @@
%% under the License.
%%
%%% -*- mode:erlang -*-
-{application, %APP_NAME%,
+{application, @PACKAGE_NAME@,
[
% A quick description of the application.
{description, "Thrift bindings"},
% The version of the applicaton
- {vsn, "%VSN%"},
+ {vsn, "@PACKAGE_VERSION@"},
% All modules used by the application.
{modules, [
- %MODULES%
]},
% All of the registered names the application uses. This can be ignored.
diff --git a/lib/erl/test/Thrift1151.thrift b/lib/erl/test/Thrift1151.thrift
new file mode 100644
index 0000000..6f934a7
--- /dev/null
+++ b/lib/erl/test/Thrift1151.thrift
@@ -0,0 +1,3 @@
+struct StructA { 1: i16 x; }
+struct StructB { 1: i32 x; }
+struct StructC { 1: StructA x; }
diff --git a/lib/erl/test/stress_server.erl b/lib/erl/test/stress_server.erl
new file mode 100644
index 0000000..35fff06
--- /dev/null
+++ b/lib/erl/test/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/lib/erl/test/test_client.erl b/lib/erl/test/test_client.erl
new file mode 100644
index 0000000..59f596d
--- /dev/null
+++ b/lib/erl/test/test_client.erl
@@ -0,0 +1,132 @@
+%%
+%% 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_client).
+
+-export([start/0, start/1]).
+
+-include("thriftTest_types.hrl").
+
+-record(options, {port = 9090,
+ client_opts = []}).
+
+parse_args(Args) -> parse_args(Args, #options{}).
+parse_args([], Opts) -> Opts;
+parse_args([Head | Rest], Opts) ->
+ NewOpts =
+ case catch list_to_integer(Head) of
+ Port when is_integer(Port) ->
+ Opts#options{port = Port};
+ _Else ->
+ case Head of
+ "framed" ->
+ Opts#options{client_opts = [{framed, true} | Opts#options.client_opts]};
+ "" ->
+ Opts;
+ _Else ->
+ erlang:error({bad_arg, Head})
+ end
+ end,
+ parse_args(Rest, NewOpts).
+
+
+start() -> start([]).
+start(Args) ->
+ #options{port = Port, client_opts = ClientOpts} = parse_args(Args),
+ {ok, Client0} = thrift_client_util:new(
+ "127.0.0.1", Port, thriftTest_thrift, ClientOpts),
+
+ DemoXtruct = #xtruct{
+ string_thing = <<"Zero">>,
+ byte_thing = 1,
+ i32_thing = 9128361,
+ i64_thing = 9223372036854775807},
+
+ DemoNest = #xtruct2{
+ byte_thing = 7,
+ struct_thing = DemoXtruct,
+ % Note that we don't set i32_thing, it will come back as undefined
+ % from the Python server, but 0 from the C++ server, since it is not
+ % optional
+ i32_thing = 2},
+
+ % Is it safe to match these things?
+ DemoDict = dict:from_list([ {Key, Key-10} || Key <- lists:seq(0,10) ]),
+ DemoSet = sets:from_list([ Key || Key <- lists:seq(-3,3) ]),
+
+ %DemoInsane = #insanity{
+ % userMap = dict:from_list([{?thriftTest_FIVE, 5000}]),
+ % xtructs = [#xtruct{ string_thing = <<"Truck">>, byte_thing = 8, i32_thing = 8, i64_thing = 8}]},
+
+ {Client01, {ok, ok}} = thrift_client:call(Client0, testVoid, []),
+
+ {Client02, {ok, <<"Test">>}} = thrift_client:call(Client01, testString, ["Test"]),
+ {Client03, {ok, <<"Test">>}} = thrift_client:call(Client02, testString, [<<"Test">>]),
+ {Client04, {ok, 63}} = thrift_client:call(Client03, testByte, [63]),
+ {Client05, {ok, -1}} = thrift_client:call(Client04, testI32, [-1]),
+ {Client06, {ok, 0}} = thrift_client:call(Client05, testI32, [0]),
+ {Client07, {ok, -34359738368}} = thrift_client:call(Client06, testI64, [-34359738368]),
+ {Client08, {ok, -5.2098523}} = thrift_client:call(Client07, testDouble, [-5.2098523]),
+ {Client09, {ok, DemoXtruct}} = thrift_client:call(Client08, testStruct, [DemoXtruct]),
+ {Client10, {ok, DemoNest}} = thrift_client:call(Client09, testNest, [DemoNest]),
+ {Client11, {ok, DemoDict}} = thrift_client:call(Client10, testMap, [DemoDict]),
+ {Client12, {ok, DemoSet}} = thrift_client:call(Client11, testSet, [DemoSet]),
+ {Client13, {ok, [-1,2,3]}} = thrift_client:call(Client12, testList, [[-1,2,3]]),
+ {Client14, {ok, 1}} = thrift_client:call(Client13, testEnum, [?thriftTest_Numberz_ONE]),
+ {Client15, {ok, 309858235082523}} = thrift_client:call(Client14, testTypedef, [309858235082523]),
+
+ % No python implementation, but works with C++ and Erlang.
+ %{Client16, {ok, InsaneResult}} = thrift_client:call(Client15, testInsanity, [DemoInsane]),
+ %io:format("~p~n", [InsaneResult]),
+ Client16 = Client15,
+
+ {Client17, {ok, #xtruct{string_thing = <<"Message">>}}} =
+ thrift_client:call(Client16, testMultiException, ["Safe", "Message"]),
+
+ Client18 =
+ try
+ {ClientS1, Result1} = thrift_client:call(Client17, testMultiException, ["Xception", "Message"]),
+ io:format("Unexpected return! ~p~n", [Result1]),
+ ClientS1
+ catch
+ throw:{ClientS2, {exception, ExnS1 = #xception{}}} ->
+ #xception{errorCode = 1001, message = <<"This is an Xception">>} = ExnS1,
+ ClientS2;
+ throw:{ClientS2, {exception, _ExnS1 = #xception2{}}} ->
+ io:format("Wrong exception type!~n", []),
+ ClientS2
+ end,
+
+ Client19 =
+ try
+ {ClientS3, Result2} = thrift_client:call(Client18, testMultiException, ["Xception2", "Message"]),
+ io:format("Unexpected return! ~p~n", [Result2]),
+ ClientS3
+ catch
+ throw:{ClientS4, {exception, _ExnS2 = #xception{}}} ->
+ io:format("Wrong exception type!~n", []),
+ ClientS4;
+ throw:{ClientS4, {exception, ExnS2 = #xception2{}}} ->
+ #xception2{errorCode = 2002,
+ struct_thing = #xtruct{
+ string_thing = <<"This is an Xception2">>}} = ExnS2,
+ ClientS4
+ end,
+
+ thrift_client:close(Client19).
diff --git a/lib/erl/test/test_disklog.erl b/lib/erl/test/test_disklog.erl
new file mode 100644
index 0000000..17a27b0
--- /dev/null
+++ b/lib/erl/test/test_disklog.erl
@@ -0,0 +1,85 @@
+%%
+%% 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).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+disklog_test() ->
+ {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, Proto} = ProtocolFactory(),
+ {ok, Client0} = thrift_client:new(Proto, 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.
+ {Client1, {ok, ok}} = thrift_client:call(Client0, testOneway, [16#deadbeef]),
+ io:format("Call written~n"),
+
+ % Use the send_call method to write a non-oneway call into the log
+ {Client2, ok} =
+ thrift_client:send_call(Client1, testString, [<<"hello world">>]),
+ io:format("Non-oneway call sent~n"),
+
+ {_Client3, ok} = thrift_client:close(Client2),
+ io:format("Client closed~n"),
+
+ ok.
+
+disklog_base64_test() ->
+ {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, Proto} = ProtocolFactory(),
+ {ok, Client0} = thrift_client:new(Proto, 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.
+ {Client1, {ok, ok}} = thrift_client:call(Client0, testOneway, [16#deadbeef]),
+ io:format("Call written~n"),
+
+ % Use the send_call method to write a non-oneway call into the log
+ {Client2, ok} =
+ thrift_client:send_call(Client1, testString, [<<"hello world">>]),
+ io:format("Non-oneway call sent~n"),
+
+ {_Client3, ok} = thrift_client:close(Client2),
+ io:format("Client closed~n"),
+
+ ok.
+
+-endif.
diff --git a/lib/erl/test/test_membuffer.erl b/lib/erl/test/test_membuffer.erl
new file mode 100644
index 0000000..7a01143
--- /dev/null
+++ b/lib/erl/test/test_membuffer.erl
@@ -0,0 +1,115 @@
+%%
+%% 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).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+-include("thriftTest_types.hrl").
+
+test_data() ->
+ #xtruct {
+ string_thing = <<"foobar">>,
+ byte_thing = 123,
+ i32_thing = 1234567,
+ i64_thing = 12345678900
+ }.
+
+encode_decode_1_test() ->
+ {ok, Transport} = thrift_memory_buffer:new(),
+ {ok, Protocol0} = thrift_binary_protocol:new(Transport),
+ TestData = test_data(),
+ {Protocol1, ok} = thrift_protocol:write(Protocol0,
+ {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
+ TestData}),
+ {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
+ {struct, element(2, thriftTest_types:struct_info('xtruct'))},
+ 'xtruct'),
+ Result = TestData.
+
+encode_decode_2_test() ->
+ {ok, Transport} = thrift_memory_buffer:new(),
+ {ok, Protocol0} = thrift_binary_protocol:new(Transport),
+ TestData = test_data(),
+ {Protocol1, ok} = thrift_protocol:write(Protocol0,
+ {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
+ TestData}),
+ {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
+ {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}.
+
+
+encode_decode_3_test() ->
+ {ok, Transport} = thrift_memory_buffer:new(),
+ {ok, Protocol0} = thrift_binary_protocol:new(Transport),
+ TestData = #bools{im_true = true, im_false = false},
+ {Protocol1, ok} = thrift_protocol:write(Protocol0,
+ {{struct, element(2, thriftTest_types:struct_info('bools'))},
+ TestData}),
+ {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
+ {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.
+
+
+encode_decode_4_test() ->
+ {ok, Transport} = thrift_memory_buffer:new(),
+ {ok, Protocol0} = thrift_binary_protocol:new(Transport),
+ TestData = #insanity{xtructs=[]},
+ {Protocol1, ok} = thrift_protocol:write(Protocol0,
+ {{struct, element(2, thriftTest_types:struct_info('insanity'))},
+ TestData}),
+ {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
+ {struct, element(2, thriftTest_types:struct_info('insanity'))},
+ 'insanity'),
+
+ TestData = Result.
+
+encode_decode_5_test() ->
+ % test writing to a buffer, getting the bytes out, putting them
+ % in a new buffer and reading them
+
+ % here's the writing part
+ {ok, Transport0} = thrift_memory_buffer:new(),
+ {ok, Protocol0} = thrift_binary_protocol:new(Transport0),
+ TestData = test_data(),
+ {Protocol1, ok} = thrift_protocol:write(Protocol0,
+ {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
+ TestData}),
+ % flush now returns the buffer
+ {_Protocol2, Buf} = thrift_protocol:flush_transport (Protocol1),
+
+ % now the reading part
+ {ok, T2} = thrift_memory_buffer:new (Buf),
+ {ok, P2} = thrift_binary_protocol:new(T2),
+ {_, {ok, Result}} = thrift_protocol:read(P2,
+ {struct, element(2, thriftTest_types:struct_info('xtruct'))},
+ 'xtruct'),
+
+ Result = TestData.
+
+-endif.
diff --git a/lib/erl/test/test_server.erl b/lib/erl/test/test_server.erl
new file mode 100644
index 0000000..63f7b08
--- /dev/null
+++ b/lib/erl/test/test_server.erl
@@ -0,0 +1,204 @@
+%%
+%% 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([go/0, go/1, start_link/2, handle_function/2]).
+
+-include("thriftTest_types.hrl").
+
+-record(options, {port = 9090,
+ server_opts = []}).
+
+parse_args(Args) -> parse_args(Args, #options{}).
+parse_args([], Opts) -> Opts;
+parse_args([Head | Rest], Opts) ->
+ NewOpts =
+ case catch list_to_integer(Head) of
+ Port when is_integer(Port) ->
+ Opts#options{port = Port};
+ _Else ->
+ case Head of
+ "framed" ->
+ Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]};
+ "" ->
+ Opts;
+ _Else ->
+ erlang:error({bad_arg, Head})
+ end
+ end,
+ parse_args(Rest, NewOpts).
+
+go() -> go([]).
+go(Args) ->
+ #options{port = Port, server_opts = ServerOpts} = parse_args(Args),
+ spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end).
+
+start_link(Port, ServerOpts) ->
+ thrift_socket_server:start([{handler, ?MODULE},
+ {service, thriftTest_thrift},
+ {port, Port}] ++
+ ServerOpts).
+
+
+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_Numberz_EIGHT, 8}]),
+ xtructs = [Goodbye]
+ },
+
+ Looney = #insanity{
+ userMap = dict:from_list([{?thriftTest_Numberz_FIVE, 5}]),
+ xtructs = [Hello]
+ },
+
+ FirstMap = dict:from_list([{?thriftTest_Numberz_TWO, Crazy},
+ {?thriftTest_Numberz_THREE, Crazy}]),
+
+ SecondMap = dict:from_list([{?thriftTest_Numberz_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 = String});
+ _ ->
+ 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/lib/erl/test/test_thrift_1151.erl b/lib/erl/test/test_thrift_1151.erl
new file mode 100644
index 0000000..9cee486
--- /dev/null
+++ b/lib/erl/test/test_thrift_1151.erl
@@ -0,0 +1,24 @@
+-module(test_thrift_1151).
+
+-include("thrift1151_types.hrl").
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+unmatched_struct_test() ->
+ S1 = #structC{x=#structB{x=1}},
+ {ok, Transport} = thrift_memory_buffer:new(),
+ {ok, Protocol} = thrift_binary_protocol:new(Transport),
+ ?assertException (error, struct_unmatched,
+ thrift_protocol:write(Protocol,
+ {{struct, element(2, thrift1151_types:struct_info('structC'))}, S1})).
+
+badarg_test() ->
+ S2 = #structC{x=#structA{x="1"}},
+ {ok, Transport} = thrift_memory_buffer:new(),
+ {ok, Protocol} = thrift_binary_protocol:new(Transport),
+ ?assertException (error, badarg,
+ thrift_protocol:write(Protocol,
+ {{struct, element(2, thrift1151_types:struct_info('structC'))}, S2})).
+
+-endif.