remailer 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/remailer.rb +1 -0
- data/lib/remailer/connection.rb +132 -377
- data/lib/remailer/connection/smtp_interpreter.rb +270 -0
- data/lib/remailer/connection/socks5_interpreter.rb +186 -0
- data/lib/remailer/interpreter.rb +253 -0
- data/lib/remailer/interpreter/state_proxy.rb +43 -0
- data/remailer.gemspec +19 -3
- data/test/config.example.rb +17 -0
- data/test/helper.rb +61 -2
- data/test/unit/remailer_connection_smtp_interpreter_test.rb +347 -0
- data/test/unit/remailer_connection_socks5_interpreter_test.rb +116 -0
- data/test/unit/remailer_connection_test.rb +287 -0
- data/test/unit/remailer_interpreter_state_proxy_test.rb +86 -0
- data/test/unit/remailer_interpreter_test.rb +153 -0
- data/test/unit/remailer_test.rb +2 -223
- metadata +20 -4
@@ -0,0 +1,287 @@
|
|
1
|
+
require File.expand_path(File.join(*%w[ .. helper ]), File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class RemailerConnectionTest < Test::Unit::TestCase
|
4
|
+
def test_connect
|
5
|
+
engine do
|
6
|
+
debug = { }
|
7
|
+
connected_host = nil
|
8
|
+
|
9
|
+
connection = Remailer::Connection.open(
|
10
|
+
TestConfig.smtp_server[:host],
|
11
|
+
:debug => STDERR,
|
12
|
+
:connect => lambda { |success, host| connected_host = host }
|
13
|
+
)
|
14
|
+
|
15
|
+
after_complete_trigger = false
|
16
|
+
|
17
|
+
connection.close_when_complete!
|
18
|
+
connection.after_complete do
|
19
|
+
after_complete_trigger = true
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_equal :initialized, connection.state
|
23
|
+
assert !connection.error?
|
24
|
+
assert !connection.closed?
|
25
|
+
|
26
|
+
assert_eventually(30) do
|
27
|
+
connection.closed?
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_equal TestConfig.smtp_server[:host], connected_host
|
31
|
+
|
32
|
+
assert_equal true, after_complete_trigger
|
33
|
+
|
34
|
+
assert_equal 52428800, connection.max_size
|
35
|
+
assert_equal :esmtp, connection.protocol
|
36
|
+
assert_equal true, connection.tls_support?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_failed_connect_no_service
|
41
|
+
engine do
|
42
|
+
error_received = nil
|
43
|
+
|
44
|
+
connection = Remailer::Connection.open(
|
45
|
+
'example.com',
|
46
|
+
:debug => STDERR,
|
47
|
+
:error => lambda { |code, message|
|
48
|
+
error_received = [ code, message ]
|
49
|
+
},
|
50
|
+
:timeout => 1
|
51
|
+
)
|
52
|
+
|
53
|
+
assert_eventually(3) do
|
54
|
+
error_received
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_equal :timeout, error_received[0]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_failed_connect_no_valid_hostname
|
62
|
+
engine do
|
63
|
+
error_received = nil
|
64
|
+
|
65
|
+
connection = Remailer::Connection.open(
|
66
|
+
'invalid-example-domain--x.com',
|
67
|
+
:debug => STDERR,
|
68
|
+
:error => lambda { |code, message|
|
69
|
+
error_received = [ code, message ]
|
70
|
+
},
|
71
|
+
:timeout => 1
|
72
|
+
)
|
73
|
+
|
74
|
+
assert_eventually(3) do
|
75
|
+
error_received
|
76
|
+
end
|
77
|
+
|
78
|
+
assert_equal :connect_error, error_received[0]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_connect_with_auth
|
83
|
+
engine do
|
84
|
+
debug = { }
|
85
|
+
|
86
|
+
connection = Remailer::Connection.open(
|
87
|
+
TestConfig.public_smtp_server[:host],
|
88
|
+
:port => TestConfig.public_smtp_server[:port] || Remailer::Connection::SMTP_PORT,
|
89
|
+
:debug => STDERR,
|
90
|
+
:username => TestConfig.public_smtp_server[:username],
|
91
|
+
:password => TestConfig.public_smtp_server[:password]
|
92
|
+
)
|
93
|
+
|
94
|
+
after_complete_trigger = false
|
95
|
+
|
96
|
+
connection.close_when_complete!
|
97
|
+
connection.after_complete do
|
98
|
+
after_complete_trigger = true
|
99
|
+
end
|
100
|
+
|
101
|
+
assert_equal :initialized, connection.state
|
102
|
+
assert !connection.error?
|
103
|
+
|
104
|
+
assert_eventually(15) do
|
105
|
+
connection.closed?
|
106
|
+
end
|
107
|
+
|
108
|
+
assert_equal TestConfig.public_smtp_server[:identifier], connection.remote
|
109
|
+
|
110
|
+
assert_equal true, after_complete_trigger
|
111
|
+
|
112
|
+
assert_equal 35651584, connection.max_size
|
113
|
+
assert_equal :esmtp, connection.protocol
|
114
|
+
assert_equal true, connection.tls_support?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_connect_via_proxy
|
119
|
+
engine do
|
120
|
+
debug = { }
|
121
|
+
|
122
|
+
connection = Remailer::Connection.open(
|
123
|
+
TestConfig.smtp_server[:host],
|
124
|
+
:debug => STDERR,
|
125
|
+
:proxy => {
|
126
|
+
:proto => :socks5,
|
127
|
+
:host => TestConfig.proxy_server
|
128
|
+
}
|
129
|
+
)
|
130
|
+
|
131
|
+
after_complete_trigger = false
|
132
|
+
|
133
|
+
connection.close_when_complete!
|
134
|
+
connection.after_complete do
|
135
|
+
after_complete_trigger = true
|
136
|
+
end
|
137
|
+
|
138
|
+
assert_equal :connect_to_proxy, connection.state
|
139
|
+
assert !connection.error?
|
140
|
+
|
141
|
+
assert_eventually(15) do
|
142
|
+
connection.closed?
|
143
|
+
end
|
144
|
+
|
145
|
+
assert_equal TestConfig.smtp_server[:identifier], connection.remote
|
146
|
+
|
147
|
+
assert_equal true, after_complete_trigger
|
148
|
+
|
149
|
+
assert_equal 52428800, connection.max_size
|
150
|
+
assert_equal :esmtp, connection.protocol
|
151
|
+
assert_equal true, connection.tls_support?
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_connect_and_send_after_start
|
156
|
+
engine do
|
157
|
+
connection = Remailer::Connection.open(
|
158
|
+
TestConfig.smtp_server[:host],
|
159
|
+
:debug => STDERR
|
160
|
+
)
|
161
|
+
|
162
|
+
assert_equal :initialized, connection.state
|
163
|
+
|
164
|
+
assert_eventually(10) do
|
165
|
+
connection.state == :ready
|
166
|
+
end
|
167
|
+
|
168
|
+
result_code = nil
|
169
|
+
callback_received = false
|
170
|
+
|
171
|
+
connection.send_email(
|
172
|
+
'remailer+test@example.postageapp.com',
|
173
|
+
'remailer+test@example.postageapp.com',
|
174
|
+
example_message
|
175
|
+
) do |c|
|
176
|
+
callback_received = true
|
177
|
+
result_code = c
|
178
|
+
end
|
179
|
+
|
180
|
+
assert_eventually(5) do
|
181
|
+
callback_received
|
182
|
+
end
|
183
|
+
|
184
|
+
assert_equal 250, result_code
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_connect_and_send_dotted_message
|
189
|
+
engine do
|
190
|
+
connection = Remailer::Connection.open(
|
191
|
+
TestConfig.smtp_server[:host],
|
192
|
+
:debug => STDERR
|
193
|
+
)
|
194
|
+
|
195
|
+
assert_equal :initialized, connection.state
|
196
|
+
assert !connection.error?
|
197
|
+
|
198
|
+
result_code = nil
|
199
|
+
connection.send_email(
|
200
|
+
'remailer+test@example.postageapp.com',
|
201
|
+
'remailer+test@example.postageapp.com',
|
202
|
+
example_message + "\r\n\.\r\nHam sandwich.\r\n"
|
203
|
+
) do |c|
|
204
|
+
result_code = c
|
205
|
+
end
|
206
|
+
|
207
|
+
assert_eventually(15) do
|
208
|
+
result_code == 250
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_connect_and_send_multiple
|
214
|
+
engine do
|
215
|
+
connection = Remailer::Connection.open(
|
216
|
+
TestConfig.smtp_server[:host],
|
217
|
+
:debug => STDERR
|
218
|
+
)
|
219
|
+
|
220
|
+
assert_equal :initialized, connection.state
|
221
|
+
assert !connection.error?
|
222
|
+
|
223
|
+
result_code = [ ]
|
224
|
+
|
225
|
+
10.times do |n|
|
226
|
+
connection.send_email(
|
227
|
+
'remailer+from@example.postageapp.com',
|
228
|
+
"remailer+to#{n}@example.postageapp.com",
|
229
|
+
example_message
|
230
|
+
) do |c|
|
231
|
+
result_code[n] = c
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
assert_eventually(15) do
|
236
|
+
result_code == [ 250 ] * 10
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_connect_and_long_send
|
242
|
+
engine do
|
243
|
+
connection = Remailer::Connection.open(
|
244
|
+
TestConfig.smtp_server[:host],
|
245
|
+
:debug => STDERR
|
246
|
+
)
|
247
|
+
|
248
|
+
assert_equal :initialized, connection.state
|
249
|
+
|
250
|
+
callback_made = false
|
251
|
+
result_code = nil
|
252
|
+
|
253
|
+
connection.send_email(
|
254
|
+
TestConfig.sender,
|
255
|
+
TestConfig.recipient,
|
256
|
+
example_message + 'a' * 100000
|
257
|
+
) do |c|
|
258
|
+
callback_made = true
|
259
|
+
result_code = c
|
260
|
+
end
|
261
|
+
|
262
|
+
assert_eventually(30) do
|
263
|
+
callback_made
|
264
|
+
end
|
265
|
+
|
266
|
+
assert_equal 250, result_code
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
protected
|
271
|
+
def example_message
|
272
|
+
example = <<__END__
|
273
|
+
Date: Sat, 13 Nov 2010 02:25:24 +0000
|
274
|
+
From: #{TestConfig.sender}
|
275
|
+
To: Remailer Test <#{TestConfig.receiver}>
|
276
|
+
Message-Id: <hfLkcIByfjYoNIxCO7DMsxBTX9svsFHikIOfAiYy@#{TestConfig.sender.split(/@/).last}>
|
277
|
+
Subject: Example Subject
|
278
|
+
Mime-Version: 1.0
|
279
|
+
Content-Type: text/plain
|
280
|
+
Auto-Submitted: auto-generated
|
281
|
+
|
282
|
+
This is a very boring message. It is dreadfully dull.
|
283
|
+
__END__
|
284
|
+
|
285
|
+
example.gsub(/\n/, "\r\n")
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path(File.join(*%w[ .. helper ]), File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class RemailerInterpreterStateTest < Test::Unit::TestCase
|
4
|
+
def test_defaults
|
5
|
+
options = { }
|
6
|
+
|
7
|
+
Remailer::Interpreter::StateProxy.new(options)
|
8
|
+
|
9
|
+
assert_equal({ }, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_simple_configuration
|
13
|
+
options = { }
|
14
|
+
|
15
|
+
proxy = Remailer::Interpreter::StateProxy.new(options)
|
16
|
+
|
17
|
+
expected = {
|
18
|
+
:enter => [ lambda { } ],
|
19
|
+
:default => [ lambda { } ],
|
20
|
+
:leave => [ lambda { } ]
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
proxy.enter(&expected[:enter][0])
|
24
|
+
proxy.default(&expected[:default][0])
|
25
|
+
proxy.leave(&expected[:leave][0])
|
26
|
+
|
27
|
+
assert_equal expected, options
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_terminal_configuration
|
31
|
+
options = { }
|
32
|
+
|
33
|
+
expected = {
|
34
|
+
:enter => [ lambda { } ],
|
35
|
+
:terminate => [ lambda { } ],
|
36
|
+
:leave => [ lambda { } ]
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
Remailer::Interpreter::StateProxy.new(options) do
|
40
|
+
enter(&expected[:enter][0])
|
41
|
+
terminate(&expected[:terminate][0])
|
42
|
+
leave(&expected[:leave][0])
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_equal expected, options
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_interpreting_configuration
|
49
|
+
options = { }
|
50
|
+
|
51
|
+
expected = {
|
52
|
+
:enter => [ lambda { } ],
|
53
|
+
:interpret => [ [ 10, lambda { } ], [ 1, lambda { } ] ],
|
54
|
+
:default => [ lambda { } ],
|
55
|
+
:leave => [ lambda { } ]
|
56
|
+
}.freeze
|
57
|
+
|
58
|
+
Remailer::Interpreter::StateProxy.new(options) do
|
59
|
+
enter(&expected[:enter][0])
|
60
|
+
interpret(10, &expected[:interpret][0][1])
|
61
|
+
interpret(1, &expected[:interpret][1][1])
|
62
|
+
default(&expected[:default][0])
|
63
|
+
leave(&expected[:leave][0])
|
64
|
+
end
|
65
|
+
|
66
|
+
assert_equal expected, options
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_rebind
|
70
|
+
options_a = { }
|
71
|
+
options_b = { }
|
72
|
+
|
73
|
+
proc = [ lambda { }, lambda { } ]
|
74
|
+
|
75
|
+
proxy = Remailer::Interpreter::StateProxy.new(options_a) do
|
76
|
+
enter(&proc[0])
|
77
|
+
end
|
78
|
+
|
79
|
+
proxy.send(:rebind, options_b)
|
80
|
+
|
81
|
+
proxy.leave(&proc[1])
|
82
|
+
|
83
|
+
assert_equal({ :enter => [ proc[0] ] }, options_a)
|
84
|
+
assert_equal({ :leave => [ proc[1] ] }, options_b)
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require File.expand_path(File.join(*%w[ .. helper ]), File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class ExampleDelegate
|
4
|
+
include TestTriggerHelper
|
5
|
+
|
6
|
+
attr_accessor :attribute
|
7
|
+
|
8
|
+
def method_no_args
|
9
|
+
trigger(:method_no_args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_with_args(arg1, arg2)
|
13
|
+
trigger(:method_with_args, [ arg1, arg2 ])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class AutomaticDelegate
|
18
|
+
include TestTriggerHelper
|
19
|
+
|
20
|
+
def enter_initialized!
|
21
|
+
trigger(:enter_initialized)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ExampleInterpreter < Remailer::Interpreter
|
26
|
+
include TestTriggerHelper
|
27
|
+
|
28
|
+
attr_accessor :message, :reply
|
29
|
+
|
30
|
+
state :initialized do
|
31
|
+
enter do
|
32
|
+
trigger(:enter_initialized_state)
|
33
|
+
end
|
34
|
+
|
35
|
+
interpret(:start) do
|
36
|
+
enter_state(:start)
|
37
|
+
end
|
38
|
+
|
39
|
+
interpret(:branch) do
|
40
|
+
enter_state(:branch)
|
41
|
+
end
|
42
|
+
|
43
|
+
leave do
|
44
|
+
trigger(:leave_initialized_state)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
state :start do
|
49
|
+
interpret(:stop) do |message|
|
50
|
+
self.message = message
|
51
|
+
enter_state(:stop)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
state :branch do
|
56
|
+
default do |reply|
|
57
|
+
@reply = reply
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
state :stop do
|
62
|
+
terminate
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class RemailerInterpreterTest < Test::Unit::TestCase
|
67
|
+
def test_default_state
|
68
|
+
assert_equal [ :initialized, :terminated ], Remailer::Interpreter.states_defined
|
69
|
+
assert_equal true, Remailer::Interpreter.state_defined?(:initialized)
|
70
|
+
assert_equal true, Remailer::Interpreter.state_defined?(:terminated)
|
71
|
+
assert_equal false, Remailer::Interpreter.state_defined?(:unknown)
|
72
|
+
|
73
|
+
interpreter = Remailer::Interpreter.new
|
74
|
+
|
75
|
+
assert_equal :initialized, interpreter.state
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_delegate
|
79
|
+
delegate = ExampleDelegate.new
|
80
|
+
|
81
|
+
assert delegate.triggered
|
82
|
+
|
83
|
+
interpreter = Remailer::Interpreter.new(:delegate => delegate)
|
84
|
+
|
85
|
+
assert_equal nil, delegate.attribute
|
86
|
+
assert_equal false, delegate.triggered[:method_no_args]
|
87
|
+
assert_equal false, delegate.triggered[:method_with_args]
|
88
|
+
|
89
|
+
interpreter.send(:delegate_call, :method_no_args)
|
90
|
+
|
91
|
+
assert_equal true, delegate.triggered[:method_no_args]
|
92
|
+
assert_equal false, delegate.triggered[:method_with_args]
|
93
|
+
|
94
|
+
interpreter.send(:delegate_call, :method_with_args, 'one', :two)
|
95
|
+
|
96
|
+
assert_equal true, delegate.triggered[:method_no_args]
|
97
|
+
assert_equal [ 'one', :two ], delegate.triggered[:method_with_args]
|
98
|
+
|
99
|
+
interpreter.send(:delegate_call, :invalid_method)
|
100
|
+
|
101
|
+
interpreter.send(:delegate_assign, :attribute, 'true')
|
102
|
+
|
103
|
+
assert_equal 'true', delegate.attribute
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_example_interpreter
|
107
|
+
interpreter = ExampleInterpreter.new
|
108
|
+
|
109
|
+
assert_equal :initialized, interpreter.state
|
110
|
+
assert_equal true, interpreter.triggered[:enter_initialized_state]
|
111
|
+
assert_equal false, interpreter.triggered[:leave_initialized_state]
|
112
|
+
|
113
|
+
interpreter.interpret(:start)
|
114
|
+
|
115
|
+
assert_equal :start, interpreter.state
|
116
|
+
assert_equal true, interpreter.triggered[:enter_initialized_state]
|
117
|
+
assert_equal true, interpreter.triggered[:leave_initialized_state]
|
118
|
+
|
119
|
+
interpreter.interpret(:stop, 'Stop message')
|
120
|
+
|
121
|
+
assert_equal 'Stop message', interpreter.message
|
122
|
+
assert_equal :terminated, interpreter.state
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_default_handler_for_interpreter
|
126
|
+
interpreter = ExampleInterpreter.new
|
127
|
+
|
128
|
+
interpreter.interpret(:branch)
|
129
|
+
|
130
|
+
assert_equal :branch, interpreter.state
|
131
|
+
|
132
|
+
assert_equal true, interpreter.interpret(:random)
|
133
|
+
|
134
|
+
assert_equal :branch, interpreter.state
|
135
|
+
assert_equal nil, interpreter.error
|
136
|
+
|
137
|
+
assert_equal :random, interpreter.reply
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_invalid_response_for_interpreter
|
141
|
+
interpreter = ExampleInterpreter.new
|
142
|
+
|
143
|
+
assert_equal :initialized, interpreter.state
|
144
|
+
|
145
|
+
interpreter.interpret(:invalid)
|
146
|
+
|
147
|
+
assert_equal :terminated, interpreter.state
|
148
|
+
assert_equal true, interpreter.error?
|
149
|
+
|
150
|
+
assert interpreter.error.index(':initialized')
|
151
|
+
assert interpreter.error.index(':invalid')
|
152
|
+
end
|
153
|
+
end
|