Skip to content

Commit a7946ab

Browse files
committed
♻️ Update many existing tests to use MockServer
* test_clear_responses * test_close * test_enable * test_responses * test_uid_expunge * test_uidplus_responses * test_unselect All of the tests that used `yields_in_test_server_thread` were updated, so that method was deleted too.
1 parent 0c57a96 commit a7946ab

File tree

1 file changed

+100
-197
lines changed

1 file changed

+100
-197
lines changed

test/net/imap/test_imap.rb

Lines changed: 100 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
require "net/imap"
44
require "test/unit"
5+
require_relative "mock_server"
56

67
class IMAPTest < Test::Unit::TestCase
78
CA_FILE = File.expand_path("../fixtures/cacert.pem", __dir__)
@@ -775,72 +776,28 @@ def test_id
775776
end
776777
end
777778

778-
def test_uid_expunge
779-
server = create_tcp_server
780-
port = server.addr[1]
781-
requests = []
782-
start_server do
783-
sock = server.accept
784-
begin
785-
sock.print("* OK test server\r\n")
786-
requests.push(sock.gets)
787-
sock.print("* 1 EXPUNGE\r\n")
788-
sock.print("* 1 EXPUNGE\r\n")
789-
sock.print("* 1 EXPUNGE\r\n")
790-
sock.print("RUBY0001 OK UID EXPUNGE completed\r\n")
791-
sock.gets
792-
sock.print("* BYE terminating connection\r\n")
793-
sock.print("RUBY0002 OK LOGOUT completed\r\n")
794-
ensure
795-
sock.close
796-
server.close
779+
def test_uidplus_uid_expunge
780+
with_mock_server(select: "INBOX",
781+
extensions: %i[UIDPLUS]) do |server, imap|
782+
server.on "UID EXPUNGE" do |resp|
783+
resp.untagged("1 EXPUNGE")
784+
resp.untagged("1 EXPUNGE")
785+
resp.untagged("1 EXPUNGE")
786+
resp.done_ok
797787
end
798-
end
799-
800-
begin
801-
imap = Net::IMAP.new(server_addr, :port => port)
802788
response = imap.uid_expunge(1000..1003)
803-
assert_equal("RUBY0001 UID EXPUNGE 1000:1003\r\n", requests.pop)
789+
cmd = server.commands.pop
790+
assert_equal ["UID EXPUNGE", "1000:1003"], [cmd.name, cmd.args]
804791
assert_equal(response, [1, 1, 1])
805-
imap.logout
806-
ensure
807-
imap.disconnect if imap
808792
end
809793
end
810794

811-
def test_uidplus_responses
812-
server = create_tcp_server
813-
port = server.addr[1]
814-
requests = []
815-
start_server do
816-
sock = server.accept
817-
begin
818-
sock.print("* OK test server\r\n")
819-
line = sock.gets
820-
size = line.slice(/{(\d+)}\r\n/, 1).to_i
821-
sock.print("+ Ready for literal data\r\n")
822-
sock.read(size)
823-
sock.gets
824-
sock.print("RUBY0001 OK [APPENDUID 38505 3955] APPEND completed\r\n")
825-
requests.push(sock.gets)
826-
sock.print("RUBY0002 OK [COPYUID 38505 3955,3960:3962 3963:3966] " \
827-
"COPY completed\r\n")
828-
requests.push(sock.gets)
829-
sock.print("RUBY0003 OK [COPYUID 38505 3955 3967] COPY completed\r\n")
830-
sock.gets
831-
sock.print("* NO [UIDNOTSTICKY] Non-persistent UIDs\r\n")
832-
sock.print("RUBY0004 OK SELECT completed\r\n")
833-
sock.gets
834-
sock.print("* BYE terminating connection\r\n")
835-
sock.print("RUBY0005 OK LOGOUT completed\r\n")
836-
ensure
837-
sock.close
838-
server.close
795+
def test_uidplus_appenduid
796+
with_mock_server(select: "INBOX",
797+
extensions: %i[UIDPLUS]) do |server, imap|
798+
server.on "APPEND" do |cmd|
799+
cmd.done_ok code: "APPENDUID 38505 3955"
839800
end
840-
end
841-
842-
begin
843-
imap = Net::IMAP.new(server_addr, :port => port)
844801
resp = imap.append("inbox", <<~EOF.gsub(/\n/, "\r\n"), [:Seen], Time.now)
845802
Subject: hello
846803
@@ -849,120 +806,76 @@ def test_uidplus_responses
849806
hello world
850807
EOF
851808
assert_equal([38505, nil, [3955]], resp.data.code.data.to_a)
809+
assert_equal "APPEND", server.commands.pop.name
810+
end
811+
end
812+
813+
def test_uidplus_copyuid_multiple
814+
with_mock_server(select: "INBOX",
815+
extensions: %i[UIDPLUS]) do |server, imap|
816+
server.on "UID COPY" do |cmd|
817+
cmd.done_ok code: "COPYUID 38505 3955,3960:3962 3963:3966"
818+
end
852819
resp = imap.uid_copy([3955,3960..3962], 'trash')
853-
assert_equal(requests.pop, "RUBY0002 UID COPY 3955,3960:3962 trash\r\n")
820+
cmd = server.commands.pop
821+
assert_equal(["UID COPY", "3955,3960:3962 trash"], [cmd.name, cmd.args])
854822
assert_equal(
855823
[38505, [3955, 3960, 3961, 3962], [3963, 3964, 3965, 3966]],
856824
resp.data.code.data.to_a
857825
)
826+
end
827+
end
828+
829+
def test_uidplus_copyuid_single
830+
with_mock_server(select: "INBOX",
831+
extensions: %i[UIDPLUS]) do |server, imap|
832+
server.on "UID COPY" do |cmd|
833+
cmd.done_ok code: "COPYUID 38505 3955 3967"
834+
end
858835
resp = imap.uid_copy(3955, 'trash')
859-
assert_equal(requests.pop, "RUBY0003 UID COPY 3955 trash\r\n")
836+
cmd = server.commands.pop
837+
assert_equal(["UID COPY", "3955 trash"], [cmd.name, cmd.args])
860838
assert_equal([38505, [3955], [3967]], resp.data.code.data.to_a)
839+
end
840+
end
841+
842+
def test_uidplus_uidnotsticky
843+
with_mock_server(extensions: %i[UIDPLUS]) do |server, imap|
844+
server.config.mailboxes["trash"] = { uidnotsticky: true }
861845
imap.select('trash')
862-
assert_equal(
863-
imap.responses("NO", &:last).code,
864-
Net::IMAP::ResponseCode.new('UIDNOTSTICKY', nil)
865-
)
866-
imap.logout
867-
ensure
868-
imap.disconnect if imap
846+
assert imap.responses("NO", &:to_a).any? {
847+
_1.code == Net::IMAP::ResponseCode.new('UIDNOTSTICKY', nil)
848+
}
869849
end
870850
end
871851

872852
def test_enable
873-
requests = Queue.new
874-
port = yields_in_test_server_thread do |sock|
875-
requests << (tag, = sock.getcmd).join(" ") + "\r\n"
876-
sock.print "* ENABLED SMTPUTF8\r\n"
877-
sock.print "#{tag} OK \r\n"
878-
requests << (tag, = sock.getcmd).join(" ") + "\r\n"
879-
sock.print "* ENABLED CONDSTORE UTF8=ACCEPT\r\n"
880-
sock.print "#{tag} OK \r\n"
881-
requests << (tag, = sock.getcmd).join(" ") + "\r\n"
882-
sock.print "* ENABLED \r\n"
883-
sock.print "#{tag} OK \r\n"
884-
sock.getcmd # waits for logout command
885-
end
853+
with_mock_server(
854+
with_extensions: %i[ENABLE CONDSTORE UTF8=ACCEPT],
855+
capabilities_enablable: %w[CONDSTORE UTF8=ACCEPT]
856+
) do |server, imap|
857+
cmdq = server.commands
886858

887-
begin
888-
imap = Net::IMAP.new(server_addr, port: port)
889-
response = imap.enable(["SMTPUTF8", "X-NO-SUCH-THING"])
890-
assert_equal("RUBY0001 ENABLE SMTPUTF8 X-NO-SUCH-THING\r\n", requests.pop)
891-
assert_equal(response, ["SMTPUTF8"])
892-
response = imap.enable(:utf8, "condstore QResync", "x-pig-latin")
893-
assert_equal("RUBY0002 ENABLE UTF8=ACCEPT condstore QResync x-pig-latin\r\n",
894-
requests.pop)
895-
response = imap.enable(:utf8, "UTF8=ACCEPT", "UTF8=ONLY")
896-
assert_equal(response, [])
897-
assert_equal("RUBY0003 ENABLE UTF8=ACCEPT\r\n",
898-
requests.pop)
899-
imap.logout
900-
ensure
901-
imap.disconnect if imap
902-
end
903-
end
859+
result1 = imap.enable(%w[CONDSTORE x-pig-latin])
860+
result2 = imap.enable(:utf8, "condstore QResync")
861+
result3 = imap.enable(:utf8, "UTF8=ACCEPT", "UTF8=ONLY")
862+
cmd1, cmd2, cmd3 = Array.new(3) { cmdq.pop.raw.strip }
904863

905-
def yields_in_test_server_thread(
906-
read_timeout: 2, # requires ruby 3.2+
907-
timeout: 10,
908-
greeting: "* OK [CAPABILITY IMAP4rev1 AUTH=PLAIN STARTTLS] test server\r\n"
909-
)
910-
server = create_tcp_server
911-
port = server.addr[1]
912-
last_tag, last_cmd, last_args = nil
913-
@threads << Thread.start do
914-
Timeout.timeout(timeout) do
915-
sock = server.accept
916-
sock.timeout = read_timeout if sock.respond_to? :timeout # ruby 3.2+
917-
sock.singleton_class.define_method(:getcmd) do
918-
buf = "".b
919-
buf << (sock.gets || "") until /\A([^ ]+) ([^ ]+) ?(.*)\r\n\z/mn =~ buf
920-
[last_tag = $1, last_cmd = $2, last_args = $3]
921-
end
922-
begin
923-
sock.print(greeting)
924-
yield sock
925-
ensure
926-
begin
927-
sock.print("* BYE terminating connection\r\n")
928-
last_cmd =~ /LOGOUT/i and
929-
sock.print("#{last_tag} OK LOGOUT completed\r\n")
930-
ensure
931-
sock.close
932-
server.close
933-
end
934-
end
935-
end
864+
assert_equal "RUBY0001 ENABLE CONDSTORE x-pig-latin", cmd1
865+
assert_equal "RUBY0002 ENABLE UTF8=ACCEPT condstore QResync", cmd2
866+
assert_equal "RUBY0003 ENABLE UTF8=ACCEPT", cmd3
867+
assert_empty cmdq
868+
869+
assert_equal %w[CONDSTORE], result1
870+
assert_equal %w[UTF8=ACCEPT], result2
871+
assert_equal [], result3
936872
end
937-
port
938873
end
939874

940-
# SELECT returns many different untagged results, so this is useful for
941-
# several different tests.
942-
RFC3501_6_3_1_SELECT_EXAMPLE_DATA = <<~RESPONSES
943-
* 172 EXISTS
944-
* 1 RECENT
945-
* OK [UNSEEN 12] Message 12 is first unseen
946-
* OK [UIDVALIDITY 3857529045] UIDs valid
947-
* OK [UIDNEXT 4392] Predicted next UID
948-
* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)
949-
* OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)] Limited
950-
%{tag} OK [READ-WRITE] SELECT completed
951-
RESPONSES
952-
.split("\n").join("\r\n").concat("\r\n").freeze
953-
954875
def test_responses
955-
port = yields_in_test_server_thread do |sock|
956-
tag, name, = sock.getcmd
957-
if name == "SELECT"
958-
sock.print RFC3501_6_3_1_SELECT_EXAMPLE_DATA % {tag: tag}
959-
end
960-
sock.getcmd # waits for logout command
961-
end
962-
begin
963-
imap = Net::IMAP.new(server_addr, port: port)
876+
with_mock_server do |server, imap|
964877
# responses available before SELECT/EXAMINE
965-
assert_equal(%w[IMAP4REV1 AUTH=PLAIN STARTTLS],
878+
assert_equal(%w[IMAP4REV1 NAMESPACE MOVE IDLE UTF8=ACCEPT],
966879
imap.responses("CAPABILITY", &:last))
967880
resp = imap.select "INBOX"
968881
# responses are cleared after SELECT/EXAMINE
@@ -978,22 +891,11 @@ def test_responses
978891
# assert_equal(%i[Answered Flagged Deleted Seen Draft],
979892
# imap.responses["FLAGS"]&.last)
980893
# end
981-
imap.logout
982-
ensure
983-
imap.disconnect if imap
984894
end
985895
end
986896

987897
def test_clear_responses
988-
port = yields_in_test_server_thread do |sock|
989-
tag, name, = sock.getcmd
990-
if name == "SELECT"
991-
sock.print RFC3501_6_3_1_SELECT_EXAMPLE_DATA % {tag: tag}
992-
end
993-
sock.getcmd # waits for logout command
994-
end
995-
begin
996-
imap = Net::IMAP.new(server_addr, port: port)
898+
with_mock_server do |server, imap|
997899
resp = imap.select "INBOX"
998900
assert_equal([Net::IMAP::TaggedResponse, "RUBY0001", "OK"],
999901
[resp.class, resp.tag, resp.name])
@@ -1013,54 +915,55 @@ def test_clear_responses
1013915
assert_equal(3, responses["PERMANENTFLAGS"].last&.size)
1014916
assert_equal({}, imap.responses(&:itself))
1015917
assert_equal({}, imap.clear_responses)
1016-
imap.logout
1017-
ensure
1018-
imap.disconnect if imap
1019918
end
1020919
end
1021920

1022921
def test_close
1023-
requests = Queue.new
1024-
port = yields_in_test_server_thread do |sock|
1025-
requests << sock.getcmd
1026-
sock.print("RUBY0001 OK CLOSE completed\r\n")
1027-
requests << sock.getcmd
1028-
end
1029-
begin
1030-
imap = Net::IMAP.new(server_addr, :port => port)
922+
with_mock_server(select: "inbox") do |server, imap|
1031923
resp = imap.close
1032-
assert_equal(["RUBY0001", "CLOSE", ""], requests.pop)
1033-
assert_equal([Net::IMAP::TaggedResponse, "RUBY0001", "OK"],
924+
assert_equal("RUBY0002 CLOSE", server.commands.pop.raw.strip)
925+
assert_equal([Net::IMAP::TaggedResponse, "RUBY0002", "OK"],
1034926
[resp.class, resp.tag, resp.name])
1035-
imap.logout
1036-
assert_equal(["RUBY0002", "LOGOUT", ""], requests.pop)
1037-
ensure
1038-
imap.disconnect if imap
927+
assert_empty server.commands
1039928
end
1040929
end
1041930

1042931
def test_unselect
1043-
requests = Queue.new
1044-
port = yields_in_test_server_thread do |sock|
1045-
requests << sock.getcmd
1046-
sock.print("RUBY0001 OK UNSELECT completed\r\n")
1047-
requests << sock.getcmd
1048-
end
1049-
begin
1050-
imap = Net::IMAP.new(server_addr, port: port)
932+
with_mock_server(select: "inbox") do |server, imap|
1051933
resp = imap.unselect
1052-
assert_equal(["RUBY0001", "UNSELECT", ""], requests.pop)
1053-
assert_equal([Net::IMAP::TaggedResponse, "RUBY0001", "OK"],
934+
sent = server.commands.pop
935+
assert_equal(["UNSELECT", nil], [sent.name, sent.args])
936+
assert_equal([Net::IMAP::TaggedResponse, "RUBY0002", "OK"],
1054937
[resp.class, resp.tag, resp.name])
1055-
imap.logout
1056-
assert_equal(["RUBY0002", "LOGOUT", ""], requests.pop)
1057-
ensure
1058-
imap.disconnect if imap
938+
assert_empty server.commands
1059939
end
1060940
end
1061941

1062942
private
1063943

944+
def with_mock_server(select: nil, timeout: 5, **opts)
945+
Timeout.timeout(timeout) do
946+
server = Net::IMAP::MockServer.new(timeout: timeout, **opts)
947+
@threads << Thread.new do server.run end
948+
tls = opts[:implicit_tls]
949+
tls = {ca_file: server.config.tls[:ca_file]} if tls == true
950+
client = Net::IMAP.new("localhost", port: server.port, ssl: tls)
951+
begin
952+
if select
953+
client.select(select)
954+
server.commands.pop
955+
assert server.state.selected?
956+
end
957+
yield server, client
958+
ensure
959+
client.logout rescue pp $!
960+
client.disconnect if !client.disconnected?
961+
end
962+
ensure
963+
server&.shutdown
964+
end
965+
end
966+
1064967
def imaps_test
1065968
server = create_tcp_server
1066969
port = server.addr[1]

0 commit comments

Comments
 (0)