rails-four-queueing 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.
@@ -0,0 +1,111 @@
1
+ # Original File: RAILS_ROOT/activesupport/test/queueing/threaded_consumer_test.rb
2
+ require "support/active_support_abstract_unit"
3
+ require "rails/four/queueing"
4
+ require "active_support/log_subscriber/test_helper"
5
+
6
+ class TestThreadConsumer < ActiveSupport::TestCase
7
+ class Job
8
+ attr_reader :id
9
+ def initialize(id = 1, &block)
10
+ @id = id
11
+ @block = block
12
+ end
13
+
14
+ def run
15
+ @block.call if @block
16
+ end
17
+ end
18
+
19
+ def setup
20
+ @logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
21
+ @queue = Rails::Four::Queueing::Queue.new(logger: @logger)
22
+ end
23
+
24
+ def teardown
25
+ @queue.drain
26
+ end
27
+
28
+ test "the jobs are executed" do
29
+ ran = false
30
+ job = Job.new { ran = true }
31
+
32
+ @queue.push job
33
+ @queue.drain
34
+
35
+ assert_equal true, ran
36
+ end
37
+
38
+ test "the jobs are not executed synchronously" do
39
+ run, ran = Queue.new, Queue.new
40
+ job = Job.new { ran.push run.pop }
41
+
42
+ @queue.consumer.start
43
+ @queue.push job
44
+ assert ran.empty?
45
+
46
+ run.push true
47
+ assert_equal true, ran.pop
48
+ end
49
+
50
+ test "shutting down the queue synchronously drains the jobs" do
51
+ ran = false
52
+ job = Job.new do
53
+ sleep 0.1
54
+ ran = true
55
+ end
56
+
57
+ @queue.consumer.start
58
+ @queue.push job
59
+ assert_equal false, ran
60
+
61
+ @queue.consumer.shutdown
62
+ assert_equal true, ran
63
+ end
64
+
65
+ test "log job that raises an exception" do
66
+ job = Job.new { raise "RuntimeError: Error!" }
67
+
68
+ @queue.push job
69
+ consume_queue @queue
70
+
71
+ assert_equal 1, @logger.logged(:error).size
72
+ assert_match "Job Error: #{job.inspect}\nRuntimeError: Error!", @logger.logged(:error).last
73
+ end
74
+
75
+ test "logger defaults to stderr" do
76
+ begin
77
+ $stderr, old_stderr = StringIO.new, $stderr
78
+ queue = Rails::Four::Queueing::Queue.new
79
+ queue.push Job.new { raise "RuntimeError: Error!" }
80
+ consume_queue queue
81
+ assert_match 'Job Error', $stderr.string
82
+ ensure
83
+ $stderr = old_stderr
84
+ end
85
+ end
86
+
87
+ test "test overriding exception handling" do
88
+ @queue.consumer.instance_eval do
89
+ def handle_exception(job, exception)
90
+ @last_error = exception.message
91
+ end
92
+
93
+ def last_error
94
+ @last_error
95
+ end
96
+ end
97
+
98
+ job = Job.new { raise "RuntimeError: Error!" }
99
+
100
+ @queue.push job
101
+ consume_queue @queue
102
+
103
+ assert_equal "RuntimeError: Error!", @queue.consumer.last_error
104
+ end
105
+
106
+ private
107
+ def consume_queue(queue)
108
+ queue.push nil
109
+ queue.consumer.consume
110
+ end
111
+ end
@@ -0,0 +1,247 @@
1
+ # require "isolation/abstract_unit"
2
+ # require 'set'
3
+
4
+ # module ApplicationTests
5
+ # class FrameworksTest < ActiveSupport::TestCase
6
+ # include ActiveSupport::Testing::Isolation
7
+
8
+ # def setup
9
+ # build_app
10
+ # boot_rails
11
+ # FileUtils.rm_rf "#{app_path}/config/environments"
12
+ # end
13
+
14
+ # def teardown
15
+ # teardown_app
16
+ # end
17
+
18
+ # # AC & AM
19
+ # test "set load paths set only if action controller or action mailer are in use" do
20
+ # assert_nothing_raised NameError do
21
+ # add_to_config <<-RUBY
22
+ # config.root = "#{app_path}"
23
+ # RUBY
24
+
25
+ # use_frameworks []
26
+ # require "#{app_path}/config/environment"
27
+ # end
28
+ # end
29
+
30
+ # test "sets action_controller and action_mailer load paths" do
31
+ # add_to_config <<-RUBY
32
+ # config.root = "#{app_path}"
33
+ # RUBY
34
+
35
+ # require "#{app_path}/config/environment"
36
+
37
+ # expanded_path = File.expand_path("app/views", app_path)
38
+ # assert_equal ActionController::Base.view_paths[0].to_s, expanded_path
39
+ # assert_equal ActionMailer::Base.view_paths[0].to_s, expanded_path
40
+ # end
41
+
42
+ # test "allows me to configure default url options for ActionMailer" do
43
+ # app_file "config/environments/development.rb", <<-RUBY
44
+ # AppTemplate::Application.configure do
45
+ # config.action_mailer.default_url_options = { :host => "test.rails" }
46
+ # end
47
+ # RUBY
48
+
49
+ # require "#{app_path}/config/environment"
50
+ # assert_equal "test.rails", ActionMailer::Base.default_url_options[:host]
51
+ # end
52
+
53
+ # test "uses the default queue for ActionMailer" do
54
+ # require "#{app_path}/config/environment"
55
+ # assert_kind_of ActiveSupport::Queue, ActionMailer::Base.queue
56
+ # end
57
+
58
+ # test "allows me to configure queue for ActionMailer" do
59
+ # app_file "config/environments/development.rb", <<-RUBY
60
+ # AppTemplate::Application.configure do
61
+ # config.action_mailer.queue = ActiveSupport::TestQueue.new
62
+ # end
63
+ # RUBY
64
+
65
+ # require "#{app_path}/config/environment"
66
+ # assert_kind_of ActiveSupport::TestQueue, ActionMailer::Base.queue
67
+ # end
68
+
69
+ # test "does not include url helpers as action methods" do
70
+ # app_file "config/routes.rb", <<-RUBY
71
+ # AppTemplate::Application.routes.draw do
72
+ # get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo
73
+ # end
74
+ # RUBY
75
+
76
+ # app_file "app/mailers/foo.rb", <<-RUBY
77
+ # class Foo < ActionMailer::Base
78
+ # def notify
79
+ # end
80
+ # end
81
+ # RUBY
82
+
83
+ # require "#{app_path}/config/environment"
84
+ # assert Foo.method_defined?(:foo_path)
85
+ # assert Foo.method_defined?(:main_app)
86
+ # assert_equal Set.new(["notify"]), Foo.action_methods
87
+ # end
88
+
89
+ # test "allows to not load all helpers for controllers" do
90
+ # add_to_config "config.action_controller.include_all_helpers = false"
91
+
92
+ # app_file "app/controllers/application_controller.rb", <<-RUBY
93
+ # class ApplicationController < ActionController::Base
94
+ # end
95
+ # RUBY
96
+
97
+ # app_file "app/controllers/foo_controller.rb", <<-RUBY
98
+ # class FooController < ApplicationController
99
+ # def included_helpers
100
+ # render :inline => "<%= from_app_helper -%> <%= from_foo_helper %>"
101
+ # end
102
+
103
+ # def not_included_helper
104
+ # render :inline => "<%= respond_to?(:from_bar_helper) -%>"
105
+ # end
106
+ # end
107
+ # RUBY
108
+
109
+ # app_file "app/helpers/application_helper.rb", <<-RUBY
110
+ # module ApplicationHelper
111
+ # def from_app_helper
112
+ # "from_app_helper"
113
+ # end
114
+ # end
115
+ # RUBY
116
+
117
+ # app_file "app/helpers/foo_helper.rb", <<-RUBY
118
+ # module FooHelper
119
+ # def from_foo_helper
120
+ # "from_foo_helper"
121
+ # end
122
+ # end
123
+ # RUBY
124
+
125
+ # app_file "app/helpers/bar_helper.rb", <<-RUBY
126
+ # module BarHelper
127
+ # def from_bar_helper
128
+ # "from_bar_helper"
129
+ # end
130
+ # end
131
+ # RUBY
132
+
133
+ # app_file "config/routes.rb", <<-RUBY
134
+ # AppTemplate::Application.routes.draw do
135
+ # get "/:controller(/:action)"
136
+ # end
137
+ # RUBY
138
+
139
+ # require 'rack/test'
140
+ # extend Rack::Test::Methods
141
+
142
+ # get "/foo/included_helpers"
143
+ # assert_equal "from_app_helper from_foo_helper", last_response.body
144
+
145
+ # get "/foo/not_included_helper"
146
+ # assert_equal "false", last_response.body
147
+ # end
148
+
149
+ # # AD
150
+ # test "action_dispatch extensions are applied to ActionDispatch" do
151
+ # add_to_config "config.action_dispatch.tld_length = 2"
152
+ # require "#{app_path}/config/environment"
153
+ # assert_equal 2, ActionDispatch::Http::URL.tld_length
154
+ # end
155
+
156
+ # test "assignment config.encoding to default_charset" do
157
+ # charset = 'Shift_JIS'
158
+ # add_to_config "config.encoding = '#{charset}'"
159
+ # require "#{app_path}/config/environment"
160
+ # assert_equal charset, ActionDispatch::Response.default_charset
161
+ # end
162
+
163
+ # # AS
164
+ # test "if there's no config.active_support.bare, all of ActiveSupport is required" do
165
+ # use_frameworks []
166
+ # require "#{app_path}/config/environment"
167
+ # assert_nothing_raised { [1,2,3].sample }
168
+ # end
169
+
170
+ # test "config.active_support.bare does not require all of ActiveSupport" do
171
+ # add_to_config "config.active_support.bare = true"
172
+
173
+ # use_frameworks []
174
+
175
+ # Dir.chdir("#{app_path}/app") do
176
+ # require "#{app_path}/config/environment"
177
+ # assert_raises(NoMethodError) { "hello".exclude? "lo" }
178
+ # end
179
+ # end
180
+
181
+ # # AR
182
+ # test "active_record extensions are applied to ActiveRecord" do
183
+ # add_to_config "config.active_record.table_name_prefix = 'tbl_'"
184
+ # require "#{app_path}/config/environment"
185
+ # assert_equal 'tbl_', ActiveRecord::Base.table_name_prefix
186
+ # end
187
+
188
+ # test "database middleware doesn't initialize when activerecord is not in frameworks" do
189
+ # use_frameworks []
190
+ # require "#{app_path}/config/environment"
191
+ # assert_nil defined?(ActiveRecord::Base)
192
+ # end
193
+
194
+ # test "use schema cache dump" do
195
+ # Dir.chdir(app_path) do
196
+ # `rails generate model post title:string;
197
+ # bundle exec rake db:migrate db:schema:cache:dump`
198
+ # end
199
+ # require "#{app_path}/config/environment"
200
+ # ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test.
201
+ # assert ActiveRecord::Base.connection.schema_cache.tables["posts"]
202
+ # end
203
+
204
+ # test "expire schema cache dump" do
205
+ # Dir.chdir(app_path) do
206
+ # `rails generate model post title:string;
207
+ # bundle exec rake db:migrate db:schema:cache:dump db:rollback`
208
+ # end
209
+ # silence_warnings {
210
+ # require "#{app_path}/config/environment"
211
+ # assert !ActiveRecord::Base.connection.schema_cache.tables["posts"]
212
+ # }
213
+ # end
214
+
215
+ # test "active record establish_connection uses Rails.env if DATABASE_URL is not set" do
216
+ # begin
217
+ # require "#{app_path}/config/environment"
218
+ # orig_database_url = ENV.delete("DATABASE_URL")
219
+ # orig_rails_env, Rails.env = Rails.env, 'development'
220
+ # ActiveRecord::Base.establish_connection
221
+ # assert ActiveRecord::Base.connection
222
+ # assert_match /#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database]
223
+ # ensure
224
+ # ActiveRecord::Base.remove_connection
225
+ # ENV["DATABASE_URL"] = orig_database_url if orig_database_url
226
+ # Rails.env = orig_rails_env if orig_rails_env
227
+ # end
228
+ # end
229
+
230
+ # test "active record establish_connection uses DATABASE_URL even if Rails.env is set" do
231
+ # begin
232
+ # require "#{app_path}/config/environment"
233
+ # orig_database_url = ENV.delete("DATABASE_URL")
234
+ # orig_rails_env, Rails.env = Rails.env, 'development'
235
+ # database_url_db_name = "db/database_url_db.sqlite3"
236
+ # ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}"
237
+ # ActiveRecord::Base.establish_connection
238
+ # assert ActiveRecord::Base.connection
239
+ # assert_match /#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]
240
+ # ensure
241
+ # ActiveRecord::Base.remove_connection
242
+ # ENV["DATABASE_URL"] = orig_database_url if orig_database_url
243
+ # Rails.env = orig_rails_env if orig_rails_env
244
+ # end
245
+ # end
246
+ # end
247
+ # end
@@ -0,0 +1,169 @@
1
+ require "support/isolation_abstract_unit"
2
+
3
+ class QueueTest < ActiveSupport::TestCase
4
+ include ActiveSupport::Testing::Isolation
5
+
6
+ # overwrite the default `build_app` method to inject the gem for testing
7
+ def build_app
8
+ super
9
+
10
+ # inject the path to the gem we're testing
11
+ environment = File.read("#{app_path}/config/application.rb")
12
+ if environment =~ /(module AppTemplate)/
13
+ rails_four_queueing_path = File.expand_path(
14
+ "../../../lib/rails-four-queueing", __FILE__
15
+ )
16
+ File.open("#{app_path}/config/application.rb", 'w') do |f|
17
+ # BOOYA!!
18
+ f.puts $` + %Q(\nrequire "#{rails_four_queueing_path}"\n) + $1 + $'
19
+ end
20
+ end
21
+ end
22
+
23
+ def setup
24
+ build_app
25
+ boot_rails
26
+ end
27
+
28
+ def teardown
29
+ teardown_app
30
+ end
31
+
32
+ def app_const
33
+ @app_const ||= Class.new(Rails::Application)
34
+ end
35
+
36
+ test "the queue is a SynchronousQueue in test mode" do
37
+ app("test")
38
+ assert_kind_of Rails::Four::Queueing::SynchronousQueue, Rails.application.queue
39
+ assert_kind_of Rails::Four::Queueing::SynchronousQueue, Rails.queue
40
+ end
41
+
42
+ test "the queue is a SynchronousQueue in development mode" do
43
+ app("development")
44
+ assert_kind_of Rails::Four::Queueing::SynchronousQueue, Rails.application.queue
45
+ assert_kind_of Rails::Four::Queueing::SynchronousQueue, Rails.queue
46
+ end
47
+
48
+ class ThreadTrackingJob
49
+ def initialize
50
+ @origin = Thread.current.object_id
51
+ end
52
+
53
+ def run
54
+ @target = Thread.current.object_id
55
+ end
56
+
57
+ def ran_in_different_thread?
58
+ @origin != @target
59
+ end
60
+
61
+ def ran?
62
+ @target
63
+ end
64
+ end
65
+
66
+ test "in development mode, an enqueued job will be processed in the same thread" do
67
+ app("development")
68
+
69
+ job = ThreadTrackingJob.new
70
+ Rails.queue.push job
71
+ sleep 0.1
72
+
73
+ assert job.ran?, "Expected job to be run"
74
+ refute job.ran_in_different_thread?, "Expected job to run in the same thread"
75
+ end
76
+
77
+ test "in test mode, an enqueued job will be processed in the same thread" do
78
+ app("test")
79
+
80
+ job = ThreadTrackingJob.new
81
+ Rails.queue.push job
82
+ sleep 0.1
83
+
84
+ assert job.ran?, "Expected job to be run"
85
+ refute job.ran_in_different_thread?, "Expected job to run in the same thread"
86
+ end
87
+
88
+ test "in production, automatically spawn a queue consumer in a background thread" do
89
+ add_to_env_config "production", <<-RUBY
90
+ config.queue = Rails::Four::Queueing::Queue.new
91
+ RUBY
92
+
93
+ app("production")
94
+
95
+ assert_nil Rails.application.config.queue_consumer
96
+ assert_kind_of Rails::Four::Queueing::ThreadedQueueConsumer, Rails.application.queue_consumer
97
+ assert_equal Rails.logger, Rails.application.queue_consumer.logger
98
+ end
99
+
100
+ test "attempting to marshal a queue will raise an exception" do
101
+ app("test")
102
+ assert_raises TypeError do
103
+ Marshal.dump Rails.queue
104
+ end
105
+ end
106
+
107
+ def setup_custom_queue
108
+ add_to_env_config "production", <<-RUBY
109
+ require "my_queue"
110
+ config.queue = MyQueue.new
111
+ RUBY
112
+
113
+ app_file "lib/my_queue.rb", <<-RUBY
114
+ class MyQueue
115
+ def push(job)
116
+ job.run
117
+ end
118
+ end
119
+ RUBY
120
+
121
+ app("production")
122
+ end
123
+
124
+ test "a custom queue implementation can be provided" do
125
+ setup_custom_queue
126
+
127
+ assert_kind_of MyQueue, Rails.queue
128
+
129
+ job = Struct.new(:id, :ran) do
130
+ def run
131
+ self.ran = true
132
+ end
133
+ end
134
+
135
+ job1 = job.new(1)
136
+ Rails.queue.push job1
137
+
138
+ assert_equal true, job1.ran
139
+ end
140
+
141
+ test "a custom consumer implementation can be provided" do
142
+ add_to_env_config "production", <<-RUBY
143
+ require "my_queue_consumer"
144
+ config.queue = Rails::Four::Queueing::Queue.new
145
+ config.queue_consumer = MyQueueConsumer.new
146
+ RUBY
147
+
148
+ app_file "lib/my_queue_consumer.rb", <<-RUBY
149
+ class MyQueueConsumer
150
+ attr_reader :started
151
+
152
+ def start
153
+ @started = true
154
+ end
155
+ end
156
+ RUBY
157
+
158
+ app("production")
159
+
160
+ assert_kind_of MyQueueConsumer, Rails.application.queue_consumer
161
+ assert Rails.application.queue_consumer.started
162
+ end
163
+
164
+ test "default consumer is not used with custom queue implementation" do
165
+ setup_custom_queue
166
+
167
+ assert_nil Rails.application.queue_consumer
168
+ end
169
+ end