diff options
Diffstat (limited to 'erts/emulator/test/send_term_SUITE.erl')
-rw-r--r-- | erts/emulator/test/send_term_SUITE.erl | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/erts/emulator/test/send_term_SUITE.erl b/erts/emulator/test/send_term_SUITE.erl new file mode 100644 index 0000000000..489adbd660 --- /dev/null +++ b/erts/emulator/test/send_term_SUITE.erl @@ -0,0 +1,354 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. 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(send_term_SUITE). + +-export([all/1,basic/1]). +-export([init_per_testcase/2,fin_per_testcase/2]). + +-export([generate_external_terms_files/1]). + +-include("test_server.hrl"). + +init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> + Dog=?t:timetrap(?t:minutes(3)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Func, Config) -> + Dog=?config(watchdog, Config), + ?t:timetrap_cancel(Dog). + +all(suite) -> + [basic]. + +basic(Config) when is_list(Config) -> + Drv = "send_term_drv", + ?line P = start_driver(Config, Drv), + + ?line [] = term(P, 0), + ?line Self = self(), + ?line {blurf,42,[],[-42,{}|"abc"++P],"kalle",3.1416,Self} = term(P, 1), + ?line Deep = lists:seq(0, 199), + ?line Deep = term(P, 2), + ?line {B1,B2} = term(P, 3), + ?line B1 = list_to_binary(lists:seq(0, 255)), + ?line B2 = list_to_binary(lists:seq(23, 255-17)), + + %% Pid sending. We need another process. + ?line Child = spawn_link(fun() -> + erlang:port_command(P, [4]) + end), + ?line {Self,Child} = receive_any(), + + %% ERL_DRV_EXT2TERM + ?line ExpectExt2Term = expected_ext2term_drv(?config(data_dir, Config)), + ?line ExpectExt2Term = term(P, 5), + + %% ERL_DRV_INT, ERL_DRV_UINT + ?line case erlang:system_info(wordsize) of + 4 -> + ?line {-1, 4294967295} = term(P, 6); + 8 -> + ?line {-1, 18446744073709551615} = term(P, 6) + end, + + %% ERL_DRV_BUF2BINARY + ?line ExpectedBinTup = {<<>>, + <<>>, + list_to_binary(lists:duplicate(17,17)), + list_to_binary(lists:duplicate(1024,17))}, + ?line ExpectedBinTup = term(P, 7), + + %% single terms + ?line [] = term(P, 8), % ERL_DRV_NIL + ?line '' = term(P, 9), % ERL_DRV_ATOM + ?line an_atom = term(P, 10), % ERL_DRV_ATOM + ?line -4711 = term(P, 11), % ERL_DRV_INT + ?line 4711 = term(P, 12), % ERL_DRV_UINT + ?line P = term(P, 13), % ERL_DRV_PORT + ?line <<>> = term(P, 14), % ERL_DRV_BINARY + ?line <<"hejsan">> = term(P, 15), % ERL_DRV_BINARY + ?line <<>> = term(P, 16), % ERL_DRV_BUF2BINARY + ?line <<>> = term(P, 17), % ERL_DRV_BUF2BINARY + ?line <<"hoppsan">> = term(P, 18), % ERL_DRV_BUF2BINARY + ?line "" = term(P, 19), % ERL_DRV_STRING + ?line "" = term(P, 20), % ERL_DRV_STRING + ?line "hippsan" = term(P, 21), % ERL_DRV_STRING + ?line {} = term(P, 22), % ERL_DRV_TUPLE + ?line [] = term(P, 23), % ERL_DRV_LIST + ?line Self = term(P, 24), % ERL_DRV_PID + ?line [] = term(P, 25), % ERL_DRV_STRING_CONS + ?line AFloat = term(P, 26), % ERL_DRV_FLOAT + ?line true = AFloat < 0.001, + ?line true = AFloat > -0.001, + ?line [] = term(P, 27), % ERL_DRV_EXT2TERM + ?line 18446744073709551615 = term(P, 28), % ERL_DRV_UINT64 + ?line 20233590931456 = term(P, 29), % ERL_DRV_UINT64 + ?line 4711 = term(P, 30), % ERL_DRV_UINT64 + ?line 0 = term(P, 31), % ERL_DRV_UINT64 + ?line 9223372036854775807 = term(P, 32), % ERL_DRV_INT64 + ?line 20233590931456 = term(P, 33), % ERL_DRV_INT64 + ?line 4711 = term(P, 34), % ERL_DRV_INT64 + ?line 0 = term(P, 35), % ERL_DRV_INT64 + ?line -1 = term(P, 36), % ERL_DRV_INT64 + ?line -4711 = term(P, 37), % ERL_DRV_INT64 + ?line -20233590931456 = term(P, 38), % ERL_DRV_INT64 + ?line -9223372036854775808 = term(P, 39), % ERL_DRV_INT64 + + %% Failure cases. + ?line [] = term(P, 127), + ?line receive + Any -> + ?line io:format("Unexpected: ~p\n", [Any]), + ?line ?t:fail() + after 0 -> + ok + end, + + ?line ok = chk_temp_alloc(), + + %% In a private heap system, verify that there are no binaries + %% left for the process. + ?line erlang:garbage_collect(), %Get rid of binaries. + case erlang:system_info(heap_type) of + private -> + ?line {binary,[]} = process_info(self(), binary); + _ -> ok + end, + + ?line stop_driver(P, Drv), + ok. + +term(P, Op) -> + erlang:port_command(P, [Op]), + receive_any(). + +receive_any() -> + receive + Any -> Any + end. + +chk_temp_alloc() -> + case erlang:system_info({allocator,temp_alloc}) of + false -> + %% Temp alloc is not enabled + ?line ok; + TIL -> + %% Verify that we havn't got anything allocated by temp_alloc + lists:foreach( + fun ({instance, _, TI}) -> + ?line {value, {mbcs, MBCInfo}} + = lists:keysearch(mbcs, 1, TI), + ?line {value, {blocks, 0, _, _}} + = lists:keysearch(blocks, 1, MBCInfo), + ?line {value, {sbcs, SBCInfo}} + = lists:keysearch(sbcs, 1, TI), + ?line {value, {blocks, 0, _, _}} + = lists:keysearch(blocks, 1, SBCInfo) + end, + TIL), + ?line ok + end. + + +%% Start/stop drivers. +start_driver(Config, Name) -> + Path = ?config(data_dir, Config), + erl_ddll:start(), + ok = load_driver(Path, Name), + open_port({spawn, Name}, []). + +load_driver(Dir, Driver) -> + case erl_ddll:load_driver(Dir, Driver) of + ok -> ok; + {error, Error} = Res -> + io:format("~s\n", [erl_ddll:format_error(Error)]), + Res + end. + +stop_driver(Port, Name) -> + ?line true = erlang:port_close(Port), + receive + {Port,Message} -> + ?t:fail({strange_message_from_port,Message}) + after 0 -> + ok + end, + + %% Unload the driver. + ok = erl_ddll:unload_driver(Name), + ?line ok = erl_ddll:stop(). + +get_external_terms(DataDir) -> + {ok, Bin} = file:read_file([DataDir, "ext_terms.bin"]), + binary_to_term(Bin). + +expected_ext2term_drv(DataDir) -> + make_expected_ext2term_drv(get_external_terms(DataDir)). + +make_expected_ext2term_drv([]) -> + []; +make_expected_ext2term_drv([T|Ts]) -> + [{T, T} | make_expected_ext2term_drv(Ts)]. + +%% +%% Generation of send_term_SUITE_data/ext_terms.h and +%% send_term_SUITE_data/ext_terms.bin +%% +%% These files should normally not need to be regenerated, +%% but we may want that if we introduce new types or make +%% backward incompatible changes to the external format. +%% + +generate_external_terms_files(BaseDir) -> + {ok,Node} = slave:start(hostname(), a_node), + RPid = rpc:call(Node, erlang, self, []), + true = is_pid(RPid), + RRef = rpc:call(Node, erlang, make_ref, []), + true = is_reference(RRef), + RPort = hd(rpc:call(Node, erlang, ports, [])), + true = is_port(RPort), + slave:stop(Node), + Terms = + [{4711, -4711, [an_atom, "a list"]}, + [1000000000000000000000,-1111111111111111, "blupp!", blipp], + {RPid, {RRef, RPort}, self(), hd(erlang:ports()), make_ref()}, + {{}, [], [], fun () -> ok end, <<"hej hopp trallalaaaaaaaaaaaaaaa">>}, + [44444444444444444444444,-44444444444, "b!", blippppppp], + {4711, RPid, {RRef, RPort}, -4711, [an_atom, "a list"]}, + {RPid, {RRef, RPort}, hd(processes()), hd(erlang:ports())}, + {4711, -4711, [an_atom, "a list"]}, + {4711, -4711, [atom, "list"]}, + {RPid, {RRef, RPort}, hd(processes()), hd(erlang:ports())}, + {4444444444444444444,-44444, {{{{{{{{{{{{}}}}}}}}}}}}, make_ref()}, + {444444444444444444444,-44444, [[[[[[[[[[[1]]]]]]]]]]], make_ref()}, + {444444444444444444,-44444, {{{{{{{{{{{{2}}}}}}}}}}}}, make_ref()}, + {4444444444444444444444,-44444, {{{{{{{{{{{{3}}}}}}}}}}}}, make_ref()}, + {44444444444444444444,-44444, {{{{{{{{{{{{4}}}}}}}}}}}}, make_ref()}, + {4444444444444444,-44444, [[[[[[[[[[[5]]]]]]]]]]], make_ref()}, + {444444444444444444444,-44444, {{{{{{{{{{{{6}}}}}}}}}}}}, make_ref()}, + {444444444444444,-44444, {{{{{{{{{{{{7}}}}}}}}}}}}, make_ref()}, + {4444444444444444444,-44444, {{{{{{{{{{{{8}}}}}}}}}}}}, make_ref()}], + ok = file:write_file(filename:join([BaseDir, + "send_term_SUITE_data", + "ext_terms.bin"]), + term_to_binary(Terms, [compressed])), + {ok, IoDev} = file:open(filename:join([BaseDir, + "send_term_SUITE_data", + "ext_terms.h"]), + [write]), + write_ext_terms_h(IoDev, Terms), + file:close(IoDev). + +write_ext_terms_h(IoDev, Terms) -> + write_license(IoDev), + io:format(IoDev, "#ifndef EXT_TERMS_H__~n",[]), + io:format(IoDev, "#define EXT_TERMS_H__~n",[]), + {ExtTerms, MaxSize} = make_ext_terms(Terms), + io:format(IoDev, + "static struct {~n" + " unsigned char ext[~p];~n" + " int ext_size;~n" + " unsigned char cext[~p];~n" + " int cext_size;~n" + "} ext_terms[] = {~n",[MaxSize, MaxSize]), + E = write_ext_terms_h(IoDev, ExtTerms, 0), + io:format(IoDev, "};~n",[]), + io:format(IoDev, "#define NO_OF_EXT_TERMS ~p~n", [E]), + io:format(IoDev, "#endif~n",[]). + +make_ext_terms([]) -> + {[], 0}; +make_ext_terms([T|Ts]) -> + E = term_to_binary(T), + ESz = size(E), + CE = term_to_binary(T, [compressed]), + CESz = size(CE), + true = CESz =< ESz, % Assertion + {ExtTerms, MaxSize} = make_ext_terms(Ts), + NewMaxSize = case MaxSize < ESz of + true -> ESz; + false -> MaxSize + end, + {[{E, ESz, CE, CESz} | ExtTerms], NewMaxSize}. + +write_ext_terms_h(IoDev, [], N) -> + io:format(IoDev, "~n",[]), + N; +write_ext_terms_h(IoDev, [ET|ETs], 0) -> + write_ext_term(IoDev, ET), + write_ext_terms_h(IoDev, ETs, 1); +write_ext_terms_h(IoDev, [ET|ETs], N) -> + io:format(IoDev, ",~n",[]), + write_ext_term(IoDev, ET), + write_ext_terms_h(IoDev, ETs, N+1). + +write_ext_term(IoDev, {E, ESz, CE, CESz}) -> + ESz = write_bytes(IoDev, " {{", binary_to_list(E), 0), + io:format(IoDev, + ",~n" + " ~p,~n", + [ESz]), + CESz = write_bytes(IoDev, " {", binary_to_list(CE), 0), + io:format(IoDev, + ",~n" + " ~p}", + [CESz]). + +write_bytes(IoDev, _, [], N) -> + io:format(IoDev, "}",[]), + N; +write_bytes(IoDev, Prefix, [B|Bs], N) -> + io:format(IoDev, "~s~w", [Prefix, B]), + write_bytes(IoDev, ",", Bs, N+1). + +write_license(IoDev) -> + S = "/* ``The contents of this file are subject to the Erlang Public License,~n" + " * Version 1.1, (the \"License\"); you may not use this file except in~n" + " * compliance with the License. You should have received a copy of the~n" + " * Erlang Public License along with this software. If not, it can be~n" + " * retrieved via the world wide web at http://www.erlang.org/.~n" + " * ~n" + " * Software distributed under the License is distributed on an \"AS IS\"~n" + " * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See~n" + " * the License for the specific language governing rights and limitations~n" + " * under the License.~n" + " * ~n" + " * The Initial Developer of the Original Code is Ericsson AB.~n" + " * Portions created by Ericsson are Copyright 2007, Ericsson AB.~n" + " * All Rights Reserved.''~n" + " * ~n" + " * $Id$~n" + " */~n" + "~n" + "/*~n" + " * Do not modify this file. This file and ext_terms.bin were~n" + " * automatically generated by send_term_SUITE:generate_external_terms_files/1~n" + " * and needs to be consistent with each other.~n" + " */~n", + io:format(IoDev, S, []). + + +hostname() -> + hostname(atom_to_list(node())). + +hostname([$@ | Hostname]) -> + list_to_atom(Hostname); +hostname([_C | Cs]) -> + hostname(Cs). |