diff options
Diffstat (limited to 'lib')
18 files changed, 3219 insertions, 0 deletions
diff --git a/lib/jinterface/test/Makefile b/lib/jinterface/test/Makefile new file mode 100644 index 0000000000..36955d1e91 --- /dev/null +++ b/lib/jinterface/test/Makefile @@ -0,0 +1,84 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/jinterface_test + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +TEST_SPEC_FILE = jinterface.dynspec + +MODULES = nc_SUITE \ + jinterface_SUITE + +GEN_MODULES = jitu + +ERL_FILES = $(MODULES:%=%.erl) $(GEN_MODULES:%=%.erl) + +GEN_TARGET_FILES = $(GEN_MODULES:%=%.$(EMULATOR)) + +SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) + +TARGET_FILES = \ + $(GEN_TARGET_FILES) \ + $(SUITE_TARGET_FILES) + +# ---------------------------------------------------- +# PROGRAMS +# ---------------------------------------------------- + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +tests debug opt: + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +docs: + +# ---------------------------------------------------- +# Special Targets +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# Release Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: + +release_docs_spec: + +release_tests_spec: tests + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(TEST_SPEC_FILE) $(ERL_FILES) $(RELSYSDIR) + @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/jinterface/test/jinterface.dynspec b/lib/jinterface/test/jinterface.dynspec new file mode 100644 index 0000000000..44712521df --- /dev/null +++ b/lib/jinterface/test/jinterface.dynspec @@ -0,0 +1,32 @@ +%% -*- erlang -*- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% You can test this file using this command. +%% file:script("jinterface.dynspec", [{'Os',"Unix"}]). + +case case code:priv_dir(jinterface) of + {error,bad_name} -> false; + P -> filelib:is_dir(P) end of + true -> + []; + false -> + NoApp = "No jinterface application", + [{skip,{nc_SUITE,NoApp}}, + {skip,{jinterface_SUITE,NoApp}}] +end. diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl new file mode 100644 index 0000000000..ea097680dd --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE.erl @@ -0,0 +1,761 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(jinterface_SUITE). + +-export([all/1, init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2]). + +-export([nodename/1, register_and_whereis/1, get_names/1, boolean_atom/1, + node_ping/1, mbox_ping/1, + java_erlang_send_receive/1, + java_internal_send_receive_same_node/1, + java_internal_send_receive_different_nodes/1, + java_internal_send_receive_self/1, + java_link_and_exit/1, erl_link_and_exit/1, + erl_link_java_exit/1, java_link_erl_exit/1, + internal_link_linking_exits/1, internal_link_linked_exits/1, + internal_unlink_linking_exits/1, internal_unlink_linked_exits/1, + normal_exit/1, kill_mbox/1, kill_erl_proc_from_java/1, + kill_mbox_from_erlang/1, erl_exit_with_reason_any_term/1, + java_exit_with_reason_any_term/1, + status_handler_localStatus/1, status_handler_remoteStatus/1, + status_handler_connAttempt/1]). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +-define(debug,true). +-ifdef(debug). +-define(dbg(Str,Args), io:format(Str,Args)). +-else. +-define(dbg(Str,Args), ok). +-endif. + +-define(link_test_reason,link_test_reason). + +%% Test cases in MboxSendReceive.java +-define(java_erlang_send_receive,1). +-define(java_internal_send_receive_same_node,2). +-define(java_internal_send_receive_different_nodes,3). +-define(java_internal_send_receive_self,4). + +%% Test cases in MboxLinkUnlink.java +-define(java_link_and_exit, 1). +-define(erl_link_and_exit, 2). +-define(erl_link_java_exit, 3). +-define(java_link_erl_exit, 4). +-define(internal_link_linking_exits, 5). +-define(internal_link_linked_exits, 6). +-define(internal_unlink_linking_exits,7). +-define(internal_unlink_linked_exits,8). +-define(normal_exit,9). +-define(kill_mbox,10). +-define(kill_erl_proc_from_java,11). +-define(kill_mbox_from_erlang,12). +-define(erl_exit_with_reason_any_term,13). +-define(java_exit_with_reason_any_term,14). + + +%% Test cases in NodeStatusHandler.java +-define(status_handler_localStatus,1). +-define(status_handler_remoteStatus,2). +-define(status_handler_connAttempt,3). + +%%%----------------------------------------------------------------- +%%% INIT/END +%%%----------------------------------------------------------------- +all(suite) -> + lists:append([ + fundamental(), + ping(), + send_receive(), + link_unlink(), + status_handler() + ]). + +fundamental() -> + [ + nodename, % Nodename.java + register_and_whereis, % RegisterAndWhereis.java + get_names, % GetNames.java + boolean_atom % BooleanAtom.java + ]. + +ping() -> + [ + %% Implemented in NodePing.java + node_ping, + + %% Implemented in MboxPing.java + mbox_ping + ]. + + +send_receive() -> + [ + %% Implemented in MboxSendReceive.java + java_erlang_send_receive, + java_internal_send_receive_same_node, + java_internal_send_receive_different_nodes, + java_internal_send_receive_self + ]. + +%% Note: +%% +%% The test cases in MboxLinkUnlink.java and in +%% NodePing.java, all uses default cookie, and if there +%% is a problem with having the same default cookie in +%% erlang vs jinterface, e.g because the home directory +%% does not get the same in some cases on Windows +%% - they will all fail. + +link_unlink() -> + [ + %% Implemented in MboxLinkUnlink.java + java_link_and_exit, + erl_link_and_exit, + erl_link_java_exit, + java_link_erl_exit, + internal_link_linking_exits, + internal_link_linked_exits, + internal_unlink_linking_exits, + internal_unlink_linked_exits, + normal_exit, + kill_mbox, + kill_erl_proc_from_java, + kill_mbox_from_erlang, + erl_exit_with_reason_any_term, + java_exit_with_reason_any_term + ]. + +status_handler() -> + [ + %% Implemented in NodeStatusHandler.java + status_handler_localStatus, + status_handler_remoteStatus, + status_handler_connAttempt + ]. + + +init_per_suite(Config) when is_list(Config) -> + jitu:init_all(Config). + +end_per_suite(Config) when is_list(Config) -> + jitu:finish_all(Config). + +init_per_testcase(_Case,Config) -> + Dog = ?t:timetrap({seconds,10}), + [{watch_dog,Dog}|Config]. + +end_per_testcase(_Case,Config) -> + ?t:timetrap_cancel(?config(watch_dog,Config)), + ok. + + +%%%----------------------------------------------------------------- +%%% TEST CASES +%%%----------------------------------------------------------------- +nodename(doc) -> + ["Nodename.java: " + "Test OtpNode.node(), OtpNode.alive() and OtpNode.host()"]; +nodename(suite) -> + []; +nodename(Config) when is_list(Config) -> + [_,Host] = string:tokens(atom_to_list(node()),"@"), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "Nodename", + [list_to_atom(Host)]). + +%%%----------------------------------------------------------------- +register_and_whereis(doc) -> + ["RegisterAndWhereis.java: " + "Test OtpNode.registerName(...), OtpMbox.registerName(...) and " + "OtpNode.whereis(...)"]; +register_and_whereis(suite) -> + []; +register_and_whereis(Config) when is_list(Config) -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "RegisterAndWhereis", + []). + +%%%----------------------------------------------------------------- +get_names(doc) -> + ["GetNames.java: " + "Test OtpNode.getNames()"]; +get_names(suite) -> + []; +get_names(Config) when is_list(Config) -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "GetNames", + []). + +%%%----------------------------------------------------------------- +boolean_atom(doc) -> + ["BooleanAtom.java: " + "Test OtpErlangAtom.booleanValue()"]; +boolean_atom(suite) -> + []; +boolean_atom(Config) when is_list(Config) -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "BooleanAtom", + []). + +%%%----------------------------------------------------------------- +node_ping(doc) -> + ["NodePing.java: " + "Test OtpNode.ping(java.lang.String node, long timeout)"]; +node_ping(suite) -> + []; +node_ping(Config) when is_list(Config) -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "NodePing", + [erlang:get_cookie(),node()]). + +%%%----------------------------------------------------------------- +mbox_ping(doc) -> + ["MboxPing.java: " + "Test OtpNode.createMbox(...) and OtpMbox.ping(...)"]; +mbox_ping(suite) -> + []; +mbox_ping(Config) when is_list(Config) -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "MboxPing", + [erlang:get_cookie(),node()]). + +%%%----------------------------------------------------------------- +java_erlang_send_receive(doc) -> + ["Test sending/receiving of erlang messages between erlang and java"]; +java_erlang_send_receive(suite) -> + []; +java_erlang_send_receive(Config) when is_list(Config) -> + send_receive(?java_erlang_send_receive, fun echo_loop/0, Config). + +echo_loop() -> + receive + {From,Msg} -> + ?dbg("erl_send_receive_server received ~p",[{From,Msg}]), + ?dbg("erl_send_receive_server sending ~p",[Msg]), + From ! Msg, + echo_loop(); + done -> + ok + end. + + +%%%----------------------------------------------------------------- +java_internal_send_receive_same_node(doc) -> + ["MboxSendReceive.java: " + "Test sending/receiving of erlang messages between mboxes " + "on the same java node."]; +java_internal_send_receive_same_node(suite) -> + []; +java_internal_send_receive_same_node(Config) when is_list(Config) -> + send_receive(?java_internal_send_receive_same_node, + fun() -> receive done -> ok end end, + Config). + +%%%----------------------------------------------------------------- +java_internal_send_receive_different_nodes(doc) -> + ["MboxSendReceive.java: " + "Test sending/receiving of erlang messages between mboxes " + "on different java nodes."]; +java_internal_send_receive_different_nodes(suite) -> + []; +java_internal_send_receive_different_nodes(Config) when is_list(Config) -> + send_receive(?java_internal_send_receive_different_nodes, + fun() -> receive done -> ok end end, + Config). + +%%%----------------------------------------------------------------- +java_internal_send_receive_self(doc) -> + ["MboxSendReceive.java: " + "Test sending/receiving of erlang messages from an mbox to itself"]; +java_internal_send_receive_self(suite) -> + []; +java_internal_send_receive_self(Config) when is_list(Config) -> + send_receive(?java_internal_send_receive_self, + fun() -> receive done -> ok end end, + Config). + +%%%----------------------------------------------------------------- +java_link_and_exit(doc) -> + ["MboxLinkUnlink.java: " + "Test link between erlang process and java mailbox." + "Java mailbox links and exits"]; +java_link_and_exit(suite) -> + []; +java_link_and_exit(Config) when is_list(Config) -> + LinkFun = + fun(Mbox) -> + Mbox ! {?java_link_and_exit,self(),?link_test_reason}, + receive after infinity -> ok end + end, + erl_java_link(LinkFun,java_link_and_exit,Config). + + +%%%----------------------------------------------------------------- +erl_link_and_exit(doc) -> + ["MboxLinkUnlink.java: " + "Test link between erlang process and java mailbox." + "Erlang process links and exits"]; +erl_link_and_exit(suite) -> + []; +erl_link_and_exit(Config) when is_list(Config) -> + LinkFun = fun(Mbox) -> + link(Mbox), + Mbox ! {?erl_link_and_exit,self(),?link_test_reason}, + receive ok -> ok end, + exit(?link_test_reason) + end, + erl_java_link(LinkFun,erl_link_and_exit,Config). + +%%%----------------------------------------------------------------- +erl_link_java_exit(doc) -> + ["MboxLinkUnlink.java: " + "Test link between erlang process and java mailbox." + "Erlang process links and java mailbox exits"]; +erl_link_java_exit(suite) -> + []; +erl_link_java_exit(Config) when is_list(Config) -> + LinkFun = fun(Mbox) -> + link(Mbox), + Mbox ! {?erl_link_java_exit,self(),?link_test_reason}, + receive after infinity -> ok end + end, + erl_java_link(LinkFun,erl_link_java_exit,Config). + + +%%%----------------------------------------------------------------- +java_link_erl_exit(doc) -> + ["MboxLinkUnlink.java: " + "Test link between erlang process and java mailbox." + "Java mailbox links and erlang process exits"]; +java_link_erl_exit(suite) -> + []; +java_link_erl_exit(Config) when is_list(Config) -> + LinkFun = + fun(Mbox) -> + Mbox ! {?java_link_erl_exit,self(),?link_test_reason}, + receive ok -> ok end, + exit(?link_test_reason) + end, + erl_java_link(LinkFun,java_link_erl_exit,Config). + +%%%----------------------------------------------------------------- +internal_link_linking_exits(doc) -> + ["MboxLinkUnlink.java: " + "Test link between two java mailboxes." + "The mailbox which creates the link is the one exiting"]; +internal_link_linking_exits(suite) -> + []; +internal_link_linking_exits(Config) when is_list(Config) -> + internal_link_unlink(?internal_link_linking_exits, + internal_link_linking_exits, + Config). + +%%%----------------------------------------------------------------- +internal_link_linked_exits(doc) -> + ["MboxLinkUnlink.java: " + "Test link between two java mailboxes." + "The mailbox which dies not create the link is the one exiting"]; +internal_link_linked_exits(suite) -> + []; +internal_link_linked_exits(Config) when is_list(Config) -> + internal_link_unlink(?internal_link_linked_exits, + internal_link_linked_exits, + Config). + +%%%----------------------------------------------------------------- +internal_unlink_linking_exits(doc) -> + ["MboxLinkUnlink.java: " + "Test link and unlink between two java mailboxes. " + "Mailbox1 creates a link to mailbox2 and removes it. " + "Then it creates another link and mailbox2 removes is. " + "Finally mailbox1 exits - mailbox2 must survive"]; +internal_unlink_linking_exits(suite) -> + []; +internal_unlink_linking_exits(Config) when is_list(Config) -> + internal_link_unlink(?internal_unlink_linking_exits, + internal_unlink_linking_exits, + Config). + +%%%----------------------------------------------------------------- +internal_unlink_linked_exits(doc) -> + ["MboxLinkUnlink.java: " + "Test link and unlink between two java mailboxes. " + "Mailbox1 creates a link to mailbox2 and removes it. " + "Then it creates another link and mailbox2 removes is. " + "Finally mailbox2 exits - mailbox1 must survive"]; +internal_unlink_linked_exits(suite) -> + []; +internal_unlink_linked_exits(Config) when is_list(Config) -> + internal_link_unlink(?internal_unlink_linked_exits, + internal_unlink_linked_exits, + Config). + +%%%----------------------------------------------------------------- +normal_exit(doc) -> + ["MboxLinkUnlink.java: " + "Test that mbox.close() uses exit reason 'normal', i.e. " + "that linked processes are not terminated."]; +normal_exit(suite) -> + []; +normal_exit(Config) when is_list(Config) -> + Fun = + fun() -> + register(erl_link_server,self()), + process_flag(trap_exit,true), + receive + {Main,Mbox} when is_pid(Main), is_pid(Mbox) -> + ?dbg("Erlang sending \"~p\"",[normal_exit]), + link(Mbox), + Pid = spawn_link(fun() -> + link(Mbox), + Mbox ! {?normal_exit}, + receive after infinity -> ok end + end), + receive + {'EXIT',Mbox,normal} -> + %% Make sure that we don't get the + %% exit signal from Pid, and Pid + %% should still be alive. + receive + {'EXIT',Pid,Reason} -> + ?dbg("Got unexpected exit signal: ~p", + [{'EXIT',Pid,Reason}]), + exit({unexpected,{'EXIT',Pid,Reason}}) + after 500 -> + true = erlang:is_process_alive(Pid), + exit(Pid,kill) + end, + receive done -> Main ! done end + after 1000 -> + receive + Other -> + ?dbg("Got garbage when waiting for exit:" + " ~p", [Other]), + Main ! done, + exit({got_unexpected,Other}) + after 0 -> + ok + end + end; + Other -> + ?dbg("Got garbage: ~p",[Other]), + exit(Other) + end + end, + + spawn_link(Fun), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "MboxLinkUnlink", + [erlang:get_cookie(),node()]). + + +%%%----------------------------------------------------------------- +kill_mbox(doc) -> + ["MboxLinkUnlink.java: " + "Test that mbox.exit(new OtpErlangAtom(\"kill\") causes linked " + "processes to exit with reason 'killed', which can be trapped."]; +kill_mbox(suite) -> + {skip, "Not yet implemented"}; +kill_mbox(Config) when is_list(Config) -> + Fun = + fun() -> + register(erl_link_server,self()), + process_flag(trap_exit,true), + receive + {Main,Mbox} when is_pid(Main), is_pid(Mbox) -> + ?dbg("Erlang sending \"~p\"",[kill_mbox]), + Pid = spawn_link(fun() -> + process_flag(trap_exit,true), + link(Mbox), + Mbox ! {?kill_mbox}, + receive + {'EXIT',Mbox,killed} -> + exit(correct_reason); + {'EXIT',Mbox,R} -> + exit({faulty_reason,R}) + end + end), + receive + {'EXIT',Pid,{faulty_reason,Reason}} -> + receive done -> Main ! done end, + exit({faulty_reason,Reason}); + {'EXIT',Pid,im_killed} -> + receive done -> Main ! done end + after 1000 -> + receive + Other -> + ?dbg("Got garbage when waiting for exit:" + " ~p", [Other]), + Main ! done, + exit({got_unexpected,Other}) + after 0 -> + ok + end + end; + Other -> + ?dbg("Got garbage: ~p",[Other]), + exit(Other) + end + end, + + spawn_link(Fun), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "MboxLinkUnlink", + [erlang:get_cookie(),node()]). + +%%%----------------------------------------------------------------- +kill_erl_proc_from_java(doc) -> + ["MboxLinkUnlink.java: " + "Test that mbox.exit(pid, new OtpErlangAtom(\"kill\") causes erlang " + "processes <pid> to be killed, even if trapping exits"]; +kill_erl_proc_from_java(suite) -> + []; +kill_erl_proc_from_java(Config) when is_list(Config) -> + LinkFun = fun(Mbox) -> + process_flag(trap_exit,true), + link(Mbox), + Mbox ! {?kill_erl_proc_from_java, self()}, + receive after infinity -> ok end + end, + erl_java_link(LinkFun,kill_erl_proc_from_java,killed,Config). + +%%%----------------------------------------------------------------- +kill_mbox_from_erlang(doc) -> + ["MboxLinkUnlink.java: " + "Test that exit(Mbox,kill) causes linked the Mbox to be killed, and" + "linked processes to exit with reason 'killed', even if trapping exits"]; +kill_mbox_from_erlang(suite) -> + {skip, "Not yet implemented"}; +kill_mbox_from_erlang(Config) when is_list(Config) -> + LinkFun = fun(Mbox) -> + link(Mbox), + Mbox ! {?kill_mbox_from_erlang}, + exit(Mbox,kill), + receive after infinity -> ok end + end, + erl_java_link(LinkFun,kill_mbox_from_erlang,killed,Config). + +%%%----------------------------------------------------------------- +erl_exit_with_reason_any_term(doc) -> + ["MboxLinkUnlink.java: " + "Test that any erlang term can be used as exit reason when erlang " + "process exits and is linked to an mbox."]; +erl_exit_with_reason_any_term(suite) -> + []; +erl_exit_with_reason_any_term(Config) when is_list(Config) -> + Reason = [hei,self(),{this,is,"a",[different,"reason"]}], + LinkFun = fun(Mbox) -> + link(Mbox), + Mbox ! {?erl_exit_with_reason_any_term,self(),Reason}, + receive ok -> ok end, + exit(Reason) + end, + erl_java_link(LinkFun,erl_exit_with_reason_any_term,Reason,Config). + +%%%----------------------------------------------------------------- +java_exit_with_reason_any_term(doc) -> + ["MboxLinkUnlink.java: " + "Test that any erlang term can be used as exit reason when mbox " + "exits and is linked to an erlang process."]; +java_exit_with_reason_any_term(suite) -> + []; +java_exit_with_reason_any_term(Config) when is_list(Config) -> + Reason = [hei,self(),{this,is,"a",[different,"reason"]}], + LinkFun = + fun(Mbox) -> + Mbox ! {?java_exit_with_reason_any_term,self(),Reason}, + receive after infinity -> ok end + end, + erl_java_link(LinkFun,java_exit_with_reason_any_term,Reason,Config). + + +%%%----------------------------------------------------------------- +status_handler_localStatus(doc) -> + ["NodeStatusHandler.java: " + "Test OtpNode.registerStatusHandler(...) and the callback " + "OtpNodeStatus.localStatus(...)"]; +status_handler_localStatus(suite) -> + []; +status_handler_localStatus(Config) when is_list(Config) -> + spawn_link(fun() -> + erl_status_server([{opt,{localStatus,"javanode1",true}}, + {localStatus,"javanode1",false}]) + end), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "NodeStatusHandler", + [erlang:get_cookie(),node(),?status_handler_localStatus]). + +%%%----------------------------------------------------------------- +status_handler_remoteStatus(doc) -> + ["NodeStatusHandler.java: " + "Test OtpNode.registerStatusHandler(...) and the callback " + "OtpNodeStatus.remoteStatus(...)"]; +status_handler_remoteStatus(suite) -> + []; +status_handler_remoteStatus(Config) when is_list(Config) -> + spawn_link(fun() -> + erl_status_server([{opt,{localStatus,"javanode1",true}}, + {remoteStatus,"javanode2",true}, + {remoteStatus,"javanode2",false}]) + end), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "NodeStatusHandler", + [erlang:get_cookie(),node(),?status_handler_remoteStatus]). + + +%%%----------------------------------------------------------------- +status_handler_connAttempt(doc) -> + ["NodeStatusHandler.java: " + "Test OtpNode.registerStatusHandler(...) and the callback " + "OtpNodeStatus.connAttempt(...)"]; +status_handler_connAttempt(suite) -> + []; +status_handler_connAttempt(Config) when is_list(Config) -> + spawn_link(fun() -> + erl_status_server([{opt,{localStatus,"javanode1",true}}, + {connAttempt,"unknown",true}, + {connAttempt,"javanode3",false}]) + end), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "NodeStatusHandler", + [erlang:get_cookie(),node(),?status_handler_connAttempt]). + + +%%%----------------------------------------------------------------- +%%% INTERNAL FUNCTIONS +%%%----------------------------------------------------------------- +send_receive(TestCaseTag,Fun,Config) -> + spawn(fun() -> + register(erl_send_receive_server,self()), + receive + From when is_pid(From) -> + JavaNode = node(From), + [JavaNode] = nodes(hidden), + From ! {TestCaseTag,self()}, + Fun(), + unregister(erl_send_receive_server) + end + end), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "MboxSendReceive", + [erlang:get_cookie(),node()]). + + +internal_link_unlink(Tag,Msg,Config) -> + Fun = + fun() -> + register(erl_link_server,self()), + process_flag(trap_exit,true), + receive + {Main,Mbox} when is_pid(Main), is_pid(Mbox) -> + ?dbg("Erlang sending \"~p\"",[Msg]), + Mbox ! {Tag,self(),?link_test_reason}, + receive done -> Main ! done end; + Other -> + ?dbg("Got garbage: ~p",[Other]), + exit(Other) + end + end, + + spawn_link(Fun), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "MboxLinkUnlink", + [erlang:get_cookie(),node()]). + + +erl_java_link(LinkFun,Msg,Config) -> + erl_java_link(LinkFun,Msg,?link_test_reason,Config). + +erl_java_link(LinkFun,Msg,Reason,Config) -> + Fun = + fun() -> + register(erl_link_server,self()), + process_flag(trap_exit,true), + receive + {Main,Mbox} when is_pid(Mbox), is_pid(Mbox) -> + ?dbg("Erlang sending \"~p\"",[Msg]), + Pid = spawn_link(fun() -> LinkFun(Mbox) end), + receive + {'EXIT',Pid,Reason} -> + receive done -> Main ! done end + after 1000 -> + receive + Other -> + ?dbg("Got garbage when waiting for exit:" + " ~p", [Other]), + Main ! done, + exit({got_unexpected,Other}) + after 0 -> + ok + end + end; + Other -> + ?dbg("Got garbage: ~p",[Other]), + exit(Other) + end + end, + + spawn_link(Fun), + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + "MboxLinkUnlink", + [erlang:get_cookie(),node()]). + +erl_status_server(List) -> + register(erl_status_server,self()), + erl_status_server(List,undefined). +erl_status_server([{opt,{Tag,NodeName,Up}},{Tag2,NodeName2,Up2}|Rest],_) -> + receive + {Tag,Node,Up,From} = M -> + ?dbg("erl_status_server got: ~p",[M]), + true = lists:prefix(NodeName,Node), + erl_status_server([{Tag2,NodeName2,Up2}|Rest],From); + {Tag2,Node2,Up2,From2} = M2 -> + ?dbg("erl_status_server got: ~p",[M2]), + true = lists:prefix(NodeName2,Node2), + erl_status_server(Rest,From2) + end; +erl_status_server([{Tag,NodeName,Up}|Rest],_) -> + receive + {Tag,Node,Up,From} = M -> + ?dbg("erl_status_server got: ~p",[M]), + true = lists:prefix(NodeName,Node), + erl_status_server(Rest,From); + Other -> + ?dbg("erl_status_server got garbage: ~p",[Other]), + exit(Other) + end; +erl_status_server([],From) -> + From ! done. diff --git a/lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java b/lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java new file mode 100644 index 0000000000..9554d50c9f --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class BooleanAtom { + + /* + Implements test case jinterface_SUITE:boolean_atom/1 + + Test the function OtpErlangAtom.booleanValue() + */ + + public static void main(String argv[]) { + + OtpErlangAtom atom = new OtpErlangAtom("true"); + if (!atom.booleanValue()) fail(1); + + atom = new OtpErlangAtom("false"); + if (atom.booleanValue()) fail(2); + + atom = new OtpErlangAtom("somethingelse"); + if (atom.booleanValue()) fail(3); + + } + + private static void fail(int reason) { + System.exit(reason); + } +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/GetNames.java b/lib/jinterface/test/jinterface_SUITE_data/GetNames.java new file mode 100644 index 0000000000..3d2bc4ac84 --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/GetNames.java @@ -0,0 +1,68 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import java.util.ArrayList; +import com.ericsson.otp.erlang.*; + +class GetNames { + + /* + Implements test case jinterface_SUITE:get_names/1 + + */ + + public static void main(String argv[]) { + + try { + OtpNode node = new OtpNode("javanode"); + OtpMbox mbox1 = node.createMbox(); + mbox1.registerName("mbox1"); + node.createMbox("mbox2"); + OtpMbox mbox3 = node.createMbox(); + node.registerName("mbox3",mbox3); + + ArrayList existing_names = new ArrayList(); + existing_names.add("mbox3"); + existing_names.add("mbox2"); + existing_names.add("mbox1"); + + String[] names = node.getNames(); + if (names.length != existing_names.size()) fail(1); + + for(int i=0; i<names.length; i++) { + System.out.println("" + names[i]); + existing_names.remove(names[i]); + } + + if (!existing_names.isEmpty()) fail(2); + } + catch (Exception e) { + fail("" + e, 3); + } + } + + private static void fail(int reason) { + System.exit(reason); + } + + private static void fail(String str, int reason) { + System.out.println(str); + System.exit(reason); + } +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/Makefile.src b/lib/jinterface/test/jinterface_SUITE_data/Makefile.src new file mode 100644 index 0000000000..2a3dca463b --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/Makefile.src @@ -0,0 +1,62 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .java + + +JAVAC = @JAVAC@ +ERLC = erlc + +JINTERFACE_CLASSPATH = @jinterface_classpath@ + +CLASSPATH = .@PS@$(JINTERFACE_CLASSPATH)@PS@ + +JAVA_FILES = \ + Nodename.java \ + RegisterAndWhereis.java \ + GetNames.java \ + BooleanAtom.java \ + NodePing.java \ + MboxPing.java \ + MboxSendReceive.java \ + MboxLinkUnlink.java \ + NodeStatusHandler.java + +CLASS_FILES = $(JAVA_FILES:.java=.class) + +all: $(CLASS_FILES) + +clean: + -rm -f $(CLASS_FILES) + -del /F /Q $(CLASS_FILES) + +$(CLASS_FILES) : $(JAVA_FILES) + $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES) + +# diff --git a/lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java b/lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java new file mode 100644 index 0000000000..5d1d097cc8 --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java @@ -0,0 +1,201 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class MboxLinkUnlink { + + /* + Implements test case jinterface_SUITE:mbox_link_unlink/1 + + + + */ + + private static final int java_link_and_exit = 1; + private static final int erl_link_and_exit = 2; + private static final int erl_link_java_exit = 3; + private static final int java_link_erl_exit = 4; + private static final int internal_link_linking_exits = 5; + private static final int internal_link_linked_exits = 6; + private static final int internal_unlink_linking_exits = 7; + private static final int internal_unlink_linked_exits = 8; + private static final int normal_exit = 9; + private static final int kill_mbox = 10; + private static final int kill_erl_proc_from_java = 11; + private static final int kill_mbox_from_erlang = 12; + private static final int erl_exit_with_reason_any_term = 13; + private static final int java_exit_with_reason_any_term = 14; + + private static boolean dbg = true; + + + public static void main(String argv[]) { + + + //String cookie = argv[0]; + String erlNode = argv[1]; + OtpErlangObject expected = null; + boolean waiting = false; + + try { // + OtpNode node = new OtpNode("javanode"); + OtpMbox mainMbox = node.createMbox(); + + try { + // Initiate and set up connection to erlang process + OtpMbox mbox = node.createMbox(); + OtpMbox mbox2; + + OtpErlangObject[] msg = {mainMbox.self(),mbox.self()}; + mbox.send("erl_link_server", erlNode, new OtpErlangTuple(msg)); + OtpErlangObject o = mbox.receive(1000); + if (o == null) System.exit(1); + OtpErlangTuple tuple = (OtpErlangTuple)o; + int tag = (int)((OtpErlangLong)tuple.elementAt(0)).longValue(); + + switch (tag) { + + case java_exit_with_reason_any_term: + case java_link_and_exit: + dbg("Java got \"java_link_and_exit\" or " + + "\"java_exit_with_reason_any_term\""); + mbox.link((OtpErlangPid)tuple.elementAt(1)); + mbox.send((OtpErlangPid)tuple.elementAt(1), + new OtpErlangAtom("ok")); + mbox.exit(tuple.elementAt(2)); + break; + case erl_exit_with_reason_any_term: + case erl_link_and_exit: + dbg("Java got \"erl_link_and_exit\" or " + + "\"erl_exit_with_reason_any_term\""); + mbox.send((OtpErlangPid)tuple.elementAt(1), + new OtpErlangAtom("ok")); + waiting = true; + expected = tuple.elementAt(2); + mbox.receive(1000); + System.exit(2); + case erl_link_java_exit: + dbg("Java got \"erl_link_java_exit\""); + mbox.exit(tuple.elementAt(2)); + break; + case java_link_erl_exit: + dbg("Java got \"java_link_erl_exit\""); + mbox.link((OtpErlangPid)tuple.elementAt(1)); + mbox.send((OtpErlangPid)tuple.elementAt(1), + new OtpErlangAtom("ok")); + waiting = true; + expected = tuple.elementAt(2); + mbox.receive(1000); + System.exit(3); + case internal_link_linking_exits: + dbg("Java got \"internal_link_linking_exits\""); + mbox2 = node.createMbox(); + mbox.link(mbox2.self()); + mbox.exit(tuple.elementAt(2)); + waiting = true; + expected = tuple.elementAt(2); + mbox2.receive(1000); // hanging waiting for exit + System.exit(4); // got someting other than exit + case internal_link_linked_exits: + dbg("Java got \"internal_link_linked_exits\""); + mbox2 = node.createMbox(); + mbox.link(mbox2.self()); + mbox2.exit(tuple.elementAt(2)); + waiting = true; + expected = tuple.elementAt(2); + mbox.receive(1000); // hanging waiting for exit + System.exit(5); // got someting other than exit + case internal_unlink_linking_exits: + dbg("Java got \"internal_unlink_linking_exits\""); + mbox2 = node.createMbox(); + mbox.link(mbox2.self()); + mbox.unlink(mbox2.self()); + mbox.link(mbox2.self()); + mbox2.unlink(mbox.self()); + mbox2.exit(tuple.elementAt(2)); + if (mbox.receive(500)!=null) System.exit(6); + break; + case internal_unlink_linked_exits: + dbg("Java got \"internal_unlink_linked_exits\""); + mbox2 = node.createMbox(); + mbox.link(mbox2.self()); + mbox.unlink(mbox2.self()); + mbox.link(mbox2.self()); + mbox2.unlink(mbox.self()); + mbox.exit(tuple.elementAt(2)); + if (mbox2.receive(500)!=null) System.exit(7); + break; + case normal_exit: + dbg("Java got \"normal_exit\""); + mbox.close(); + break; + case kill_mbox: + dbg("Java got \"kill_mbox\""); + mbox.exit("kill"); + break; + case kill_erl_proc_from_java: + dbg("Java got \"kill_erl_proc_from_java\""); + mbox.exit((OtpErlangPid)tuple.elementAt(1),"kill"); + break; + case kill_mbox_from_erlang: + dbg("Java got \"kill_mbox_from_erlang\""); + /* This will make the testcase successful, but it is + not the correct way to do it... + Mbox should probably just die when the kill signal is + received from erlang (or other mbox). + + try { + mbox.receive(1000); + System.exit(8); + } + catch (OtpErlangExit exit) { + if(!(exit.reason().equals(new OtpErlangAtom("kill")))) + System.exit(9); + mbox.exit("killed"); + } + */ + break; + } + } + catch (OtpErlangExit exit) { + dbg("Java got exit: " + exit.reason()); + if(!(waiting && exit.reason().equals(expected))) + System.exit(10); + } + + OtpErlangAtom done = new OtpErlangAtom("done"); + mainMbox.send("erl_link_server", erlNode, done); + OtpErlangObject o = mainMbox.receive(1000); + if (o == null) System.exit(11); + else if (!((OtpErlangAtom)o).equals(done)) + System.exit(12); + + } + catch (Exception e) { + System.out.println("EXCEPTION: " + e); + System.exit(13); + } + } + + private static void dbg(String str) { + if (dbg) System.out.println(str); + } + +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/MboxPing.java b/lib/jinterface/test/jinterface_SUITE_data/MboxPing.java new file mode 100644 index 0000000000..3a8497028e --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/MboxPing.java @@ -0,0 +1,50 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class MboxPing { + + /* + Implements test case jinterface_SUITE:mbox_ping/1 + + Creates an OtpNode object with an OtpMbox object. The test_server + node is pinged from the OtpMbox. + */ + + public static void main(String argv[]) { + + try { + OtpNode node = new OtpNode("javanode",argv[0]); + OtpMbox mbox = node.createMbox(); + if (mbox.ping(argv[1],2000)) { + System.out.println("OtpMbox.ping(" + argv[1] + ") -> true"); + } + else { + System.out.println("ERROR: OtpMbox.ping(" + argv[1] + + ") -> false"); + System.exit(1); + } + } + catch (Exception e) { + System.out.println("" + e); + System.exit(2); + } + } +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java b/lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java new file mode 100644 index 0000000000..2db71bb5cd --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java @@ -0,0 +1,229 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class MboxSendReceive { + + /* + Implements test case jinterface_SUITE:mbox_send_receive/1 + + Test OtpMbox.send(...) and OtpMbox.receive(...) + */ + + private static final boolean dbg = true; + private static final int recTime = 2000; + + private static final int java_erlang_send_receive = 1; + private static final int java_internal_send_receive_same_node = 2; + private static final int java_internal_send_receive_different_nodes = 3; + private static final int java_internal_send_receive_self = 4; + + public static void main(String argv[]) { + + String cookie = argv[0]; + String erlNode = argv[1]; + + OtpErlangObject[] msgArray = new OtpErlangObject[2]; + msgArray[1] = new OtpErlangAtom("hello world"); + OtpErlangTuple msg = null; + + try { + // Initiate: create javanode and mboxes + OtpNode node = new OtpNode("javanode",cookie); + OtpMbox mbox = node.createMbox(); + OtpMbox mbox2 = node.createMbox("java_echo_server2"); + + // Send the pid of mbox to erlang and wait for test case + // instruction: {TestCaseTag, Pid} + mbox.send("erl_send_receive_server", erlNode, mbox.self()); + OtpErlangObject o = mbox.receive(recTime); + if (o == null) System.exit(1); + OtpErlangTuple testCase = (OtpErlangTuple)o; + dbg("mbox received " + testCase); + int tag = (int)((OtpErlangLong)testCase.elementAt(0)).longValue(); + OtpErlangPid erlangPid = (OtpErlangPid)testCase.elementAt(1); + + switch (tag) { + + case java_erlang_send_receive: + + // Test1 (happened during initiation): + // Send mbox pid to erlang process with registered name. + // Erlang process sent back its pid to the mbox pid. + + // Test2: Register name and sent it to the erlang pid. Erlang + // process shall send message back to my registered name. + + mbox.registerName("java_echo_server"); + msgArray[0] = getNameNode("java_echo_server",node); + msg = new OtpErlangTuple(msgArray); + + dbg("java_echo_server sending " + msg); + mbox.send(erlangPid,msg); + + o = mbox.receive(recTime); + dbg("java_echo_server received " + o); + if (o == null) System.exit(2); + if (!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(3); + + // Test3: Same as Test2, but using a new mbox2 which + // got its name already when it is created - i.e. not + // using mbox.registerName + msgArray[0] = getNameNode("java_echo_server2",node); + msg = new OtpErlangTuple(msgArray); + + dbg("java_echo_server2 sending " + msg); + mbox2.send(erlangPid,msg); + + o = mbox2.receive(recTime); + dbg("java_echo_server received " + o); + if (o == null) System.exit(4); + if (!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(5); + + break; + + case java_internal_send_receive_same_node: + + // Test1: Sending message between mboxes on same node + // given registered name and node without host. + mbox.send("java_echo_server2","javanode",msgArray[1]); + o = mbox2.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(6); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(7); + + // Test2: Sending message between mboxes on same node + // given registered name and node with host. + mbox.send("java_echo_server2",mbox2.self().node(),msgArray[1]); + o = mbox2.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(8); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(9); + + // Test3: Sending message between mboxes on same node + // given registered name but not node. + mbox.send("java_echo_server2",msgArray[1]); + o = mbox2.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(10); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(11); + + // Test4: Sending message between mboxes on same node + // given pid. + mbox.send(mbox2.self(),msgArray[1]); + o = mbox2.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(12); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(13); + + break; + + case java_internal_send_receive_different_nodes: + + OtpNode node2 = new OtpNode("javanode2", cookie); + OtpMbox mboxOtherNode = node2.createMbox("mboxOtherNode"); + + // Test1: Sending message between mboxes on different + // nodes given registered name and node without host. + mbox.send("mboxOtherNode","javanode2",msgArray[1]); + o = mboxOtherNode.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(14); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(15); + + // Test2: Sending message between mboxes on different + // nodes given registered name and node with host. + mbox.send("mboxOtherNode",mboxOtherNode.self().node(), + msgArray[1]); + o = mboxOtherNode.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(16); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(17); + + // Test3: Sending message between mboxes on different + // nodes given pid. + mbox.send(mboxOtherNode.self(),msgArray[1]); + o = mboxOtherNode.receive(recTime); + dbg("Mbox at same node: " + o); + if (o == null) System.exit(18); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(19); + + break; + + + case java_internal_send_receive_self: + + // Test1: Sending message to myself given registered + // name and node without host. + mbox2.send("java_echo_server2","javanode",msgArray[1]); + o = mbox2.receive(recTime); + dbg("Self: " + o); + if (o == null) System.exit(18); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(19); + + // Test2: Sending message to myself given registered + // name and node with host. + mbox2.send("java_echo_server2",mbox2.self().node(),msgArray[1]); + o = mbox2.receive(recTime); + dbg("Self: " + o); + if (o == null) System.exit(20); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(21); + + // Test3: Sending message to myself given registered + // name but not host. + mbox2.send("java_echo_server2",msgArray[1]); + o = mbox2.receive(recTime); + dbg("Self: " + o); + if (o == null) System.exit(22); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(23); + + // Test4: Sending message to myself given pid. + mbox2.send(mbox2.self(),msgArray[1]); + o = mbox2.receive(recTime); + dbg("Self: " + o); + if (o == null) System.exit(24); + if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(25); + + break; + + } + + // Closing erl_send_receive_server by sending the atom 'done' to it. + mbox.send(erlangPid,new OtpErlangAtom("done")); + } + catch (Exception e) { + System.out.println("" + e); + System.exit(26); + } + } + + private static OtpErlangTuple getNameNode(String mboxName,OtpNode node) { + OtpErlangObject[] array = {new OtpErlangAtom(mboxName), + new OtpErlangAtom(node.node())}; + return new OtpErlangTuple(array); + + } + + private static void dbg(String str) { + if (dbg) System.out.println(str); + } + + +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/NodePing.java b/lib/jinterface/test/jinterface_SUITE_data/NodePing.java new file mode 100644 index 0000000000..d0df5c46b5 --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/NodePing.java @@ -0,0 +1,83 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class NodePing { + + /* + Implements test case jinterface_SUITE:node_ping/1 + + Creates three OtpNode objects. One with default cookie, one with + specified same cookie as the node running the test case and one + with a faulty cookie. From each OtpNode object the test_server + node is pinged. + + Also the default cookie node pings itself, and the node with the + specified cookie pings the node with default cookie. + */ + + public static void main(String argv[]) { + + String cookie = argv[0]; + String erlNode = argv[1]; + + try { + OtpNode node1 = new OtpNode("javanode1"); + ping(node1,erlNode,"Default cookie:",true,1); + ping(node1,node1.node(),"Self:",true,2); + ping(node1,"javanode1","Self:",true,3); + + OtpNode node2 = new OtpNode("javanode2",cookie); + ping(node2,erlNode,"Specified cookie:",true,4); + ping(node2,"javanode1","Javanode (no host):",true,5); + ping(node2,node1.node(),"Javanode:",true,6); + + OtpNode node3 = new OtpNode("javanode3","faultycookie"); + ping(node3,erlNode,"Faulty cookie:",false,7); + + // Test OtpNode.cookie() and OtpNode.setCookie(cookie) as well + if (!node3.cookie().equals("faultycookie")) + fail("Testing OtpNode.cookie()",8); + String old = node3.setCookie(cookie); + if (!old.equals("faultycookie")) + fail("Checking return of OtpNode.setCookie(cookie)",9); + ping(node3,erlNode,"setCookie:",true,10); + } + catch (Exception e) { + fail("" + e, 11); + } + } + + private static void ping(OtpNode node, String remote, String descr, + boolean expected, int reason) { + if ( node.ping(remote,2000) == expected ) { + System.out.println(descr + " ping(" + remote + ") -> " + expected); + } + else { + fail("ERROR: " + descr + " ping(" + remote +") -> " + !expected, + reason); + } + } + + private static void fail(String str, int reason) { + System.out.println(str); + System.exit(reason); + } +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java b/lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java new file mode 100644 index 0000000000..51ea15b5ef --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java @@ -0,0 +1,168 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +public class NodeStatusHandler extends OtpNodeStatus { + /* + Implements java side of test cases in jinterface_SUITE.erl + + Test OtpNode.registerStatusHandler(...) and class OtpNodeStatus. + */ + + private static final boolean dbg = true; + private static final int recTime = 2000; + + private static String erlNode = null; + private static String cookie = null; + private static OtpMbox mbox = null; + + private static final int status_handler_localStatus = 1; + private static final int status_handler_remoteStatus = 2; + private static final int status_handler_connAttempt = 3; + + public static void main(String argv[]) { + + cookie = argv[0]; + erlNode = argv[1]; + + try { + OtpNode javaNode = new OtpNode("javanode", cookie); + mbox = javaNode.createMbox(); + } + catch (Exception e) { + dbg("EXCEPTION when creating javanode: " + e); + System.exit(1); + } + + try { + OtpNode node1 = new OtpNode("javanode1", cookie); + node1.registerStatusHandler(new NodeStatusHandler()); + + switch (Integer.parseInt(argv[2])) { + + case status_handler_localStatus: + dbg("java running test case \"status_handler_localStatus\""); + + Thread.sleep(200); // Give 'nodeup' message a chance + // before closing + node1.close(); + Thread.sleep(500); + break; + + case status_handler_remoteStatus: + dbg("java running test case \"status_handler_remoteStatus\""); + + OtpNode node2 = new OtpNode("javanode2", cookie); + node2.ping(node1.node(),2000); + node2.close(); + Thread.sleep(500); + break; + + case status_handler_connAttempt: + dbg("java running test case \"status_handler_connAttempt\""); + + OtpNode node3 = new OtpNode("javanode3","othercookie"); + node3.ping(node1.node(),2000); + node1.ping(node3.node(),2000); + break; + + } + + OtpErlangObject o = mbox.receive(recTime); + if (o == null) System.exit(2); + if (! ((OtpErlangAtom)o).atomValue().equals("done")) + System.exit(3); + + } + catch (Exception e) { + dbg("EXCEPTION: " + e); + System.exit(4); + } + + } + + + + public void remoteStatus(String node, boolean up, Object info) { + try { + dbg("Got remoteStatus: " + node + " " + up + " " + info); + OtpErlangObject[] msgArray = new OtpErlangObject[4]; + msgArray[0] = new OtpErlangAtom("remoteStatus"); + msgArray[1] = new OtpErlangString(node); + msgArray[2] = new OtpErlangBoolean(up); + msgArray[3] = mbox.self(); + OtpErlangTuple msg = new OtpErlangTuple(msgArray); + mbox.send("erl_status_server", erlNode, msg); + + } + catch (Exception e) { + dbg("EXCEPTION in remoteStatus: " + e + "\nArgs: " + + node + " " + up + " " + info); + System.exit(5); + } + } + + + public void localStatus(String node, boolean up, Object info) { + try { + dbg("Got localStatus: " + node + " " + up + " " + info); + OtpErlangObject[] msgArray = new OtpErlangObject[4]; + msgArray[0] = new OtpErlangAtom("localStatus"); + msgArray[1] = new OtpErlangString(node); + msgArray[2] = new OtpErlangBoolean(up); + msgArray[3] = mbox.self(); + OtpErlangTuple msg = new OtpErlangTuple(msgArray); + mbox.send("erl_status_server", erlNode, msg); + + } + catch (Exception e) { + dbg("EXCEPTION in localStatus: " + e + "\nArgs: " + + node + " " + up + " " + info); + System.exit(6); + } + } + + + + public void connAttempt(String node, boolean incoming, Object info) { + try { + dbg("Got connAttempt: " + node + " " + incoming + " " + info); + OtpErlangObject[] msgArray = new OtpErlangObject[4]; + msgArray[0] = new OtpErlangAtom("connAttempt"); + msgArray[1] = new OtpErlangString(node); + msgArray[2] = new OtpErlangBoolean(incoming); + msgArray[3] = mbox.self(); + OtpErlangTuple msg = new OtpErlangTuple(msgArray); + mbox.send("erl_status_server", erlNode, msg); + + } + catch (Exception e) { + dbg("EXCEPTION in connAttempt: " + e + "\nArgs: " + + node + " " + incoming + " " + info); + System.exit(7); + } + } + + + private static void dbg(String str) { + if (dbg) System.out.println(str); + } + +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/Nodename.java b/lib/jinterface/test/jinterface_SUITE_data/Nodename.java new file mode 100644 index 0000000000..dc8cb9c49f --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/Nodename.java @@ -0,0 +1,54 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class Nodename { + + /* + Implements test case jinterface_SUITE:nodename/1 + + */ + + public static void main(String argv[]) { + + String host = argv[0]; + + try { + OtpNode node = new OtpNode("javanode"); + System.out.println("Given host: " + host + + " Host: " + node.host() + + " Alive: " + node.alive() + + " Node: " + node.node()); + + if (!node.host().equals(host)) fail(1); + if (!node.alive().equals("javanode")) fail(2); + if (!node.node().equals("javanode@" + host)) fail(3); + } + catch (Exception e) { + System.out.println("" + e); + fail(4); + } + } + + private static void fail(int reason) { + System.exit(reason); + } + +} diff --git a/lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java b/lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java new file mode 100644 index 0000000000..9df01981b2 --- /dev/null +++ b/lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java @@ -0,0 +1,79 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +class RegisterAndWhereis { + + /* + Implements test case jinterface_SUITE:register_and_whereis/1 + + */ + + public static void main(String argv[]) { + + try { + OtpNode node = new OtpNode("javanode"); + OtpMbox mbox1 = node.createMbox(); + mbox1.registerName("mbox1"); + OtpMbox mbox2 = node.createMbox("mbox2"); + OtpMbox mbox3 = node.createMbox(); + node.registerName("mbox3",mbox3); + + OtpErlangPid pid1 = mbox1.self(); + OtpErlangPid pid2 = mbox2.self(); + OtpErlangPid pid3 = mbox3.self(); + + if (!pid1.equals(node.whereis("mbox1"))) fail(1); + if (!pid1.equals(mbox1.whereis("mbox1"))) fail(2); + if (!pid1.equals(mbox2.whereis("mbox1"))) fail(3); + if (!pid1.equals(mbox3.whereis("mbox1"))) fail(4); + if (!pid2.equals(node.whereis("mbox2"))) fail(5); + if (!pid2.equals(mbox2.whereis("mbox2"))) fail(6); + if (!pid3.equals(node.whereis("mbox3"))) fail(7); + if (!pid3.equals(mbox3.whereis("mbox3"))) fail(8); + + node.closeMbox(mbox1); + mbox2.close(); + + if (node.whereis("mbox1") != null) fail(9); + if (node.whereis("mbox2") != null) fail(10); + if (mbox3.whereis("mbox1") != null) fail(11); + if (mbox3.whereis("mbox2") != null) fail(12); + + mbox3.close(); + if (mbox2.whereis("mbox3") != null) fail(13); + + + + } + catch (Exception e) { + fail("" + e, 14); + } + } + + private static void fail(int reason) { + System.exit(reason); + } + + private static void fail(String str, int reason) { + System.out.println(str); + System.exit(reason); + } +} diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl new file mode 100644 index 0000000000..c57fb9bfad --- /dev/null +++ b/lib/jinterface/test/jitu.erl @@ -0,0 +1,156 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%---------------------------------------------------------------------- +%% JInterface Test Utils +%%---------------------------------------------------------------------- +-module(jitu). + + +-export([java/3, + java/4, + java/5, + init_all/1, + finish_all/1]). + +%% +%% Lots of stuff here are originating from java_client_erl_server_SUITE.erl +%% (ic) ... +%% + + + +java(Java, Dir, ClassAndArgs) -> + cmd(Java++" -classpath "++classpath(Dir)++" "++ClassAndArgs). + +java(Java, Dir, Class, Args) -> + java(Java, Dir, Class++" "++to_string(Args)). + +java(Java, Dir, Class, Args, Props) -> + java(Java, Dir, Props++" "++Class, Args). + + + + +init_all(Config) when list(Config) -> + case find_executable(["java"]) of + false -> {skip,"Found no Java VM"}; + Path -> [{java,Path}|Config] + end. + +finish_all(Config) -> Config. + +%% +%% Internal stuff... +%% + + +find_executable([]) -> + false; +find_executable([E|T]) -> + case os:find_executable(E) of + false -> find_executable(T); + Path -> Path + end. + +to_string([H|T]) when integer(H) -> + integer_to_list(H)++" "++to_string(T); +to_string([H|T]) when atom(H) -> + atom_to_list(H)++" "++to_string(T); +to_string([H|T]) when pid(H) -> + pid_to_list(H)++" "++to_string(T); +to_string([H|T]) when list(H) -> + lists:flatten(H)++" "++to_string(T); +to_string([]) -> []. + +% javac(Dir, File) -> +% cmd("javac -d "++Dir++" -classpath "++classpath(Dir)++" "++ +% filename:join(Dir, File)). + +classpath(Dir) -> + PS = + case os:type() of + {win32, _} -> ";"; + _ -> ":" + end, + Dir++PS++ + filename:join([code:lib_dir(jinterface),"priv","OtpErlang.jar"])++PS++ + case os:getenv("CLASSPATH") of + false -> ""; + Classpath -> Classpath + end. + + +cmd(Cmd) -> + PortOpts = [{line,80},eof,exit_status,stderr_to_stdout], + io:format("cmd: ~s~n", [Cmd]), + case catch open_port({spawn,Cmd}, PortOpts) of + Port when port(Port) -> + Result = cmd_loop(Port, []), + io:format("cmd res: ~w~n", [Result]), + case Result of + 0 -> ok; + ExitCode when integer(ExitCode) -> {error,ExitCode}; + Error -> Error + end; + {'EXIT',Reason} -> + {error,Reason} + end. + +cmd_loop(Port, Line) -> + receive + {Port,eof} -> + receive + {Port,{exit_status,ExitStatus}} -> + ExitStatus + after 1 -> + undefined + end; + {Port,{exit_status,ExitStatus}} -> + receive + {Port,eof} -> + ok after 1 -> ok end, + ExitStatus; + {Port,{data,{Tag,Data}}} -> + case Tag of + eol -> + io:put_chars([Line|cr_to_nl(Data)]), + io:nl(), + cmd_loop(Port, []); + noeol -> + cmd_loop(Port, [Line|cr_to_nl(Data)]) + end; + {'EXIT',Port,Reason} -> + {error,Reason}; + Other -> + io:format("WARNING: Unexpected at ~s:~p: ~p~n", + [?MODULE_STRING,?LINE,Other]), + cmd_loop(Port, Line) + end. + +%% Convert lonely CR to NL, and CRLF to NL +%% +cr_to_nl([$\r,$\n|T]) -> + [$\n|cr_to_nl(T)]; +cr_to_nl([$\r|T]) -> + [$\n|cr_to_nl(T)]; +cr_to_nl([C|T]) -> + [C|cr_to_nl(T)]; +cr_to_nl([]) -> + []. diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl new file mode 100644 index 0000000000..82dd3c2535 --- /dev/null +++ b/lib/jinterface/test/nc_SUITE.erl @@ -0,0 +1,736 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(nc_SUITE). + + +-include("test_server.hrl"). +-include("test_server_line.hrl"). + + +-export([all/1, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + end_per_testcase/2]). + +-export([pid_roundtrip/1, + port_roundtrip/1, + ref_roundtrip/1, + new_float/1, + old_stuff/1, + binary_roundtrip/1, + decompress_roundtrip/1, + compress_roundtrip/1, + integer_roundtrip/1, + fun_roundtrip/1, + lists_roundtrip/1, + lists_roundtrip_2/1, + lists_iterator/1, + unicode/1, + unicode_list_to_string/1, + unicode_string_to_list/1, + connect/1]). + + +%% Top of cases + +all(doc) -> []; +all(suite) -> [pid_roundtrip, + port_roundtrip, + ref_roundtrip, + new_float, + old_stuff, + binary_roundtrip, + decompress_roundtrip, + compress_roundtrip, + integer_roundtrip, + fun_roundtrip, + lists_roundtrip, + lists_roundtrip_2, + lists_iterator, + unicode, + unicode_list_to_string, + unicode_string_to_list, + connect]. + + + + +init_per_suite(Config) when is_list(Config) -> + jitu:init_all(Config). + +end_per_suite(Config) -> + jitu:finish_all(Config). + + + +%% Add/remove watchdog before/after each test case. +%% +init_per_testcase(Case, Config) -> + T = case atom_to_list(Case) of + "unicode"++_ -> 240; + _ -> 20 + end, + WatchDog = test_server:timetrap(test_server:seconds(T)), + [{watchdog, WatchDog}| Config]. + +end_per_testcase(_Case, Config) -> + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + + +%% +%% Test cases +%% + +pid_roundtrip(doc) -> []; +pid_roundtrip(suite) -> []; +pid_roundtrip(Config) when is_list(Config)-> + ThisNode = {node(), erlang:system_info(creation)}, + RemNode = {gurka@sallad, 2}, + do_echo([self(), + mk_pid(ThisNode, 4711, 4711), + mk_pid(ThisNode, 32767, 8191), + mk_pid(RemNode, 4711, 4711), + mk_pid(RemNode, 32767, 8191)], + Config). + +fun_roundtrip(doc) -> []; +fun_roundtrip(suite) -> []; +fun_roundtrip(Config) when is_list(Config)-> + do_echo([fun(A, B) -> A + B end, + fun(A) -> lists:reverse(A) end, + fun() -> ok end, + fun fun_roundtrip/1], + Config). + +port_roundtrip(doc) -> []; +port_roundtrip(suite) -> []; +port_roundtrip(Config) when is_list(Config)-> + ThisNode = {node(), erlang:system_info(creation)}, + RemNode = {gurka@sallad, 2}, + do_echo([hd(erlang:ports()), + mk_port(ThisNode, 4711), + mk_port(ThisNode, 268435455), + mk_port(RemNode, 4711), + mk_port(RemNode, 268435455)], + Config). + +ref_roundtrip(doc) -> []; +ref_roundtrip(suite) -> []; +ref_roundtrip(Config) when is_list(Config)-> + ThisNode = {node(), erlang:system_info(creation)}, + RemNode = {gurka@sallad, 2}, + do_echo([make_ref(), + mk_ref(ThisNode, [4711]), + mk_ref(ThisNode, [4711, 4711, 4711]), + mk_ref(ThisNode, [262143, 4294967295, 4294967295]), + mk_ref(RemNode, [4711]), + mk_ref(RemNode, [4711, 4711, 4711]), + mk_ref(RemNode, [262143, 4294967295, 4294967295])], + Config). + +new_float(doc) -> []; +new_float(suite) -> []; +new_float(Config) when is_list(Config)-> + Two16 = float(1 bsl 16), + X = math:sqrt(2), + Floats = lists:reverse(seq(1/X, 63, fun(Y) -> Y / Two16 end), + [0.0|seq(X, 63, fun(Y) -> Y * Two16 end)]), + io:format("~w", [Floats]), + do_echo(Floats, Config). + +old_stuff(doc) -> []; +old_stuff(suite) -> []; +old_stuff(Config) when is_list(Config)-> + Terms = [0.0,math:sqrt(2)], + OutTrans = + fun (D) -> + {self(),term_to_binary(D, [{minor_version,0}]),binary} + end, + InTrans = + fun (Echoer, D, {Echoer,D,binary}) -> + ok + end, + do_echo(Terms, Config, OutTrans, InTrans). + +binary_roundtrip(doc) -> []; +binary_roundtrip(suite) -> []; +binary_roundtrip(Config) when is_list(Config) -> + do_echo([<<17>>, + <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17>>, + <<3:2>>, + <<3,7:3>>, + <<>>], + Config). + +decompress_roundtrip(doc) -> []; +decompress_roundtrip(suite) -> []; +decompress_roundtrip(Config) when is_list(Config) -> + Terms = + [0.0, + math:sqrt(2), + <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>, + make_ref()], + OutTrans = + fun (D) -> + {self(),term_to_binary(D, [compressed]),binary} + end, + InTrans = + fun (Echoer, D, {Echoer,D,binary}) -> + ok + end, + do_echo(Terms, Config, OutTrans, InTrans). + +compress_roundtrip(doc) -> []; +compress_roundtrip(suite) -> []; +compress_roundtrip(Config) when is_list(Config) -> + Terms = + [0.0, + math:sqrt(2), + <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>, + make_ref()], + OutTrans = + fun (D) -> + {self(),D,compress} + end, + InTrans = + fun (Echoer, D, {Echoer,B,compress}) -> + D = binary_to_term(B) + end, + do_echo(Terms, Config, OutTrans, InTrans). + + + +integer_roundtrip(doc) -> []; +integer_roundtrip(suite) -> []; +integer_roundtrip(Config) when is_list(Config) -> + Xs = [1 bsl X || X <- [26,27,28,29,30,31,32,33, + 62,63,64,65, + 126,127,128,129]], + Terms = [0,1,-1,-2] + ++lists:flatmap(fun (X) -> [X-2,X-1,X,-X+1,-X,-X-1] end, + Xs), + io:format("~w", [Terms]), + OutTrans = + fun (V) -> + {self(),V,bigint} + end, + InTrans = + fun (Echoer, V, {Echoer,{V,W,X,L,U},bigint}) -> + Bitlength = bitlength(V), + {w,W} = {w,signum(V) * Bitlength}, + Y = V band 16#FFFFffffFFFFffff, + {y,Y} = {y,X band 16#FFFFffffFFFFffff}, + {l,L} = {l,if V =:= X, Bitlength < 64 -> 1; + true -> 0 end}, + {u,U} = {u,if V =:= Y, V >= 0, Bitlength =< 64 -> 1; + true -> 0 end} + end, + do_echo(Terms, Config, OutTrans, InTrans). + +signum(V) when is_integer(V), V > 0 -> 1; +signum(V) when is_integer(V), V < 0 -> -1; +signum(0) -> 0. + +bitlength(0) -> + 0; +bitlength(-1) -> + 0; +bitlength(V) when is_integer(V) -> + 1 + bitlength(V bsr 1). + + + +lists_roundtrip(doc) -> []; +lists_roundtrip(suite) -> []; +lists_roundtrip(Config) when is_list(Config) -> + Ls = [lists:seq(1,10), + lists:seq(11,17)++last_tail, + [{default}], + [car|cdr], + [[]], + []], + do_echo(Ls, Config). + + + +lists_roundtrip_2(doc) -> []; +lists_roundtrip_2(suite) -> []; +lists_roundtrip_2(Config) when is_list(Config) -> + Ls = [{[a,b],tail}, + {[c,d,e],tail}, + {[],tail}, + {[f],tail}, + {[g,h|i],tail}, + {[j,k,l|m],tail}, + {[n|o],tail}, + {[z,1,2,3,4],tail3}, + {[z,5,6,7],tail3}, + {[z,8,9],tail3}, + {[z,10],tail3}, + {[],tail3}, + {[z,11,12,13,14|15],tail3}, + {[z,16,17,18|19],tail3}, + {[z,20,21|22],tail3}, + {[z,23|24],tail3}, + {[z|25],tail3}, + {"abc123",sub3atom}, + {"abc",sub3atom} + ], + Trans = + fun ([_|T], tail) -> + T; + (L, tail) when is_list(L) -> + null; + ([_,_,_|T], tail3) -> + T; + (L, tail3) when is_list(L) -> + null; + ([_,_,_|L], sub3atom) -> + list_to_atom(L) + end, + OutTrans = + fun ({L,Twist}) -> + {self(),L,Twist} + end, + InTrans = + fun (Echoer, {L,Twist}, {Echoer,X,Twist}) -> + Y = Trans(L, Twist), + io:format("## ~w ~w ~w ~w~n", [L,Twist,X,Y]), + X = Y + end, + do_echo(Ls, Config, OutTrans, InTrans). + + + + +lists_iterator(doc) -> []; +lists_iterator(suite) -> []; +lists_iterator(Config) when is_list(Config) -> + Ls = [["able ","was ","I ","ere ","I ","saw ","elba"]], + do_echo(Ls, Config, + fun (L) -> {self(),L,strcat} end, + fun (Echoer, L, {Echoer,X,strcat}) -> + io:format("## ~p ~p~n", [L,X]), + X = lists:flatten(L) + end). + + + +unicode(doc) -> []; +unicode(suite) -> []; +unicode(Config) when is_list(Config) -> + S1 = "plain ascii", + S2 = "iso-latin ��� �", + S3 = "Codepoints... ��� \x{1000}", + S4 = [0,1,31,32,63,64,127,128,255], + S5 = [0,1,127,128,255,256,16#d7ff, + 16#e000,16#fffd,16#10000,16#10ffff], + Ss = [S1,S2,S3,S4,S5], + do_echo(unicode_cp_gen([{S,valid} || S <- Ss] ++ cp_gen(71)), Config, + fun ({L,invalid}) -> {self(),L,utf8}; + ({L,Tag}) -> {self(),L,Tag}; + ({L}) -> {self(),L} + end, + fun (Echoer, {L,invalid}=Out, {Echoer,X,utf8}=In) -> + case L of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end; + (Echoer, {L,Tag}=Out, {Echoer,X,Tag}=In) -> + case unicode:characters_to_binary(L, utf8) of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end; + (Echoer, {L}=Out, {Echoer,X}=In) -> + case L of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end + end, ["unicode"]). + +%% Lazy wrapper to lazy list +unicode_cp_gen([{S,valid}|Ss]) -> + [{S,utf8},{S}|unicode_cp_gen(Ss)]; +unicode_cp_gen([{S,invalid}=St|Ss]) -> + [St,{S}|unicode_cp_gen(Ss)]; +unicode_cp_gen([]) -> + []; +unicode_cp_gen(Cont) when is_function(Cont, 0) -> + fun () -> + unicode_cp_gen(Cont()) + end. + + + +unicode_list_to_string(doc) -> []; +unicode_list_to_string(suite) -> []; +unicode_list_to_string(Config) when is_list(Config) -> + do_echo(cp_gen(73), Config, + fun ({L,_}) -> {self(),L,to_string_neg_int_list} end, + fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) -> + case L of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end; + (Echoer, {L,valid}=Out, {Echoer,X,_}=In) -> + B = unicode:characters_to_binary(L, unicode, {utf16,big}), + case [-D || <<D:16/big>> <= B] of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end + end). + + + +unicode_string_to_list(doc) -> []; +unicode_string_to_list(suite) -> []; +unicode_string_to_list(Config) when is_list(Config) -> + do_echo(cp_gen(79), Config, + fun ({L,_}) -> {self(),L,to_neg_int_list} end, + fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) -> + case L of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end; + (Echoer, {L,valid}=Out, {Echoer,X,_}=In) -> + case [-C || C <- L] of + X -> ok; + _ -> + ?t:fail({mismatch,Out,In}) + end + end, ["unicode"]). + + +%% Lazy list +cp_gen(N) -> + cp_gen(N, -1, 16#110000). + +cp_gen(N, Start, End) -> + cp_gen(N, Start, End, cp_validity(Start), [], 0, [], 0). + +cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Len >= N -> + cp_gen(N, U, End, PrevValidity, [], 0, [{Acc,PrevValidity}|Ss], Ls+1); +cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Ls >= N -> + Ss ++ fun () -> + cp_gen(N, U, End, PrevValidity, Acc, Len, [], 0) + end; +cp_gen(_, U, End, _, Acc, _, Ss, _) when U > End -> + [{Acc,valid}|Ss]; +cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) -> + Validity = cp_validity(U), + NextU = U+1, + {NextAcc,NextLen} = case Validity of + valid -> {[U|Acc],Len+1}; + invalid -> {Acc,Len} + end, + {NextSs,NextLs} = case Validity of + PrevValidity -> {Ss,Ls}; + valid -> {[{[U-1],PrevValidity}|Ss],Ls+1}; + invalid -> {[{[U],Validity}|Ss],Ls+1} + end, + cp_gen(N, NextU, End, Validity, NextAcc, NextLen, NextSs, NextLs). + +cp_validity(UnicodeCP) -> + try <<UnicodeCP/big-utf32>> of + _ -> valid + catch + error:_ -> invalid + end. + + + +connect(doc) -> []; +connect(suite) -> []; +connect(Config) when is_list(Config) -> + WD = filename:dirname(code:which(?MODULE)), + {ok,Other} = ?t:start_node(make_name(), slave, [{args,"-pa "++WD}]), + Action = + fun (Pid) -> + JName = node(Pid), + Hidden = [JName], + Pid ! {self(),Other}, + receive + {Pid,Other,true} -> + ok; + Unexpected1 -> + ?t:fail({result,Unexpected1}) + end, + Hidden = erlang:nodes(hidden), + Hidden = rpc:call(Other, erlang, nodes, [hidden]), + true = + rpc:call(Other, erlang, disconnect_node, [JName]), + [] = + rpc:call(Other, erlang, nodes, [hidden]), + Hidden = erlang:nodes(hidden), + %% Again + receive after 2000 -> ok end, + %% We have no way of knowing when the Java node + %% detects the nodedown. + Pid ! {self(),Other}, + receive + {Pid,Other,true} -> + ok; + Unexpected2-> + ?t:fail({result,Unexpected2}) + end, + Hidden = rpc:call(Other, erlang, nodes, [hidden]) + end, + run_server(connection_server, Config, Action, []). + + + +seq(_, 0, _) -> + []; +seq(X, N, Fun) -> + [X|seq(Fun(X), N-1, Fun)]. + +do_echo(DataList, Config) -> + do_echo(DataList, Config, + fun (D) -> % OutTrans + {self(),D} + end, + fun (Echoer, D, {Echoer,D}) -> % InTrans + ok + end, []). + +do_echo(DataList, Config, OutTrans, InTrans) -> + do_echo(DataList, Config, OutTrans, InTrans, []). + +do_echo(DataList, Config, OutTrans, InTrans, ExtraArgs) + when is_list(DataList), is_list(Config) -> + run_server(echo_server, Config, + fun (Echoer) -> + echo_loop(DataList, Echoer, OutTrans, InTrans, []) + end, + ExtraArgs). + +echo_loop([D|Ds], Echoer, OutTrans, InTrans, TermAcc) -> + OutMsg = OutTrans(D), + Echoer ! OutMsg, + io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]), + receive + Reply -> + io:format("echo_server ~p: receive ~P~n", + [self(),Reply,10]), + InTrans(Echoer, D, Reply) + end, + Term = case OutMsg of + {_, T, _} -> T; + {_, T} -> T + end, + echo_loop(Ds, Echoer, OutTrans, InTrans, [Term | TermAcc]); +echo_loop([], Echoer, _, _, TermAcc) -> + check_terms(Echoer, TermAcc); +%% Lazy list +echo_loop(Cont, Echoer, OutTrans, InTrans, TermAcc) + when is_function(Cont, 0) -> + check_terms(Echoer, TermAcc), + OutMsg = Echoer ! {self(),undefined,hash_clear}, + io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]), + receive + {Echoer,hash_cleared,hash_clear}=Reply -> + io:format("echo_server ~p: receive ~P~n", + [self(),Reply,10]), + ok; + Other -> + io:format("echo_server_terms unexpected ~p: receive ~P~n", + [self(),Other,10]), + ?t:fail({unexpected, Other}) + end, + echo_loop(Cont(), Echoer, OutTrans, InTrans, []). + +check_terms(Echoer, [Term | Rest]) -> + OutMsg = {self(),Term,hash_lookup}, + Echoer ! OutMsg, + io:format("check_terms ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]), + receive + {Echoer,true,hash_lookup} = ReplyMsg -> + io:format("check_terms ~p: receive ~P~n", + [self(),ReplyMsg,10]), + check_terms(Echoer, Rest); + Other -> + io:format("check_terms unexpected ~p: receive ~P~n", + [self(),Other,10]), + ?t:fail({unexpected, Other}) + end; +check_terms(_, []) -> + ok. + +run_server(Server, Config, Action, ExtraArgs) -> + Name = make_name(), + true = register(Name, self()), + JName = make_name(), + spawn_link(fun () -> + ok = jitu:java(?config(java, Config), + ?config(data_dir, Config), + atom_to_list(Server), + [JName, + erlang:get_cookie(), + node(), + Name]++ExtraArgs + ), + %,"-DOtpConnection.trace=3"), + Name ! {done, JName} + end), + receive + {Server, JName, Pid} -> + ?t:format("~w: ~p (~p)~n", + [Server, Pid, node(Pid)]), + ?t:format("nodes(hidden): ~p~n", + [nodes(hidden)]), + Action(Pid), + Pid ! bye, + receive + {done, JName} -> + ok + end; + Other -> + ?t:fail({unexpected,Other}) + end. + +%% +%% Utils... +%% + +make_name() -> + {A, B, C} = now(), + list_to_atom(atom_to_list(?MODULE) + ++ "-" ++ integer_to_list(A) + ++ "-" ++ integer_to_list(B) + ++ "-" ++ integer_to_list(C)). + + + +-define(VERSION_MAGIC, 131). + +-define(ATOM_EXT, 100). +-define(REFERENCE_EXT, 101). +-define(PORT_EXT, 102). +-define(PID_EXT, 103). +-define(NEW_REFERENCE_EXT, 114). + +uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> + [(Uint bsr 24) band 16#ff, + (Uint bsr 16) band 16#ff, + (Uint bsr 8) band 16#ff, + Uint band 16#ff]; +uint32_be(Uint) -> + exit({badarg, uint32_be, [Uint]}). + + +uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> + [(Uint bsr 8) band 16#ff, + Uint band 16#ff]; +uint16_be(Uint) -> + exit({badarg, uint16_be, [Uint]}). + +uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> + Uint band 16#ff; +uint8(Uint) -> + exit({badarg, uint8, [Uint]}). + + + +mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> + mk_pid({atom_to_list(NodeName), Creation}, Number, Serial); +mk_pid({NodeName, Creation}, Number, Serial) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?PID_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint32_be(Serial), + uint8(Creation)])) of + Pid when is_pid(Pid) -> + Pid; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> + mk_port({atom_to_list(NodeName), Creation}, Number); +mk_port({NodeName, Creation}, Number) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?PORT_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint8(Creation)])) of + Port when is_port(Port) -> + Port; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_port, [{NodeName, Creation}, Number]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), + is_integer(Creation), + is_list(Numbers) -> + mk_ref({atom_to_list(NodeName), Creation}, Numbers); +mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName), + is_integer(Creation), + is_integer(Number) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?REFERENCE_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint8(Creation)])) of + Ref when is_reference(Ref) -> + Ref; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end; +mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), + is_integer(Creation), + is_list(Numbers) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?NEW_REFERENCE_EXT, + uint16_be(length(Numbers)), + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint8(Creation), + lists:map(fun (N) -> + uint32_be(N) + end, + Numbers)])) of + Ref when is_reference(Ref) -> + Ref; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. diff --git a/lib/jinterface/test/nc_SUITE_data/Makefile.src b/lib/jinterface/test/nc_SUITE_data/Makefile.src new file mode 100644 index 0000000000..3d131250be --- /dev/null +++ b/lib/jinterface/test/nc_SUITE_data/Makefile.src @@ -0,0 +1,53 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# Makefile.src for java_client_erl_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .java + + +JAVAC = @JAVAC@ +ERLC = erlc + +JINTERFACE_CLASSPATH = @jinterface_classpath@ + +CLASSPATH = .@PS@$(JINTERFACE_CLASSPATH)@PS@ + +JAVA_FILES = echo_server.java connection_server.java +CLASS_FILES = $(JAVA_FILES:.java=.class) + +all: $(CLASS_FILES) + +clean: + -rm -f $(CLASS_FILES) + -del /F /Q $(CLASS_FILES) + +$(CLASS_FILES) : $(JAVA_FILES) + $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES) + +# diff --git a/lib/jinterface/test/nc_SUITE_data/connection_server.java b/lib/jinterface/test/nc_SUITE_data/connection_server.java new file mode 100644 index 0000000000..19ed1c7d5c --- /dev/null +++ b/lib/jinterface/test/nc_SUITE_data/connection_server.java @@ -0,0 +1,96 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import com.ericsson.otp.erlang.*; + +public class connection_server { + static java.lang.String Name = "connection_server"; + + public static void main(String[] argv) { + try { + System.out.println("connection_server booting..."); + + for (int j = 0; j < argv.length; j++) + System.out.println("argv[" + j + "] = \"" + argv[j] + "\""); + + if (argv.length != 4) { + System.out.println("Wrong number of arguments!"); + System.exit(1); + } + + // Start node and mbox + OtpNode node = new OtpNode(argv[0], argv[1]); + OtpMbox mbox = node.createMbox(); + if (! mbox.registerName(Name)) { + System.out.println("Could not register name " + Name); + System.exit(3); + } + + // Announce our presence + OtpErlangObject[] amsg = new OtpErlangObject[3]; + amsg[0] = new OtpErlangAtom(Name); + amsg[1] = new OtpErlangAtom(argv[0]); + amsg[2] = mbox.self(); + OtpErlangTuple atuple = new OtpErlangTuple(amsg); + mbox.send(argv[3], argv[2], atuple); + + // Do connects ... + while (true) { + OtpErlangObject o = mbox.receive(); + if (o == null) + continue; + if (o instanceof OtpErlangTuple) { + OtpErlangTuple msg = (OtpErlangTuple) o; + OtpErlangPid from = (OtpErlangPid)(msg.elementAt(0)); + OtpErlangAtom conn_node = (OtpErlangAtom) msg.elementAt(1); + + System.out.println("Got request to connect to: " + + conn_node); + OtpErlangObject[] rmsg = new OtpErlangObject[3]; + rmsg[0] = mbox.self(); + rmsg[1] = conn_node; + if (node.ping(conn_node.atomValue(), 1000)) { + System.out.println("Successfully connected to " + + conn_node.toString()); + rmsg[2] = new OtpErlangAtom("true"); + } + else { + System.out.println("Failed to connect to " + + conn_node.toString()); + rmsg[2] = new OtpErlangAtom("false"); + } + + OtpErlangTuple rtuple = new OtpErlangTuple(rmsg); + + mbox.send(from, rtuple); + } + else { // probably 'bye' + System.out.println("connection_server halting..."); + System.exit(0); + } + } + } + catch (Exception e) { + System.out.println("" + e); + System.exit(2); + } + + } + +} diff --git a/lib/jinterface/test/nc_SUITE_data/echo_server.java b/lib/jinterface/test/nc_SUITE_data/echo_server.java new file mode 100644 index 0000000000..0550e4beb1 --- /dev/null +++ b/lib/jinterface/test/nc_SUITE_data/echo_server.java @@ -0,0 +1,261 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +import java.io.UnsupportedEncodingException; +import java.util.HashSet; + +import com.ericsson.otp.erlang.OtpErlangAtom; +import com.ericsson.otp.erlang.OtpErlangBinary; +import com.ericsson.otp.erlang.OtpErlangBoolean; +import com.ericsson.otp.erlang.OtpErlangException; +import com.ericsson.otp.erlang.OtpErlangInt; +import com.ericsson.otp.erlang.OtpErlangList; +import com.ericsson.otp.erlang.OtpErlangLong; +import com.ericsson.otp.erlang.OtpErlangObject; +import com.ericsson.otp.erlang.OtpErlangPid; +import com.ericsson.otp.erlang.OtpErlangString; +import com.ericsson.otp.erlang.OtpErlangTuple; +import com.ericsson.otp.erlang.OtpExternal; +import com.ericsson.otp.erlang.OtpInputStream; +import com.ericsson.otp.erlang.OtpMbox; +import com.ericsson.otp.erlang.OtpNode; +import com.ericsson.otp.erlang.OtpOutputStream; + +public class echo_server { + private static boolean debug = false; + + public static void main(final String[] argv) { + try { + System.out.println("echo_server booting..."); + + for (int j = 0; j < argv.length; j++) { + System.out.println("argv[" + j + "] = \"" + argv[j] + "\""); + } + + if (argv.length != 4 && argv.length != 5) { + System.out.println("Wrong number of arguments!"); + System.exit(1); + } + + // Start node and mbox + final OtpNode node = new OtpNode(argv[0], argv[1]); + if (argv.length == 5 && argv[4].equals("unicode")) { + System.out.println("Setting unicode string mode."); + node.setFlags(OtpInputStream.DECODE_INT_LISTS_AS_STRINGS); + } + final OtpMbox mbox = node.createMbox(); + + // Announce our presence + final OtpErlangObject[] amsg = new OtpErlangObject[3]; + amsg[0] = new OtpErlangAtom("echo_server"); + amsg[1] = new OtpErlangAtom(argv[0]); + amsg[2] = mbox.self(); + final OtpErlangTuple atuple = new OtpErlangTuple(amsg); + mbox.send(argv[3], argv[2], atuple); + + // Do echoing... + while (true) { + final OtpErlangObject o = mbox.receive(); + if (o == null) { + continue; + } + if (o instanceof OtpErlangTuple) { + final OtpErlangTuple msg = (OtpErlangTuple) o; + final int arity = msg.arity(); + if (arity < 2) { + System.out + .println("Arity < 2; echo_server aborting..."); + System.exit(2); + } else if (arity == 2) { + final OtpErlangPid from = (OtpErlangPid) msg + .elementAt(0); + if (debug) System.out.println("Echoing: " + + msg.elementAt(1)); + + final OtpErlangObject[] rmsg = new OtpErlangObject[2]; + rmsg[0] = mbox.self(); + rmsg[1] = msg.elementAt(1); + final OtpErlangTuple rtuple = new OtpErlangTuple(rmsg); + + mbox.send(from, rtuple); + continue; + } else if (arity == 3) { + echoTwisted(mbox, msg); + continue; + } else { + System.out + .println("Arity > 3; echo_server aborting..."); + System.exit(2); + } + } else if (o instanceof OtpErlangAtom) { + OtpErlangAtom a = (OtpErlangAtom) o; + if (a.atomValue().equals("debug")) { + debug = true; + } else if (a.atomValue().equals("bye")) { + System.out.println("echo_server halting..."); + System.exit(0); + } + } else { // probably 'bye' + } + System.out.println("Unexpected: " + o + + " echo_server aborting..."); + System.exit(2); + } + } catch (final Exception e) { + System.out.println("" + e); + System.exit(2); + } + } + + private static void echoTwisted(final OtpMbox mbox, + final OtpErlangTuple msg) + throws OtpErlangException { + final OtpErlangPid from = (OtpErlangPid) msg.elementAt(0); + + final OtpErlangObject[] rmsg = new OtpErlangObject[3]; + if (debug) System.out.println("Echo in: " + msg); + rmsg[0] = mbox.self(); + rmsg[1] = twist(msg.elementAt(1), rmsg[2] = msg.elementAt(2)); + final OtpErlangTuple rtuple = new OtpErlangTuple(rmsg); + if (debug) System.out.println("Echo out: " + rtuple); + + mbox.send(from, rtuple); + } + + private static HashSet<OtpErlangObject> hash_set = + new HashSet<OtpErlangObject>(); + + private static OtpErlangObject twist(final OtpErlangObject i, + final OtpErlangObject t) throws OtpErlangException { + hash_set.add(i); + if (t instanceof OtpErlangAtom) { + final String atomValue = ((OtpErlangAtom) t).atomValue(); + if (atomValue.equals("binary") && i instanceof OtpErlangBinary) { + final OtpErlangBinary b = (OtpErlangBinary) i; + final OtpInputStream bis = new OtpInputStream(b.binaryValue(), + 0); + final OtpErlangObject o = bis.read_any(); + return o; + } else if (atomValue.equals("compress")) { + final OtpOutputStream oos = new OtpOutputStream(); + oos.write1(OtpExternal.versionTag); + oos.write_compressed(i); + final OtpErlangBinary o = + new OtpErlangBinary(oos.toByteArray()); + return o; + } else if (atomValue.equals("bigint") + && i instanceof OtpErlangLong) { + final OtpErlangLong l = (OtpErlangLong) i; + final int w = l.signum() * l.bitLength(); + final OtpErlangLong x = new OtpErlangLong(l.longValue()); + final java.math.BigInteger b = l.bigIntegerValue(); + System.out.println("long: " + l + ": " + w + ": " + b.signum() + * b.bitLength() + ": " + x + ": " + l.isLong() + ": " + + l.isULong()); + return new OtpErlangTuple(new OtpErlangObject[] { l, + new OtpErlangInt(w), x, + new OtpErlangInt(l.isLong() ? 1 : 0), + new OtpErlangInt(l.isULong() ? 1 : 0) }); + } else if (atomValue.equals("tail") + && i instanceof OtpErlangList) { + final OtpErlangObject o = ((OtpErlangList) i).getTail(); + if (o == null) { + return new OtpErlangAtom("null"); + } + return o; + } else if (atomValue.equals("tail3") + && i instanceof OtpErlangList) { + final OtpErlangObject o = ((OtpErlangList) i).getNthTail(3); + if (o == null) { + return new OtpErlangAtom("null"); + } + return o; + } else if (atomValue.equals("strcat") + && i instanceof OtpErlangList) { + final java.lang.StringBuffer b = new java.lang.StringBuffer(); + final OtpErlangList l = (OtpErlangList) i; + for (final OtpErlangObject j : l) { + final OtpErlangString k = (OtpErlangString) j; + b.append(k.stringValue()); + } + final OtpErlangObject o = new OtpErlangString(b.toString()); + return o; + } else if (atomValue.equals("sub3atom") + && i instanceof OtpErlangString) { + final OtpErlangString s = (OtpErlangString) i; + final OtpErlangAtom o = new OtpErlangAtom(s.stringValue() + .substring(3)); + return o; + } else if (atomValue.equals("utf8")) { + if (i instanceof OtpErlangString) { + final OtpErlangString s = (OtpErlangString) i; + byte[] bytes; + try { + bytes = s.stringValue().getBytes("UTF-8"); + } catch (final UnsupportedEncodingException e) { + bytes = new byte[] { 'e', 'r', 'r', 'o', 'r' }; + } + final OtpErlangBinary b = new OtpErlangBinary(bytes); + return b; + } + } else if(atomValue.equals("to_string_neg_int_list")) { + OtpErlangString oes = null; + if (i instanceof OtpErlangString) { + oes = (OtpErlangString) i; + } else if (i instanceof OtpErlangList) { + OtpErlangList oel = (OtpErlangList) i; + try { + oes = new OtpErlangString(oel); + } catch (final Exception e) { + } + } + if (oes != null) { + String s = oes.stringValue(); + int n = s.length(); + OtpErlangObject l[] = new OtpErlangObject[n]; + for (int j = 0; j < n; j++) { + int c = s.charAt(j); + l[j] = new OtpErlangInt(-c); + } + return new OtpErlangList(l); + } + } else if(atomValue.equals("to_neg_int_list")) { + if (i instanceof OtpErlangString) { + OtpErlangString oes = (OtpErlangString) i; + OtpErlangList oel = new OtpErlangList(oes.stringValue()); + int n = oel.arity(); + OtpErlangObject l[] = new OtpErlangObject[n]; + for (int j = 0; j < n; j++) { + OtpErlangLong c = (OtpErlangLong) oel.elementAt(j); + l[j] = new OtpErlangInt(-c.intValue()); + } + return new OtpErlangList(l); + } + } else if (atomValue.equals("hash_lookup")) { + final boolean exists = hash_set.contains(i); + final OtpErlangBoolean b = new OtpErlangBoolean(exists); + return b; + } else if (atomValue.equals("hash_clear")) { + hash_set.clear(); + return new OtpErlangAtom("hash_cleared"); + } + } + return i; + } +} |