You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by ns...@apache.org on 2015/11/01 11:48:53 UTC

[1/6] thrift git commit: THRIFT-2856 refactor erlang basic transports and unify interfaces Client: Erlang Patch: Alisdair Sullivan

Repository: thrift
Updated Branches:
  refs/heads/master 826ea998d -> f58bca7ad


THRIFT-2856 refactor erlang basic transports and unify interfaces
Client: Erlang
Patch: Alisdair Sullivan

This closes #288


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/a559f8d9
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/a559f8d9
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/a559f8d9

Branch: refs/heads/master
Commit: a559f8d903074afa76b4e9255e0d883b7401bf95
Parents: 826ea99
Author: alisdair sullivan <al...@yahoo.ca>
Authored: Mon Nov 17 20:28:35 2014 -0800
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Nov 1 18:03:40 2015 +0900

----------------------------------------------------------------------
 build/travis/installDependencies.sh             |   2 +-
 contrib/Vagrantfile                             |   2 +-
 lib/erl/Makefile.am                             |   4 +-
 lib/erl/rebar.test.config                       |   5 +
 lib/erl/src/thrift.app.src                      |   1 +
 lib/erl/src/thrift_buffered_transport.erl       |  97 +++--
 lib/erl/src/thrift_file_transport.erl           | 126 +++---
 lib/erl/src/thrift_framed_transport.erl         | 172 ++++----
 lib/erl/src/thrift_membuffer_transport.erl      |  83 ++++
 lib/erl/src/thrift_memory_buffer.erl            |  45 +--
 lib/erl/src/thrift_socket_transport.erl         | 208 ++++++----
 lib/erl/src/thrift_transport.erl                | 133 +++---
 lib/erl/test/test_membuffer.erl                 | 115 ------
 lib/erl/test/test_thrift_buffered_transport.erl | 359 ++++++++++++++++
 lib/erl/test/test_thrift_file_transport.erl     | 213 ++++++++++
 lib/erl/test/test_thrift_framed_transport.erl   | 404 +++++++++++++++++++
 .../test/test_thrift_membuffer_transport.erl    | 167 ++++++++
 lib/erl/test/test_thrift_socket_transport.erl   | 199 +++++++++
 18 files changed, 1901 insertions(+), 434 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/build/travis/installDependencies.sh
----------------------------------------------------------------------
diff --git a/build/travis/installDependencies.sh b/build/travis/installDependencies.sh
index 5b74140..eb2f7de 100755
--- a/build/travis/installDependencies.sh
+++ b/build/travis/installDependencies.sh
@@ -46,7 +46,7 @@ sudo apt-get install -qq php5 php5-dev php5-cli php-pear re2c
 sudo apt-get install -qq libglib2.0-dev
 
 # Erlang dependencies
-sudo apt-get install -qq erlang-base erlang-eunit erlang-dev
+sudo apt-get install -qq erlang-base erlang-eunit erlang-dev erlang-tools
 
 # GO dependencies
 echo "golang-go golang-go/dashboard boolean false" | debconf-set-selections

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/contrib/Vagrantfile
----------------------------------------------------------------------
diff --git a/contrib/Vagrantfile b/contrib/Vagrantfile
index d9a908d..f967f04 100644
--- a/contrib/Vagrantfile
+++ b/contrib/Vagrantfile
@@ -62,7 +62,7 @@ sudo apt-get install -qq php5 php5-dev php5-cli php-pear re2c
 sudo apt-get install -qq libglib2.0-dev
 
 # Erlang dependencies
-sudo apt-get install -qq erlang-base erlang-eunit erlang-dev
+sudo apt-get install -qq erlang-base erlang-eunit erlang-dev erlang-tools
 
 # GO dependencies
 echo "golang-go golang-go/dashboard boolean false" | debconf-set-selections

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/erl/Makefile.am b/lib/erl/Makefile.am
index 21d21bf..d140858 100644
--- a/lib/erl/Makefile.am
+++ b/lib/erl/Makefile.am
@@ -45,7 +45,9 @@ all: .generated
 	./rebar compile
 
 check: .generated
-	./rebar skip_deps=true eunit
+	./rebar -C rebar.test.config get-deps
+	./rebar -C rebar.test.config compile
+	./rebar -C rebar.test.config skip_deps=true eunit
 
 install: all
 	mkdir -p $(DESTDIR)$(ERLANG_INSTALL_LIB_DIR_thrift) ; \

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/rebar.test.config
----------------------------------------------------------------------
diff --git a/lib/erl/rebar.test.config b/lib/erl/rebar.test.config
new file mode 100644
index 0000000..204f7ee
--- /dev/null
+++ b/lib/erl/rebar.test.config
@@ -0,0 +1,5 @@
+{erl_opts, [{platform_define, "^R.*", otp16_or_less}, debug_info]}.
+
+{deps, [
+  {meck, "", {git, "git://github.com/eproxus/meck.git", {tag, "0.8.2"}}}
+]}.

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift.app.src
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src
index 28b8cb5..1a23f0d 100644
--- a/lib/erl/src/thrift.app.src
+++ b/lib/erl/src/thrift.app.src
@@ -37,6 +37,7 @@
     thrift_http_transport,
     thrift_json_parser,
     thrift_json_protocol,
+    thrift_membuffer_transport,
     thrift_memory_buffer,
     thrift_processor,
     thrift_protocol,

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_buffered_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_buffered_transport.erl b/lib/erl/src/thrift_buffered_transport.erl
index d4d614e..e9d3fff 100644
--- a/lib/erl/src/thrift_buffered_transport.erl
+++ b/lib/erl/src/thrift_buffered_transport.erl
@@ -21,57 +21,78 @@
 
 -behaviour(thrift_transport).
 
-%% API
--export([new/1, new_transport_factory/1]).
+%% constructor
+-export([new/1]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_transport_factory/1]).
+
+
+-record(t_buffered, {
+  wrapped,
+  write_buffer
+}).
+
+-type state() :: #t_buffered{}.
+
+
+-spec new(Transport::thrift_transport:t_transport()) ->
+  thrift_transport:t_transport().
+
+new(Wrapped) ->
+  State = #t_buffered{
+    wrapped = Wrapped,
+    write_buffer = []
+  },
+  thrift_transport:new(?MODULE, State).
 
-%% thrift_transport callbacks
--export([write/2, read/2, flush/1, close/1]).
 
--record(buffered_transport, {wrapped, % a thrift_transport
-                             write_buffer % iolist()
-                            }).
--type state() :: #buffered_transport{}.
 -include("thrift_transport_behaviour.hrl").
 
 
-new(WrappedTransport) ->
-    State = #buffered_transport{wrapped = WrappedTransport,
-                                write_buffer = []},
-    thrift_transport:new(?MODULE, State).
+%% reads data through from the wrapped transport
+read(State = #t_buffered{wrapped = Wrapped}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Response} = thrift_transport:read(Wrapped, Len),
+  {State#t_buffered{wrapped = NewState}, Response}.
 
 
-%% Writes data into the buffer
-write(State = #buffered_transport{write_buffer = WBuf}, Data) ->
-    {State#buffered_transport{write_buffer = [WBuf, Data]}, ok}.
+%% reads data through from the wrapped transport
+read_exact(State = #t_buffered{wrapped = Wrapped}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Response} = thrift_transport:read_exact(Wrapped, Len),
+  {State#t_buffered{wrapped = NewState}, Response}.
 
-%% Flushes the buffer through to the wrapped transport
-flush(State = #buffered_transport{write_buffer = WBuf,
-                                  wrapped = Wrapped0}) ->
-    {Wrapped1, Response} = thrift_transport:write(Wrapped0, WBuf),
-    {Wrapped2, _} = thrift_transport:flush(Wrapped1),
-    NewState = State#buffered_transport{write_buffer = [],
-                                        wrapped = Wrapped2},
-    {NewState, Response}.
 
-%% Closes the transport and the wrapped transport
-close(State = #buffered_transport{wrapped = Wrapped0}) ->
-    {Wrapped1, Result} = thrift_transport:close(Wrapped0),
-    NewState = State#buffered_transport{wrapped = Wrapped1},
-    {NewState, Result}.
+write(State = #t_buffered{write_buffer = Buffer}, Data) ->
+  {State#t_buffered{write_buffer = [Buffer, Data]}, ok}.
+
+
+flush(State = #t_buffered{wrapped = Wrapped, write_buffer = Buffer}) ->
+  case iolist_size(Buffer) of
+    %% if write buffer is empty, do nothing
+    0 -> {State, ok};
+    _ ->
+      {Written, Response} = thrift_transport:write(Wrapped, Buffer),
+      {Flushed, ok} = thrift_transport:flush(Written),
+      {State#t_buffered{wrapped = Flushed, write_buffer = []}, Response}
+  end.
+
+
+close(State = #t_buffered{wrapped = Wrapped}) ->
+  {Closed, Result} = thrift_transport:close(Wrapped),
+  {State#t_buffered{wrapped = Closed}, Result}.
 
-%% Reads data through from the wrapped transport
-read(State = #buffered_transport{wrapped = Wrapped0}, Len) when is_integer(Len) ->
-    {Wrapped1, Response} = thrift_transport:read(Wrapped0, Len),
-    NewState = State#buffered_transport{wrapped = Wrapped1},
-    {NewState, Response}.
 
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
 %%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 new_transport_factory(WrapFactory) ->
-    F = fun() ->
-                {ok, Wrapped} = WrapFactory(),
-                new(Wrapped)
-        end,
-    {ok, F}.
+  F = fun() ->
+    {ok, Wrapped} = WrapFactory(),
+    new(Wrapped)
+  end,
+  {ok, F}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_file_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_file_transport.erl b/lib/erl/src/thrift_file_transport.erl
index ba3aa89..071152b 100644
--- a/lib/erl/src/thrift_file_transport.erl
+++ b/lib/erl/src/thrift_file_transport.erl
@@ -21,69 +21,95 @@
 
 -behaviour(thrift_transport).
 
--export([new_reader/1,
-         new/1,
-         new/2,
-         write/2, read/2, flush/1, close/1]).
-
--record(t_file_transport, {device,
-                           should_close = true,
-                           mode = write}).
--type state() :: #t_file_transport{}.
--include("thrift_transport_behaviour.hrl").
+%% constructors
+-export([new/1, new/2]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_reader/1]).
 
-%%%% CONSTRUCTION   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-new_reader(Filename) ->
-    case file:open(Filename, [read, binary, {read_ahead, 1024*1024}]) of
-        {ok, IODevice} ->
-            new(IODevice, [{should_close, true}, {mode, read}]);
-        Error -> Error
-    end.
+-record(t_file, {
+  device,
+  should_close = true,
+  mode = write
+}).
 
-new(Device) ->
-    new(Device, []).
+-type state() :: #t_file{}.
+
+
+-spec new(Device::file:io_device()) ->
+  thrift_transport:t_transport().
+
+new(Device) -> new(Device, []).
+
+-spec new(Device::file:io_device(), Opts::list()) ->
+  thrift_transport:t_transport().
 
-%% Device :: io_device()
-%%
 %% Device should be opened in raw and binary mode.
 new(Device, Opts) when is_list(Opts) ->
-    State = parse_opts(Opts, #t_file_transport{device = Device}),
-    thrift_transport:new(?MODULE, State).
+  State = parse_opts(Opts, #t_file{device = Device}),
+  thrift_transport:new(?MODULE, State).
 
 
-%% Parse options
-parse_opts([{should_close, Bool} | Rest], State) when is_boolean(Bool) ->
-    parse_opts(Rest, State#t_file_transport{should_close = Bool});
-parse_opts([{mode, Mode} | Rest], State)
-  when Mode =:= write;
-       Mode =:= read ->
-    parse_opts(Rest, State#t_file_transport{mode = Mode});
+parse_opts([{should_close, Bool}|Rest], State)
+when is_boolean(Bool) ->
+  parse_opts(Rest, State#t_file{should_close = Bool});
+parse_opts([{mode, Mode}|Rest], State)
+when Mode =:= write; Mode =:= read ->
+  parse_opts(Rest, State#t_file{mode = Mode});
 parse_opts([], State) ->
-     State.
+  State.
 
 
-%%%% TRANSPORT IMPL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-include("thrift_transport_behaviour.hrl").
+
 
-write(This = #t_file_transport{device = Device, mode = write}, Data) ->
-    {This, file:write(Device, Data)};
-write(This, _D) ->
-    {This, {error, read_mode}}.
+read(State = #t_file{device = Device, mode = read}, Len)
+when is_integer(Len), Len >= 0 ->
+  case file:read(Device, Len) of
+    eof -> {State, {error, eof}};
+    {ok, Result} -> {State, {ok, iolist_to_binary(Result)}}
+  end;
+read(State, _) ->
+  {State, {error, write_mode}}.
 
 
-read(This = #t_file_transport{device = Device, mode = read}, Len)
-  when is_integer(Len), Len >= 0 ->
-    {This, file:read(Device, Len)};
-read(This, _D) ->
-    {This, {error, read_mode}}.
+read_exact(State = #t_file{device = Device, mode = read}, Len)
+when is_integer(Len), Len >= 0 ->
+  case file:read(Device, Len) of
+    eof -> {State, {error, eof}};
+    {ok, Result} ->
+      case iolist_size(Result) of
+        X when X < Len -> {State, {error, eof}};
+        _ -> {State, {ok, iolist_to_binary(Result)}}
+      end
+  end;
+read_exact(State, _) ->
+  {State, {error, write_mode}}.
 
-flush(This = #t_file_transport{device = Device, mode = write}) ->
-    {This, file:sync(Device)}.
 
-close(This = #t_file_transport{device = Device, should_close = SC}) ->
-    case SC of
-        true ->
-            {This, file:close(Device)};
-        false ->
-            {This, ok}
-    end.
+write(State = #t_file{device = Device, mode = write}, Data) ->
+  {State, file:write(Device, Data)};
+write(State, _) ->
+  {State, {error, read_mode}}.
+
+
+flush(State = #t_file{device = Device, mode = write}) ->
+  {State, file:sync(Device)}.
+
+
+close(State = #t_file{device = Device, should_close = SC}) ->
+  case SC of
+    true -> {State, file:close(Device)};
+    false -> {State, ok}
+  end.
+
+
+%% legacy api. left for compatibility
+new_reader(Filename) ->
+  case file:open(Filename, [read, binary, {read_ahead, 1024*1024}]) of
+    {ok, IODevice} -> new(IODevice, [{should_close, true}, {mode, read}]);
+    Error -> Error
+  end.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_framed_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_framed_transport.erl b/lib/erl/src/thrift_framed_transport.erl
index eca3cbe..715f090 100644
--- a/lib/erl/src/thrift_framed_transport.erl
+++ b/lib/erl/src/thrift_framed_transport.erl
@@ -21,83 +21,105 @@
 
 -behaviour(thrift_transport).
 
-%% API
+%% constructor
 -export([new/1]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+
+
+-record(t_framed, {
+  wrapped,
+  read_buffer,
+  write_buffer
+}).
+
+-type state() :: #t_framed{}.
+
+
+-spec new(Transport::thrift_transport:t_transport()) ->
+  thrift_transport:t_transport().
+
+new(Wrapped) ->
+  State = #t_framed{
+    wrapped = Wrapped,
+    read_buffer = [],
+    write_buffer = []
+  },
+  thrift_transport:new(?MODULE, State).
 
-%% thrift_transport callbacks
--export([write/2, read/2, flush/1, close/1]).
 
--record(framed_transport, {wrapped, % a thrift_transport
-                           read_buffer, % iolist()
-                           write_buffer % iolist()
-                          }).
--type state() :: #framed_transport{}.
 -include("thrift_transport_behaviour.hrl").
 
-new(WrappedTransport) ->
-    State = #framed_transport{wrapped = WrappedTransport,
-                              read_buffer = [],
-                              write_buffer = []},
-    thrift_transport:new(?MODULE, State).
-
-%% Writes data into the buffer
-write(State = #framed_transport{write_buffer = WBuf}, Data) ->
-    {State#framed_transport{write_buffer = [WBuf, Data]}, ok}.
-
-%% Flushes the buffer through to the wrapped transport
-flush(State0 = #framed_transport{write_buffer = Buffer,
-                                   wrapped = Wrapped0}) ->
-    FrameLen = iolist_size(Buffer),
-    Data     = [<<FrameLen:32/integer-signed-big>>, Buffer],
-
-    {Wrapped1, Response} = thrift_transport:write(Wrapped0, Data),
-
-    {Wrapped2, _} = thrift_transport:flush(Wrapped1),
-
-    State1 = State0#framed_transport{wrapped = Wrapped2, write_buffer = []},
-    {State1, Response}.
-
-%% Closes the transport and the wrapped transport
-close(State = #framed_transport{wrapped = Wrapped0}) ->
-    {Wrapped1, Result} = thrift_transport:close(Wrapped0),
-    NewState = State#framed_transport{wrapped = Wrapped1},
-    {NewState, Result}.
-
-%% Reads data through from the wrapped transport
-read(State0 = #framed_transport{wrapped = Wrapped0, read_buffer = RBuf},
-     Len) when is_integer(Len) ->
-    {Wrapped1, {RBuf1, RBuf1Size}} =
-        %% if the read buffer is empty, read another frame
-        %% otherwise, just read from what's left in the buffer
-        case iolist_size(RBuf) of
-            0 ->
-                %% read the frame length
-                case thrift_transport:read(Wrapped0, 4) of
-                  {WrappedS1,
-                    {ok, <<FrameLen:32/integer-signed-big, _/binary>>}} ->
-                    %% then read the data
-                    case thrift_transport:read(WrappedS1, FrameLen) of
-                      {WrappedS2, {ok, Bin}} ->
-                        {WrappedS2, {Bin, erlang:byte_size(Bin)}};
-                      {WrappedS2, {error, Reason1}} ->
-                        {WrappedS2, {error, Reason1}}
-                    end;
-                  {WrappedS1, {error, Reason2}} ->
-                    {WrappedS1, {error, Reason2}}
-                end;
-            Sz ->
-                {Wrapped0, {RBuf, Sz}}
-        end,
-
-    %% pull off Give bytes, return them to the user, leave the rest in the buffer
-    case RBuf1 of
-      error ->
-        { State0#framed_transport {wrapped = Wrapped1, read_buffer = [] },
-          {RBuf1, RBuf1Size} };
-      _ ->
-        Give = min(RBuf1Size, Len),
-        <<Data:Give/binary, RBuf2/binary>> = iolist_to_binary(RBuf1),
-
-        { State0#framed_transport{wrapped = Wrapped1, read_buffer=RBuf2},
-          {ok, Data} }
-    end.
+
+read(State = #t_framed{wrapped = Wrapped, read_buffer = Buffer}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buffer),
+  case Binary of
+    <<>> when Len > 0 ->
+      case next_frame(Wrapped) of
+        {NewState, {ok, Frame}} ->
+          NewBinary = iolist_to_binary([Binary, Frame]),
+          Give = min(iolist_size(NewBinary), Len),
+          {Result, Remaining} = split_binary(NewBinary, Give),
+          {State#t_framed{wrapped = NewState, read_buffer = Remaining}, {ok, Result}};
+        Error -> Error
+      end;
+    %% read of zero bytes
+    <<>> -> {State, {ok, <<>>}};
+    %% read buffer is nonempty
+    _ ->
+      Give = min(iolist_size(Binary), Len),
+      {Result, Remaining} = split_binary(Binary, Give),
+      {State#t_framed{read_buffer = Remaining}, {ok, Result}}
+  end.
+
+
+read_exact(State = #t_framed{wrapped = Wrapped, read_buffer = Buffer}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buffer),
+  case iolist_size(Binary) of
+    %% read buffer is larger than requested read size
+    X when X >= Len ->
+      {Result, Remaining} = split_binary(Binary, Len),
+      {State#t_framed{read_buffer = Remaining}, {ok, Result}};
+    %% read buffer is insufficient for requested read size
+    _ ->
+      case next_frame(Wrapped) of
+        {NewState, {ok, Frame}} ->
+          read_exact(
+            State#t_framed{wrapped = NewState, read_buffer = [Buffer, Frame]},
+            Len
+          );
+        {NewState, Error} ->
+          {State#t_framed{wrapped = NewState}, Error}
+      end
+  end.
+
+next_frame(Transport) ->
+  case thrift_transport:read_exact(Transport, 4) of
+    {NewState, {ok, <<FrameLength:32/integer-signed-big>>}} ->
+      thrift_transport:read_exact(NewState, FrameLength);
+    Error -> Error
+  end.
+
+
+write(State = #t_framed{write_buffer = Buffer}, Data) ->
+  {State#t_framed{write_buffer = [Buffer, Data]}, ok}.
+
+
+flush(State = #t_framed{write_buffer = Buffer, wrapped = Wrapped}) ->
+  case iolist_size(Buffer) of
+    %% if write buffer is empty, do nothing
+    0 -> {State, ok};
+    FrameLen ->
+      Data = [<<FrameLen:32/integer-signed-big>>, Buffer],
+      {Written, Response} = thrift_transport:write(Wrapped, Data),
+      {Flushed, ok} = thrift_transport:flush(Written),
+      {State#t_framed{wrapped = Flushed, write_buffer = []}, Response}
+  end.
+
+
+close(State = #t_framed{wrapped = Wrapped}) ->
+  {Closed, Result} = thrift_transport:close(Wrapped),
+  {State#t_framed{wrapped = Closed}, Result}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_membuffer_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_membuffer_transport.erl b/lib/erl/src/thrift_membuffer_transport.erl
new file mode 100644
index 0000000..be9acb2
--- /dev/null
+++ b/lib/erl/src/thrift_membuffer_transport.erl
@@ -0,0 +1,83 @@
+%%
+%% 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(thrift_membuffer_transport).
+
+-behaviour(thrift_transport).
+
+%% constructors
+-export([new/0, new/1]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+
+
+-record(t_membuffer, {
+  buffer = []
+}).
+
+-type state() :: #t_membuffer{}.
+
+
+-spec new() -> thrift_transport:t_transport().
+
+new() -> new([]).
+
+-spec new(Buf::iodata()) -> thrift_transport:t_transport().
+
+new(Buf) when is_list(Buf) ->
+  State = #t_membuffer{buffer = Buf},
+  thrift_transport:new(?MODULE, State);
+new(Buf) when is_binary(Buf) ->
+  State = #t_membuffer{buffer = [Buf]},
+  thrift_transport:new(?MODULE, State).
+
+
+-include("thrift_transport_behaviour.hrl").
+
+
+read(State = #t_membuffer{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  Give = min(iolist_size(Binary), Len),
+  {Result, Remaining} = split_binary(Binary, Give),
+  {State#t_membuffer{buffer = Remaining}, {ok, Result}}.
+
+
+read_exact(State = #t_membuffer{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  case iolist_size(Binary) of
+    X when X >= Len ->
+      {Result, Remaining} = split_binary(Binary, Len),
+      {State#t_membuffer{buffer = Remaining}, {ok, Result}};
+    _ ->
+      {State, {error, eof}}
+  end.
+
+
+write(State = #t_membuffer{buffer = Buf}, Data)
+when is_list(Data); is_binary(Data) ->
+  {State#t_membuffer{buffer = [Buf, Data]}, ok}.
+
+
+flush(State) -> {State, ok}.
+
+
+close(State) -> {State, ok}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_memory_buffer.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_memory_buffer.erl b/lib/erl/src/thrift_memory_buffer.erl
index 53abbc4..6a59ea5 100644
--- a/lib/erl/src/thrift_memory_buffer.erl
+++ b/lib/erl/src/thrift_memory_buffer.erl
@@ -21,42 +21,27 @@
 
 -behaviour(thrift_transport).
 
-%% API
--export([new/0, new/1, new_transport_factory/0]).
+%% constructors
+-export([new/0, new/1]).
+%% protocol callbacks
+-export([read/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_transport_factory/0]).
 
-%% thrift_transport callbacks
--export([write/2, read/2, flush/1, close/1]).
 
--record(memory_buffer, {buffer}).
--type state() :: #memory_buffer{}.
--include("thrift_transport_behaviour.hrl").
+%% wrapper around thrift_membuffer_transport for legacy reasons
 
-new() ->
-    State = #memory_buffer{buffer = []},
-    thrift_transport:new(?MODULE, State).
+new() -> thrift_membuffer_transport:new().
 
-new (Buf) when is_list (Buf) ->
-  State = #memory_buffer{buffer = Buf},
-  thrift_transport:new(?MODULE, State);
-new (Buf) ->
-  State = #memory_buffer{buffer = [Buf]},
-  thrift_transport:new(?MODULE, State).
+new(State) -> thrift_membuffer_transport:new(State).
 
-new_transport_factory() ->
-    {ok, fun() -> new() end}.
+new_transport_factory() -> {ok, fun() -> new() end}.
 
-%% Writes data into the buffer
-write(State = #memory_buffer{buffer = Buf}, Data) ->
-    {State#memory_buffer{buffer = [Buf, Data]}, ok}.
+write(State, Data) -> thrift_membuffer_transport:write(State, Data).
 
-flush(State = #memory_buffer {buffer = Buf}) ->
-    {State#memory_buffer{buffer = []}, Buf}.
+read(State, Data) -> thrift_membuffer_transport:read(State, Data).
 
-close(State) ->
-    {State, ok}.
+flush(State) -> thrift_membuffer_transport:flush(State).
+
+close(State) -> thrift_membuffer_transport:close(State).
 
-read(State = #memory_buffer{buffer = Buf}, Len) when is_integer(Len) ->
-    Binary = iolist_to_binary(Buf),
-    Give = min(iolist_size(Binary), Len),
-    {Result, Remaining} = split_binary(Binary, Give),
-    {State#memory_buffer{buffer = Remaining}, {ok, Result}}.

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_socket_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_socket_transport.erl b/lib/erl/src/thrift_socket_transport.erl
index fec0241..fa10ed0 100644
--- a/lib/erl/src/thrift_socket_transport.erl
+++ b/lib/erl/src/thrift_socket_transport.erl
@@ -21,104 +21,156 @@
 
 -behaviour(thrift_transport).
 
--export([new/1,
-         new/2,
-         write/2, read/2, flush/1, close/1,
+%% constructors
+-export([new/1, new/2]).
+%% transport callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_transport_factory/3]).
 
-         new_transport_factory/3]).
 
--record(data, {socket,
-               recv_timeout=infinity}).
--type state() :: #data{}.
--include("thrift_transport_behaviour.hrl").
+-record(t_socket, {
+  socket,
+  recv_timeout=60000,
+  buffer = []
+}).
 
-new(Socket) ->
-    new(Socket, []).
+-type state() :: #t_socket{}.
 
-new(Socket, Opts) when is_list(Opts) ->
-    State =
-        case lists:keysearch(recv_timeout, 1, Opts) of
-            {value, {recv_timeout, Timeout}}
-            when is_integer(Timeout), Timeout > 0 ->
-                #data{socket=Socket, recv_timeout=Timeout};
-            _ ->
-                #data{socket=Socket}
-        end,
-    thrift_transport:new(?MODULE, State).
 
-%% Data :: iolist()
-write(This = #data{socket = Socket}, Data) ->
-    {This, gen_tcp:send(Socket, Data)}.
+-spec new(Socket::any()) ->
+  thrift_transport:t_transport().
 
-read(This = #data{socket=Socket, recv_timeout=Timeout}, Len)
-  when is_integer(Len), Len >= 0 ->
-    case gen_tcp:recv(Socket, Len, Timeout) of
-        Err = {error, timeout} ->
-            gen_tcp:close(Socket),
-            {This, Err};
-        Data ->
-            {This, Data}
-    end.
+new(Socket) -> new(Socket, []).
 
-%% We can't really flush - everything is flushed when we write
-flush(This) ->
-    {This, ok}.
+-spec new(Socket::any(), Opts::list()) ->
+  thrift_transport:t_transport().
+
+new(Socket, Opts) when is_list(Opts) ->
+  State = parse_opts(Opts, #t_socket{socket = Socket}),
+  thrift_transport:new(?MODULE, State).
 
-close(This = #data{socket = Socket}) ->
-    {This, gen_tcp:close(Socket)}.
 
+parse_opts([{recv_timeout, Timeout}|Rest], State)
+when is_integer(Timeout), Timeout > 0 ->
+  parse_opts(Rest, State#t_socket{recv_timeout = Timeout});
+parse_opts([{recv_timeout, infinity}|Rest], State) ->
+  parse_opts(Rest, State#t_socket{recv_timeout = infinity});
+parse_opts([], State) ->
+  State.
 
-%%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+-include("thrift_transport_behaviour.hrl").
+
+
+read(State = #t_socket{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  case iolist_size(Binary) of
+    X when X >= Len ->
+      {Result, Remaining} = split_binary(Binary, Len),
+      {State#t_socket{buffer = Remaining}, {ok, Result}};
+    _ -> recv(State, Len)
+  end.
+
+recv(State = #t_socket{socket = Socket, buffer = Buf}, Len) ->
+  case gen_tcp:recv(Socket, 0, State#t_socket.recv_timeout) of
+    {error, Error} ->
+      gen_tcp:close(Socket),
+      {State, {error, Error}};
+    {ok, Data} ->
+      Binary = iolist_to_binary([Buf, Data]),
+      Give = min(iolist_size(Binary), Len),
+      {Result, Remaining} = split_binary(Binary, Give),
+      {State#t_socket{buffer = Remaining}, {ok, Result}}
+  end.
+
+
+read_exact(State = #t_socket{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  case iolist_size(Binary) of
+    X when X >= Len -> read(State, Len);
+    X ->
+      case gen_tcp:recv(State#t_socket.socket, Len - X, State#t_socket.recv_timeout) of
+        {error, Error} ->
+          gen_tcp:close(State#t_socket.socket),
+          {State, {error, Error}};
+        {ok, Data} ->
+          {State#t_socket{buffer = []}, {ok, <<Binary/binary, Data/binary>>}}
+      end
+  end.
+
+
+write(State = #t_socket{socket = Socket}, Data) ->
+  case gen_tcp:send(Socket, Data) of
+    {error, Error} ->
+      gen_tcp:close(Socket),
+      {State, {error, Error}};
+    ok -> {State, ok}
+  end.
+
+
+flush(State) ->
+  {State#t_socket{buffer = []}, ok}.
+
+
+close(State = #t_socket{socket = Socket}) ->
+  {State, gen_tcp:close(Socket)}.
+
+
+%% legacy api. left for compatibility
 
 %% The following "local" record is filled in by parse_factory_options/2
 %% below. These options can be passed to new_protocol_factory/3 in a
 %% proplists-style option list. They're parsed like this so it is an O(n)
 %% operation instead of O(n^2)
--record(factory_opts, {connect_timeout = infinity,
-                       sockopts = [],
-                       framed = false}).
-
-parse_factory_options([], Opts) ->
-    Opts;
-parse_factory_options([{framed, Bool} | Rest], Opts) when is_boolean(Bool) ->
-    parse_factory_options(Rest, Opts#factory_opts{framed=Bool});
-parse_factory_options([{sockopts, OptList} | Rest], Opts) when is_list(OptList) ->
-    parse_factory_options(Rest, Opts#factory_opts{sockopts=OptList});
-parse_factory_options([{connect_timeout, TO} | Rest], Opts) when TO =:= infinity; is_integer(TO) ->
-    parse_factory_options(Rest, Opts#factory_opts{connect_timeout=TO});
-parse_factory_options([{recv_timeout, TO} | Rest], Opts) when TO =:= infinity; is_integer(TO) ->
-    parse_factory_options(Rest, Opts).
+-record(factory_opts, {
+  connect_timeout = infinity,
+  sockopts = [],
+  framed = false
+}).
+
+parse_factory_options([], FactoryOpts, TransOpts) -> {FactoryOpts, TransOpts};
+parse_factory_options([{framed, Bool}|Rest], FactoryOpts, TransOpts)
+when is_boolean(Bool) ->
+  parse_factory_options(Rest, FactoryOpts#factory_opts{framed = Bool}, TransOpts);
+parse_factory_options([{sockopts, OptList}|Rest], FactoryOpts, TransOpts)
+when is_list(OptList) ->
+  parse_factory_options(Rest, FactoryOpts#factory_opts{sockopts = OptList}, TransOpts);
+parse_factory_options([{connect_timeout, TO}|Rest], FactoryOpts, TransOpts)
+when TO =:= infinity; is_integer(TO) ->
+  parse_factory_options(Rest, FactoryOpts#factory_opts{connect_timeout = TO}, TransOpts);
+parse_factory_options([{recv_timeout, TO}|Rest], FactoryOpts, TransOpts)
+when TO =:= infinity; is_integer(TO) ->
+  parse_factory_options(Rest, FactoryOpts, [{recv_timeout, TO}] ++ TransOpts).
 
 
-%%
 %% Generates a "transport factory" function - a fun which returns a thrift_transport()
 %% instance.
-%% This can be passed into a protocol factory to generate a connection to a
+%% State can be passed into a protocol factory to generate a connection to a
 %% thrift server over a socket.
-%%
 new_transport_factory(Host, Port, Options) ->
-    ParsedOpts = parse_factory_options(Options, #factory_opts{}),
-
-    F = fun() ->
-                SockOpts = [binary,
-                            {packet, 0},
-                            {active, false},
-                            {nodelay, true} |
-                            ParsedOpts#factory_opts.sockopts],
-                case catch gen_tcp:connect(Host, Port, SockOpts,
-                                           ParsedOpts#factory_opts.connect_timeout) of
-                    {ok, Sock} ->
-                        {ok, Transport} =
-                          thrift_socket_transport:new(Sock, Options),
-                        {ok, BufTransport} =
-                            case ParsedOpts#factory_opts.framed of
-                                true  -> thrift_framed_transport:new(Transport);
-                                false -> thrift_buffered_transport:new(Transport)
-                            end,
-                        {ok, BufTransport};
-                    Error  ->
-                        Error
-                end
+  {FactoryOpts, TransOpts} = parse_factory_options(Options, #factory_opts{}, []),
+  {ok, fun() -> SockOpts = [binary,
+      {packet, 0},
+      {active, false},
+      {nodelay, true}|FactoryOpts#factory_opts.sockopts
+    ],
+    case catch gen_tcp:connect(
+      Host,
+      Port,
+      SockOpts,
+      FactoryOpts#factory_opts.connect_timeout
+    ) of
+      {ok, Sock} ->
+        {ok, Transport} = thrift_socket_transport:new(Sock, TransOpts),
+        {ok, BufTransport} = case FactoryOpts#factory_opts.framed of
+          true  -> thrift_framed_transport:new(Transport);
+          false -> thrift_buffered_transport:new(Transport)
         end,
-    {ok, F}.
+        {ok, BufTransport};
+      Error  -> Error
+    end
+  end}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/src/thrift_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_transport.erl b/lib/erl/src/thrift_transport.erl
index 39f8c05..0fdf970 100644
--- a/lib/erl/src/thrift_transport.erl
+++ b/lib/erl/src/thrift_transport.erl
@@ -20,59 +20,102 @@
 -module(thrift_transport).
 
 -export([behaviour_info/1]).
+%% constructors
+-export([new/1, new/2]).
+%% transport callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+
+-export_type([t_transport/0]).
 
--export([new/2,
-         write/2,
-         read/2,
-         flush/1,
-         close/1
-        ]).
 
 behaviour_info(callbacks) ->
-    [{read, 2},
-     {write, 2},
-     {flush, 1},
-     {close, 1}
-    ].
+  [{read, 2}, {write, 2}, {flush, 1}, {close, 1}].
+
+
+-record(t_transport, {
+  module,
+  state
+}).
+
+-type state() :: #t_transport{}.
+-type t_transport() :: #t_transport{}.
 
--record(transport, {module, data}).
 
 -ifdef(transport_wrapper_module).
 -define(debug_wrap(Transport),
-        case Transport#transport.module of
-            ?transport_wrapper_module ->
-                Transport;
-            _Else ->
-                {ok, Result} = ?transport_wrapper_module:new(Transport),
-                Result
-        end).
+  case Transport#t_transport.module of
+    ?transport_wrapper_module -> Transport;
+    _Else ->
+      {ok, Result} = ?transport_wrapper_module:new(Transport),
+      Result
+  end
+).
 -else.
 -define(debug_wrap(Transport), Transport).
 -endif.
 
-new(Module, Data) when is_atom(Module) ->
-    Transport0 = #transport{module = Module, data = Data},
-    Transport1 = ?debug_wrap(Transport0),
-    {ok, Transport1}.
-
--spec write(#transport{}, iolist() | binary()) -> {#transport{}, ok | {error, _Reason}}.
-write(Transport, Data) ->
-    Module = Transport#transport.module,
-    {NewTransData, Result} = Module:write(Transport#transport.data, Data),
-    {Transport#transport{data = NewTransData}, Result}.
-
--spec read(#transport{}, non_neg_integer()) -> {#transport{}, {ok, binary()} | {error, _Reason}}.
-read(Transport, Len) when is_integer(Len) ->
-    Module = Transport#transport.module,
-    {NewTransData, Result} = Module:read(Transport#transport.data, Len),
-    {Transport#transport{data = NewTransData}, Result}.
-
--spec flush(#transport{}) -> {#transport{}, ok | {error, _Reason}}.
-flush(Transport = #transport{module = Module, data = Data}) ->
-    {NewTransData, Result} = Module:flush(Data),
-    {Transport#transport{data = NewTransData}, Result}.
-
--spec close(#transport{}) -> {#transport{}, ok | {error, _Reason}}.
-close(Transport = #transport{module = Module, data = Data}) ->
-    {NewTransData, Result} = Module:close(Data),
-    {Transport#transport{data = NewTransData}, Result}.
+
+-type wrappable() ::
+  binary() |
+  list() |
+  {membuffer, binary() | list()} |
+  {tcp, port()} |
+  {tcp, port(), list()} |
+  {file, file:io_device()} |
+  {file, file:io_device(), list()} |
+  {file, file:filename()} |
+  {file, file:filename(), list()}.
+
+-spec new(wrappable()) -> {ok, #t_transport{}}.
+
+new({membuffer, Membuffer}) when is_binary(Membuffer); is_list(Membuffer) ->
+  thrift_membuffer_transport:new(Membuffer);
+new({membuffer, Membuffer, []}) when is_binary(Membuffer); is_list(Membuffer) ->
+  thrift_membuffer_transport:new(Membuffer);
+new({tcp, Socket}) when is_port(Socket) ->
+  new({tcp, Socket, []});
+new({tcp, Socket, Opts}) when is_port(Socket) ->
+  thrift_socket_transport:new(Socket, Opts);
+new({file, Filename}) when is_list(Filename); is_binary(Filename) ->
+  new({file, Filename, []});
+new({file, Filename, Opts}) when is_list(Filename); is_binary(Filename) ->
+  {ok, File} = file:open(Filename, [raw, binary]),
+  new({file, File, Opts});
+new({file, File, Opts}) ->
+  thrift_file_transport:new(File, Opts).
+
+-spec new(Module::module(), State::any()) -> {ok, #t_transport{}}.
+
+new(Module, State) when is_atom(Module) ->
+  {ok, ?debug_wrap(#t_transport{module = Module, state = State})}.
+
+
+-include("thrift_transport_behaviour.hrl").
+
+
+read(Transport = #t_transport{module = Module}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Result} = Module:read(Transport#t_transport.state, Len),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+read_exact(Transport = #t_transport{module = Module}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Result} = Module:read_exact(Transport#t_transport.state, Len),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+write(Transport = #t_transport{module = Module}, Data) ->
+  {NewState, Result} = Module:write(Transport#t_transport.state, Data),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+flush(Transport = #t_transport{module = Module}) ->
+  {NewState, Result} = Module:flush(Transport#t_transport.state),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+close(Transport = #t_transport{module = Module}) ->
+  {NewState, Result} = Module:close(Transport#t_transport.state),
+  {Transport#t_transport{state = NewState}, Result}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/test/test_membuffer.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/test_membuffer.erl b/lib/erl/test/test_membuffer.erl
deleted file mode 100644
index 671ae11..0000000
--- a/lib/erl/test/test_membuffer.erl
+++ /dev/null
@@ -1,115 +0,0 @@
-%%
-%% 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("gen-erl/thrift_test_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, thrift_test_types:struct_info('Xtruct'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thrift_test_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, thrift_test_types:struct_info('Xtruct'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thrift_test_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, thrift_test_types:struct_info('Bools'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thrift_test_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, thrift_test_types:struct_info('Insanity'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thrift_test_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, thrift_test_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, thrift_test_types:struct_info('Xtruct'))},
-    'Xtruct'),
-
-  Result = TestData.
-
--endif.

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/test/test_thrift_buffered_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/test_thrift_buffered_transport.erl b/lib/erl/test/test_thrift_buffered_transport.erl
new file mode 100644
index 0000000..8519e82
--- /dev/null
+++ b/lib/erl/test/test_thrift_buffered_transport.erl
@@ -0,0 +1,359 @@
+%%
+%% 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_thrift_buffered_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(Transport) -> thrift_buffered_transport:new(Transport).
+
+new_test_() ->
+  [
+    {"new buffered membuffer", ?_assertMatch(
+      {ok, {t_transport, thrift_buffered_transport, {t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, []}},
+        []
+      }}},
+      new({t_transport, thrift_membuffer_transport, {t_membuffer, []}})
+    )}
+  ].
+
+
+read(Frame, Bytes) -> thrift_buffered_transport:read(Frame, Bytes).
+
+read_test_() ->
+  [
+    {"read zero bytes from an empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from an empty buffered membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read zero bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read a zillion bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        {ok, <<"hallo world">>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+read_exact(Frame, Bytes) -> thrift_buffered_transport:read_exact(Frame, Bytes).
+
+read_exact_test_() ->
+  [
+    {"read exactly zero bytes from an empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from an empty buffered membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly zero bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly a zillion bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        {error, eof}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+write(Framed, Data) -> thrift_buffered_transport:write(Framed, Data).
+
+write_test_() ->
+  [
+    {"write empty list to empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [[], []]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        []
+      )
+    )},
+    {"write empty list to nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [["hallo world"], []]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          ["hallo world"]
+        },
+        []
+      )
+    )},
+    {"write empty binary to empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [[], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        <<>>
+      )
+    )},
+    {"write empty binary to nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [["hallo world"], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          ["hallo world"]
+        },
+        <<>>
+      )
+    )}
+  ].
+
+
+flush(Transport) -> thrift_buffered_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush empty buffered membuffer", ?_assertMatch(
+      {{t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        ok
+      },
+      flush({t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        []
+      })
+    )},
+    {"flush nonempty buffered membuffer", ?_assertMatch(
+      {{t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            [<<>>, <<"hallo world">>]
+          }},
+          []
+        },
+        ok
+      },
+      flush({t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        <<"hallo world">>
+      })
+    )}
+  ].
+
+
+close(Transport) -> thrift_buffered_transport:close(Transport).
+
+close_test_() ->
+  {"close buffered membuffer", ?_assertMatch(
+    {{t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        []
+      },
+      ok
+    },
+    close({t_buffered,
+      {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+      []
+    })
+  )}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/test/test_thrift_file_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/test_thrift_file_transport.erl b/lib/erl/test/test_thrift_file_transport.erl
new file mode 100644
index 0000000..3e5c1d1
--- /dev/null
+++ b/lib/erl/test/test_thrift_file_transport.erl
@@ -0,0 +1,213 @@
+%%
+%% 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_thrift_file_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(File) -> thrift_file_transport:new(File).
+new(File, Opts) -> thrift_file_transport:new(File, Opts).
+
+new_test_() ->
+  [
+    {"new file", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, write}}},
+      new(a_fake_file)
+    )},
+    {"new file in read mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, read}}},
+      new(a_fake_file, [{mode, read}])
+    )},
+    {"new file in write mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, write}}},
+      new(a_fake_file, [{mode, write}])
+    )},
+    {"new file in should_close true mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, write}}},
+      new(a_fake_file, [{should_close, true}])
+    )},
+    {"new file in should_close false mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, false, write}}},
+      new(a_fake_file, [{should_close, false}])
+    )}
+  ].
+
+
+read(File, Bytes) -> thrift_file_transport:read(File, Bytes).
+
+read_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, read, fun(Bin, N) ->
+        {Result, _} = split_binary(Bin, min(iolist_size(Bin), N)),
+        {ok, Result}
+      end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"read zero bytes from empty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_file, <<>>, true, read}, 0)
+      )},
+      {"read 1 byte from empty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_file, <<>>, true, read}, 1)
+      )},
+      {"read zero bytes from nonempty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_file, <<"hallo world">>, true, read}, 0)
+      )},
+      {"read 1 byte from nonempty file", ?_assertMatch(
+        {_, {ok, <<"h">>}},
+        read({t_file, <<"hallo world">>, true, read}, 1)
+      )},
+      {"read a zillion bytes from nonempty file", ?_assertMatch(
+        {_, {ok, <<"hallo world">>}},
+        read({t_file, <<"hallo world">>, true, read}, 65536)
+      )},
+      {"read 0 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read({t_file, <<>>, true, write}, 0)
+      )},
+      {"read 1 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read({t_file, <<>>, true, write}, 1)
+      )}
+    ]
+  }.
+
+
+read_exact(File, Bytes) -> thrift_file_transport:read_exact(File, Bytes).
+
+read_exact_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, read, fun(Bin, N) ->
+        {Result, _} = split_binary(Bin, min(iolist_size(Bin), N)),
+        {ok, Result}
+      end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"read exactly zero bytes from empty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read_exact({t_file, <<>>, true, read}, 0)
+      )},
+      {"read exactly 1 byte from empty file", ?_assertMatch(
+        {_, {error, eof}},
+        read_exact({t_file, <<>>, true, read}, 1)
+      )},
+      {"read exactly zero bytes from nonempty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read_exact({t_file, <<"hallo world">>, true, read}, 0)
+      )},
+      {"read exactly 1 byte from nonempty file", ?_assertMatch(
+        {_, {ok, <<"h">>}},
+        read_exact({t_file, <<"hallo world">>, true, read}, 1)
+      )},
+      {"read exactly a zillion bytes from nonempty file", ?_assertMatch(
+        {_, {error, eof}},
+        read_exact({t_file, <<"hallo world">>, true, read}, 65536)
+      )},
+      {"read exactly 0 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read_exact({t_file, <<>>, true, write}, 0)
+      )},
+      {"read exactly 1 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read_exact({t_file, <<>>, true, write}, 1)
+      )}
+    ]
+  }.
+
+
+write(File, Data) -> thrift_file_transport:write(File, Data).
+
+write_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, write, fun(_, _) -> ok end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"write empty list to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, [])
+      )},
+      {"write empty binary to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, <<>>)
+      )},
+      {"write a list to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, "hallo world")
+      )},
+      {"write a binary to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, <<"hallo world">>)
+      )},
+      {"write a binary to file in read mode", ?_assertMatch(
+        {_, {error, read_mode}},
+        write({t_file, a_fake_file, true, read}, <<"hallo world">>)
+      )},
+      {"write a list to file in read mode", ?_assertMatch(
+        {_, {error, read_mode}},
+        write({t_file, a_fake_file, true, read}, "hallo world")
+      )}
+    ]
+  }.
+
+
+flush(Transport) -> thrift_file_transport:flush(Transport).
+
+flush_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, sync, fun(_File) -> ok end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"flush file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        flush({t_file, a_fake_file, true, write})
+      )}
+    ]
+  }.
+
+
+close(Transport) -> thrift_file_transport:close(Transport).
+
+close_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, close, fun(_) -> ok end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"close file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        close({t_file, a_fake_file, true, write})
+      )}
+    ]
+  }.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/test/test_thrift_framed_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/test_thrift_framed_transport.erl b/lib/erl/test/test_thrift_framed_transport.erl
new file mode 100644
index 0000000..8a538a5
--- /dev/null
+++ b/lib/erl/test/test_thrift_framed_transport.erl
@@ -0,0 +1,404 @@
+%%
+%% 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_thrift_framed_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(Transport) -> thrift_framed_transport:new(Transport).
+
+new_test_() ->
+  [
+    {"new framed membuffer", ?_assertMatch(
+      {ok, {t_transport, thrift_framed_transport, {t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, []}},
+        [],
+        []
+      }}},
+      new({t_transport, thrift_membuffer_transport, {t_membuffer, []}})
+    )}
+  ].
+
+
+read(Frame, Bytes) -> thrift_framed_transport:read(Frame, Bytes).
+
+read_test_() ->
+  [
+    {"read zero bytes from an empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from an empty framed membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read zero bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"hallo world">>,
+          []
+        },
+        1
+      )
+    )},
+    {"read a zillion bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<>>,
+          []
+        },
+        {ok, <<"hallo world">>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+read_exact(Frame, Bytes) -> thrift_framed_transport:read_exact(Frame, Bytes).
+
+read_exact_test_() ->
+  [
+    {"read exactly zero bytes from an empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<>>,
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from an empty framed membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly zero bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          <<>>,
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"hallo world">>,
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly a zillion bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [[],<<"hallo world">>],
+          []
+        },
+        {error, eof}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+write(Framed, Data) -> thrift_framed_transport:write(Framed, Data).
+
+write_test_() ->
+  [
+    {"write empty list to empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [[], []]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        []
+      )
+    )},
+    {"write empty list to nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [["hallo world"], []]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          ["hallo world"]
+        },
+        []
+      )
+    )},
+    {"write empty binary to empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [[], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        <<>>
+      )
+    )},
+    {"write empty binary to nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [["hallo world"], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          ["hallo world"]
+        },
+        <<>>
+      )
+    )}
+  ].
+
+
+flush(Transport) -> thrift_framed_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush empty framed membuffer", ?_assertMatch(
+      {{t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        ok
+      },
+      flush({t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        [],
+        []
+      })
+    )},
+    {"flush nonempty framed membuffer", ?_assertMatch(
+      {{t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            [<<>>, [<<0, 0, 0, 11>>, <<"hallo world">>]]
+          }},
+          [],
+          []
+        },
+        ok
+      },
+      flush({t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        [],
+        <<"hallo world">>
+      })
+    )}
+  ].
+
+
+close(Transport) -> thrift_framed_transport:close(Transport).
+
+close_test_() ->
+  {"close framed membuffer", ?_assertMatch(
+    {{t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        [],
+        []
+      },
+      ok
+    },
+    close({t_framed,
+      {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+      [],
+      []
+    })
+  )}.
+

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/test/test_thrift_membuffer_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/test_thrift_membuffer_transport.erl b/lib/erl/test/test_thrift_membuffer_transport.erl
new file mode 100644
index 0000000..9689c79
--- /dev/null
+++ b/lib/erl/test/test_thrift_membuffer_transport.erl
@@ -0,0 +1,167 @@
+%%
+%% 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_thrift_membuffer_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new() -> thrift_membuffer_transport:new().
+new(Data) -> thrift_membuffer_transport:new(Data).
+
+new_test_() ->
+  [
+    {"new empty membuffer", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, []}}},
+      new()
+    )},
+    {"new membuffer with <<>>", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, [<<>>]}}},
+      new(<<>>)
+    )},
+    {"new membuffer with []", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, []}}},
+      new([])
+    )},
+    {"new membuffer with <<\"hallo world\">>", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, [<<"hallo world">>]}}},
+      new(<<"hallo world">>)
+    )},
+    {"new membuffer with \"hallo world\"", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, "hallo world"}}},
+      new("hallo world")
+    )}
+  ].
+
+
+read(Membuffer, Bytes) -> thrift_membuffer_transport:read(Membuffer, Bytes).
+
+read_test_() ->
+  [
+    {"read zero bytes from an empty membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read({t_membuffer, []}, 0)
+    )},
+    {"read 1 byte from an empty membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read({t_membuffer, []}, 1)
+    )},
+    {"read zero bytes from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"hallo world">>}, {ok, <<>>}},
+      read({t_membuffer, [["hallo", " "], "world"]}, 0)
+    )},
+    {"read 1 byte from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"allo world">>}, {ok, <<"h">>}},
+      read({t_membuffer, [["hallo", " "], "world"]}, 1)
+    )},
+    {"read a zillion bytes from nonempty buffer", ?_assertMatch(
+      {{t_membuffer, <<>>}, {ok, <<"hallo world">>}},
+      read({t_membuffer, [["hallo", " "], "world"]}, 65536)
+    )}
+  ].
+
+
+read_exact(Membuffer, Bytes) ->
+  thrift_membuffer_transport:read_exact(Membuffer, Bytes).
+
+read_exact_test_() ->
+  [
+    {"read exactly zero bytes from an empty membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read_exact({t_membuffer, []}, 0)
+    )},
+    {"read exactly 1 byte from an empty membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read_exact({t_membuffer, []}, 1)
+    )},
+    {"read exactly zero bytes from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"hallo world">>}, {ok, <<>>}},
+      read_exact({t_membuffer, [["hallo", " "], "world"]}, 0)
+    )},
+    {"read exactly 1 byte from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"allo world">>}, {ok, <<"h">>}},
+      read_exact({t_membuffer, [["hallo", " "], "world"]}, 1)
+    )},
+    {"read exactly a zillion bytes from nonempty buffer", ?_assertMatch(
+      {{t_membuffer, [["hallo", " "], "world"]}, {error, eof}},
+      read_exact({t_membuffer, [["hallo", " "], "world"]}, 65536)
+    )}
+  ].
+
+
+write(Membuffer, Data) -> thrift_membuffer_transport:write(Membuffer, Data).
+
+write_test_() ->
+  [
+    {"write empty list to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], []]}, ok},
+      write({t_membuffer, []}, [])
+    )},
+    {"write empty list to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, ["hallo world", []]}, ok},
+      write({t_membuffer, "hallo world"}, [])
+    )},
+    {"write empty binary to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], <<>>]}, ok},
+      write({t_membuffer, []}, <<>>)
+    )},
+    {"write empty binary to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, ["hallo world", <<>>]}, ok},
+      write({t_membuffer, "hallo world"}, <<>>)
+    )},
+    {"write a list to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], "hallo world"]}, ok},
+      write({t_membuffer, []}, "hallo world")
+    )},
+    {"write a list to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, [["hallo", " "], "world"]}, ok},
+      write({t_membuffer, ["hallo", " "]}, "world")
+    )},
+    {"write a binary to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], <<"hallo world">>]}, ok},
+      write({t_membuffer, []}, <<"hallo world">>)
+    )},
+    {"write a binary to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, [["hallo", " "], <<"world">>]}, ok},
+      write({t_membuffer, ["hallo", " "]}, <<"world">>)
+    )}
+  ].
+
+
+flush(Transport) -> thrift_membuffer_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush empty membuffer", ?_assertMatch(
+      {{t_membuffer, []}, ok},
+      flush({t_membuffer, []})
+    )},
+    {"flush nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, [<<"hallo world">>]}, ok},
+      flush({t_membuffer, [<<"hallo world">>]})
+    )}
+  ].
+
+
+close(Transport) -> thrift_membuffer_transport:close(Transport).
+
+close_test_() ->
+  {"close membuffer", ?_assertMatch(
+    {{t_membuffer, _}, ok},
+    close({t_membuffer, []})
+  )}.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/a559f8d9/lib/erl/test/test_thrift_socket_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/test_thrift_socket_transport.erl b/lib/erl/test/test_thrift_socket_transport.erl
new file mode 100644
index 0000000..5bc0f24
--- /dev/null
+++ b/lib/erl/test/test_thrift_socket_transport.erl
@@ -0,0 +1,199 @@
+%%
+%% 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_thrift_socket_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(Socket) -> thrift_socket_transport:new(Socket).
+new(Socket, Opts) -> thrift_socket_transport:new(Socket, Opts).
+
+new_test_() ->
+  [
+    {"new socket", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, 60000, []}}},
+      new(a_fake_socket)
+    )},
+    {"new socket with no options", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, 60000, []}}},
+      new(a_fake_socket, [])
+    )},
+    {"new socket with integer timeout", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, 5000, []}}},
+      new(a_fake_socket, [{recv_timeout, 5000}])
+    )},
+    {"new socket with infinity timeout", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, infinity, []}}},
+      new(a_fake_socket, [{recv_timeout, infinity}])
+    )}
+  ].
+
+
+read(Socket, Bytes) -> thrift_socket_transport:read(Socket, Bytes).
+
+read_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, recv, fun(Bin, 0, _) -> {ok, Bin} end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"read zero bytes from empty socket", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_socket, <<>>, 60000, []}, 0)
+      )},
+      {"read 1 byte from empty socket", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_socket, <<>>, 60000, []}, 1)
+      )},
+      {"read zero bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, _}, {ok, <<>>}},
+        read({t_socket, <<"hallo world">>, 60000, []}, 0)
+      )},
+      {"read 1 byte from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, <<"allo world">>}, {ok, <<"h">>}},
+        read({t_socket, <<"hallo world">>, 60000, []}, 1)
+      )},
+      {"read a zillion bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, <<>>}, {ok, <<"hallo world">>}},
+        read({t_socket, <<"hallo world">>, 60000, []}, 65536)
+      )},
+      {"read 1 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"allo">>}, {ok, <<"h">>}},
+        read({t_socket, <<" world">>, 60000, <<"hallo">>}, 1)
+      )},
+      {"read 6 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"world">>}, {ok, <<"hallo ">>}},
+        read({t_socket, <<" world">>, 60000, <<"hallo">>}, 6)
+      )},
+      {"read a zillion bytes from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<>>}, {ok, <<"hallo world">>}},
+        read({t_socket, <<" world">>, 60000, <<"hallo">>}, 65536)
+      )}
+    ]
+  }.
+
+
+read_exact(Socket, Bytes) -> thrift_socket_transport:read_exact(Socket, Bytes).
+
+read_exact_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, recv, fun(Bin, N, _) ->
+        case N of
+          0 -> {ok, Bin};
+          1 -> {ok, <<"h">>};
+          N when N > 2 -> {error, timeout}
+        end
+      end),
+      meck:expect(gen_tcp, close, fun(_) -> ok end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"read_exact zero bytes from empty socket", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read_exact({t_socket, <<>>, 60000, []}, 0)
+      )},
+      {"read_exact zero bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, _}, {ok, <<>>}},
+        read_exact({t_socket, <<"hallo world">>, 60000, []}, 0)
+      )},
+      {"read_exact 1 byte from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, []}, {ok, <<"h">>}},
+        read_exact({t_socket, <<"hallo world">>, 60000, []}, 1)
+      )},
+      {"read_exact a zillion bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, []}, {error, timeout}},
+        read_exact({t_socket, <<"hallo world">>, 60000, []}, 65536)
+      )},
+      {"read_exact 1 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"allo">>}, {ok, <<"h">>}},
+        read_exact({t_socket, <<" world">>, 60000, <<"hallo">>}, 1)
+      )},
+      {"read_exact 6 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, []}, {ok, <<"more h">>}},
+        read_exact({t_socket, <<"hallo">>, 60000, <<"more ">>}, 6)
+      )},
+      {"read_exact a zillion bytes from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"hallo">>}, {error, timeout}},
+        read_exact({t_socket, <<" world">>, 60000, <<"hallo">>}, 65536)
+      )}
+    ]
+  }.
+
+
+write(Socket, Data) -> thrift_socket_transport:write(Socket, Data).
+
+write_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, send, fun(_, _) -> ok end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"write empty list to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, [])
+      )},
+      {"write empty binary to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, <<>>)
+      )},
+      {"write a list to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, "hallo world")
+      )},
+      {"write a binary to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, <<"hallo world">>)
+      )}
+    ]
+  }.
+
+
+flush(Transport) -> thrift_socket_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush socket", ?_assertMatch(
+      {{t_socket, a_fake_socket, 60000, []}, ok},
+      flush({t_socket, a_fake_socket, 60000, []})
+    )}
+  ].
+
+
+close(Transport) -> thrift_socket_transport:close(Transport).
+
+close_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, close, fun(_) -> ok end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"close membuffer", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        close({t_socket, a_fake_socket, 60000, []})
+      )}
+    ]
+  }.
\ No newline at end of file


[6/6] thrift git commit: THRIFT-2113 Erlang SSL Socket Support Client: Erlang Patch: Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-2113 Erlang SSL Socket Support
Client: Erlang
Patch: Nobuaki Sukegawa

Enable SSL cross test


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/f58bca7a
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/f58bca7a
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/f58bca7a

Branch: refs/heads/master
Commit: f58bca7adb780f40afe26e32629515d64f581773
Parents: a7d6a97
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Sat Oct 31 12:17:51 2015 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Nov 1 18:30:46 2015 +0900

----------------------------------------------------------------------
 test/known_failures_Linux.json | 4 ++++
 test/tests.json                | 3 ++-
 2 files changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/f58bca7a/test/known_failures_Linux.json
----------------------------------------------------------------------
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index 801b1dc..12bf7e6 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -28,6 +28,8 @@
   "csharp-cpp_compact_framed-ip-ssl",
   "csharp-cpp_json_buffered-ip-ssl",
   "csharp-cpp_json_framed-ip-ssl",
+  "csharp-erl_binary_buffered-ip-ssl",
+  "csharp-erl_binary_framed-ip-ssl",
   "csharp-go_binary_buffered-ip-ssl",
   "csharp-go_binary_framed-ip-ssl",
   "csharp-go_compact_buffered-ip-ssl",
@@ -44,6 +46,8 @@
   "csharp-nodejs_json_buffered-ip-ssl",
   "csharp-nodejs_json_framed-ip",
   "csharp-nodejs_json_framed-ip-ssl",
+  "erl-go_binary_buffered-ip-ssl",
+  "erl-go_binary_framed-ip-ssl",
   "erl-nodejs_binary_buffered-ip",
   "erl-rb_binary-accel_buffered-ip",
   "erl-rb_binary-accel_framed-ip",

http://git-wip-us.apache.org/repos/asf/thrift/blob/f58bca7a/test/tests.json
----------------------------------------------------------------------
diff --git a/test/tests.json b/test/tests.json
index 3d8ddbe..981f764 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -384,7 +384,8 @@
       "framed"
     ],
     "sockets": [
-      "ip"
+      "ip",
+      "ip-ssl"
     ],
     "protocols": [
       "binary"


[5/6] thrift git commit: THRIFT-2113 Erlang SSL Socket Support Client: Erlang Patch: David Robakowski

Posted by ns...@apache.org.
THRIFT-2113 Erlang SSL Socket Support
Client: Erlang
Patch: David Robakowski


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/a7d6a970
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/a7d6a970
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/a7d6a970

Branch: refs/heads/master
Commit: a7d6a970339ff11ed60dbb8b73e59b1ed6482acb
Parents: 7ab56e8
Author: David Robakowski <da...@synlay.com>
Authored: Wed Aug 7 05:51:00 2013 +0200
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Nov 1 18:30:46 2015 +0900

----------------------------------------------------------------------
 lib/erl/src/thrift_client_util.erl         |  13 ++-
 lib/erl/src/thrift_socket_server.erl       |  35 ++++--
 lib/erl/src/thrift_sslsocket_transport.erl | 147 ++++++++++++++++++++++++
 test/erl/src/test_client.erl               |   8 ++
 test/erl/src/test_thrift_server.erl        |   8 ++
 5 files changed, 196 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/a7d6a970/lib/erl/src/thrift_client_util.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_client_util.erl b/lib/erl/src/thrift_client_util.erl
index 7a11f3a..b51a0b4 100644
--- a/lib/erl/src/thrift_client_util.erl
+++ b/lib/erl/src/thrift_client_util.erl
@@ -41,7 +41,9 @@ split_options([Opt = {OptKey, _} | Rest], ProtoIn, TransIn)
   when OptKey =:= framed;
        OptKey =:= connect_timeout;
        OptKey =:= recv_timeout;
-       OptKey =:= sockopts ->
+       OptKey =:= sockopts;
+       OptKey =:= ssltransport;
+       OptKey =:= ssloptions->
     split_options(Rest, ProtoIn, [Opt | TransIn]).
 
 
@@ -49,10 +51,15 @@ split_options([Opt = {OptKey, _} | Rest], ProtoIn, TransIn)
 %% with the binary protocol
 new(Host, Port, Service, Options)
   when is_integer(Port), is_atom(Service), is_list(Options) ->
-    {ProtoOpts, TransOpts} = split_options(Options),
+    {ProtoOpts, TransOpts0} = split_options(Options),
+
+    {TransportModule, TransOpts2} = case lists:keytake(ssltransport, 1, TransOpts0) of
+                                        {value, {_, true}, TransOpts1} -> {thrift_sslsocket_transport, TransOpts1};
+                                        false -> {thrift_socket_transport, TransOpts0}
+                                    end,
 
     {ok, TransportFactory} =
-        thrift_socket_transport:new_transport_factory(Host, Port, TransOpts),
+        TransportModule:new_transport_factory(Host, Port, TransOpts2),
 
     {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(
                               TransportFactory, ProtoOpts),

http://git-wip-us.apache.org/repos/asf/thrift/blob/a7d6a970/lib/erl/src/thrift_socket_server.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_socket_server.erl b/lib/erl/src/thrift_socket_server.erl
index f7c7a02..233b992 100644
--- a/lib/erl/src/thrift_socket_server.erl
+++ b/lib/erl/src/thrift_socket_server.erl
@@ -38,7 +38,9 @@
          listen=null,
          acceptor=null,
          socket_opts=[{recv_timeout, 500}],
-         framed=false
+         framed=false,
+         ssltransport=false,
+         ssloptions=[]
         }).
 
 start(State=#thrift_socket_server{}) ->
@@ -103,8 +105,14 @@ parse_options([{max, Max} | Rest], State) ->
                      Max
              end,
     parse_options(Rest, State#thrift_socket_server{max=MaxInt});
+
 parse_options([{framed, Framed} | Rest], State) when is_boolean(Framed) ->
-    parse_options(Rest, State#thrift_socket_server{framed=Framed}).
+    parse_options(Rest, State#thrift_socket_server{framed=Framed});
+
+parse_options([{ssltransport, SSLTransport} | Rest], State) when is_boolean(SSLTransport) ->
+    parse_options(Rest, State#thrift_socket_server{ssltransport=SSLTransport});
+parse_options([{ssloptions, SSLOptions} | Rest], State) when is_list(SSLOptions) ->
+    parse_options(Rest, State#thrift_socket_server{ssloptions=SSLOptions}).
 
 start_server(State=#thrift_socket_server{name=Name}) ->
     case Name of
@@ -168,25 +176,28 @@ new_acceptor(State=#thrift_socket_server{max=0}) ->
     State#thrift_socket_server{acceptor=null};
 new_acceptor(State=#thrift_socket_server{listen=Listen,
                                          service=Service, handler=Handler,
-                                         socket_opts=Opts, framed=Framed
+                                         socket_opts=Opts, framed=Framed,
+                                         ssltransport=SslTransport, ssloptions=SslOptions
                                         }) ->
     Pid = proc_lib:spawn_link(?MODULE, acceptor_loop,
-                              [{self(), Listen, Service, Handler, Opts, Framed}]),
+                              [{self(), Listen, Service, Handler, Opts, Framed, SslTransport, SslOptions}]),
     State#thrift_socket_server{acceptor=Pid}.
 
-acceptor_loop({Server, Listen, Service, Handler, SocketOpts, Framed})
+acceptor_loop({Server, Listen, Service, Handler, SocketOpts, Framed, SslTransport, SslOptions})
   when is_pid(Server), is_list(SocketOpts) ->
     case catch gen_tcp:accept(Listen) of % infinite timeout
         {ok, Socket} ->
             gen_server:cast(Server, {accepted, self()}),
             ProtoGen = fun() ->
-                               {ok, SocketTransport}   = thrift_socket_transport:new(Socket, SocketOpts),
-                               {ok, Transport}         =
-                                   case Framed of
-                                       true  -> thrift_framed_transport:new(SocketTransport);
-                                       false -> thrift_buffered_transport:new(SocketTransport)
-                                   end,
-                               {ok, Protocol}          = thrift_binary_protocol:new(Transport),
+                               {ok, SocketTransport} = case SslTransport of
+                                                           true  -> thrift_sslsocket_transport:new(Socket, SocketOpts, SslOptions);
+                                                           false -> thrift_socket_transport:new(Socket, SocketOpts)
+                                                       end,
+                               {ok, Transport}       = case Framed of
+                                                           true  -> thrift_framed_transport:new(SocketTransport);
+                                                           false -> thrift_buffered_transport:new(SocketTransport)
+                                                       end,
+                               {ok, Protocol}        = thrift_binary_protocol:new(Transport),
                                {ok, Protocol}
                        end,
             thrift_processor:init({Server, ProtoGen, Service, Handler});

http://git-wip-us.apache.org/repos/asf/thrift/blob/a7d6a970/lib/erl/src/thrift_sslsocket_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_sslsocket_transport.erl b/lib/erl/src/thrift_sslsocket_transport.erl
new file mode 100644
index 0000000..211153f
--- /dev/null
+++ b/lib/erl/src/thrift_sslsocket_transport.erl
@@ -0,0 +1,147 @@
+%%
+%% 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(thrift_sslsocket_transport).
+
+-include("thrift_transport_behaviour.hrl").
+
+-behaviour(thrift_transport).
+
+-export([new/3,
+         write/2, read/2, flush/1, close/1,
+
+         new_transport_factory/3]).
+
+%% Export only for the transport factory
+-export([new/2]).
+
+-record(data, {socket,
+               recv_timeout=infinity}).
+-type state() :: #data{}.
+
+%% The following "local" record is filled in by parse_factory_options/2
+%% below. These options can be passed to new_protocol_factory/3 in a
+%% proplists-style option list. They're parsed like this so it is an O(n)
+%% operation instead of O(n^2)
+-record(factory_opts, {connect_timeout = infinity,
+                       sockopts = [],
+                       framed = false,
+                       ssloptions = []}).
+
+parse_factory_options([], Opts) ->
+    Opts;
+parse_factory_options([{framed, Bool} | Rest], Opts) when is_boolean(Bool) ->
+    parse_factory_options(Rest, Opts#factory_opts{framed=Bool});
+parse_factory_options([{sockopts, OptList} | Rest], Opts) when is_list(OptList) ->
+    parse_factory_options(Rest, Opts#factory_opts{sockopts=OptList});
+parse_factory_options([{connect_timeout, TO} | Rest], Opts) when TO =:= infinity; is_integer(TO) ->
+    parse_factory_options(Rest, Opts#factory_opts{connect_timeout=TO});
+parse_factory_options([{ssloptions, SslOptions} | Rest], Opts) when is_list(SslOptions) ->
+    parse_factory_options(Rest, Opts#factory_opts{ssloptions=SslOptions}).
+
+new(Socket, SockOpts, SslOptions) when is_list(SockOpts), is_list(SslOptions) ->
+    inet:setopts(Socket, [{active, false}]), %% => prevent the ssl handshake messages get lost
+
+    %% upgrade to an ssl socket
+    case catch ssl:ssl_accept(Socket, SslOptions) of % infinite timeout
+        {ok, SslSocket} ->
+            new(SslSocket, SockOpts);
+        {error, Reason} ->
+            exit({error, Reason});
+        Other ->
+            error_logger:error_report(
+              [{application, thrift},
+               "SSL accept failed error",
+               lists:flatten(io_lib:format("~p", [Other]))]),
+            exit({error, ssl_accept_failed})
+    end.
+
+new(SslSocket, SockOpts) ->
+    State =
+        case lists:keysearch(recv_timeout, 1, SockOpts) of
+            {value, {recv_timeout, Timeout}}
+              when is_integer(Timeout), Timeout > 0 ->
+                #data{socket=SslSocket, recv_timeout=Timeout};
+            _ ->
+                #data{socket=SslSocket}
+        end,
+    thrift_transport:new(?MODULE, State).
+
+%% Data :: iolist()
+write(This = #data{socket = Socket}, Data) ->
+    {This, ssl:send(Socket, Data)}.
+
+read(This = #data{socket=Socket, recv_timeout=Timeout}, Len)
+  when is_integer(Len), Len >= 0 ->
+    case ssl:recv(Socket, Len, Timeout) of
+        Err = {error, timeout} ->
+            error_logger:info_msg("read timeout: peer conn ~p", [inet:peername(Socket)]),
+            ssl:close(Socket),
+            {This, Err};
+        Data ->
+            {This, Data}
+    end.
+
+%% We can't really flush - everything is flushed when we write
+flush(This) ->
+    {This, ok}.
+
+close(This = #data{socket = Socket}) ->
+    {This, ssl:close(Socket)}.
+
+%%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%
+%% Generates a "transport factory" function - a fun which returns a thrift_transport()
+%% instance.
+%% This can be passed into a protocol factory to generate a connection to a
+%% thrift server over a socket.
+%%
+new_transport_factory(Host, Port, Options) ->
+    ParsedOpts = parse_factory_options(Options, #factory_opts{}),
+
+    F = fun() ->
+                SockOpts = [binary,
+                            {packet, 0},
+                            {active, false},
+                            {nodelay, true} |
+                            ParsedOpts#factory_opts.sockopts],
+                case catch gen_tcp:connect(Host, Port, SockOpts,
+                                           ParsedOpts#factory_opts.connect_timeout) of
+                    {ok, Sock} ->
+                        SslSock = case catch ssl:connect(Sock, ParsedOpts#factory_opts.ssloptions,
+                                                         ParsedOpts#factory_opts.connect_timeout) of
+                                      {ok, SslSocket} ->
+                                          SslSocket;
+                                      Other ->
+                                          error_logger:info_msg("error while connecting over ssl - reason: ~p~n", [Other]),
+                                          catch gen_tcp:close(Sock),
+                                          exit(error)
+                                  end,
+                        {ok, Transport} = thrift_sslsocket_transport:new(SslSock, SockOpts),
+                        {ok, BufTransport} =
+                            case ParsedOpts#factory_opts.framed of
+                                true  -> thrift_framed_transport:new(Transport);
+                                false -> thrift_buffered_transport:new(Transport)
+                            end,
+                        {ok, BufTransport};
+                    Error  ->
+                        Error
+                end
+        end,
+    {ok, F}.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/a7d6a970/test/erl/src/test_client.erl
----------------------------------------------------------------------
diff --git a/test/erl/src/test_client.erl b/test/erl/src/test_client.erl
index 8cfeb8b..7b9efd6 100644
--- a/test/erl/src/test_client.erl
+++ b/test/erl/src/test_client.erl
@@ -47,6 +47,14 @@ parse_args([Head | Rest], Opts) ->
                     _Else ->
                         Opts
                 end;
+            "--ssl" ->
+                ssl:start(),
+                SslOptions =
+                    {ssloptions, [
+                        {certfile, "../keys/client.crt"}
+                        ,{keyfile, "../keys/server.key"}
+                    ]},
+                Opts#options{client_opts = [{ssltransport, true} | [SslOptions | Opts#options.client_opts]]};
             "--protocol=binary" ->
                 % TODO: Enable JSON protocol
                 Opts;

http://git-wip-us.apache.org/repos/asf/thrift/blob/a7d6a970/test/erl/src/test_thrift_server.erl
----------------------------------------------------------------------
diff --git a/test/erl/src/test_thrift_server.erl b/test/erl/src/test_thrift_server.erl
index 51457f5..884eb9e 100644
--- a/test/erl/src/test_thrift_server.erl
+++ b/test/erl/src/test_thrift_server.erl
@@ -47,6 +47,14 @@ parse_args([Head | Rest], Opts) ->
                     _Else ->
                         Opts
                 end;
+            "--ssl" ->
+                ssl:start(),
+                SslOptions =
+                    {ssloptions, [
+                         {certfile, "../keys/server.crt"}
+                        ,{keyfile,  "../keys/server.key"}
+                    ]},
+                Opts#options{server_opts = [{ssltransport, true} | [SslOptions | Opts#options.server_opts]]};
             "--protocol=" ++ _ -> Opts;
             _Else ->
                 erlang:error({bad_arg, Head})


[3/6] thrift git commit: THRIFT-2708 add support for oneway (async) function calls in erlang client Client: Erlang Patch: Alisdair Sullivan modified by Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-2708 add support for oneway (async) function calls in erlang client
Client: Erlang
Patch: Alisdair Sullivan modified by Nobuaki Sukegawa

Modification: Fix invalid send_call return type.

This closes #231


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/7bdba5c0
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/7bdba5c0
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/7bdba5c0

Branch: refs/heads/master
Commit: 7bdba5c06a7aa40cf83352c214270a2f1f4dd572
Parents: 149ecc1
Author: alisdair sullivan <al...@yahoo.ca>
Authored: Tue Sep 30 22:03:34 2014 -0700
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Nov 1 18:07:15 2015 +0900

----------------------------------------------------------------------
 lib/erl/src/thrift_client.erl       | 71 ++++++++++++++++++--------------
 test/erl/src/test_client.erl        |  4 +-
 test/erl/src/test_thrift_server.erl |  1 +
 3 files changed, 43 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/7bdba5c0/lib/erl/src/thrift_client.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_client.erl b/lib/erl/src/thrift_client.erl
index ff5c3dc..209bd4c 100644
--- a/lib/erl/src/thrift_client.erl
+++ b/lib/erl/src/thrift_client.erl
@@ -36,13 +36,11 @@ new(Protocol, Service)
 
 -spec call(#tclient{}, atom(), list()) -> {#tclient{}, {ok, any()} | {error, any()}}.
 call(Client = #tclient{}, Function, Args)
-  when is_atom(Function), is_list(Args) ->
-    case send_function_call(Client, Function, Args) of
-        {Client1, ok} ->
-            receive_function_result(Client1, Function);
-        Else ->
-            Else
-    end.
+when is_atom(Function), is_list(Args) ->
+  case send_function_call(Client, Function, Args) of
+    {ok, Client1} -> receive_function_result(Client1, Function);
+    Else -> Else
+  end.
 
 
 %% Sends a function call but does not read the result. This is useful
@@ -51,7 +49,10 @@ call(Client = #tclient{}, Function, Args)
 -spec send_call(#tclient{}, atom(), list()) -> {#tclient{}, ok}.
 send_call(Client = #tclient{}, Function, Args)
   when is_atom(Function), is_list(Args) ->
-    send_function_call(Client, Function, Args).
+    case send_function_call(Client, Function, Args) of
+      {ok, Client1} -> {Client1, ok};
+      Else -> Else
+    end.
 
 -spec close(#tclient{}) -> ok.
 close(#tclient{protocol=Protocol}) ->
@@ -61,30 +62,36 @@ close(#tclient{protocol=Protocol}) ->
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
--spec send_function_call(#tclient{}, atom(), list()) -> {#tclient{}, ok | {error, any()}}.
-send_function_call(Client = #tclient{protocol = Proto0,
-                                     service  = Service,
-                                     seqid    = SeqId},
-                   Function,
-                   Args) ->
-    Params = try Service:function_info(Function, params_type)
-    catch error:function_clause -> no_function
-    end,
-    case Params of
-        no_function ->
-            {Client, {error, {no_function, Function}}};
-        {struct, PList} when length(PList) =/= length(Args) ->
-            {Client, {error, {bad_args, Function, Args}}};
-        {struct, _PList} ->
-            Begin = #protocol_message_begin{name = atom_to_list(Function),
-                                            type = ?tMessageType_CALL,
-                                            seqid = SeqId},
-            {Proto1, ok} = thrift_protocol:write(Proto0, Begin),
-            {Proto2, ok} = thrift_protocol:write(Proto1, {Params, list_to_tuple([Function | Args])}),
-            {Proto3, ok} = thrift_protocol:write(Proto2, message_end),
-            {Proto4, ok} = thrift_protocol:flush_transport(Proto3),
-            {Client#tclient{protocol = Proto4}, ok}
-    end.
+-spec send_function_call(#tclient{}, atom(), list()) -> {sync | async | {error, any()}, #tclient{}}.
+send_function_call(Client = #tclient{service = Service}, Function, Args) ->
+  {Params, Reply} = try
+    {Service:function_info(Function, params_type), Service:function_info(Function, reply_type)}
+  catch error:function_clause -> no_function
+  end,
+  MsgType = case Reply of
+    oneway_void -> ?tMessageType_ONEWAY;
+    _ -> ?tMessageType_CALL
+  end,
+  case Params of
+    no_function ->
+      {{error, {no_function, Function}}, Client};
+    {struct, PList} when length(PList) =/= length(Args) ->
+      {{error, {bad_args, Function, Args}}, Client};
+    {struct, _PList} -> write_message(Client, Function, Args, Params, MsgType)
+  end.
+
+-spec write_message(#tclient{}, atom(), list(), {struct, list()}, integer()) ->
+  {ok, #tclient{}}.
+write_message(Client = #tclient{protocol = P0, seqid = Seq}, Function, Args, Params, MsgType) ->
+  {P1, ok} = thrift_protocol:write(P0, #protocol_message_begin{
+    name = atom_to_list(Function),
+    type = MsgType,
+    seqid = Seq
+  }),
+  {P2, ok} = thrift_protocol:write(P1, {Params, list_to_tuple([Function|Args])}),
+  {P3, ok} = thrift_protocol:write(P2, message_end),
+  {P4, ok} = thrift_protocol:flush_transport(P3),
+  {ok, Client#tclient{protocol = P4}}.
 
 -spec receive_function_result(#tclient{}, atom()) -> {#tclient{}, {ok, any()} | {error, any()}}.
 receive_function_result(Client = #tclient{service = Service}, Function) ->

http://git-wip-us.apache.org/repos/asf/thrift/blob/7bdba5c0/test/erl/src/test_client.erl
----------------------------------------------------------------------
diff --git a/test/erl/src/test_client.erl b/test/erl/src/test_client.erl
index fad0988..7dd5cbc 100644
--- a/test/erl/src/test_client.erl
+++ b/test/erl/src/test_client.erl
@@ -136,4 +136,6 @@ start(Args) ->
         ClientS4
     end,
 
-  thrift_client:close(Client19).
+  {Client20, {ok, ok}} = thrift_client:call(Client19, testOneway, [1]),
+
+  thrift_client:close(Client20).

http://git-wip-us.apache.org/repos/asf/thrift/blob/7bdba5c0/test/erl/src/test_thrift_server.erl
----------------------------------------------------------------------
diff --git a/test/erl/src/test_thrift_server.erl b/test/erl/src/test_thrift_server.erl
index 6969465..51457f5 100644
--- a/test/erl/src/test_thrift_server.erl
+++ b/test/erl/src/test_thrift_server.erl
@@ -219,5 +219,6 @@ handle_function(testMultiException, {Arg0, Arg1}) ->
     end;
 
 handle_function(testOneway, {Seconds}) ->
+    io:format("testOneway: ~p~n", [Seconds]),
     timer:sleep(1000 * Seconds),
     ok.


[2/6] thrift git commit: THRIFT-2856 refactor erlang basic transports and unify interfaces Client: Erlang Patch: Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-2856 refactor erlang basic transports and unify interfaces
Client: Erlang
Patch: Nobuaki Sukegawa

Add read_exact default implementation so that every transport is usable
under framed transport.


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/149ecc1a
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/149ecc1a
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/149ecc1a

Branch: refs/heads/master
Commit: 149ecc1a5fff2f68d413df730b97cc7272813077
Parents: a559f8d
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Sat Oct 31 12:17:31 2015 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Nov 1 18:04:02 2015 +0900

----------------------------------------------------------------------
 lib/erl/src/thrift_transport.erl | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/149ecc1a/lib/erl/src/thrift_transport.erl
----------------------------------------------------------------------
diff --git a/lib/erl/src/thrift_transport.erl b/lib/erl/src/thrift_transport.erl
index 0fdf970..31dac86 100644
--- a/lib/erl/src/thrift_transport.erl
+++ b/lib/erl/src/thrift_transport.erl
@@ -101,8 +101,12 @@ when is_integer(Len), Len >= 0 ->
 
 read_exact(Transport = #t_transport{module = Module}, Len)
 when is_integer(Len), Len >= 0 ->
-  {NewState, Result} = Module:read_exact(Transport#t_transport.state, Len),
-  {Transport#t_transport{state = NewState}, Result}.
+  case erlang:function_exported(Module, read_exact, 2) of
+      true ->
+        {NewState, Result} = Module:read_exact(Transport#t_transport.state, Len),
+        {Transport#t_transport{state = NewState}, Result};
+      false -> read(Transport, Len)
+  end.
 
 
 write(Transport = #t_transport{module = Module}, Data) ->


[4/6] thrift git commit: THRIFT-2708 add support for oneway (async) function calls in erlang client Client: Erlang Patch: Nobuaki Sukegawa

Posted by ns...@apache.org.
THRIFT-2708 add support for oneway (async) function calls in erlang client
Client: Erlang
Patch: Nobuaki Sukegawa

Add timeout to oneway call in cross test client.


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/7ab56e83
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/7ab56e83
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/7ab56e83

Branch: refs/heads/master
Commit: 7ab56e835c8e44198c4f6875a8b2d761ae31ee40
Parents: 7bdba5c
Author: Nobuaki Sukegawa <ns...@apache.org>
Authored: Sat Oct 31 12:17:46 2015 +0900
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Sun Nov 1 18:30:20 2015 +0900

----------------------------------------------------------------------
 test/erl/src/test_client.erl | 9 +++++++++
 1 file changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/7ab56e83/test/erl/src/test_client.erl
----------------------------------------------------------------------
diff --git a/test/erl/src/test_client.erl b/test/erl/src/test_client.erl
index 7dd5cbc..8cfeb8b 100644
--- a/test/erl/src/test_client.erl
+++ b/test/erl/src/test_client.erl
@@ -136,6 +136,15 @@ start(Args) ->
         ClientS4
     end,
 
+  %% Use deprecated erlang:now until we start requiring OTP18
+  %% Started = erlang:monotonic_time(milli_seconds),
+  {_, StartSec, StartUSec} = erlang:now(),
   {Client20, {ok, ok}} = thrift_client:call(Client19, testOneway, [1]),
+  {_, EndSec, EndUSec} = erlang:now(),
+  Elapsed = (EndSec - StartSec) * 1000 + (EndUSec - StartUSec) / 1000,
+  if
+    Elapsed > 1000 -> exit(1);
+    true -> true
+  end,
 
   thrift_client:close(Client20).