mail_sandbox 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
- script: "bundle exec turn -Itest test/mail_sandbox"
2
+ script: "bundle exec turn -Itest test/integration test/unit"
3
3
  rvm:
4
4
  - 1.9.3
5
5
  branches:
@@ -10,6 +10,8 @@ module MailSandbox
10
10
  # :config_file:String - path to yaml config file
11
11
  # :http_observe?:Boolean - subscribe Observer::Http to receive new messages and push them by http protocol
12
12
  # :http_observe_url:String - url for push on receive new messages, use by Observer::Http
13
+ # :daemonize:Bool - run daemonized in the background
14
+ # :pidfile:String - PATH to pid file
13
15
  #
14
16
  def initialize
15
17
  @config = {
@@ -1,5 +1,6 @@
1
1
  require "eventmachine"
2
2
  require 'optparse'
3
+ require 'simple_pid'
3
4
  require 'fileutils'
4
5
 
5
6
  module MailSandbox
@@ -22,6 +23,14 @@ module MailSandbox
22
23
  config.environment = f
23
24
  end
24
25
 
26
+ opts.on("-D", "--daemonize", "Run daemonized") do |f|
27
+ config.daemonize = f
28
+ end
29
+
30
+ opts.on("-P", "--pid FILE", "File to store PID") do |f|
31
+ config.pidfile = ::File.expand_path(f)
32
+ end
33
+
25
34
  end.parse!
26
35
  end
27
36
 
@@ -39,13 +48,16 @@ module MailSandbox
39
48
  when :debug then Logger::DEBUG
40
49
  end
41
50
  STDOUT.sync = true
42
- MailSandbox::Signals.trap
51
+ MailSandbox::Signals.trap(self)
43
52
  MailSandbox::Server.parms = config.server_params
44
53
  end
45
54
 
46
55
  def start
47
56
  configure
48
57
 
58
+ Process.daemon if config.daemonize
59
+ write_pidfile if config.pidfile
60
+
49
61
  MailSandbox.logger.info "Start MailSandbox::Server on #{config.listen}:#{config.port}"
50
62
 
51
63
  EventMachine::run {
@@ -57,6 +69,26 @@ module MailSandbox
57
69
  config.environment || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || :development
58
70
  end
59
71
 
72
+ def write_pidfile
73
+ @simple_pid = SimplePid.new(config.pidfile)
74
+
75
+ if @simple_pid.exists?
76
+ unless @simple_pid.running?
77
+ @simple_pid.cleanup
78
+ @simple_pid.write!
79
+ end
80
+ else
81
+ @simple_pid.write!
82
+ end
83
+
84
+ end
85
+
86
+ def terminate
87
+ MailSandbox.logger.info "Got quit/terminate signal. Bye."
88
+ @simple_pid.cleanup if @simple_pid
89
+ exit
90
+ end
91
+
60
92
  end
61
93
 
62
94
  end
@@ -20,7 +20,7 @@ module MailSandbox
20
20
 
21
21
  def receive_message
22
22
  message.completed_at = Time.now
23
- Subscribe.notify(message)
23
+ MailSandbox.subscriber.notify(message)
24
24
  true
25
25
  end
26
26
 
@@ -1,14 +1,14 @@
1
1
  module MailSandbox
2
2
  class Signals
3
3
 
4
- def self.trap
4
+ def self.trap(server)
5
+
5
6
  %w'TERM QUIT'.each do |signal|
6
7
  Signal.trap(signal) do
7
- MailSandbox.logger.info "Got #{signal} signal. Bye."
8
- exit
8
+ server.terminate
9
9
  end
10
-
11
10
  end
11
+
12
12
  end
13
13
 
14
14
  end
@@ -0,0 +1,35 @@
1
+ module MailSandbox
2
+ class Subscriber
3
+
4
+ def subscribe(observer)
5
+ observers[observer] ||= observer
6
+ end
7
+
8
+ def unsubscribe(observer)
9
+ observers.delete(observer)
10
+ end
11
+
12
+ def notify(message)
13
+ observers.each_value do |observer|
14
+
15
+ thread = Thread.new do
16
+ mutex.synchronize do
17
+ observer.update(message)
18
+ end
19
+ end
20
+
21
+ thread.abort_on_exception = true
22
+ #thread.run
23
+ end
24
+ end
25
+
26
+ def observers
27
+ @observers ||= {}
28
+ end
29
+
30
+ def mutex
31
+ @mutex ||= Mutex.new
32
+ end
33
+
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module MailSandbox
2
- VERSION = "0.0.7"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/mail_sandbox.rb CHANGED
@@ -6,21 +6,25 @@ module MailSandbox
6
6
  autoload :Server, 'mail_sandbox/server'
7
7
  autoload :Message, 'mail_sandbox/message'
8
8
  autoload :Observer, 'mail_sandbox/observer'
9
- autoload :Subscribe, 'mail_sandbox/subscribe'
9
+ autoload :Subscriber, 'mail_sandbox/subscriber'
10
10
  autoload :Config, 'mail_sandbox/config'
11
11
  autoload :Runner, 'mail_sandbox/runner'
12
12
  autoload :Signals, 'mail_sandbox/signals'
13
13
 
14
14
  def self.subscribe(observer)
15
- Subscribe.subscribe observer
15
+ subscriber.subscribe observer
16
16
  end
17
17
 
18
18
  def self.unsubscribe(observer)
19
- Subscribe.unsubscribe observer
19
+ subscriber.unsubscribe observer
20
20
  end
21
21
 
22
22
  def self.logger
23
23
  @logger ||= Logger.new(STDOUT)
24
24
  end
25
25
 
26
+ def self.subscriber
27
+ @subscriber ||= Subscriber.new
28
+ end
29
+
26
30
  end
data/mail_sandbox.gemspec CHANGED
@@ -19,8 +19,10 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency('em-http-request', '~> 0.3.0')
20
20
  gem.add_dependency('OptionParser')
21
21
  gem.add_dependency('file-utils')
22
+ gem.add_dependency('simple_pid')
22
23
 
23
24
  gem.add_development_dependency('rake')
24
25
  gem.add_development_dependency('minitest')
25
26
  gem.add_development_dependency('turn')
27
+ gem.add_development_dependency('mocha', '>= 0.13.1')
26
28
  end
@@ -0,0 +1,9 @@
1
+ HTTP/1.0 200 OK
2
+ Date: Mon, 16 Nov 2009 20:39:15 GMT
3
+ Expires: -1
4
+ Cache-Control: private, max-age=0
5
+ Content-Type: text/html; charset=ISO-8859-1
6
+ Via: 1.0 .:80 (squid)
7
+ Connection: close
8
+
9
+ Success
@@ -0,0 +1,7 @@
1
+ From: Private Person <me@fromdomain.com>
2
+ To: A Test User <test@todomain.com>
3
+ Subject: SMTP e-mail test
4
+
5
+ 1 This is a test e-mail message.
6
+ 2 This is a test e-mail message.
7
+ 3 This is a test e-mail message.
@@ -0,0 +1,24 @@
1
+ require "test_helper"
2
+
3
+ class DaemonizeTest < MiniTest::Unit::TestCase
4
+ include SpawnHelper
5
+
6
+ def teardown
7
+ kill_server
8
+ end
9
+
10
+ def test_daemonize
11
+ pid = spawn command("-D -P #{PID_FILE}")
12
+
13
+ assert wait_pid_file, "Pid file doesn't exist."
14
+ assert !alive?, "Server didn't daemonize."
15
+
16
+ real_pid = File.read(PID_FILE).to_i
17
+ assert pid != real_pid
18
+
19
+ @pid = real_pid
20
+ assert alive?, "Real server doesn't alive."
21
+ end
22
+
23
+
24
+ end
@@ -0,0 +1,22 @@
1
+ require "test_helper"
2
+
3
+ class PidfileTest < MiniTest::Unit::TestCase
4
+ include SpawnHelper
5
+
6
+ def teardown
7
+ kill_server
8
+ end
9
+
10
+ def test_pidfile
11
+ pid = spawn_server "-P #{PID_FILE}"
12
+ assert wait_pid_file, "Pid file doesn't exist."
13
+
14
+ pidfile_pid = File.read(PID_FILE).to_i
15
+ assert_equal pid, pidfile_pid
16
+
17
+ kill_server
18
+ assert !File.exist?(PID_FILE)
19
+ end
20
+
21
+
22
+ end
@@ -0,0 +1,60 @@
1
+ require "test_helper"
2
+
3
+ class ServerTest < MiniTest::Unit::TestCase
4
+ include SpawnHelper
5
+
6
+ def setup
7
+ spawn_server
8
+ end
9
+
10
+ def teardown
11
+ kill_server
12
+ end
13
+
14
+ def test_server_run
15
+ assert alive?, "Server not alive."
16
+ end
17
+
18
+ def test_server_bind_port
19
+ assert wait_bind, "Server doesn't bind."
20
+ end
21
+
22
+ def test_server_helo
23
+ wait_bind
24
+
25
+ bye, helo = nil
26
+ Socket.tcp('127.0.0.1', 2525) do |socket|
27
+ helo = socket.readline
28
+ socket.print "EHLO localhost.localdomain\r\n"
29
+ socket.readpartial(65536)
30
+ socket.print "QUIT\r\n"
31
+ bye = socket.readline
32
+ socket.close_write
33
+ socket.close_read
34
+ end
35
+
36
+ assert_match /^220 .*/, helo
37
+ assert_match /^221 .*/, bye
38
+ end
39
+
40
+ def test_server_auth
41
+ wait_bind
42
+
43
+ user = 'app_user'
44
+ password = 'KnesSGaF9TQ9wOOdXd2m'
45
+
46
+ @message = File.read(File.expand_path("../../fixtures/message.txt", __FILE__))
47
+
48
+ smtp = Net::SMTP.new('localhost', 2525)
49
+ smtp.start do |smtp|
50
+ smtp.auth_plain(user, password)
51
+ smtp.send_message @message, 'me@fromdomain.com', 'test@todomain.com'
52
+ end
53
+
54
+ assert alive?
55
+ end
56
+
57
+
58
+
59
+
60
+ end
File without changes
File without changes
data/test/test_helper.rb CHANGED
@@ -1,12 +1,58 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
1
+ require "bundler/setup"
2
+ Bundler.require(:default, :test)
3
3
 
4
- require 'test/unit'
5
-
6
- require 'mail_sandbox'
7
4
  require 'em-http-request'
8
-
9
5
  require "socket"
6
+ require 'support/my_observer'
10
7
  require 'net/smtp'
11
- require 'my_observer'
8
+ require 'mocha'
9
+
10
+ module SpawnHelper
11
+ PID_FILE = "/tmp/mail_sandbox.#{rand*1000.to_i}.pid"
12
+
13
+ def spawn_server(options = "")
14
+ @pid = spawn command(options)
15
+ sleep 0.1 until alive?
16
+ Process.detach @pid
17
+ sleep 1
18
+ @pid
19
+ end
20
+
21
+ def command(options)
22
+ "bundle exec mail_sandbox #{options}"
23
+ end
24
+
25
+ def kill_server(pid = nil)
26
+ pid ||= @pid
27
+ Process.kill "QUIT", pid rescue false
28
+ sleep 0.1 while alive?(pid)
29
+ end
30
+
31
+ def alive?(pid = nil)
32
+ pid ||= @pid
33
+ Process.kill 0, pid rescue false
34
+ end
35
+
36
+ def wait_pid_file
37
+ 50.times do
38
+ return true if File.exist?(PID_FILE)
39
+ sleep 0.1
40
+ end
41
+ false
42
+ end
43
+
44
+ def wait_bind
45
+ 50.times do
46
+ begin
47
+ Socket.tcp('127.0.0.1', 2525)
48
+ rescue
49
+ sleep 0.1
50
+ next
51
+ end
52
+ return true
53
+ end
54
+ false
55
+ end
56
+
12
57
 
58
+ end
@@ -13,14 +13,14 @@ class ConfigTest < MiniTest::Unit::TestCase
13
13
  end
14
14
 
15
15
  def test_load_from_yml_file
16
- @config.load_from_yml_file(:development, 'test/config.yml')
16
+ @config.load_from_yml_file(:development, 'test/support/config.yml')
17
17
 
18
18
  assert @config.test_key
19
19
  assert_equal 'development value', @config.test_key
20
20
  end
21
21
 
22
22
  def test_load_file
23
- @config.config_file = 'test/config.yml'
23
+ @config.config_file = 'test/support/config.yml'
24
24
 
25
25
  @config.load_from_yml_file(:production)
26
26
 
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+
3
+ class SubscribeTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @message = MailSandbox::Message.new
7
+ @subscriber = MailSandbox::Subscriber.new
8
+ @observer = MyObserver.new
9
+ end
10
+
11
+ def test_subscribe
12
+ @subscriber.subscribe @observer
13
+
14
+ assert_equal 1, @subscriber.observers.count
15
+ end
16
+
17
+ def test_observer_notify
18
+ @subscriber.subscribe @observer
19
+
20
+ @subscriber.notify @message and sleep 1
21
+ assert_equal @message, @observer.message
22
+ end
23
+
24
+ def test_http_observer
25
+ url = "http://localhost/api"
26
+ body = {:body => {:message => @message.to_a}}
27
+
28
+ http_mock = mock()
29
+ http_mock.stubs(:callback)
30
+ http_mock.stubs(:errback)
31
+
32
+ EventMachine::HttpRequest.any_instance.expects(:post).with(body).returns(http_mock)
33
+
34
+ @observer = MailSandbox::Observer::Http.new url
35
+ @subscriber.subscribe @observer
36
+
37
+ @subscriber.notify @message and sleep 1
38
+
39
+ assert true
40
+ end
41
+
42
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail_sandbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-27 00:00:00.000000000 Z
12
+ date: 2012-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: simple_pid
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: rake
80
96
  requirement: !ruby/object:Gem::Requirement
@@ -123,6 +139,22 @@ dependencies:
123
139
  - - ! '>='
124
140
  - !ruby/object:Gem::Version
125
141
  version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: mocha
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: 0.13.1
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: 0.13.1
126
158
  description: Gem has run SMTP server and manipulate letters received. Using the Observer
127
159
  pattern you can subscribe to the event server.
128
160
  email:
@@ -147,14 +179,19 @@ files:
147
179
  - lib/mail_sandbox/runner.rb
148
180
  - lib/mail_sandbox/server.rb
149
181
  - lib/mail_sandbox/signals.rb
150
- - lib/mail_sandbox/subscribe.rb
182
+ - lib/mail_sandbox/subscriber.rb
151
183
  - lib/mail_sandbox/version.rb
152
184
  - mail_sandbox.gemspec
153
- - test/config.yml
154
- - test/mail_sandbox/config_test.rb
155
- - test/mail_sandbox/server_test.rb
156
- - test/my_observer.rb
185
+ - test/fixtures/http_response.txt
186
+ - test/fixtures/message.txt
187
+ - test/integration/daemonize_test.rb
188
+ - test/integration/pidfile_test.rb
189
+ - test/integration/spawn_test.rb
190
+ - test/support/config.yml
191
+ - test/support/my_observer.rb
157
192
  - test/test_helper.rb
193
+ - test/unit/config_test.rb
194
+ - test/unit/subscribe_test.rb
158
195
  homepage: https://github.com/kaize/mail_sandbox
159
196
  licenses: []
160
197
  post_install_message:
@@ -167,12 +204,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
204
  - - ! '>='
168
205
  - !ruby/object:Gem::Version
169
206
  version: '0'
207
+ segments:
208
+ - 0
209
+ hash: 501385496686318604
170
210
  required_rubygems_version: !ruby/object:Gem::Requirement
171
211
  none: false
172
212
  requirements:
173
213
  - - ! '>='
174
214
  - !ruby/object:Gem::Version
175
215
  version: '0'
216
+ segments:
217
+ - 0
218
+ hash: 501385496686318604
176
219
  requirements: []
177
220
  rubyforge_project:
178
221
  rubygems_version: 1.8.24
@@ -180,8 +223,13 @@ signing_key:
180
223
  specification_version: 3
181
224
  summary: SMTP server sandbox
182
225
  test_files:
183
- - test/config.yml
184
- - test/mail_sandbox/config_test.rb
185
- - test/mail_sandbox/server_test.rb
186
- - test/my_observer.rb
226
+ - test/fixtures/http_response.txt
227
+ - test/fixtures/message.txt
228
+ - test/integration/daemonize_test.rb
229
+ - test/integration/pidfile_test.rb
230
+ - test/integration/spawn_test.rb
231
+ - test/support/config.yml
232
+ - test/support/my_observer.rb
187
233
  - test/test_helper.rb
234
+ - test/unit/config_test.rb
235
+ - test/unit/subscribe_test.rb
@@ -1,37 +0,0 @@
1
- module MailSandbox
2
- class Subscribe
3
- class<<self
4
-
5
- def subscribe(observer)
6
- observers[observer] ||= observer
7
- end
8
-
9
- def unsubscribe(observer)
10
- observers.delete(observer)
11
- end
12
-
13
- def notify(message)
14
- observers.each_value do |observer|
15
-
16
- thread = Thread.new do
17
- mutex.synchronize do
18
- observer.update(message)
19
- end
20
- end
21
-
22
- thread.abort_on_exception = true
23
- #thread.run
24
- end
25
- end
26
-
27
- def observers
28
- @observers ||= {}
29
- end
30
-
31
- def mutex
32
- @mutex ||= Mutex.new
33
- end
34
-
35
- end
36
- end
37
- end
@@ -1,128 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ServerTest < MiniTest::Unit::TestCase
4
-
5
- def setup
6
- EventMachine::MockHttpRequest.reset_registry!
7
- EventMachine::MockHttpRequest.reset_counts!
8
- EventMachine::MockHttpRequest.pass_through_requests = false
9
-
10
- EventMachine::MockHttpRequest.activate!
11
-
12
- @server = Thread.new do
13
- MailSandbox::Runner.new.start
14
- end
15
-
16
- @server.abort_on_exception = true
17
- @server.run
18
-
19
- @message = <<MESSAGE_END
20
- From: Private Person <me@fromdomain.com>
21
- To: A Test User <test@todomain.com>
22
- Subject: SMTP e-mail test
23
-
24
- 1 This is a test e-mail message.
25
- 2 This is a test e-mail message.
26
- 3 This is a test e-mail message.
27
- MESSAGE_END
28
-
29
- @http_response = <<-RESPONSE.gsub(/^ +/, '')
30
- HTTP/1.0 200 OK
31
- Date: Mon, 16 Nov 2009 20:39:15 GMT
32
- Expires: -1
33
- Cache-Control: private, max-age=0
34
- Content-Type: text/html; charset=ISO-8859-1
35
- Via: 1.0 .:80 (squid)
36
- Connection: close
37
-
38
- Success
39
- RESPONSE
40
-
41
- @url = 'http://localhost:8080/api/mails'
42
-
43
- #wait run server
44
- sleep 0.5
45
- end
46
-
47
- def teardown
48
- EventMachine::MockHttpRequest.deactivate!
49
- MailSandbox::Subscribe.observers.clear
50
- @server.terminate
51
- sleep 0.5
52
- end
53
-
54
- def test_server_run
55
- server_run = @server.alive?
56
- assert server_run, "Server not alive"
57
- end
58
-
59
- def test_server_helo
60
- bye, helo = nil
61
- Socket.tcp('127.0.0.1', 2525) do |socket|
62
- helo = socket.readline
63
- socket.print "EHLO localhost.localdomain\r\n"
64
- socket.readpartial(65536)
65
- socket.print "QUIT\r\n"
66
- bye = socket.readline
67
- socket.close_write
68
- socket.close_read
69
- end
70
- assert_match /^220 .*/, helo
71
- assert_match /^221 .*/, bye
72
- end
73
-
74
- def test_subscribe_mailsandox
75
-
76
- observer = MyObserver.new
77
- MailSandbox.subscribe observer
78
-
79
- Net::SMTP.start('localhost', 2525) do |smtp|
80
- smtp.send_message @message, 'me@fromdomain.com', 'test@todomain.com'
81
- end
82
-
83
- sleep 1
84
-
85
- assert observer.message
86
-
87
- end
88
-
89
- def test_http_observer
90
-
91
- EventMachine::MockHttpRequest.register(@url,:post, nil, @http_response)
92
-
93
- observer = MailSandbox::Observer::Http.new(@url)
94
- MailSandbox.subscribe observer
95
-
96
- Net::SMTP.start('localhost', 2525) do |smtp|
97
- smtp.send_message @message, 'me@fromdomain.com', 'test@todomain.com'
98
- end
99
-
100
- sleep 1
101
-
102
- assert_equal 1, EM::HttpRequest.count(@url, :post)
103
-
104
- end
105
-
106
- def test_auth
107
- user = 'app_user'
108
- password = 'KnesSGaF9TQ9wOOdXd2m'
109
-
110
- observer = MyObserver.new
111
- MailSandbox.subscribe observer
112
-
113
- smtp = Net::SMTP.new('localhost', 2525)
114
- smtp.start do |smtp|
115
- smtp.auth_plain(user, password)
116
- smtp.send_message @message, 'me@fromdomain.com', 'test@todomain.com'
117
- end
118
-
119
- sleep 1
120
-
121
- assert observer.message
122
- assert_equal user, observer.message.user
123
- assert_equal password, observer.message.password
124
-
125
- end
126
-
127
-
128
- end