1: %% -*- coding: utf-8 -*- 2: %% 3: %% %CopyrightBegin% 4: %% 5: %% Copyright Ericsson AB 2004-2013. All Rights Reserved. 6: %% 7: %% The contents of this file are subject to the Erlang Public License, 8: %% Version 1.1, (the "License"); you may not use this file except in 9: %% compliance with the License. You should have received a copy of the 10: %% Erlang Public License along with this software. If not, it can be 11: %% retrieved online at http://www.erlang.org/. 12: %% 13: %% Software distributed under the License is distributed on an "AS IS" 14: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 15: %% the License for the specific language governing rights and limitations 16: %% under the License. 17: %% 18: %% %CopyrightEnd% 19: %% 20: -module(nc_SUITE). 21: 22: 23: -include_lib("common_test/include/ct.hrl"). 24: -include("test_server_line.hrl"). 25: 26: -define(VERSION_MAGIC, 131). 27: 28: -define(ATOM_EXT, 100). 29: -define(REFERENCE_EXT, 101). 30: -define(PORT_EXT, 102). 31: -define(PID_EXT, 103). 32: -define(NEW_REFERENCE_EXT, 114). 33: -define(ATOM_UTF8_EXT, 118). 34: -define(SMALL_ATOM_UTF8_EXT, 119). 35: 36: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, 37: init_per_suite/1, 38: end_per_suite/1, 39: init_per_testcase/2, 40: end_per_testcase/2]). 41: 42: -export([pid_roundtrip/1, 43: port_roundtrip/1, 44: ref_roundtrip/1, 45: new_float/1, 46: old_stuff/1, 47: binary_roundtrip/1, 48: decompress_roundtrip/1, 49: compress_roundtrip/1, 50: integer_roundtrip/1, 51: fun_roundtrip/1, 52: lists_roundtrip/1, 53: lists_roundtrip_2/1, 54: lists_iterator/1, 55: unicode/1, 56: unicode_list_to_string/1, 57: unicode_string_to_list/1, 58: utf8_atom/1, 59: utf8_pid/1, 60: utf8_port/1, 61: utf8_ref/1, 62: connect/1]). 63: 64: 65: %% Top of cases 66: 67: suite() -> [{ct_hooks,[ts_install_cth]}]. 68: 69: all() -> 70: [pid_roundtrip, port_roundtrip, ref_roundtrip, 71: new_float, old_stuff, binary_roundtrip, 72: decompress_roundtrip, compress_roundtrip, 73: integer_roundtrip, fun_roundtrip, lists_roundtrip, 74: lists_roundtrip_2, lists_iterator, unicode, 75: unicode_list_to_string, unicode_string_to_list, 76: utf8_atom, utf8_pid, utf8_port, utf8_ref, 77: connect]. 78: 79: groups() -> 80: []. 81: 82: init_per_group(_GroupName, Config) -> 83: Config. 84: 85: end_per_group(_GroupName, Config) -> 86: Config. 87: 88: init_per_suite(Config) when is_list(Config) -> 89: case case code:priv_dir(jinterface) of 90: {error,bad_name} -> false; 91: P -> filelib:is_dir(P) end of 92: true -> 93: jitu:init_all(Config); 94: false -> 95: {skip,"No jinterface application"} 96: end. 97: 98: end_per_suite(Config) -> 99: jitu:finish_all(Config). 100: 101: 102: 103: %% Add/remove watchdog before/after each test case. 104: %% 105: init_per_testcase(Case, Config) -> 106: T = case atom_to_list(Case) of 107: "unicode"++_ -> 240; 108: _ -> 120 109: end, 110: WatchDog = test_server:timetrap(test_server:seconds(T)), 111: [{watchdog, WatchDog}| Config]. 112: 113: end_per_testcase(_Case, Config) -> 114: jitu:kill_all_jnodes(), 115: WatchDog = ?config(watchdog, Config), 116: test_server:timetrap_cancel(WatchDog). 117: 118: 119: %% 120: %% Test cases 121: %% 122: 123: pid_roundtrip(doc) -> []; 124: pid_roundtrip(suite) -> []; 125: pid_roundtrip(Config) when is_list(Config)-> 126: ThisNode = {node(), erlang:system_info(creation)}, 127: RemNode = {gurka@sallad, 2}, 128: do_echo([self(), 129: mk_pid(ThisNode, 4711, 4711), 130: mk_pid(ThisNode, 32767, 8191), 131: mk_pid(RemNode, 4711, 4711), 132: mk_pid(RemNode, 32767, 8191)], 133: Config). 134: 135: fun_roundtrip(doc) -> []; 136: fun_roundtrip(suite) -> []; 137: fun_roundtrip(Config) when is_list(Config)-> 138: do_echo([fun(A, B) -> A + B end, 139: fun(A) -> lists:reverse(A) end, 140: fun() -> ok end, 141: fun fun_roundtrip/1], 142: Config). 143: 144: port_roundtrip(doc) -> []; 145: port_roundtrip(suite) -> []; 146: port_roundtrip(Config) when is_list(Config)-> 147: ThisNode = {node(), erlang:system_info(creation)}, 148: RemNode = {gurka@sallad, 2}, 149: do_echo([hd(erlang:ports()), 150: mk_port(ThisNode, 4711), 151: mk_port(ThisNode, 268435455), 152: mk_port(RemNode, 4711), 153: mk_port(RemNode, 268435455)], 154: Config). 155: 156: ref_roundtrip(doc) -> []; 157: ref_roundtrip(suite) -> []; 158: ref_roundtrip(Config) when is_list(Config)-> 159: ThisNode = {node(), erlang:system_info(creation)}, 160: RemNode = {gurka@sallad, 2}, 161: do_echo([make_ref(), 162: mk_ref(ThisNode, [4711]), 163: mk_ref(ThisNode, [4711, 4711, 4711]), 164: mk_ref(ThisNode, [262143, 4294967295, 4294967295]), 165: mk_ref(RemNode, [4711]), 166: mk_ref(RemNode, [4711, 4711, 4711]), 167: mk_ref(RemNode, [262143, 4294967295, 4294967295])], 168: Config). 169: 170: new_float(doc) -> []; 171: new_float(suite) -> []; 172: new_float(Config) when is_list(Config)-> 173: Two16 = float(1 bsl 16), 174: X = math:sqrt(2), 175: Floats = lists:reverse(seq(1/X, 63, fun(Y) -> Y / Two16 end), 176: [0.0|seq(X, 63, fun(Y) -> Y * Two16 end)]), 177: io:format("~w", [Floats]), 178: do_echo(Floats, Config). 179: 180: old_stuff(doc) -> []; 181: old_stuff(suite) -> []; 182: old_stuff(Config) when is_list(Config)-> 183: Terms = [0.0,math:sqrt(2)], 184: OutTrans = 185: fun (D) -> 186: {self(),term_to_binary(D, [{minor_version,0}]),binary} 187: end, 188: InTrans = 189: fun (Echoer, D, {Echoer,D,binary}) -> 190: ok 191: end, 192: do_echo(Terms, Config, OutTrans, InTrans). 193: 194: binary_roundtrip(doc) -> []; 195: binary_roundtrip(suite) -> []; 196: binary_roundtrip(Config) when is_list(Config) -> 197: do_echo([<<17>>, 198: <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17>>, 199: <<3:2>>, 200: <<3,7:3>>, 201: <<>>], 202: Config). 203: 204: decompress_roundtrip(doc) -> []; 205: decompress_roundtrip(suite) -> []; 206: decompress_roundtrip(Config) when is_list(Config) -> 207: RandomBin = erlang:term_to_binary(lists:seq(1, 5 * 1024 * 1024)), % roughly 26MB 208: <<RandomBin1k:1024/binary,_/binary>> = RandomBin, 209: <<RandomBin1M:1048576/binary,_/binary>> = RandomBin, 210: <<RandomBin10M:10485760/binary,_/binary>> = RandomBin, 211: Terms = 212: [{}, 213: {a,b,c}, 214: [], 215: 0.0, 216: math:sqrt(2), 217: <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>, 218: RandomBin1k, 219: RandomBin1M, 220: RandomBin10M, 221: RandomBin, 222: make_ref()], 223: OutTrans = 224: fun (D) -> 225: {self(),term_to_binary(D, [compressed]),binary} 226: end, 227: InTrans = 228: fun (Echoer, D, {Echoer,D,binary}) -> 229: ok 230: end, 231: do_echo(Terms, Config, OutTrans, InTrans). 232: 233: compress_roundtrip(doc) -> []; 234: compress_roundtrip(suite) -> []; 235: compress_roundtrip(Config) when is_list(Config) -> 236: RandomBin = erlang:term_to_binary(lists:seq(1, 5 * 1024 * 1024)), % roughly 26MB 237: <<RandomBin1k:1024/binary,_/binary>> = RandomBin, 238: <<RandomBin1M:1048576/binary,_/binary>> = RandomBin, 239: <<RandomBin10M:10485760/binary,_/binary>> = RandomBin, 240: Terms = 241: [{}, 242: {a,b,c}, 243: [], 244: 0.0, 245: math:sqrt(2), 246: <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>, 247: RandomBin1k, 248: RandomBin1M, 249: RandomBin10M, 250: RandomBin, 251: make_ref()], 252: OutTrans = 253: fun (D) -> 254: {self(),D,compress} 255: end, 256: InTrans = 257: fun (Echoer, D, {Echoer,B,compress}) -> 258: D = binary_to_term(B) 259: end, 260: do_echo(Terms, Config, OutTrans, InTrans). 261: 262: 263: 264: integer_roundtrip(doc) -> []; 265: integer_roundtrip(suite) -> []; 266: integer_roundtrip(Config) when is_list(Config) -> 267: Xs = [1 bsl X || X <- [26,27,28,29,30,31,32,33, 268: 62,63,64,65, 269: 126,127,128,129]], 270: Terms = [0,1,-1,-2] 271: ++lists:flatmap(fun (X) -> [X-2,X-1,X,-X+1,-X,-X-1] end, 272: Xs), 273: io:format("~w", [Terms]), 274: OutTrans = 275: fun (V) -> 276: {self(),V,bigint} 277: end, 278: InTrans = 279: fun (Echoer, V, {Echoer,{V,W,X,L,U},bigint}) -> 280: Bitlength = bitlength(V), 281: {w,W} = {w,signum(V) * Bitlength}, 282: Y = V band 16#FFFFffffFFFFffff, 283: {y,Y} = {y,X band 16#FFFFffffFFFFffff}, 284: {l,L} = {l,if V =:= X, Bitlength < 64 -> 1; 285: true -> 0 end}, 286: {u,U} = {u,if V =:= Y, V >= 0, Bitlength =< 64 -> 1; 287: true -> 0 end} 288: end, 289: do_echo(Terms, Config, OutTrans, InTrans). 290: 291: signum(V) when is_integer(V), V > 0 -> 1; 292: signum(V) when is_integer(V), V < 0 -> -1; 293: signum(0) -> 0. 294: 295: bitlength(0) -> 296: 0; 297: bitlength(-1) -> 298: 0; 299: bitlength(V) when is_integer(V) -> 300: 1 + bitlength(V bsr 1). 301: 302: 303: 304: lists_roundtrip(doc) -> []; 305: lists_roundtrip(suite) -> []; 306: lists_roundtrip(Config) when is_list(Config) -> 307: Ls = [lists:seq(1,10), 308: lists:seq(11,17)++last_tail, 309: [{default}], 310: [car|cdr], 311: [[]], 312: []], 313: do_echo(Ls, Config). 314: 315: 316: 317: lists_roundtrip_2(doc) -> []; 318: lists_roundtrip_2(suite) -> []; 319: lists_roundtrip_2(Config) when is_list(Config) -> 320: Ls = [{[a,b],tail}, 321: {[c,d,e],tail}, 322: {[],tail}, 323: {[f],tail}, 324: {[g,h|i],tail}, 325: {[j,k,l|m],tail}, 326: {[n|o],tail}, 327: {[z,1,2,3,4],tail3}, 328: {[z,5,6,7],tail3}, 329: {[z,8,9],tail3}, 330: {[z,10],tail3}, 331: {[],tail3}, 332: {[z,11,12,13,14|15],tail3}, 333: {[z,16,17,18|19],tail3}, 334: {[z,20,21|22],tail3}, 335: {[z,23|24],tail3}, 336: {[z|25],tail3}, 337: {"abc123",sub3atom}, 338: {"abc",sub3atom}, 339: {"abcdefg",codepointBug} 340: ], 341: Trans = 342: fun ([_|T], tail) -> 343: T; 344: (L, tail) when is_list(L) -> 345: null; 346: ([_,_,_|T], tail3) -> 347: T; 348: (L, tail3) when is_list(L) -> 349: null; 350: ([_,_,_|L], sub3atom) -> 351: list_to_atom(L); 352: (L, codepointBug) -> 353: L 354: end, 355: OutTrans = 356: fun ({L,Twist}) -> 357: {self(),L,Twist} 358: end, 359: InTrans = 360: fun (Echoer, {L,Twist}, {Echoer,X,Twist}) -> 361: Y = Trans(L, Twist), 362: io:format("## ~w ~w ~w ~w~n", [L,Twist,X,Y]), 363: X = Y 364: end, 365: do_echo(Ls, Config, OutTrans, InTrans). 366: 367: 368: 369: 370: lists_iterator(doc) -> []; 371: lists_iterator(suite) -> []; 372: lists_iterator(Config) when is_list(Config) -> 373: Ls = [["able ","was ","I ","ere ","I ","saw ","elba"]], 374: do_echo(Ls, Config, 375: fun (L) -> {self(),L,strcat} end, 376: fun (Echoer, L, {Echoer,X,strcat}) -> 377: io:format("## ~p ~p~n", [L,X]), 378: X = lists:flatten(L) 379: end). 380: 381: 382: 383: unicode(doc) -> []; 384: unicode(suite) -> []; 385: unicode(Config) when is_list(Config) -> 386: S1 = "plain ascii", 387: S2 = "iso-latin åäö ñ", 388: S3 = "Codepoints... åäö \x{1000}", 389: S4 = [0,1,31,32,63,64,127,128,255], 390: S5 = [0,1,127,128,255,256,16#d7ff, 391: 16#e000,16#fffd,16#10000,16#10ffff], 392: Ss = [S1,S2,S3,S4,S5], 393: do_echo(unicode_cp_gen([{S,valid} || S <- Ss] ++ cp_gen(71)), Config, 394: fun ({L,invalid}) -> {self(),L,utf8}; 395: ({L,Tag}) -> {self(),L,Tag}; 396: ({L}) -> {self(),L} 397: end, 398: fun (Echoer, {L,invalid}=Out, {Echoer,X,utf8}=In) -> 399: case L of 400: X -> ok; 401: _ -> 402: ?t:fail({mismatch,Out,In}) 403: end; 404: (Echoer, {L,Tag}=Out, {Echoer,X,Tag}=In) -> 405: case unicode:characters_to_binary(L, utf8) of 406: X -> ok; 407: _ -> 408: ?t:fail({mismatch,Out,In}) 409: end; 410: (Echoer, {L}=Out, {Echoer,X}=In) -> 411: case L of 412: X -> ok; 413: _ -> 414: ?t:fail({mismatch,Out,In}) 415: end 416: end, ["unicode"]). 417: 418: %% Lazy wrapper to lazy list 419: unicode_cp_gen([{S,valid}|Ss]) -> 420: [{S,utf8},{S}|unicode_cp_gen(Ss)]; 421: unicode_cp_gen([{S,invalid}=St|Ss]) -> 422: [St,{S}|unicode_cp_gen(Ss)]; 423: unicode_cp_gen([]) -> 424: []; 425: unicode_cp_gen(Cont) when is_function(Cont, 0) -> 426: fun () -> 427: unicode_cp_gen(Cont()) 428: end. 429: 430: 431: 432: unicode_list_to_string(doc) -> []; 433: unicode_list_to_string(suite) -> []; 434: unicode_list_to_string(Config) when is_list(Config) -> 435: do_echo(cp_gen(73), Config, 436: fun ({L,_}) -> {self(),L,to_string_neg_int_list} end, 437: fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) -> 438: case L of 439: X -> ok; 440: _ -> 441: ?t:fail({mismatch,Out,In}) 442: end; 443: (Echoer, {L,valid}=Out, {Echoer,X,_}=In) -> 444: B = unicode:characters_to_binary(L, unicode, {utf16,big}), 445: case [-D || <<D:16/big>> <= B] of 446: X -> ok; 447: _ -> 448: ?t:fail({mismatch,Out,In}) 449: end 450: end). 451: 452: 453: 454: unicode_string_to_list(doc) -> []; 455: unicode_string_to_list(suite) -> []; 456: unicode_string_to_list(Config) when is_list(Config) -> 457: do_echo(cp_gen(79), Config, 458: fun ({L,_}) -> {self(),L,to_neg_int_list} end, 459: fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) -> 460: case L of 461: X -> ok; 462: _ -> 463: ?t:fail({mismatch,Out,In}) 464: end; 465: (Echoer, {L,valid}=Out, {Echoer,X,_}=In) -> 466: case [-C || C <- L] of 467: X -> ok; 468: _ -> 469: ?t:fail({mismatch,Out,In}) 470: end 471: end, ["unicode"]). 472: 473: 474: evil_smiley() -> 475: <<240,159,152,136>>. 476: 477: evil_smileys(0) -> 478: []; 479: evil_smileys(N) -> 480: [evil_smiley() | evil_smileys(N-1)]. 481: 482: utf8_atom(Config) when is_list(Config) -> 483: ES = evil_smiley(), 484: SmallUA = binary_to_term(list_to_binary([?VERSION_MAGIC, 485: ?SMALL_ATOM_UTF8_EXT, 486: size(ES), 487: ES])), 488: true = is_atom(SmallUA), 489: NoESs = 300 div size(ES), 490: ESs = evil_smileys(NoESs), 491: LargeUA = binary_to_term(list_to_binary([?VERSION_MAGIC, 492: ?ATOM_UTF8_EXT, 493: uint16_be(NoESs*size(ES)), 494: ESs])), 495: true = is_atom(LargeUA), 496: erlang:display({atom, SmallUA, LargeUA}), 497: do_echo([SmallUA, LargeUA], Config). 498: 499: utf8_nodenames_ext() -> 500: H = "@host", 501: ES = evil_smiley(), 502: SmallUANodeExt = list_to_binary([?SMALL_ATOM_UTF8_EXT, 503: size(ES)+length(H), 504: ES, 505: H]), 506: NoESs = 300 div size(ES), 507: ESs = evil_smileys(NoESs), 508: LargeUANodeExt = list_to_binary([?ATOM_UTF8_EXT, 509: uint16_be(NoESs*size(ES)+length(H)), 510: ESs, 511: H]), 512: {SmallUANodeExt, LargeUANodeExt}. 513: 514: utf8_pid(Config) when is_list(Config) -> 515: {SmallUANodeExt, LargeUANodeExt} = utf8_nodenames_ext(), 516: SmallPid = mk_pid({SmallUANodeExt, 2}, 4711, 4711), 517: LargePid = mk_pid({LargeUANodeExt, 2}, 4711, 4711), 518: erlang:display({pid, SmallPid, node(SmallPid)}), 519: erlang:display({pid, LargePid, node(LargePid)}), 520: do_echo([SmallPid, LargePid], Config). 521: 522: utf8_port(Config) when is_list(Config) -> 523: {SmallUANodeExt, LargeUANodeExt} = utf8_nodenames_ext(), 524: SmallPort = mk_port({SmallUANodeExt, 2}, 4711), 525: erlang:display({port, SmallPort, node(SmallPort)}), 526: LargePort = mk_port({LargeUANodeExt, 2}, 4711), 527: erlang:display({port, LargePort, node(LargePort)}), 528: do_echo([SmallPort, LargePort], Config). 529: 530: utf8_ref(Config) when is_list(Config) -> 531: {SmallUANodeExt, LargeUANodeExt} = utf8_nodenames_ext(), 532: SmallRef = mk_ref({SmallUANodeExt, 2}, [4711, 4711, 4711]), 533: erlang:display({ref, SmallRef, node(SmallRef)}), 534: LargeRef = mk_ref({LargeUANodeExt, 2}, [4711, 4711, 4711]), 535: erlang:display({ref, LargeRef, node(LargeRef)}), 536: do_echo([SmallRef, LargeRef], Config). 537: 538: 539: %% Lazy list 540: cp_gen(N) -> 541: cp_gen(N, -1, 16#110000). 542: 543: cp_gen(N, Start, End) -> 544: cp_gen(N, Start, End, cp_validity(Start), [], 0, [], 0). 545: 546: cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Len >= N -> 547: cp_gen(N, U, End, PrevValidity, [], 0, [{Acc,PrevValidity}|Ss], Ls+1); 548: cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Ls >= N -> 549: Ss ++ fun () -> 550: cp_gen(N, U, End, PrevValidity, Acc, Len, [], 0) 551: end; 552: cp_gen(_, U, End, _, Acc, _, Ss, _) when U > End -> 553: [{Acc,valid}|Ss]; 554: cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) -> 555: Validity = cp_validity(U), 556: NextU = U+1, 557: {NextAcc,NextLen} = case Validity of 558: valid -> {[U|Acc],Len+1}; 559: invalid -> {Acc,Len} 560: end, 561: {NextSs,NextLs} = case Validity of 562: PrevValidity -> {Ss,Ls}; 563: valid -> {[{[U-1],PrevValidity}|Ss],Ls+1}; 564: invalid -> {[{[U],Validity}|Ss],Ls+1} 565: end, 566: cp_gen(N, NextU, End, Validity, NextAcc, NextLen, NextSs, NextLs). 567: 568: cp_validity(UnicodeCP) -> 569: try <<UnicodeCP/big-utf32>> of 570: _ -> valid 571: catch 572: error:_ -> invalid 573: end. 574: 575: 576: 577: connect(doc) -> []; 578: connect(suite) -> []; 579: connect(Config) when is_list(Config) -> 580: WD = filename:dirname(code:which(?MODULE)), 581: {ok,Other} = ?t:start_node(make_name(), slave, [{args,"-pa "++WD}]), 582: Action = 583: fun (Pid) -> 584: JName = node(Pid), 585: Hidden = [JName], 586: Pid ! {self(),Other}, 587: receive 588: {Pid,Other,true} -> 589: ok; 590: Unexpected1 -> 591: ?t:fail({result,Unexpected1}) 592: end, 593: Hidden = erlang:nodes(hidden), 594: Hidden = rpc:call(Other, erlang, nodes, [hidden]), 595: true = 596: rpc:call(Other, erlang, disconnect_node, [JName]), 597: [] = 598: rpc:call(Other, erlang, nodes, [hidden]), 599: Hidden = erlang:nodes(hidden), 600: %% Again 601: receive after 2000 -> ok end, 602: %% We have no way of knowing when the Java node 603: %% detects the nodedown. 604: Pid ! {self(),Other}, 605: receive 606: {Pid,Other,true} -> 607: ok; 608: Unexpected2-> 609: ?t:fail({result,Unexpected2}) 610: end, 611: Hidden = rpc:call(Other, erlang, nodes, [hidden]) 612: end, 613: run_server(connection_server, Config, Action, []). 614: 615: 616: 617: seq(_, 0, _) -> 618: []; 619: seq(X, N, Fun) -> 620: [X|seq(Fun(X), N-1, Fun)]. 621: 622: do_echo(DataList, Config) -> 623: do_echo(DataList, Config, 624: fun (D) -> % OutTrans 625: {self(),D} 626: end, 627: fun (Echoer, D, {Echoer,D}) -> % InTrans 628: ok 629: end, []). 630: 631: do_echo(DataList, Config, OutTrans, InTrans) -> 632: do_echo(DataList, Config, OutTrans, InTrans, []). 633: 634: do_echo(DataList, Config, OutTrans, InTrans, ExtraArgs) 635: when is_list(DataList), is_list(Config) -> 636: run_server(echo_server, Config, 637: fun (Echoer) -> 638: echo_loop(DataList, Echoer, OutTrans, InTrans, []) 639: end, 640: ExtraArgs). 641: 642: echo_loop([D|Ds], Echoer, OutTrans, InTrans, TermAcc) -> 643: OutMsg = OutTrans(D), 644: Echoer ! OutMsg, 645: io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]), 646: receive 647: Reply -> 648: io:format("echo_server ~p: receive ~P~n", 649: [self(),Reply,10]), 650: InTrans(Echoer, D, Reply) 651: end, 652: Term = case OutMsg of 653: {_, T, _} -> T; 654: {_, T} -> T 655: end, 656: echo_loop(Ds, Echoer, OutTrans, InTrans, [Term | TermAcc]); 657: echo_loop([], Echoer, _, _, TermAcc) -> 658: check_terms(Echoer, TermAcc); 659: %% Lazy list 660: echo_loop(Cont, Echoer, OutTrans, InTrans, TermAcc) 661: when is_function(Cont, 0) -> 662: check_terms(Echoer, TermAcc), 663: OutMsg = Echoer ! {self(),undefined,hash_clear}, 664: io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]), 665: receive 666: {Echoer,hash_cleared,hash_clear}=Reply -> 667: io:format("echo_server ~p: receive ~P~n", 668: [self(),Reply,10]), 669: ok; 670: Other -> 671: io:format("echo_server_terms unexpected ~p: receive ~P~n", 672: [self(),Other,10]), 673: ?t:fail({unexpected, Other}) 674: end, 675: echo_loop(Cont(), Echoer, OutTrans, InTrans, []). 676: 677: check_terms(Echoer, [Term | Rest]) -> 678: OutMsg = {self(),Term,hash_lookup}, 679: Echoer ! OutMsg, 680: io:format("check_terms ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]), 681: receive 682: {Echoer,true,hash_lookup} = ReplyMsg -> 683: io:format("check_terms ~p: receive ~P~n", 684: [self(),ReplyMsg,10]), 685: check_terms(Echoer, Rest); 686: Other -> 687: io:format("check_terms unexpected ~p: receive ~P~n", 688: [self(),Other,10]), 689: ?t:fail({unexpected, Other}) 690: end; 691: check_terms(_, []) -> 692: ok. 693: 694: run_server(Server, Config, Action, ExtraArgs) -> 695: Name = make_name(), 696: true = register(Name, self()), 697: JName = make_name(), 698: spawn_link(fun () -> 699: %% Setting max memory to 256. This is due to 700: %% echo_server sometimes failing with 701: %% OutOfMemoryException one some test machines. 702: ok = jitu:java(?config(java, Config), 703: ?config(data_dir, Config), 704: atom_to_list(Server), 705: [JName, 706: erlang:get_cookie(), 707: node(), 708: Name]++ExtraArgs, 709: " -Xmx256m"), 710: %% " -Xmx256m -DOtpConnection.trace=3"), 711: Name ! {done, JName} 712: end), 713: receive 714: {Server, JName, Pid} -> 715: ?t:format("~w: ~p (~p)~n", 716: [Server, Pid, node(Pid)]), 717: ?t:format("nodes(hidden): ~p~n", 718: [nodes(hidden)]), 719: Action(Pid), 720: Pid ! bye, 721: receive 722: {done, JName} -> 723: ok 724: end; 725: Other -> 726: ?t:fail({unexpected,Other}) 727: end. 728: 729: %% 730: %% Utils... 731: %% 732: 733: make_name() -> 734: {A, B, C} = now(), 735: list_to_atom(atom_to_list(?MODULE) 736: ++ "-" ++ integer_to_list(A) 737: ++ "-" ++ integer_to_list(B) 738: ++ "-" ++ integer_to_list(C)). 739: 740: uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> 741: [(Uint bsr 24) band 16#ff, 742: (Uint bsr 16) band 16#ff, 743: (Uint bsr 8) band 16#ff, 744: Uint band 16#ff]; 745: uint32_be(Uint) -> 746: exit({badarg, uint32_be, [Uint]}). 747: 748: 749: uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> 750: [(Uint bsr 8) band 16#ff, 751: Uint band 16#ff]; 752: uint16_be(Uint) -> 753: exit({badarg, uint16_be, [Uint]}). 754: 755: uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> 756: Uint band 16#ff; 757: uint8(Uint) -> 758: exit({badarg, uint8, [Uint]}). 759: 760: 761: 762: mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> 763: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 764: mk_pid({NodeNameExt, Creation}, Number, Serial); 765: mk_pid({NodeNameExt, Creation}, Number, Serial) -> 766: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 767: ?PID_EXT, 768: NodeNameExt, 769: uint32_be(Number), 770: uint32_be(Serial), 771: uint8(Creation)])) of 772: Pid when is_pid(Pid) -> 773: Pid; 774: {'EXIT', {badarg, _}} -> 775: exit({badarg, mk_pid, [{NodeNameExt, Creation}, Number, Serial]}); 776: Other -> 777: exit({unexpected_binary_to_term_result, Other}) 778: end. 779: 780: mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> 781: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 782: mk_port({NodeNameExt, Creation}, Number); 783: mk_port({NodeNameExt, Creation}, Number) -> 784: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 785: ?PORT_EXT, 786: NodeNameExt, 787: uint32_be(Number), 788: uint8(Creation)])) of 789: Port when is_port(Port) -> 790: Port; 791: {'EXIT', {badarg, _}} -> 792: exit({badarg, mk_port, [{NodeNameExt, Creation}, Number]}); 793: Other -> 794: exit({unexpected_binary_to_term_result, Other}) 795: end. 796: 797: mk_ref({NodeName, Creation}, [Number] = NL) when is_atom(NodeName), 798: is_integer(Creation), 799: is_integer(Number) -> 800: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 801: mk_ref({NodeNameExt, Creation}, NL); 802: mk_ref({NodeNameExt, Creation}, [Number]) when is_integer(Creation), 803: is_integer(Number) -> 804: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 805: ?REFERENCE_EXT, 806: NodeNameExt, 807: uint32_be(Number), 808: uint8(Creation)])) of 809: Ref when is_reference(Ref) -> 810: Ref; 811: {'EXIT', {badarg, _}} -> 812: exit({badarg, mk_ref, [{NodeNameExt, Creation}, [Number]]}); 813: Other -> 814: exit({unexpected_binary_to_term_result, Other}) 815: end; 816: mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), 817: is_integer(Creation), 818: is_list(Numbers) -> 819: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 820: mk_ref({NodeNameExt, Creation}, Numbers); 821: mk_ref({NodeNameExt, Creation}, Numbers) when is_integer(Creation), 822: is_list(Numbers) -> 823: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 824: ?NEW_REFERENCE_EXT, 825: uint16_be(length(Numbers)), 826: NodeNameExt, 827: uint8(Creation), 828: lists:map(fun (N) -> 829: uint32_be(N) 830: end, 831: Numbers)])) of 832: Ref when is_reference(Ref) -> 833: Ref; 834: {'EXIT', {badarg, _}} -> 835: exit({badarg, mk_ref, [{NodeNameExt, Creation}, Numbers]}); 836: Other -> 837: exit({unexpected_binary_to_term_result, Other}) 838: end.