diff options
Diffstat (limited to 'test/testclnt.lua')
| -rw-r--r-- | test/testclnt.lua | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/test/testclnt.lua b/test/testclnt.lua index 170e187..3e897c9 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
| @@ -619,6 +619,177 @@ remote([[ | |||
| 619 | end | 619 | end |
| 620 | 620 | ||
| 621 | ------------------------------------------------------------------------ | 621 | ------------------------------------------------------------------------ |
| 622 | function test_maxsize() | ||
| 623 | -- Group A: argument errors, raised before any I/O | ||
| 624 | reconnect() | ||
| 625 | printf("argument errors: ") | ||
| 626 | -- bounds pre-implementation calls (where arg 4 is silently dropped and | ||
| 627 | -- these become real, otherwise-unbounded blocking reads on an idle | ||
| 628 | -- socket) so a meaningful failure doesn't hang the suite | ||
| 629 | data:settimeout(0.2) | ||
| 630 | local ok | ||
| 631 | ok = pcall(data.receive, data, "*l", nil, 0) | ||
| 632 | assert(not ok, "A1 failed: maxsize=0 should raise") | ||
| 633 | ok = pcall(data.receive, data, "*l", nil, -1) | ||
| 634 | assert(not ok, "A2 failed: maxsize=-1 should raise") | ||
| 635 | ok = pcall(data.receive, data, "*l", nil, "abc") | ||
| 636 | assert(not ok, "A3 failed: non-number maxsize should raise") | ||
| 637 | ok = pcall(data.receive, data, "*l", string.rep("x", 10), 10) | ||
| 638 | assert(not ok, "A4 failed: #prefix == maxsize should raise") | ||
| 639 | ok = pcall(data.receive, data, "*l", string.rep("x", 11), 10) | ||
| 640 | assert(not ok, "A5 failed: #prefix > maxsize should raise") | ||
| 641 | ok = pcall(data.receive, data, 100, nil, 50) | ||
| 642 | assert(not ok, "A6 failed: wanted > maxsize should raise") | ||
| 643 | data:settimeout(0.1) | ||
| 644 | ok = pcall(data.receive, data, 50, nil, 100) | ||
| 645 | assert(ok, "A7 failed: wanted <= maxsize should not raise") | ||
| 646 | data:settimeout(-1) | ||
| 647 | remote [[ data:send('intact\n') ]] | ||
| 648 | local line, err = data:receive("*l", nil, 100) | ||
| 649 | assert(line == "intact", | ||
| 650 | "A8 failed: socket touched by a failed argcheck (err=" .. | ||
| 651 | tostring(err) .. ")") | ||
| 652 | pass("ok") | ||
| 653 | |||
| 654 | -- Group B: *l boundary | ||
| 655 | reconnect() | ||
| 656 | printf("*l boundary: ") | ||
| 657 | remote [[ data:send('hello\n') ]] | ||
| 658 | local d, e, p = data:receive("*l", nil, 100) | ||
| 659 | assert(d == "hello" and e == nil, "B1 failed") | ||
| 660 | |||
| 661 | remote(string.format([[data:send(string.rep('a',%d) .. '\n')]], 100)) | ||
| 662 | d, e = data:receive("*l", nil, 100) | ||
| 663 | assert(d == string.rep("a", 100) and e == nil, | ||
| 664 | "B2 failed: exact-budget line should succeed") | ||
| 665 | |||
| 666 | remote(string.format([[data:send(string.rep('a',%d) .. '\n')]], 101)) | ||
| 667 | d, e, p = data:receive("*l", nil, 100) | ||
| 668 | assert(d == nil and e == "oversized" and p == string.rep("a", 100), | ||
| 669 | "B3 failed: one-over-budget should be oversized") | ||
| 670 | d, e = data:receive("*l", nil, 100) | ||
| 671 | assert(d == "a" and e == nil, | ||
| 672 | "B3 failed: leftover byte and terminator should still be there") | ||
| 673 | |||
| 674 | remote(string.format([[data:send(string.rep('\r',%d) .. string.rep('a',%d) .. '\n')]], 50, 100)) | ||
| 675 | d, e = data:receive("*l", nil, 100) | ||
| 676 | assert(d == string.rep("a", 100) and e == nil, "B4 failed: CRs must not count") | ||
| 677 | |||
| 678 | remote(string.format([[data:send(string.rep('a',%d) .. '\r\n')]], 100)) | ||
| 679 | d, e = data:receive("*l", nil, 100) | ||
| 680 | assert(d == string.rep("a", 100) and e == nil, "B5 failed: CRLF at boundary") | ||
| 681 | pass("ok") | ||
| 682 | |||
| 683 | -- Group C: *l and I1 (timeout/close at the cap) | ||
| 684 | reconnect() | ||
| 685 | printf("I1 (timeout/closed at the cap): ") | ||
| 686 | remote(string.format([[data:send(string.rep('a',%d))]], 50)) | ||
| 687 | data:settimeout(0.5) | ||
| 688 | d, e, p = data:receive("*l", nil, 100) | ||
| 689 | assert(d == nil and e == "timeout", "C1 failed: expected timeout below cap") | ||
| 690 | assert(#p < 100, "C1 failed: timeout partial must be strictly < maxsize") | ||
| 691 | ok = pcall(data.receive, data, "*l", p, 100) | ||
| 692 | assert(ok, "C1 failed: retry with prefix=partial, same maxsize must not raise") | ||
| 693 | |||
| 694 | reconnect() | ||
| 695 | remote(string.format([[data:send(string.rep('a',%d))]], 100)) | ||
| 696 | data:settimeout(0.5) | ||
| 697 | d, e, p = data:receive("*l", nil, 100) | ||
| 698 | assert(e == "oversized" and #p == 100, | ||
| 699 | "C2 failed: exactly-at-cap timeout must be oversized, got " .. tostring(e)) | ||
| 700 | |||
| 701 | reconnect() | ||
| 702 | remote(string.format([[data:send(string.rep('a',%d)) data:close() data = nil]], 100)) | ||
| 703 | d, e, p = data:receive("*l", nil, 100) | ||
| 704 | assert(e == "oversized" and #p == 100, | ||
| 705 | "C3 failed: exactly-at-cap close must be oversized, got " .. tostring(e)) | ||
| 706 | pass("ok") | ||
| 707 | |||
| 708 | -- Group D: drain idiom | ||
| 709 | -- 5030 (not a multiple of the 100 cap) so the boundary of the 50th | ||
| 710 | -- oversized chunk doesn't land exactly on the '\n': when it does, the | ||
| 711 | -- terminator check wins over the cap check (by design -- see B2/I1) and | ||
| 712 | -- the would-be 50th oversized chunk instead succeeds outright. | ||
| 713 | reconnect() | ||
| 714 | printf("drain idiom: ") | ||
| 715 | remote(string.format([[data:send(string.rep('x',%d) .. '\n' .. 'next\n')]], 5030)) | ||
| 716 | local iterations = 0 | ||
| 717 | repeat | ||
| 718 | d, e, p = data:receive("*l", "", 100) | ||
| 719 | if e == "oversized" then | ||
| 720 | assert(#p == 100, "D1 failed: oversized partial length " .. #p) | ||
| 721 | iterations = iterations + 1 | ||
| 722 | end | ||
| 723 | until e ~= "oversized" | ||
| 724 | assert(iterations == 50, | ||
| 725 | "D1 failed: expected 50 oversized iterations, got " .. iterations) | ||
| 726 | assert(d == string.rep("x", 30) and e == nil, "D1 failed: final call should succeed") | ||
| 727 | local nextline = data:receive("*l") | ||
| 728 | assert(nextline == "next", "D1 failed: stream misaligned, got " .. tostring(nextline)) | ||
| 729 | pass("ok") | ||
| 730 | |||
| 731 | -- Group E: *a | ||
| 732 | reconnect() | ||
| 733 | printf("*a boundary: ") | ||
| 734 | remote [[ data:send('abc') data:close() data = nil ]] | ||
| 735 | d, e = data:receive("*a", nil, 100) | ||
| 736 | assert(d == "abc" and e == nil, "E1 failed") | ||
| 737 | |||
| 738 | reconnect() | ||
| 739 | remote(string.format([[data:send(string.rep('a',%d)) data:close() data = nil]], 100)) | ||
| 740 | d, e = data:receive("*a", nil, 100) | ||
| 741 | assert(d == string.rep("a", 100) and e == nil, | ||
| 742 | "E2 failed: completion should beat the cap") | ||
| 743 | |||
| 744 | reconnect() | ||
| 745 | remote(string.format([[data:send(string.rep('a',%d)) data:close() data = nil]], 250)) | ||
| 746 | d, e, p = data:receive("*a", "", 100) | ||
| 747 | assert(e == "oversized" and #p == 100, "E3 failed: first chunk") | ||
| 748 | d, e, p = data:receive("*a", "", 100) | ||
| 749 | assert(e == "oversized" and #p == 100, "E3 failed: second chunk") | ||
| 750 | d, e = data:receive("*a", "", 100) | ||
| 751 | assert(d == string.rep("a", 50) and e == nil, "E3 failed: final chunk") | ||
| 752 | |||
| 753 | reconnect() | ||
| 754 | remote(string.format([[data:send(string.rep('a',%d))]], 100)) | ||
| 755 | data:settimeout(0.3) | ||
| 756 | d, e, p = data:receive("*a", nil, 100) | ||
| 757 | assert(e == "oversized" and #p == 100, | ||
| 758 | "E4 failed: expected oversized not timeout, got " .. tostring(e)) | ||
| 759 | |||
| 760 | reconnect() | ||
| 761 | remote(string.format([[data:send(string.rep('a',%d))]], 50)) | ||
| 762 | data:settimeout(0.3) | ||
| 763 | d, e, p = data:receive("*a", nil, 100) | ||
| 764 | assert(e == "timeout" and #p < 100, "E5 failed") | ||
| 765 | pass("ok") | ||
| 766 | |||
| 767 | -- Group F: numeric pattern (recvraw untouched) | ||
| 768 | reconnect() | ||
| 769 | printf("numeric pattern (recvraw unchanged): ") | ||
| 770 | remote(string.format([[data:send(string.rep('a',%d))]], 50)) | ||
| 771 | d, e = data:receive(50, nil, 100) | ||
| 772 | assert(d == string.rep("a", 50) and e == nil, "F1 failed") | ||
| 773 | |||
| 774 | reconnect() | ||
| 775 | remote(string.format([[data:send(string.rep('a',%d))]], 25)) | ||
| 776 | d, e = data:receive(50, string.rep("p", 25), 100) | ||
| 777 | assert(e == nil and #d == 50, "F2 failed") | ||
| 778 | pass("ok") | ||
| 779 | |||
| 780 | -- Group G: no-maxsize regression snapshot | ||
| 781 | reconnect() | ||
| 782 | printf("no-maxsize regression: ") | ||
| 783 | remote(string.format([[data:send(string.rep('a',%d) .. '\n')]], 5000)) | ||
| 784 | d, e = data:receive("*l") | ||
| 785 | assert(d == string.rep("a", 5000) and e == nil, "G2 failed: plain *l") | ||
| 786 | remote(string.format([[data:send(string.rep('a',%d) .. '\n')]], 5000)) | ||
| 787 | d, e = data:receive("*l", "") | ||
| 788 | assert(d == string.rep("a", 5000) and e == nil, "G2 failed: *l with prefix") | ||
| 789 | pass("ok") | ||
| 790 | end | ||
| 791 | |||
| 792 | ------------------------------------------------------------------------ | ||
| 622 | test("method registration") | 793 | test("method registration") |
| 623 | 794 | ||
| 624 | local tcp_methods = { | 795 | local tcp_methods = { |
| @@ -796,6 +967,9 @@ test_blockingtimeoutreceive(800091, 2, 3) | |||
| 796 | test_blockingtimeoutreceive(800091, 3, 2) | 967 | test_blockingtimeoutreceive(800091, 3, 2) |
| 797 | test_blockingtimeoutreceive(800091, 3, 1) | 968 | test_blockingtimeoutreceive(800091, 3, 1) |
| 798 | 969 | ||
| 970 | test("receive maxsize") | ||
| 971 | test_maxsize() | ||
| 972 | |||
| 799 | test("shutting server down") | 973 | test("shutting server down") |
| 800 | reconnect() | 974 | reconnect() |
| 801 | remote("os.exit()") | 975 | remote("os.exit()") |
