Skip to content

Commit 681423a

Browse files
committed
[PortsRb] Implement part of the SMTP placeholders for Ruby's Net::SMTP module
1 parent a3fa49c commit 681423a

File tree

3 files changed

+263
-2
lines changed

3 files changed

+263
-2
lines changed

ports-rb/ports.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,28 @@ def ports_assert_eq(expected, actual)
7373
raise Test::Unit::AssertionFailedError, "Expected #{actual} to be #{expected}" unless expected == actual
7474
end
7575

76+
def ports_thread(proc)
77+
Thread.new { proc.call }
78+
end
79+
80+
def ports_thread_kill(thread)
81+
Thread.kill(thread)
82+
end
83+
84+
def ports_thread_join(thread)
85+
# thread.join
86+
Thread.kill(thread)
87+
end
88+
89+
def ports_thread_sleep(time)
90+
sleep(time)
91+
end
92+
93+
def ports_thread_yield
94+
# Thread.pass
95+
sleep(0)
96+
end
97+
7698
class PortsSuite
7799
attr_reader :scheme_env, :suite_name, :suite_version, :sources,
78100
:placeholders, :root_capability
@@ -132,7 +154,11 @@ def initialize_ports_primitives
132154
"is-placeholder?" => lambda { |x| x.is_a?(Placeholder) },
133155
"assert" => method(:ports_assert),
134156
"assert-equal" => method(:ports_assert_eq),
135-
"is-assertion-error?" => lambda { |e| e.is_a?(Test::Unit::AssertionFailedError) }
157+
"is-assertion-error?" => lambda { |e| e.is_a?(Test::Unit::AssertionFailedError) },
158+
"thread" => method(:ports_thread),
159+
"thread-wait-for-completion" => method(:ports_thread_join),
160+
"thread-sleep!" => method(:ports_thread_sleep),
161+
"thread-yield" => method(:ports_thread_yield)
136162
}
137163

138164
primitives.each do |key, value|
@@ -229,3 +255,7 @@ def suite(file_name, &block)
229255
obj.instance_eval(&block)
230256
obj.run
231257
end
258+
259+
def fixture_path(file_name)
260+
File.join(".", "suites", file_name)
261+
end

ports-rb/scheme.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def call(*args)
7878
:"list-ref" => proc { |list, idx| list[idx] },
7979
:"list-set!" => proc { |list, idx, value| list[idx] = value },
8080
:not => proc { |a| !a },
81-
:null? => proc { |a| a.nil? || a.empty? },
81+
:null? => proc { |a| a.nil? || (a.respond_to?(:empty?) && a.empty?) },
8282
:pair? => proc { |tokens| tokens.is_a?(Array) && !tokens.empty? },
8383
:raise => proc { |e| raise e },
8484
:sqrt => proc { |a| Math.sqrt(a) },

ports-rb/smtp.rb

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
require_relative "ports"
2+
require "socket"
3+
require "net/smtp"
4+
require "openssl"
5+
6+
suite "suites/smtp.ports" do
7+
only_capabilities "root.connection", "root.commands"
8+
9+
exclude_capabilities "root.commands.expn",
10+
"root.commands.help",
11+
"root.commands.vrfy",
12+
"root.commands.auth.xoauth2",
13+
"root.commands.automatic-starttls"
14+
15+
expected_failures "test_starttls_without_server_support",
16+
"test_plain_auth_not_supported"
17+
18+
placeholder "create-socket" do |env|
19+
TCPServer.new(0)
20+
rescue => e
21+
e
22+
end
23+
24+
placeholder "socket-receive" do |env, socket|
25+
socket.recvfrom(4096).first
26+
end
27+
28+
placeholder "socket-write" do |env, socket, data|
29+
socket.write(data)
30+
end
31+
32+
placeholder "socket-port" do |env, socket|
33+
socket.addr[1]
34+
end
35+
36+
placeholder "socket-accept" do |env, socket|
37+
client, _addrinfo = socket.accept
38+
client
39+
end
40+
41+
placeholder "socket-close" do |env, socket|
42+
socket.close
43+
end
44+
45+
placeholder "secure-server-socket-wrap" do |env, socket, ca_file, cert_file, key_file, close_underlying_socket|
46+
ctx = OpenSSL::SSL::SSLContext.new
47+
ctx.ca_file = fixture_path(ca_file)
48+
ctx.cert = fixture_path(cert_file)
49+
ctx.key = fixture_path(key_file)
50+
51+
ssl_socket = OpenSSL::SSL::SSLServer.new(socket, ctx)
52+
ssl_socket.start_immediately = true
53+
ssl_socket.to_io
54+
end
55+
56+
placeholder "smtp-connect" do |env, host, port|
57+
Net::SMTP.start(host, port)
58+
rescue => e
59+
e
60+
end
61+
62+
placeholder "smtp-connect-with-auto-starttls" do |env, host, port, starttls_mode|
63+
# TODO: doesn't work yet
64+
mode = case starttls_mode
65+
when :automatic
66+
:auto
67+
when :required
68+
:always
69+
when :never
70+
false
71+
else
72+
raise "Unknown starttls_mode: #{starttls_mode}"
73+
end
74+
75+
Net::SMTP.start(host, port, starttls: mode)
76+
rescue => e
77+
e
78+
end
79+
80+
placeholder "smtp-secure-connect" do |env, host, port, ca_file|
81+
raise Test::Unit::AssertionFailedError, "Placeholder not implemented: smtp-secure-connect"
82+
end
83+
84+
placeholder "smtp-secure-connect-with-timeout" do |env, host, port, ca_file, timeout|
85+
raise Test::Unit::AssertionFailedError, "Placeholder not implemented: smtp-secure-connect-with-timeout"
86+
end
87+
88+
placeholder "smtp-disconnect" do |env, connection|
89+
connection.finish
90+
rescue => e
91+
e
92+
end
93+
94+
placeholder "smtp-connected?" do |env, connection|
95+
connection.started?
96+
end
97+
98+
placeholder "smtp-ehlo" do |env, connection, content|
99+
connection.ehlo(content)
100+
rescue => e
101+
e
102+
end
103+
104+
def address_with_options_list(address, options)
105+
opts = if options.nil?
106+
{}
107+
else
108+
options.map do |option|
109+
key, value = option
110+
value = value.join(",") if value.is_a?(Array)
111+
[key.to_sym, value]
112+
end.to_h
113+
end
114+
115+
Net::SMTP::Address.new(address, **opts)
116+
end
117+
118+
def address_with_options(address, options)
119+
opts = if options.nil?
120+
{}
121+
else
122+
options.map do |option|
123+
key, value = option.split("=")
124+
[key.to_sym, value]
125+
end.to_h
126+
end
127+
128+
Net::SMTP::Address.new(address, **opts)
129+
end
130+
131+
placeholder "smtp-mail-with-options" do |env, connection, from, options|
132+
addr = address_with_options(from, options)
133+
connection.mailfrom(addr)
134+
rescue => e
135+
e
136+
end
137+
138+
placeholder "smtp-rcpt" do |env, connection, to_list, options_list|
139+
to_list.zip(options_list).map do |to, options|
140+
address = address_with_options_list(to, options)
141+
connection.rcptto(address)
142+
rescue => e
143+
e
144+
end
145+
end
146+
147+
placeholder "smtp-data" do |env, connection, content|
148+
connection.data(content)
149+
rescue => e
150+
e
151+
end
152+
153+
placeholder "smtp-rset" do |env, connection|
154+
connection.rset
155+
end
156+
157+
placeholder "smtp-vrfy" do |env, connection, content|
158+
raise Test::Unit::AssertionFailedError, "Placeholder not implemented: smtp-vrfy"
159+
end
160+
161+
placeholder "smtp-help" do |env, connection, content|
162+
raise Test::Unit::AssertionFailedError, "Placeholder not implemented: smtp-help"
163+
end
164+
165+
placeholder "smtp-expn" do |env, connection, content|
166+
raise Test::Unit::AssertionFailedError, "Placeholder not implemented: smtp-expn"
167+
end
168+
169+
placeholder "smtp-starttls" do |env, connection, cert_file, key_file|
170+
connection.starttls
171+
end
172+
173+
placeholder "smtp-quit" do |env, connection|
174+
connection.quit
175+
end
176+
177+
placeholder "smtp-send-message-with-options" do |env, connection, message_content, from, to_list, message_options, to_list_options|
178+
to_addresses = to_list.zip(to_list_options).map { |addr, opts| address_with_options(addr, opts) }
179+
connection.send_message(message_content, from, to_addresses)
180+
rescue => e
181+
e
182+
end
183+
184+
placeholder "smtp-response-code" do |env, response|
185+
if response.is_a?(Net::SMTPError)
186+
response.response.status.to_i
187+
else
188+
response.status.to_i
189+
end
190+
end
191+
192+
placeholder "smtp-response-message" do |env, response|
193+
response.string[4..]
194+
end
195+
196+
placeholder "smtp-error?" do |env, response|
197+
response.is_a?(Net::SMTPError) || response.is_a?(SocketError)
198+
end
199+
200+
placeholder "smtp-extensions" do |env, connection, ehlo_response|
201+
connection.capabilities
202+
end
203+
204+
placeholder "smtp-extension-not-supported-error?" do |env, response|
205+
response.is_a?(Net::SMTPUnsupportedCommand)
206+
end
207+
208+
placeholder "smtp-expn-response-users-list" do |env, response|
209+
raise Test::Unit::AssertionFailedError, "Placeholder not implemented: smtp-expn-response-users-list"
210+
end
211+
212+
placeholder "smtp-authenticate-initial-response" do |env, connection, method, credentials, initial_response|
213+
auth_method = method.downcase.to_s.tr("-", "_").to_sym
214+
215+
connection.authenticate(credentials[0], credentials[1], auth_method)
216+
rescue => e
217+
e
218+
end
219+
220+
placeholder "smtp-auth-successful?" do |env, response|
221+
response.is_a?(Net::SMTP::Response) && response.success?
222+
end
223+
224+
placeholder "smtp-auth-credentials-error?" do |env, response|
225+
response.is_a?(Net::SMTPAuthenticationError) && response.response.status == "535"
226+
end
227+
228+
placeholder "smtp-auth-not-supported-error?" do |env, response|
229+
response.is_a?(Net::SMTPSyntaxError) && response.response.status == "504"
230+
end
231+
end

0 commit comments

Comments
 (0)