test: cover FakeSmtpServer and initialize
This commit is contained in:
1 parent
3fb6c9f5f3
commit
e1ef112db8
1 file changed
+144
@@ -0,0 +1,144 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'socket'
|
||||||
|
|
||||||
|
# A minimal but real SMTP server: enough of RFC 5321 (EHLO/MAIL FROM/RCPT
|
||||||
|
# TO/DATA/QUIT) for Ruby's Net::SMTP client to complete a full session
|
||||||
|
# against it over an actual TCP socket. Used to prove Prism::Mailer's :smtp
|
||||||
|
# delivery path really speaks SMTP, not just that it calls into Net::SMTP.
|
||||||
|
class FakeSmtpServer
|
||||||
|
attr_reader :commands, :data
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@server = TCPServer.new('127.0.0.1', 0)
|
||||||
|
@commands = []
|
||||||
|
@data = nil
|
||||||
|
@mutex = Mutex.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def port
|
||||||
|
@server.addr[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
@thread = Thread.new { accept_loop }
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
@server.close
|
||||||
|
@thread&.join(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def accept_loop
|
||||||
|
loop do
|
||||||
|
client = @server.accept
|
||||||
|
handle(client)
|
||||||
|
client.close
|
||||||
|
end
|
||||||
|
rescue IOError, Errno::EBADF
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle(client)
|
||||||
|
client.print "220 fake.smtp ready\r\n"
|
||||||
|
loop do
|
||||||
|
line = client.gets
|
||||||
|
break unless line
|
||||||
|
|
||||||
|
record(line.chomp)
|
||||||
|
break unless dispatch(client, line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def record(line)
|
||||||
|
@mutex.synchronize { @commands << line }
|
||||||
|
end
|
||||||
|
|
||||||
|
def dispatch(client, line)
|
||||||
|
case line
|
||||||
|
when /\A(EHLO|HELO)/i
|
||||||
|
client.print "250 fake.smtp\r\n"
|
||||||
|
when /\AMAIL FROM/i, /\ARCPT TO/i
|
||||||
|
client.print "250 OK\r\n"
|
||||||
|
when /\ADATA/i
|
||||||
|
client.print "354 go ahead\r\n"
|
||||||
|
read_data(client)
|
||||||
|
client.print "250 OK queued\r\n"
|
||||||
|
when /\AQUIT/i
|
||||||
|
client.print "221 bye\r\n"
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
client.print "500 unrecognized\r\n"
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_data(client)
|
||||||
|
body = +''
|
||||||
|
while (line = client.gets)
|
||||||
|
break if line == ".\r\n"
|
||||||
|
|
||||||
|
body << line
|
||||||
|
end
|
||||||
|
@mutex.synchronize { @data = body }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MailerSmtpTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@previous_method = Prism::Mailer.delivery_method
|
||||||
|
@previous_settings = Prism::Mailer.smtp_settings
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
Prism::Mailer.delivery_method = @previous_method
|
||||||
|
Prism::Mailer.smtp_settings = @previous_settings
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_smtp_delivery_speaks_real_smtp_to_a_live_server_over_tcp
|
||||||
|
server = FakeSmtpServer.new.start
|
||||||
|
Prism::Mailer.delivery_method = :smtp
|
||||||
|
Prism::Mailer.smtp_settings = { address: '127.0.0.1', port: server.port, domain: 'test.local' }
|
||||||
|
|
||||||
|
message = Prism::Mailer::Message.new
|
||||||
|
message.from = 'sender@example.com'
|
||||||
|
message.to = 'receiver@example.com'
|
||||||
|
message.subject = 'Live SMTP test'
|
||||||
|
message.text_body = 'delivered over a real socket'
|
||||||
|
|
||||||
|
Prism::Mailer.deliver!(message)
|
||||||
|
server.stop
|
||||||
|
|
||||||
|
assert(server.commands.any? { |c| c =~ /\AMAIL FROM:<sender@example\.com>/i })
|
||||||
|
assert(server.commands.any? { |c| c =~ /\ARCPT TO:<receiver@example\.com>/i })
|
||||||
|
assert_includes server.data, 'delivered over a real socket'
|
||||||
|
assert_includes server.data, 'Subject: Live SMTP test'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_smtp_delivery_raises_when_no_server_is_listening
|
||||||
|
Prism::Mailer.delivery_method = :smtp
|
||||||
|
Prism::Mailer.smtp_settings = { address: '127.0.0.1', port: 1, domain: 'test.local' }
|
||||||
|
|
||||||
|
message = Prism::Mailer::Message.new
|
||||||
|
message.from = 'sender@example.com'
|
||||||
|
message.to = 'receiver@example.com'
|
||||||
|
message.subject = 'Unreachable'
|
||||||
|
message.text_body = 'never sent'
|
||||||
|
|
||||||
|
assert_raises(StandardError) { Prism::Mailer.deliver!(message) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unknown_delivery_method_raises_immediately
|
||||||
|
Prism::Mailer.delivery_method = :carrier_pigeon
|
||||||
|
message = Prism::Mailer::Message.new
|
||||||
|
message.from = 'sender@example.com'
|
||||||
|
message.to = 'receiver@example.com'
|
||||||
|
message.subject = 'x'
|
||||||
|
message.text_body = 'x'
|
||||||
|
|
||||||
|
assert_raises(ArgumentError) { Prism::Mailer.deliver!(message) }
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in new issue
Block a user