ryespy 0.7.0 → 1.0.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +15 -1
- data/CHANGELOG.md +24 -0
- data/README.md +155 -34
- data/bin/ryespy +186 -80
- data/lib/ryespy.rb +4 -49
- data/lib/ryespy/app.rb +159 -0
- data/lib/ryespy/listener/amzn_s3.rb +37 -0
- data/lib/ryespy/listener/base.rb +34 -0
- data/lib/ryespy/listener/fogable.rb +59 -0
- data/lib/ryespy/listener/ftp.rb +92 -0
- data/lib/ryespy/listener/goog_cs.rb +37 -0
- data/lib/ryespy/listener/imap.rb +79 -0
- data/lib/ryespy/listener/rax_cf.rb +53 -0
- data/lib/ryespy/notifier/sidekiq.rb +69 -0
- data/lib/ryespy/version.rb +1 -1
- data/ryespy.gemspec +8 -7
- data/test/helper.rb +41 -0
- data/test/ryespy/app_test.rb +348 -0
- data/test/ryespy/listener/amzn_s3_test.rb +138 -0
- data/test/ryespy/listener/ftp_test.rb +96 -0
- data/test/ryespy/listener/goog_cs_test.rb +138 -0
- data/test/ryespy/listener/imap_test.rb +68 -0
- data/test/ryespy/listener/rax_cf_test.rb +142 -0
- data/test/ryespy/notifier/sidekiq_test.rb +44 -0
- data/test/ryespy/version_test.rb +1 -1
- metadata +109 -32
- data/lib/ryespy/config.rb +0 -83
- data/lib/ryespy/listeners/ftp.rb +0 -86
- data/lib/ryespy/listeners/imap.rb +0 -74
- data/lib/ryespy/notifiers/sidekiq.rb +0 -49
- data/lib/ryespy/redis_conn.rb +0 -32
- data/test/ryespy/config_test.rb +0 -223
- data/test/ryespy_test.rb +0 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'net/imap'
|
2
|
+
|
3
|
+
|
4
|
+
module Ryespy
|
5
|
+
module Listener
|
6
|
+
class IMAP < Base
|
7
|
+
|
8
|
+
REDIS_KEY_PREFIX = 'imap'.freeze
|
9
|
+
SIDEKIQ_JOB_CLASS = 'RyespyIMAPJob'.freeze
|
10
|
+
|
11
|
+
def initialize(opts = {})
|
12
|
+
@imap_config = {
|
13
|
+
:host => opts[:host],
|
14
|
+
:port => opts[:port],
|
15
|
+
:ssl => opts[:ssl],
|
16
|
+
:username => opts[:username],
|
17
|
+
:password => opts[:password],
|
18
|
+
}
|
19
|
+
|
20
|
+
super(opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
def close
|
24
|
+
@imap.disconnect
|
25
|
+
end
|
26
|
+
|
27
|
+
def check(mailbox)
|
28
|
+
@logger.debug { "mailbox: #{mailbox}" }
|
29
|
+
|
30
|
+
@logger.debug { "redis_key: #{redis_key(mailbox)}" }
|
31
|
+
|
32
|
+
last_seen_uid = @redis.get(redis_key(mailbox)).to_i
|
33
|
+
|
34
|
+
unseen_uids = get_unseen_uids(mailbox, last_seen_uid)
|
35
|
+
|
36
|
+
@logger.debug { "unseen_uids: #{unseen_uids}" }
|
37
|
+
|
38
|
+
unseen_uids.each do |uid|
|
39
|
+
@redis.set(redis_key(mailbox), uid)
|
40
|
+
|
41
|
+
@notifiers.each { |n| n.notify(SIDEKIQ_JOB_CLASS, [mailbox, uid]) }
|
42
|
+
end
|
43
|
+
|
44
|
+
@logger.info { "#{mailbox} has #{unseen_uids.count} new emails" }
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def connect_service
|
50
|
+
@imap = Net::IMAP.new(@imap_config[:host], {
|
51
|
+
:port => @imap_config[:port],
|
52
|
+
:ssl => @imap_config[:ssl],
|
53
|
+
})
|
54
|
+
|
55
|
+
@imap.login(@imap_config[:username], @imap_config[:password])
|
56
|
+
end
|
57
|
+
|
58
|
+
def redis_key(mailbox)
|
59
|
+
[
|
60
|
+
REDIS_KEY_PREFIX,
|
61
|
+
@imap_config[:host],
|
62
|
+
@imap_config[:port],
|
63
|
+
@imap_config[:username],
|
64
|
+
mailbox,
|
65
|
+
].join(':')
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_unseen_uids(mailbox, last_seen_uid = nil)
|
69
|
+
@imap.select(mailbox)
|
70
|
+
|
71
|
+
uids = @imap.uid_search("#{last_seen_uid + 1}:*")
|
72
|
+
|
73
|
+
# filter as IMAP search gets fun with edge cases
|
74
|
+
uids.find_all { |uid| uid > last_seen_uid }
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
require_relative 'fogable'
|
4
|
+
|
5
|
+
|
6
|
+
module Ryespy
|
7
|
+
module Listener
|
8
|
+
class RaxCF < Base
|
9
|
+
|
10
|
+
include Listener::Fogable
|
11
|
+
|
12
|
+
REDIS_KEY_PREFIX = 'rax_cf'.freeze
|
13
|
+
SIDEKIQ_JOB_CLASS = 'RyespyRaxCFJob'.freeze
|
14
|
+
|
15
|
+
def initialize(opts = {})
|
16
|
+
@config = {
|
17
|
+
:auth_url => Fog::Rackspace.const_get(
|
18
|
+
"#{opts[:endpoint].upcase}_AUTH_ENDPOINT"
|
19
|
+
),
|
20
|
+
:region => opts[:region].downcase.to_sym,
|
21
|
+
:username => opts[:username],
|
22
|
+
:api_key => opts[:api_key],
|
23
|
+
:directory => opts[:container],
|
24
|
+
}
|
25
|
+
|
26
|
+
super(opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def connect_service
|
32
|
+
@fog_storage = Fog::Storage.new({
|
33
|
+
:provider => 'Rackspace',
|
34
|
+
:rackspace_auth_url => @config[:auth_url],
|
35
|
+
:rackspace_region => @config[:region],
|
36
|
+
:rackspace_username => @config[:username],
|
37
|
+
:rackspace_api_key => @config[:api_key],
|
38
|
+
})
|
39
|
+
end
|
40
|
+
|
41
|
+
def redis_key
|
42
|
+
# CF container (directory) is unique across an account (region?).
|
43
|
+
[
|
44
|
+
REDIS_KEY_PREFIX,
|
45
|
+
@config[:username],
|
46
|
+
@config[:directory],
|
47
|
+
@config[:region],
|
48
|
+
].join(':')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'redis'
|
3
|
+
require 'redis-namespace'
|
4
|
+
require 'json'
|
5
|
+
require 'securerandom'
|
6
|
+
|
7
|
+
|
8
|
+
module Ryespy
|
9
|
+
module Notifier
|
10
|
+
class Sidekiq
|
11
|
+
|
12
|
+
SIDEKIQ_QUEUE = 'ryespy'.freeze
|
13
|
+
SIDEKIQ_KEY_QUEUES = 'queues'.freeze
|
14
|
+
SIDEKIQ_KEY_QUEUE_X = "queue:#{SIDEKIQ_QUEUE}".freeze
|
15
|
+
|
16
|
+
def initialize(opts = {})
|
17
|
+
@redis_config = {
|
18
|
+
:url => opts[:url],
|
19
|
+
:namespace => opts[:namespace],
|
20
|
+
}
|
21
|
+
|
22
|
+
@logger = opts[:logger] || Logger.new(nil)
|
23
|
+
|
24
|
+
connect_redis
|
25
|
+
|
26
|
+
if block_given?
|
27
|
+
yield self
|
28
|
+
|
29
|
+
close
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def close
|
34
|
+
@redis.quit
|
35
|
+
end
|
36
|
+
|
37
|
+
def notify(job_class, args)
|
38
|
+
@redis.sadd(SIDEKIQ_KEY_QUEUES, SIDEKIQ_QUEUE)
|
39
|
+
|
40
|
+
sidekiq_job_payload = sidekiq_job(job_class, args)
|
41
|
+
|
42
|
+
@logger.debug { "Setting Redis Key #{SIDEKIQ_KEY_QUEUE_X} Payload #{sidekiq_job_payload.to_json}" }
|
43
|
+
|
44
|
+
@redis.rpush(SIDEKIQ_KEY_QUEUE_X, sidekiq_job_payload.to_json)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def connect_redis
|
50
|
+
@redis = Redis::Namespace.new(@redis_config[:namespace],
|
51
|
+
:redis => Redis.connect(:url => @redis_config[:url])
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def sidekiq_job(job_class, args)
|
56
|
+
{
|
57
|
+
# resque
|
58
|
+
:class => job_class,
|
59
|
+
:args => args,
|
60
|
+
# sidekiq (extra)
|
61
|
+
:queue => SIDEKIQ_QUEUE,
|
62
|
+
:retry => true,
|
63
|
+
:jid => SecureRandom.hex(12),
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ryespy/version.rb
CHANGED
data/ryespy.gemspec
CHANGED
@@ -8,11 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Ryespy::VERSION
|
9
9
|
spec.authors = ["tiredpixel"]
|
10
10
|
spec.email = ["tp@tiredpixel.com"]
|
11
|
-
spec.description = %q{
|
12
|
-
|
13
|
-
and notifies Redis in a way in which Resque and Sidekiq can process using
|
14
|
-
workers.}
|
15
|
-
spec.summary = %q{Ryespy listens to IMAP and FTP and queues in Redis (Sidekiq/Resque).}
|
11
|
+
spec.description = %q{Redis Sidekiq/Resque IMAP, FTP, Amazon S3, Google Cloud Storage, Rackspace Cloud Files listener.}
|
12
|
+
spec.summary = %q{Redis Sidekiq/Resque IMAP, FTP, Amazon S3, Google Cloud Storage, Rackspace Cloud Files listener.}
|
16
13
|
spec.homepage = "https://github.com/tiredpixel/ryespy"
|
17
14
|
spec.license = "MIT"
|
18
15
|
|
@@ -21,8 +18,12 @@ Gem::Specification.new do |spec|
|
|
21
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
19
|
spec.require_paths = ["lib"]
|
23
20
|
|
24
|
-
spec.add_dependency "redis", "~> 3.0
|
21
|
+
spec.add_dependency "redis", "~> 3.0"
|
22
|
+
spec.add_dependency "redis-namespace", "~> 1.4"
|
25
23
|
|
26
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3", "!= 1.5.0"
|
27
25
|
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "fog", "~> 1.19" # conditional dependency
|
27
|
+
spec.add_development_dependency "mocha", "~> 0.14"
|
28
|
+
spec.add_development_dependency "sidekiq-spy", "~> 0.3"
|
28
29
|
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'json'
|
5
|
+
require 'redis'
|
6
|
+
require 'redis-namespace'
|
7
|
+
|
8
|
+
|
9
|
+
module Ryespy
|
10
|
+
module Test
|
11
|
+
|
12
|
+
def self.config
|
13
|
+
@config ||= {
|
14
|
+
:redis => {
|
15
|
+
:url => ENV['REDIS_URL'], # defaults
|
16
|
+
:namespace => 'ryespy:test',
|
17
|
+
},
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
module Redis
|
22
|
+
|
23
|
+
def self.setup
|
24
|
+
::Redis.current = ::Redis::Namespace.new(self.namespace,
|
25
|
+
:redis => ::Redis.connect(:url => Ryespy::Test.config[:redis][:url])
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.namespace
|
30
|
+
"#{Ryespy::Test.config[:redis][:namespace]}:#{SecureRandom.hex}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.flush_namespace(redis)
|
34
|
+
# Redis::Namespace means only namespaced keys removed
|
35
|
+
redis.keys('*').each { |k| redis.del(k) }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'net/imap'
|
3
|
+
|
4
|
+
|
5
|
+
require_relative '../helper'
|
6
|
+
|
7
|
+
require_relative '../../lib/ryespy'
|
8
|
+
|
9
|
+
|
10
|
+
def start_and_stop_app(app)
|
11
|
+
app_thread = Thread.new { app.start }
|
12
|
+
|
13
|
+
sleep 1 # patience, patience; give app time to start
|
14
|
+
|
15
|
+
app.stop
|
16
|
+
|
17
|
+
app_thread.join(2)
|
18
|
+
|
19
|
+
Thread.kill(app_thread)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
describe Ryespy::App do
|
24
|
+
|
25
|
+
describe "#initialize" do
|
26
|
+
before do
|
27
|
+
@app = Ryespy::App.new
|
28
|
+
end
|
29
|
+
|
30
|
+
it "defaults running to false" do
|
31
|
+
@app.running.must_equal false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#configure" do
|
36
|
+
before do
|
37
|
+
@app = Ryespy::App.new
|
38
|
+
|
39
|
+
@config = @app.config
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "main" do
|
43
|
+
before do
|
44
|
+
@app.configure do |c|
|
45
|
+
c.log_level = 'ERROR'
|
46
|
+
c.listener = 'imap'
|
47
|
+
c.polling_interval = 13
|
48
|
+
c.redis_url = 'redis://127.0.0.1:6379/1'
|
49
|
+
c.redis_ns_ryespy = 'WithMyLittleEye!'
|
50
|
+
c.redis_ns_notifiers = 'LaLaLiLi-'
|
51
|
+
c.notifiers = [{ :sidekiq => 'redis://127.0.0.1:6379/2' }]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "configures log_level" do
|
56
|
+
@config.log_level.must_equal 'ERROR'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "sets logger level" do
|
60
|
+
@app.instance_variable_get(:@logger).level.must_equal Logger::ERROR
|
61
|
+
end
|
62
|
+
|
63
|
+
it "configures listener" do
|
64
|
+
@config.listener.must_equal 'imap'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "configures polling_interval" do
|
68
|
+
@config.polling_interval.must_equal 13
|
69
|
+
end
|
70
|
+
|
71
|
+
it "configures redis_url" do
|
72
|
+
@config.redis_url.must_equal 'redis://127.0.0.1:6379/1'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "configures redis_ns_ryespy" do
|
76
|
+
@config.redis_ns_ryespy.must_equal 'WithMyLittleEye!'
|
77
|
+
end
|
78
|
+
|
79
|
+
it "configures redis_ns_notifiers" do
|
80
|
+
@config.redis_ns_notifiers.must_equal 'LaLaLiLi-'
|
81
|
+
end
|
82
|
+
|
83
|
+
it "configures notifiers" do
|
84
|
+
@config.notifiers.must_equal [{ :sidekiq => 'redis://127.0.0.1:6379/2' }]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "listener IMAP" do
|
89
|
+
before do
|
90
|
+
@app.configure do |c|
|
91
|
+
c.imap_host = 'imap.example.com'
|
92
|
+
c.imap_port = 143
|
93
|
+
c.imap_ssl = false
|
94
|
+
c.imap_username = 'lucy.westenra@example.com'
|
95
|
+
c.imap_password = 'white'
|
96
|
+
c.imap_filters = 'BoxA,Sent Messages'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it "configures imap_host" do
|
101
|
+
@config.imap_host.must_equal 'imap.example.com'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "configures imap_port" do
|
105
|
+
@config.imap_port.must_equal 143
|
106
|
+
end
|
107
|
+
|
108
|
+
it "configures imap_ssl" do
|
109
|
+
@config.imap_ssl.must_equal false
|
110
|
+
end
|
111
|
+
|
112
|
+
it "configures imap_username" do
|
113
|
+
@config.imap_username.must_equal 'lucy.westenra@example.com'
|
114
|
+
end
|
115
|
+
|
116
|
+
it "configures imap_password" do
|
117
|
+
@config.imap_password.must_equal 'white'
|
118
|
+
end
|
119
|
+
|
120
|
+
it "configures imap_filters" do
|
121
|
+
@config.imap_filters.must_equal 'BoxA,Sent Messages'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "listener FTP" do
|
126
|
+
before do
|
127
|
+
@app.configure do |c|
|
128
|
+
c.ftp_host = 'ftp.example.org'
|
129
|
+
c.ftp_port = 2121
|
130
|
+
c.ftp_passive = true
|
131
|
+
c.ftp_username = 'madam.mina@example.com'
|
132
|
+
c.ftp_password = 'black'
|
133
|
+
c.ftp_filters = ['BoxA', 'Sent Messages']
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it "configures ftp_host" do
|
138
|
+
@config.ftp_host.must_equal 'ftp.example.org'
|
139
|
+
end
|
140
|
+
|
141
|
+
it "configures ftp_port" do
|
142
|
+
@config.ftp_port.must_equal 2121
|
143
|
+
end
|
144
|
+
|
145
|
+
it "configures ftp_passive" do
|
146
|
+
@config.ftp_passive.must_equal true
|
147
|
+
end
|
148
|
+
|
149
|
+
it "configures ftp_username" do
|
150
|
+
@config.ftp_username.must_equal 'madam.mina@example.com'
|
151
|
+
end
|
152
|
+
|
153
|
+
it "configures ftp_password" do
|
154
|
+
@config.ftp_password.must_equal 'black'
|
155
|
+
end
|
156
|
+
|
157
|
+
it "configures ftp_filters" do
|
158
|
+
@config.ftp_filters.must_equal ['BoxA', 'Sent Messages']
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "listener amzn-s3" do
|
163
|
+
before do
|
164
|
+
@app.configure do |c|
|
165
|
+
c.amzn_s3_access_key = 'r.m.renfield'
|
166
|
+
c.amzn_s3_secret_key = 'master'
|
167
|
+
c.amzn_s3_bucket = 'i-can-wait'
|
168
|
+
c.amzn_s3_filters = ['flies/', 'spiders/']
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
it "configures amzn_s3_access_key" do
|
173
|
+
@config.amzn_s3_access_key.must_equal 'r.m.renfield'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "configures amzn_s3_secret_key" do
|
177
|
+
@config.amzn_s3_secret_key.must_equal 'master'
|
178
|
+
end
|
179
|
+
|
180
|
+
it "configures amzn_s3_bucket" do
|
181
|
+
@config.amzn_s3_bucket.must_equal 'i-can-wait'
|
182
|
+
end
|
183
|
+
|
184
|
+
it "configures amzn_s3_filters" do
|
185
|
+
@config.amzn_s3_filters.must_equal ["flies/", "spiders/"]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "listener goog-cs" do
|
190
|
+
before do
|
191
|
+
@app.configure do |c|
|
192
|
+
c.goog_cs_access_key = 'r.m.renfield'
|
193
|
+
c.goog_cs_secret_key = 'master'
|
194
|
+
c.goog_cs_bucket = 'i-can-wait'
|
195
|
+
c.goog_cs_filters = ['flies/', 'spiders/']
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
it "configures goog_cs_access_key" do
|
200
|
+
@config.goog_cs_access_key.must_equal 'r.m.renfield'
|
201
|
+
end
|
202
|
+
|
203
|
+
it "configures goog_cs_secret_key" do
|
204
|
+
@config.goog_cs_secret_key.must_equal 'master'
|
205
|
+
end
|
206
|
+
|
207
|
+
it "configures goog_cs_bucket" do
|
208
|
+
@config.goog_cs_bucket.must_equal 'i-can-wait'
|
209
|
+
end
|
210
|
+
|
211
|
+
it "configures goog_cs_filters" do
|
212
|
+
@config.goog_cs_filters.must_equal ["flies/", "spiders/"]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "listener rax-cf" do
|
217
|
+
before do
|
218
|
+
@app.configure do |c|
|
219
|
+
c.rax_cf_endpoint = 'uk'
|
220
|
+
c.rax_cf_region = 'lon'
|
221
|
+
c.rax_cf_username = 'van.helsing'
|
222
|
+
c.rax_cf_api_key = 'M.D., D.Ph., D.Litt., etc.'
|
223
|
+
c.rax_cf_container = 'the-milk-that-is-spilt-cries-not-out-afterwards'
|
224
|
+
c.rax_cf_filters = ['abraham/', 'van/']
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
it "configures rax_cf_endpoint" do
|
229
|
+
@config.rax_cf_endpoint.must_equal 'uk'
|
230
|
+
end
|
231
|
+
|
232
|
+
it "configures rax_cf_region" do
|
233
|
+
@config.rax_cf_region.must_equal 'lon'
|
234
|
+
end
|
235
|
+
|
236
|
+
it "configures rax_cf_username" do
|
237
|
+
@config.rax_cf_username.must_equal 'van.helsing'
|
238
|
+
end
|
239
|
+
|
240
|
+
it "configures rax_cf_api_key" do
|
241
|
+
@config.rax_cf_api_key.must_equal 'M.D., D.Ph., D.Litt., etc.'
|
242
|
+
end
|
243
|
+
|
244
|
+
it "configures rax_cf_container" do
|
245
|
+
@config.rax_cf_container.must_equal 'the-milk-that-is-spilt-cries-not-out-afterwards'
|
246
|
+
end
|
247
|
+
|
248
|
+
it "configures rax_cf_filters" do
|
249
|
+
@config.rax_cf_filters.must_equal ["abraham/", "van/"]
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "#notifiers" do
|
255
|
+
before do
|
256
|
+
@app = Ryespy::App.new
|
257
|
+
|
258
|
+
@app.configure do |c|
|
259
|
+
c.notifiers = { :sidekiq => ['redis://127.0.0.1:6379/11'] }
|
260
|
+
end
|
261
|
+
|
262
|
+
@app.instance_variable_set(:@notifiers, nil)
|
263
|
+
end
|
264
|
+
|
265
|
+
it "creates notifiers when empty" do
|
266
|
+
@app.notifiers.map(&:class).must_equal [Ryespy::Notifier::Sidekiq]
|
267
|
+
end
|
268
|
+
|
269
|
+
it "returns notifiers when extant" do
|
270
|
+
@notifiers = stub
|
271
|
+
|
272
|
+
@app.instance_variable_set(:@notifiers, @notifiers)
|
273
|
+
|
274
|
+
@app.notifiers.must_equal @notifiers
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe "#start" do
|
279
|
+
before do
|
280
|
+
Net::IMAP.stubs(:new).returns(stub(
|
281
|
+
:login => nil,
|
282
|
+
:select => nil,
|
283
|
+
:uid_search => [],
|
284
|
+
:disconnect => nil
|
285
|
+
))
|
286
|
+
|
287
|
+
@app = Ryespy::App.new(true)
|
288
|
+
|
289
|
+
@app.instance_variable_set(:@logger, Logger.new(nil))
|
290
|
+
|
291
|
+
@app.configure do |c|
|
292
|
+
c.listener = :imap
|
293
|
+
c.polling_interval = 10
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
it "sets status running within 1s" do
|
298
|
+
thread_app = Thread.new { @app.start }
|
299
|
+
|
300
|
+
sleep 1 # patience, patience; give app time to start
|
301
|
+
|
302
|
+
@app.running.must_equal true
|
303
|
+
|
304
|
+
Thread.kill(thread_app)
|
305
|
+
end
|
306
|
+
|
307
|
+
it "stops running within 1s" do
|
308
|
+
thread_app = Thread.new { @app.start }
|
309
|
+
|
310
|
+
sleep 1 # patience, patience; give app time to start
|
311
|
+
|
312
|
+
@app.stop; t0 = Time.now
|
313
|
+
|
314
|
+
thread_app.join(2)
|
315
|
+
|
316
|
+
Thread.kill(thread_app)
|
317
|
+
|
318
|
+
assert_operator (Time.now - t0), :<=, 1
|
319
|
+
end
|
320
|
+
|
321
|
+
it "calls #setup hook" do
|
322
|
+
@app.expects(:setup)
|
323
|
+
|
324
|
+
start_and_stop_app(@app)
|
325
|
+
end
|
326
|
+
|
327
|
+
it "calls #cleanup hook" do
|
328
|
+
@app.expects(:cleanup)
|
329
|
+
|
330
|
+
start_and_stop_app(@app)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
describe "#stop" do
|
335
|
+
before do
|
336
|
+
@app = Ryespy::App.new
|
337
|
+
|
338
|
+
@app.instance_variable_set(:@running, true)
|
339
|
+
end
|
340
|
+
|
341
|
+
it "sets status not-running" do
|
342
|
+
@app.stop
|
343
|
+
|
344
|
+
@app.running.must_equal false
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|