ruby/test/net/smtp/test_smtp.rb
TOMITA Masahiro 141404e898 [ruby/net-smtp] Net::SMTP.start arguments are keyword arguments
The helo argument is not important, but the helo argument must be
specified to specify the user and secret arguments.
If helo, user, secret, and authtype arguments are keyword arguments,
it is not necessary to specify the helo argument.

269774deac
2020-09-14 17:23:41 +09:00

282 lines
8.2 KiB
Ruby

# frozen_string_literal: true
require 'net/smtp'
require 'stringio'
require 'test/unit'
module Net
class TestSMTP < Test::Unit::TestCase
CA_FILE = File.expand_path("../fixtures/cacert.pem", __dir__)
SERVER_KEY = File.expand_path("../fixtures/server.key", __dir__)
SERVER_CERT = File.expand_path("../fixtures/server.crt", __dir__)
class FakeSocket
attr_reader :write_io
def initialize out = "250 OK\n"
@write_io = StringIO.new
@read_io = StringIO.new out
end
def writeline line
@write_io.write "#{line}\r\n"
end
def readline
line = @read_io.gets
raise 'ran out of input' unless line
line.chop
end
end
def test_critical
smtp = Net::SMTP.new 'localhost', 25
assert_raise RuntimeError do
smtp.send :critical do
raise 'fail on purpose'
end
end
assert_kind_of Net::SMTP::Response, smtp.send(:critical),
'[Bug #9125]'
end
def test_esmtp
smtp = Net::SMTP.new 'localhost', 25
assert smtp.esmtp
assert smtp.esmtp?
smtp.esmtp = 'omg'
assert_equal 'omg', smtp.esmtp
assert_equal 'omg', smtp.esmtp?
end
def test_rset
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, FakeSocket.new
assert smtp.rset
end
def test_mailfrom
sock = FakeSocket.new
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, sock
assert smtp.mailfrom("foo@example.com").success?
assert_equal "MAIL FROM:<foo@example.com>\r\n", sock.write_io.string
end
def test_rcptto
sock = FakeSocket.new
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, sock
assert smtp.rcptto("foo@example.com").success?
assert_equal "RCPT TO:<foo@example.com>\r\n", sock.write_io.string
end
def test_auth_plain
sock = FakeSocket.new
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, sock
assert smtp.auth_plain("foo", "bar").success?
assert_equal "AUTH PLAIN AGZvbwBiYXI=\r\n", sock.write_io.string
end
def test_crlf_injection
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, FakeSocket.new
assert_raise(ArgumentError) do
smtp.mailfrom("foo\r\nbar")
end
assert_raise(ArgumentError) do
smtp.mailfrom("foo\rbar")
end
assert_raise(ArgumentError) do
smtp.mailfrom("foo\nbar")
end
assert_raise(ArgumentError) do
smtp.rcptto("foo\r\nbar")
end
end
def test_tls_connect
servers = Socket.tcp_server_sockets("localhost", 0)
ctx = OpenSSL::SSL::SSLContext.new
ctx.ca_file = CA_FILE
ctx.key = File.open(SERVER_KEY) { |f|
OpenSSL::PKey::RSA.new(f)
}
ctx.cert = File.open(SERVER_CERT) { |f|
OpenSSL::X509::Certificate.new(f)
}
begin
sock = nil
Thread.start do
s = accept(servers)
sock = OpenSSL::SSL::SSLSocket.new(s, ctx)
sock.sync_close = true
sock.accept
sock.write("220 localhost Service ready\r\n")
sock.gets
sock.write("250 localhost\r\n")
sock.gets
sock.write("221 localhost Service closing transmission channel\r\n")
end
smtp = Net::SMTP.new("localhost", servers[0].local_address.ip_port)
smtp.enable_tls
smtp.open_timeout = 1
smtp.start do
end
ensure
sock.close if sock
servers.each(&:close)
end
rescue LoadError
# skip (require openssl)
end
def test_tls_connect_timeout
servers = Socket.tcp_server_sockets("localhost", 0)
begin
sock = nil
Thread.start do
sock = accept(servers)
end
smtp = Net::SMTP.new("localhost", servers[0].local_address.ip_port)
smtp.enable_tls
smtp.open_timeout = 0.1
assert_raise(Net::OpenTimeout) do
smtp.start do
end
end
rescue LoadError
# skip (require openssl)
ensure
sock.close if sock
servers.each(&:close)
end
end
def test_eof_error_backtrace
bug13018 = '[ruby-core:78550] [Bug #13018]'
servers = Socket.tcp_server_sockets("localhost", 0)
begin
sock = nil
t = Thread.start do
sock = accept(servers)
sock.close
end
smtp = Net::SMTP.new("localhost", servers[0].local_address.ip_port)
e = assert_raise(EOFError, bug13018) do
smtp.start do
end
end
assert_equal(EOFError, e.class, bug13018)
assert(e.backtrace.grep(%r"\bnet/smtp\.rb:").size > 0, bug13018)
ensure
sock.close if sock
servers.each(&:close)
t.join
end
end
def test_start
port = fake_server_start
smtp = Net::SMTP.start('localhost', port)
smtp.quit
end
def test_start_with_position_argument
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
smtp = Net::SMTP.start('localhost', port, 'myname', 'account', 'password', :plain)
smtp.quit
end
def test_start_with_keyword_argument
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
smtp = Net::SMTP.start('localhost', port, helo: 'myname', user: 'account', secret: 'password', authtype: :plain)
smtp.quit
end
def test_start_password_is_secret
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
smtp = Net::SMTP.start('localhost', port, helo: 'myname', user: 'account', password: 'password', authtype: :plain)
smtp.quit
end
def test_start_invalid_number_of_arguments
err = assert_raise ArgumentError do
Net::SMTP.start('localhost', 25, 'myname', 'account', 'password', :plain, :invalid_arg)
end
assert_equal('wrong number of arguments (given 7, expected 1..6)', err.message)
end
def test_start_instance
port = fake_server_start
smtp = Net::SMTP.new('localhost', port)
smtp.start
smtp.quit
end
def test_start_instance_with_position_argument
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
smtp = Net::SMTP.new('localhost', port)
smtp.start('myname', 'account', 'password', :plain)
smtp.quit
end
def test_start_instance_with_keyword_argument
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
smtp = Net::SMTP.new('localhost', port)
smtp.start(helo: 'myname', user: 'account', secret: 'password', authtype: :plain)
smtp.quit
end
def test_start_instance_password_is_secret
port = fake_server_start(helo: 'myname', user: 'account', password: 'password')
smtp = Net::SMTP.new('localhost', port)
smtp.start(helo: 'myname', user: 'account', password: 'password', authtype: :plain)
smtp.quit
end
def test_start_instance_invalid_number_of_arguments
smtp = Net::SMTP.new('localhost')
err = assert_raise ArgumentError do
smtp.start('myname', 'account', 'password', :plain, :invalid_arg)
end
assert_equal('wrong number of arguments (given 5, expected 0..4)', err.message)
end
private
def accept(servers)
Socket.accept_loop(servers) { |s, _| break s }
end
def fake_server_start(helo: 'localhost', user: nil, password: nil)
servers = Socket.tcp_server_sockets('localhost', 0)
Thread.start do
Thread.current.abort_on_exception = true
sock = accept(servers)
sock.puts "220 ready\r\n"
assert_equal("EHLO #{helo}\r\n", sock.gets)
sock.puts "220-servername\r\n220 AUTH PLAIN\r\n"
if user
credential = ["\0#{user}\0#{password}"].pack('m0')
assert_equal("AUTH PLAIN #{credential}\r\n", sock.gets)
sock.puts "235 2.7.0 Authentication successful\r\n"
end
assert_equal("QUIT\r\n", sock.gets)
sock.puts "221 2.0.0 Bye\r\n"
sock.close
servers.each(&:close)
end
port = servers[0].local_address.ip_port
return port
end
end
end