inbox-sync 0.1.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/.gitignore +21 -0
- data/Gemfile +7 -0
- data/LICENSE +22 -0
- data/README.md +185 -0
- data/Rakefile +8 -0
- data/inbox-sync.gemspec +23 -0
- data/lib/inbox-sync/config/credentials.rb +29 -0
- data/lib/inbox-sync/config/imap_config.rb +28 -0
- data/lib/inbox-sync/config/smtp_config.rb +30 -0
- data/lib/inbox-sync/config.rb +30 -0
- data/lib/inbox-sync/mail_item.rb +78 -0
- data/lib/inbox-sync/notice/base.rb +47 -0
- data/lib/inbox-sync/notice/run_sync_error.rb +44 -0
- data/lib/inbox-sync/notice/sync_mail_item_error.rb +45 -0
- data/lib/inbox-sync/runner.rb +123 -0
- data/lib/inbox-sync/sync.rb +249 -0
- data/lib/inbox-sync/version.rb +3 -0
- data/lib/inbox-sync.rb +16 -0
- data/log/.gitkeep +0 -0
- data/test/config_test.rb +302 -0
- data/test/helper.rb +87 -0
- data/test/irb.rb +9 -0
- data/test/mail_item_test.rb +62 -0
- data/test/runner_test.rb +40 -0
- data/test/sync/basic_test.rb +62 -0
- data/test/sync/login_test.rb +110 -0
- metadata +141 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'inbox-sync/notice/run_sync_error'
|
2
|
+
|
3
|
+
module InboxSync
|
4
|
+
|
5
|
+
class Runner
|
6
|
+
|
7
|
+
attr_reader :syncs, :interval, :logger
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
opts, syncs = [
|
11
|
+
args.last.kind_of?(Hash) ? args.pop : {},
|
12
|
+
args.flatten
|
13
|
+
]
|
14
|
+
|
15
|
+
@syncs = syncs || []
|
16
|
+
@interval = opts[:interval].kind_of?(Fixnum) ? opts[:interval] : -1
|
17
|
+
@logger = opts[:logger] || Logger.new(STDOUT)
|
18
|
+
@shutdown = false
|
19
|
+
@running_syncs_thread = nil
|
20
|
+
|
21
|
+
Signal.trap('SIGINT', lambda{ self.stop })
|
22
|
+
Signal.trap('SIGQUIT', lambda{ self.stop })
|
23
|
+
end
|
24
|
+
|
25
|
+
def start
|
26
|
+
startup
|
27
|
+
loop do
|
28
|
+
break if @shutdown
|
29
|
+
loop_run
|
30
|
+
end
|
31
|
+
shutdown
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop
|
35
|
+
main_log "Stop signal - waiting for any running syncs to finish."
|
36
|
+
@shutdown = true
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def startup
|
42
|
+
main_log "Starting up the runner."
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutdown
|
46
|
+
main_log "Shutting down the runner"
|
47
|
+
end
|
48
|
+
|
49
|
+
def loop_run
|
50
|
+
main_log "Starting syncs in fresh thread."
|
51
|
+
|
52
|
+
@running_syncs_thread = Thread.new do
|
53
|
+
thread_log "starting syncs..."
|
54
|
+
|
55
|
+
begin
|
56
|
+
run_syncs
|
57
|
+
rescue Exception => err
|
58
|
+
thread_log_error(err, :error)
|
59
|
+
end
|
60
|
+
|
61
|
+
thread_log "...syncs finished"
|
62
|
+
end
|
63
|
+
|
64
|
+
if @interval < 0
|
65
|
+
main_log "run-once interval - signaling stop"
|
66
|
+
stop
|
67
|
+
@interval = 0
|
68
|
+
end
|
69
|
+
|
70
|
+
main_log "Sleeping for #{@interval} seconds."
|
71
|
+
sleep(@interval)
|
72
|
+
main_log "Woke from sleep - waiting for running syncs thread to join..."
|
73
|
+
@running_syncs_thread.join
|
74
|
+
main_log "... running sycs thread joined."
|
75
|
+
end
|
76
|
+
|
77
|
+
def run_syncs
|
78
|
+
@syncs.each do |sync|
|
79
|
+
begin
|
80
|
+
sync.setup
|
81
|
+
sync.run
|
82
|
+
rescue Exception => err
|
83
|
+
run_sync_handle_error(sync, err)
|
84
|
+
end
|
85
|
+
|
86
|
+
begin
|
87
|
+
sync.teardown
|
88
|
+
rescue Exception => err
|
89
|
+
run_sync_handle_error(sync, err)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
GC.start
|
93
|
+
end
|
94
|
+
|
95
|
+
def run_sync_handle_error(sync, err)
|
96
|
+
thread_log_error(err)
|
97
|
+
notice = Notice::RunSyncError.new(sync.notify_smtp, sync.config.notify, {
|
98
|
+
:error => err,
|
99
|
+
:sync => sync
|
100
|
+
})
|
101
|
+
sync.notify(notice)
|
102
|
+
end
|
103
|
+
|
104
|
+
def thread_log_error(err, level=:warn)
|
105
|
+
thread_log "#{err.message} (#{err.class.name})", level
|
106
|
+
err.backtrace.each { |bt| thread_log bt.to_s, level }
|
107
|
+
end
|
108
|
+
|
109
|
+
def main_log(msg, level=:info)
|
110
|
+
log "[MAIN]: #{msg}", level
|
111
|
+
end
|
112
|
+
|
113
|
+
def thread_log(msg, level=:info)
|
114
|
+
log "[THREAD]: #{msg}", level
|
115
|
+
end
|
116
|
+
|
117
|
+
def log(msg, level)
|
118
|
+
@logger.send(level, msg)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'net/imap'
|
2
|
+
require 'net/smtp'
|
3
|
+
|
4
|
+
require 'inbox-sync/config'
|
5
|
+
require 'inbox-sync/notice/sync_mail_item_error'
|
6
|
+
|
7
|
+
module InboxSync
|
8
|
+
|
9
|
+
class Sync
|
10
|
+
|
11
|
+
attr_reader :config, :source_imap, :notify_smtp
|
12
|
+
|
13
|
+
def initialize(configs={})
|
14
|
+
@config = InboxSync::Config.new(configs)
|
15
|
+
@source_imap = nil
|
16
|
+
@notify_smtp = nil
|
17
|
+
@logged_in = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def logger
|
21
|
+
@config.logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def uid
|
25
|
+
"#{@config.source.login.user}:#{@config.source.host}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
"#{@config.source.login.user} (#{@config.source.host})"
|
30
|
+
end
|
31
|
+
|
32
|
+
def logged_in?
|
33
|
+
!!@logged_in
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure(&config_block)
|
37
|
+
@config.instance_eval(&config_block) if config_block
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
logger.info "=== #{config_log_detail(@config.source)} sync started. ==="
|
43
|
+
|
44
|
+
@notify_smtp ||= setup_smtp(:notify, @config.notify)
|
45
|
+
@config.validate!
|
46
|
+
login if !logged_in?
|
47
|
+
end
|
48
|
+
|
49
|
+
def teardown
|
50
|
+
logout if logged_in?
|
51
|
+
@source_imap = @notify_smtp = nil
|
52
|
+
logger.info "=== #{config_log_detail(@config.source)} sync finished. ==="
|
53
|
+
end
|
54
|
+
|
55
|
+
def run
|
56
|
+
each_source_mail_item do |mail_item|
|
57
|
+
begin
|
58
|
+
response = send_to_dest(mail_item)
|
59
|
+
dest_uid = parse_append_response_uid(response)
|
60
|
+
logger.debug "** dest uid: #{dest_uid.inspect}"
|
61
|
+
rescue Exception => err
|
62
|
+
log_error(err)
|
63
|
+
notify(Notice::SyncMailItemError.new(@notify_smtp, @config.notify, {
|
64
|
+
:error => err,
|
65
|
+
:mail_item => mail_item,
|
66
|
+
:sync => self
|
67
|
+
}))
|
68
|
+
ensure
|
69
|
+
archive_on_source(mail_item)
|
70
|
+
mail_item = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def notify(notice)
|
76
|
+
logger.info "** sending '#{notice.subject}' to #{notice.to.inspect}"
|
77
|
+
begin
|
78
|
+
notice.send
|
79
|
+
rescue Exception => err
|
80
|
+
log_error(err)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def login
|
87
|
+
@source_imap = login_imap(:source, @config.source)
|
88
|
+
@logged_in = true
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
def logout
|
93
|
+
logout_imap(@source_imap, @config.source)
|
94
|
+
@logged_in = false
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def each_source_mail_item
|
99
|
+
items = MailItem.find(@source_imap)
|
100
|
+
logger.info "* found #{items.size} mails"
|
101
|
+
|
102
|
+
items.each do |mail_item|
|
103
|
+
logger.debug "** #{mail_item.inspect}"
|
104
|
+
yield mail_item
|
105
|
+
end
|
106
|
+
items = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
# Send a mail item to the destination:
|
110
|
+
# The idea here is that destinations may not accept corrupted or invalid
|
111
|
+
# mail items. If appending the original mail item in any way fails,
|
112
|
+
# create a stripped down version of the mail item and try to append that.
|
113
|
+
# If appending the stripped down version still fails, error on up
|
114
|
+
# and it will be archived and notified.
|
115
|
+
|
116
|
+
def send_to_dest(mail_item)
|
117
|
+
begin
|
118
|
+
append_to_dest(mail_item)
|
119
|
+
rescue Exception => err
|
120
|
+
log_error(err)
|
121
|
+
|
122
|
+
logger.debug "** trying to append a the stripped down version"
|
123
|
+
append_to_dest(mail_item.stripped, 'stripped down ')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def append_to_dest(mail_item, desc='')
|
128
|
+
logger.info "** Appending #{desc}#{mail_item.uid} to dest #{@config.dest.inbox}..."
|
129
|
+
|
130
|
+
inbox = @config.dest.inbox
|
131
|
+
mail_s = mail_item.meta['RFC822']
|
132
|
+
flags = []
|
133
|
+
date = mail_item.meta['INTERNALDATE']
|
134
|
+
|
135
|
+
using_dest_imap do |imap|
|
136
|
+
imap.append(inbox, mail_s, flags, date)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def archive_on_source(mail_item)
|
141
|
+
folder = @config.archive_folder
|
142
|
+
if !folder.nil? && !folder.empty?
|
143
|
+
logger.debug "** Archiving #{mail_item.uid.inspect}"
|
144
|
+
|
145
|
+
begin
|
146
|
+
@source_imap.select(folder)
|
147
|
+
rescue Net::IMAP::NoResponseError => err
|
148
|
+
logger.debug "* Creating #{folder.inspect} archive folder"
|
149
|
+
@source_imap.create(folder)
|
150
|
+
ensure
|
151
|
+
@source_imap.select(@config.source.inbox)
|
152
|
+
end
|
153
|
+
|
154
|
+
mark_as_seen(@source_imap, mail_item.uid)
|
155
|
+
|
156
|
+
logger.debug "** Copying #{mail_item.uid.inspect} to #{folder.inspect}"
|
157
|
+
@source_imap.uid_copy(mail_item.uid, folder)
|
158
|
+
end
|
159
|
+
|
160
|
+
mark_as_deleted(@source_imap, mail_item.uid)
|
161
|
+
|
162
|
+
expunge_imap(@source_imap, @config.source)
|
163
|
+
|
164
|
+
@source_imap.expunge
|
165
|
+
end
|
166
|
+
|
167
|
+
def using_dest_imap
|
168
|
+
dest_imap = login_imap(:dest, @config.dest)
|
169
|
+
result = yield dest_imap
|
170
|
+
logout_imap(dest_imap, @config.dest)
|
171
|
+
result
|
172
|
+
end
|
173
|
+
|
174
|
+
def login_imap(named, config)
|
175
|
+
logger.debug "* LOGIN: #{config_log_detail(config)}"
|
176
|
+
begin
|
177
|
+
named_imap = Net::IMAP.new(config.host, config.port, config.ssl)
|
178
|
+
rescue Errno::ECONNREFUSED => err
|
179
|
+
raise Errno::ECONNREFUSED, "#{named} imap {:host => #{config.host}, :port => #{config.port}, :ssl => #{config.ssl}}: #{err.message}"
|
180
|
+
end
|
181
|
+
|
182
|
+
begin
|
183
|
+
named_imap.login(config.login.user, config.login.pw)
|
184
|
+
rescue Net::IMAP::NoResponseError => err
|
185
|
+
raise Net::IMAP::NoResponseError, "#{named} imap #{config.login.to_hash.inspect}: #{err.message}"
|
186
|
+
end
|
187
|
+
|
188
|
+
logger.debug "* SELECT #{config.inbox.inspect}: #{config_log_detail(config)}"
|
189
|
+
begin
|
190
|
+
named_imap.select(config.inbox)
|
191
|
+
rescue Net::IMAP::NoResponseError => err
|
192
|
+
raise Net::IMAP::NoResponseError, "#{named} imap: #{err.message}"
|
193
|
+
end
|
194
|
+
|
195
|
+
expunge_imap(named_imap, config)
|
196
|
+
|
197
|
+
named_imap
|
198
|
+
end
|
199
|
+
|
200
|
+
def expunge_imap(imap, config)
|
201
|
+
if config.expunge
|
202
|
+
logger.debug "* EXPUNGE #{config.inbox.inspect}: #{config_log_detail(config)}"
|
203
|
+
imap.expunge
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def logout_imap(imap, config)
|
208
|
+
logger.debug "* LOGOUT: #{config_log_detail(config)}"
|
209
|
+
imap.logout
|
210
|
+
end
|
211
|
+
|
212
|
+
def setup_smtp(named, config)
|
213
|
+
logger.debug "* SMTP: #{config_log_detail(config)}"
|
214
|
+
|
215
|
+
named_smtp = Net::SMTP.new(config.host, config.port)
|
216
|
+
named_smtp.enable_starttls if config.tls
|
217
|
+
|
218
|
+
named_smtp
|
219
|
+
end
|
220
|
+
|
221
|
+
def config_log_detail(config)
|
222
|
+
"host=#{config.host.inspect}, user=#{config.login.user.inspect}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def log_error(err)
|
226
|
+
logger.warn "#{err.message} (#{err.class.name})"
|
227
|
+
err.backtrace.each { |bt| logger.warn bt.to_s }
|
228
|
+
end
|
229
|
+
|
230
|
+
# Given a response like this:
|
231
|
+
# #<struct Net::IMAP::TaggedResponse tag="RUBY0012", name="OK", data=#<struct Net::IMAP::ResponseText code=#<struct Net::IMAP::ResponseCode name="APPENDUID", data="6 9">, text=" (Success)">, raw_data="RUBY0012 OK [APPENDUID 6 9] (Success)\r\n">
|
232
|
+
# (here '9' is the UID)
|
233
|
+
def parse_append_response_uid(response)
|
234
|
+
response.data.code.data.split(/\s+/).last
|
235
|
+
end
|
236
|
+
|
237
|
+
def mark_as_seen(imap, uid)
|
238
|
+
logger.debug "** Marking #{uid.inspect} as :Seen"
|
239
|
+
imap.uid_store(uid, "+FLAGS", [:Seen])
|
240
|
+
end
|
241
|
+
|
242
|
+
def mark_as_deleted(imap, uid)
|
243
|
+
logger.debug "** Marking #{uid.inspect} as :Deleted"
|
244
|
+
imap.uid_store(uid, "+FLAGS", [:Deleted])
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
data/lib/inbox-sync.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'inbox-sync/mail_item'
|
2
|
+
require 'inbox-sync/config'
|
3
|
+
require 'inbox-sync/sync'
|
4
|
+
require 'inbox-sync/runner'
|
5
|
+
|
6
|
+
module InboxSync
|
7
|
+
|
8
|
+
def self.new(settings={})
|
9
|
+
Sync.new(settings)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.run(*args)
|
13
|
+
Runner.new(*args).start
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/log/.gitkeep
ADDED
File without changes
|
data/test/config_test.rb
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
require 'assert'
|
2
|
+
require 'ns-options/assert_macros'
|
3
|
+
|
4
|
+
require 'inbox-sync/config'
|
5
|
+
|
6
|
+
module InboxSync
|
7
|
+
|
8
|
+
class ConfigTests < Assert::Context
|
9
|
+
include NsOptions::AssertMacros
|
10
|
+
|
11
|
+
before do
|
12
|
+
@config = InboxSync::Config.new
|
13
|
+
end
|
14
|
+
subject { @config }
|
15
|
+
|
16
|
+
should have_option :source, InboxSync::Config::IMAPConfig, {
|
17
|
+
:default => {},
|
18
|
+
:required => true
|
19
|
+
}
|
20
|
+
|
21
|
+
should have_option :dest, InboxSync::Config::IMAPConfig, {
|
22
|
+
:default => {},
|
23
|
+
:required => true
|
24
|
+
}
|
25
|
+
|
26
|
+
should have_option :notify, InboxSync::Config::SMTPConfig, {
|
27
|
+
:default => {},
|
28
|
+
:required => true
|
29
|
+
}
|
30
|
+
|
31
|
+
should have_option :archive_folder, {
|
32
|
+
:default => "Archived"
|
33
|
+
}
|
34
|
+
|
35
|
+
should have_option :logger, Logger, {
|
36
|
+
:required => true,
|
37
|
+
:default => STDOUT
|
38
|
+
}
|
39
|
+
|
40
|
+
should have_instance_method :validate!
|
41
|
+
|
42
|
+
should "complain if missing :source config" do
|
43
|
+
assert_raises ArgumentError do
|
44
|
+
subject.source = nil
|
45
|
+
subject.validate!
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
should "complain if missing :dest config" do
|
50
|
+
assert_raises ArgumentError do
|
51
|
+
subject.dest = nil
|
52
|
+
subject.validate!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
should "complain if missing :notify config" do
|
57
|
+
assert_raises ArgumentError do
|
58
|
+
subject.notify = nil
|
59
|
+
subject.validate!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
should "complain if missing :archive_folder config" do
|
64
|
+
assert_raises ArgumentError do
|
65
|
+
subject.archive_folder = nil
|
66
|
+
subject.validate!
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
should "validate its source" do
|
71
|
+
assert_raises ArgumentError do
|
72
|
+
subject.source.host = nil
|
73
|
+
subject.validate!
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
should "validate its dest" do
|
78
|
+
assert_raises ArgumentError do
|
79
|
+
subject.dest.host = nil
|
80
|
+
subject.validate!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
should "validate its notify" do
|
85
|
+
assert_raises ArgumentError do
|
86
|
+
subject.notify.host = nil
|
87
|
+
subject.validate!
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class CredentialsTests < ConfigTests
|
94
|
+
subject { @config.source.login }
|
95
|
+
|
96
|
+
should have_option :user, :required => true
|
97
|
+
should have_option :pw, :required => true
|
98
|
+
|
99
|
+
should have_instance_method :validate!
|
100
|
+
|
101
|
+
should "complain if missing :user config" do
|
102
|
+
assert_raises ArgumentError do
|
103
|
+
subject.user = nil
|
104
|
+
subject.validate!
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
should "complain if missing :pw config" do
|
109
|
+
assert_raises ArgumentError do
|
110
|
+
subject.pw = nil
|
111
|
+
subject.validate!
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
should "be built from set of args" do
|
116
|
+
cred = InboxSync::Config::Credentials.new 'me', 'secret'
|
117
|
+
|
118
|
+
assert_equal 'me', cred.user
|
119
|
+
assert_equal 'secret', cred.pw
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class IMAPConfigTests < ConfigTests
|
125
|
+
subject { @config.source }
|
126
|
+
|
127
|
+
should have_option :host, :required => true
|
128
|
+
|
129
|
+
should have_option :port, {
|
130
|
+
:default => 143,
|
131
|
+
:required => true
|
132
|
+
}
|
133
|
+
|
134
|
+
should have_option :ssl, NsOptions::Boolean, {
|
135
|
+
:default => false,
|
136
|
+
:required => true
|
137
|
+
}
|
138
|
+
|
139
|
+
should have_option :login, InboxSync::Config::Credentials, {
|
140
|
+
:default => {},
|
141
|
+
:required => true
|
142
|
+
}
|
143
|
+
|
144
|
+
should have_option :inbox, {
|
145
|
+
:default => "INBOX",
|
146
|
+
:required => true
|
147
|
+
}
|
148
|
+
|
149
|
+
should have_option :expunge, NsOptions::Boolean, {
|
150
|
+
:default => true,
|
151
|
+
:required => true
|
152
|
+
}
|
153
|
+
|
154
|
+
should "complain if missing :host config" do
|
155
|
+
assert_raises ArgumentError do
|
156
|
+
subject.host = nil
|
157
|
+
subject.validate!
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
should "complain if missing :port config" do
|
162
|
+
assert_raises ArgumentError do
|
163
|
+
subject.port = nil
|
164
|
+
subject.validate!
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
should "complain if missing :ssl config" do
|
169
|
+
assert_raises ArgumentError do
|
170
|
+
subject.ssl = nil
|
171
|
+
subject.validate!
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
should "complain if missing :login config" do
|
176
|
+
assert_raises ArgumentError do
|
177
|
+
subject.login = nil
|
178
|
+
subject.validate!
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
should "complain if missing :inbox config" do
|
183
|
+
assert_raises ArgumentError do
|
184
|
+
subject.inbox = nil
|
185
|
+
subject.validate!
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
should "complain if missing :host config" do
|
190
|
+
assert_raises ArgumentError do
|
191
|
+
subject.expunge = nil
|
192
|
+
subject.validate!
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
class SMTPConfigTests < ConfigTests
|
199
|
+
subject { @config.notify }
|
200
|
+
|
201
|
+
should have_option :host, :required => true
|
202
|
+
|
203
|
+
should have_option :port, {
|
204
|
+
:default => 25,
|
205
|
+
:required => true
|
206
|
+
}
|
207
|
+
|
208
|
+
should have_option :tls, NsOptions::Boolean, {
|
209
|
+
:default => false,
|
210
|
+
:required => true
|
211
|
+
}
|
212
|
+
|
213
|
+
should have_option :helo, :required => true
|
214
|
+
|
215
|
+
should have_option :login, InboxSync::Config::Credentials, {
|
216
|
+
:default => {},
|
217
|
+
:required => true
|
218
|
+
}
|
219
|
+
|
220
|
+
should have_option :authtype, {
|
221
|
+
:default => :login,
|
222
|
+
:required => true
|
223
|
+
}
|
224
|
+
|
225
|
+
should have_option :from_addr, :required => true
|
226
|
+
|
227
|
+
should have_option :to_addr, :required => true
|
228
|
+
|
229
|
+
should have_instance_method :validate!
|
230
|
+
|
231
|
+
should "complain if missing :host config" do
|
232
|
+
assert_raises ArgumentError do
|
233
|
+
subject.host = nil
|
234
|
+
subject.validate!
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
should "complain if missing :port config" do
|
239
|
+
assert_raises ArgumentError do
|
240
|
+
subject.port = nil
|
241
|
+
subject.validate!
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
should "complain if missing :tls config" do
|
246
|
+
assert_raises ArgumentError do
|
247
|
+
subject.tls = nil
|
248
|
+
subject.validate!
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
should "complain if missing :helo config" do
|
253
|
+
assert_raises ArgumentError do
|
254
|
+
subject.helo = nil
|
255
|
+
subject.validate!
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
should "complain if missing :login config" do
|
260
|
+
assert_raises ArgumentError do
|
261
|
+
subject.login = nil
|
262
|
+
subject.validate!
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
should "complain if missing :authtype config" do
|
267
|
+
assert_raises ArgumentError do
|
268
|
+
subject.authtype = nil
|
269
|
+
subject.validate!
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
should "complain if missing :from_addr config" do
|
274
|
+
assert_raises ArgumentError do
|
275
|
+
subject.from_addr = nil
|
276
|
+
subject.validate!
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
should "complain if missing :to_addr config" do
|
281
|
+
assert_raises ArgumentError do
|
282
|
+
subject.to_addr = nil
|
283
|
+
subject.validate!
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
should "complain if empty addrs configs" do
|
288
|
+
assert_raises ArgumentError do
|
289
|
+
subject.from_addr = ""
|
290
|
+
subject.validate!
|
291
|
+
end
|
292
|
+
|
293
|
+
assert_raises ArgumentError do
|
294
|
+
subject.to_addr = ""
|
295
|
+
subject.validate!
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|