shinq 0.8.1 → 1.0.0.rc1
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/README.md +2 -0
- data/lib/generators/shinq/worker/templates/create_table_migration.erb +1 -0
- data/lib/shinq.rb +10 -2
- data/lib/shinq/active_job/queue_adapters/shinq_adapter.rb +9 -0
- data/lib/shinq/cli.rb +6 -3
- data/lib/shinq/client.rb +33 -5
- data/lib/shinq/configuration.rb +9 -1
- data/lib/shinq/launcher.rb +4 -0
- data/shinq.gemspec +2 -1
- data/spec/db/structure.sql.erb +15 -0
- data/spec/helpers/my_worker.rb +4 -0
- data/spec/integration_spec.rb +82 -10
- data/spec/shinq/cli_spec.rb +22 -4
- data/spec/shinq/client_spec.rb +46 -0
- data/spec/shinq/configuration_spec.rb +15 -0
- data/spec/shinq_spec.rb +51 -37
- data/spec/spec_helper.rb +18 -1
- metadata +24 -6
- data/spec/db/structure.sql +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64209cd09dc412fa47ad5de740fdc48a1a4882a6
|
4
|
+
data.tar.gz: ac63880ed26db5f5c417d068a1a5ca6c71d76cd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c55c274a6a76c8397cf344f10d8a1f692cea198e2c4f92474077771736f1f051f688334753da31d8f6c803b43cf43925ec6c05078bdff105e5d53503bff357a1
|
7
|
+
data.tar.gz: 611ff43357eeeef74737ed6d67432d706b2e0a10ad8746c224f2fddc786fe5425f8169faa4597eebebf17f663ac8de06a022b4be7b8ec32d9fa1d637f7048544
|
data/README.md
CHANGED
@@ -58,6 +58,7 @@ class CreateWorkerNames < ActiveRecord::Migration
|
|
58
58
|
create_table :worker_names, id: false, options: "ENGINE=QUEUE" do |t|
|
59
59
|
t.string :job_id, null: false
|
60
60
|
t.string :title
|
61
|
+
t.integer :scheduled_at, limit: 8, default: 0, null: false
|
61
62
|
t.datetime :enqueued_at, null: false
|
62
63
|
end
|
63
64
|
end
|
@@ -78,6 +79,7 @@ mysql> show create table worker_names\G
|
|
78
79
|
Create Table: CREATE TABLE `worker_names` (
|
79
80
|
`job_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
|
80
81
|
`title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
|
82
|
+
`scheduled_at` bigint(20) NOT NULL DEFAULT '0',
|
81
83
|
`enqueued_at` datetime NOT NULL
|
82
84
|
) ENGINE=QUEUE DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
|
83
85
|
```
|
@@ -5,6 +5,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
|
|
5
5
|
<% attributes.each do |attribute| -%>
|
6
6
|
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
7
7
|
<% end -%>
|
8
|
+
t.integer :scheduled_at, limit: 8, default: 0, null: false
|
8
9
|
t.datetime :enqueued_at, null: false
|
9
10
|
end
|
10
11
|
end
|
data/lib/shinq.rb
CHANGED
@@ -24,12 +24,20 @@ module Shinq
|
|
24
24
|
|
25
25
|
def self.setup_db_connection(db_name)
|
26
26
|
raise Shinq::ConfigurationError unless self.configuration.db_defined?(db_name)
|
27
|
-
@connections[db_name] = Mysql2::Client.new(self.configuration.db_config[db_name])
|
27
|
+
@connections[db_name.to_sym] = Mysql2::Client.new(self.configuration.db_config[db_name])
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.connection(db_name: self.default_db)
|
31
31
|
@connections ||= {}
|
32
|
-
@connections[db_name] ||= setup_db_connection(db_name)
|
32
|
+
@connections[db_name.to_sym] ||= setup_db_connection(db_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.clear_all_connections!
|
36
|
+
return unless @connections
|
37
|
+
@connections.each do |_db_name, connection|
|
38
|
+
connection && connection.close
|
39
|
+
end
|
40
|
+
@connections = {}
|
33
41
|
end
|
34
42
|
|
35
43
|
def self.logger
|
@@ -9,6 +9,15 @@ module ActiveJob
|
|
9
9
|
args: job.arguments.first
|
10
10
|
)
|
11
11
|
end
|
12
|
+
|
13
|
+
def enqueue_at(job, timestamp)
|
14
|
+
Shinq::Client.enqueue(
|
15
|
+
table_name: job.queue_name,
|
16
|
+
job_id: job.job_id,
|
17
|
+
args: job.arguments.first,
|
18
|
+
scheduled_at: timestamp,
|
19
|
+
)
|
20
|
+
end
|
12
21
|
end
|
13
22
|
end
|
14
23
|
end
|
data/lib/shinq/cli.rb
CHANGED
@@ -15,6 +15,7 @@ module Shinq
|
|
15
15
|
def initialize(args=ARGV)
|
16
16
|
setup_option(args)
|
17
17
|
bootstrap
|
18
|
+
initialize_shinq
|
18
19
|
end
|
19
20
|
|
20
21
|
def setup_option(args)
|
@@ -31,10 +32,7 @@ module Shinq
|
|
31
32
|
end
|
32
33
|
|
33
34
|
opt.on('-w', '--worker VALUE', 'Name of worker class') do |v|
|
34
|
-
worker_class = v.camelize.safe_constantize
|
35
|
-
raise OptionParseError, "worker class #{v.camelize} corresponding to #{v} does not exist" unless worker_class
|
36
35
|
opts[:worker_name] = v
|
37
|
-
opts[:worker_class] = worker_class
|
38
36
|
end
|
39
37
|
|
40
38
|
opt.on('-p', '--process VALUE', 'Number of workers') do |v|
|
@@ -104,6 +102,11 @@ module Shinq
|
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
105
|
+
def initialize_shinq
|
106
|
+
Shinq::Client.fetch_column_names(table_name: Shinq.configuration.worker_name.pluralize)
|
107
|
+
Shinq.configuration.worker_class # check if worker_class is constantizable before running ServerEngine
|
108
|
+
end
|
109
|
+
|
107
110
|
def run
|
108
111
|
klass = !options.statistics.nil? && options.statistics ? Shinq::Statistics : Shinq::Launcher
|
109
112
|
|
data/lib/shinq/client.rb
CHANGED
@@ -8,13 +8,19 @@ module Shinq
|
|
8
8
|
@builder ||= SQL::Maker.new(driver: 'mysql', auto_bind: true)
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.enqueue(table_name: , job_id: , args:)
|
11
|
+
def self.enqueue(table_name: , job_id: , args:, scheduled_at: nil)
|
12
|
+
if scheduled_at && !schedulable?(table_name: table_name)
|
13
|
+
raise ArgumentError, "table #{table_name} is not schedulable. You need column `scheduled_at`"
|
14
|
+
end
|
15
|
+
|
12
16
|
case args
|
13
17
|
when Hash
|
14
|
-
|
18
|
+
attributes = args.merge(
|
15
19
|
job_id: job_id,
|
16
|
-
|
17
|
-
|
20
|
+
scheduled_at: scheduled_at ? scheduled_at.to_i : nil,
|
21
|
+
enqueued_at: Time.now,
|
22
|
+
).compact
|
23
|
+
sql = builder.insert(table_name, attributes)
|
18
24
|
Shinq.connection.query(sql)
|
19
25
|
else
|
20
26
|
raise ArgumentError, "`args` should be a Hash"
|
@@ -22,7 +28,9 @@ module Shinq
|
|
22
28
|
end
|
23
29
|
|
24
30
|
def self.dequeue(table_name:)
|
25
|
-
|
31
|
+
condition = schedulable?(table_name: table_name) ? ":scheduled_at<=#{Time.now.to_i}" : ''
|
32
|
+
quoted = SQL::Maker::Quoting.quote("#{table_name}#{condition}")
|
33
|
+
|
26
34
|
queue_timeout_quoted = SQL::Maker::Quoting.quote(Shinq.configuration.queue_timeout)
|
27
35
|
|
28
36
|
wait_query = "queue_wait(#{quoted}, #{queue_timeout_quoted})"
|
@@ -52,6 +60,26 @@ module Shinq
|
|
52
60
|
)
|
53
61
|
end
|
54
62
|
|
63
|
+
def self.schedulable?(table_name:)
|
64
|
+
self.column_names(table_name: table_name).include?('scheduled_at')
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.column_names(table_name:)
|
68
|
+
@column_names_by_table_name ||= {}
|
69
|
+
@column_names_by_table_name[table_name.to_sym] ||= begin
|
70
|
+
quoted = SQL::Maker::Quoting.quote(table_name)
|
71
|
+
column = Shinq.connection.query(<<-EOS).map { |record| record['column_name'] }
|
72
|
+
select column_name from information_schema.columns where table_schema = database() and table_name = #{quoted}
|
73
|
+
EOS
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.fetch_column_names(table_name:)
|
78
|
+
@column_names_by_table_name ||= {}
|
79
|
+
@column_names_by_table_name.delete(table_name.to_sym)
|
80
|
+
column_names(table_name: table_name)
|
81
|
+
end
|
82
|
+
|
55
83
|
def self.done
|
56
84
|
Shinq.connection.query('select queue_end()')
|
57
85
|
end
|
data/lib/shinq/configuration.rb
CHANGED
@@ -10,7 +10,7 @@ module Shinq
|
|
10
10
|
# You may need to set it +false+ for jobs which take very long time to proceed.
|
11
11
|
# You may also need to handle performing error manually then.
|
12
12
|
class Configuration
|
13
|
-
attr_accessor :require, :worker_name, :
|
13
|
+
attr_accessor :require, :worker_name, :db_config, :queue_db, :default_db, :process, :graceful_kill_timeout, :queue_timeout, :daemonize, :statistics, :lifecycle, :abort_on_error
|
14
14
|
|
15
15
|
DEFAULT = {
|
16
16
|
require: '.',
|
@@ -27,6 +27,14 @@ module Shinq
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def worker_class
|
31
|
+
worker_class = worker_name.camelize.safe_constantize
|
32
|
+
unless worker_class
|
33
|
+
raise ConfigurationError, "worker class #{worker_name.camelize} corresponding to #{worker_name} does not exist"
|
34
|
+
end
|
35
|
+
worker_class
|
36
|
+
end
|
37
|
+
|
30
38
|
def default_db_config
|
31
39
|
raise ConfigurationError if !(default_db && db_defined?(default_db))
|
32
40
|
db_config[default_db]
|
data/lib/shinq/launcher.rb
CHANGED
data/shinq.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "shinq"
|
7
|
-
spec.version = '0.
|
7
|
+
spec.version = '1.0.0.rc1'
|
8
8
|
spec.authors = ["Ryoichi SEKIGUCHI"]
|
9
9
|
spec.email = ["ryopeko@gmail.com"]
|
10
10
|
spec.summary = %q{Worker and enqueuer for Q4M using the interface of ActiveJob.}
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "rspec"
|
24
24
|
spec.add_development_dependency "rspec-mocks"
|
25
25
|
spec.add_development_dependency "simplecov"
|
26
|
+
spec.add_development_dependency "timecop"
|
26
27
|
|
27
28
|
spec.add_dependency "mysql2", ">= 0.3.16", "< 0.5"
|
28
29
|
spec.add_dependency "sql-maker", "~> 0.0.4"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
DROP TABLE IF EXISTS `queue_test`;
|
2
|
+
CREATE TABLE `queue_test` (
|
3
|
+
`job_id` varchar(255) NOT NULL,
|
4
|
+
`title` varchar(255),
|
5
|
+
`scheduled_at` bigint(20) NOT NULL DEFAULT '0',
|
6
|
+
`enqueued_at` datetime NOT NULL
|
7
|
+
) ENGINE=<%= engine %>;
|
8
|
+
|
9
|
+
DROP TABLE IF EXISTS `queue_test_without_scheduled_at`;
|
10
|
+
|
11
|
+
CREATE TABLE `queue_test_without_scheduled_at` (
|
12
|
+
`job_id` varchar(255) NOT NULL,
|
13
|
+
`title` varchar(255),
|
14
|
+
`enqueued_at` datetime NOT NULL
|
15
|
+
) ENGINE=<%= engine %>;
|
data/spec/integration_spec.rb
CHANGED
@@ -3,7 +3,6 @@ require 'shinq'
|
|
3
3
|
require 'shinq/client'
|
4
4
|
|
5
5
|
describe "Integration", skip: ENV['TRAVIS'] do
|
6
|
-
let(:queue_table) { 'queue_test' }
|
7
6
|
|
8
7
|
before do
|
9
8
|
Shinq.configuration = {
|
@@ -13,28 +12,97 @@ describe "Integration", skip: ENV['TRAVIS'] do
|
|
13
12
|
end
|
14
13
|
|
15
14
|
after do
|
16
|
-
Shinq.
|
15
|
+
Shinq.clear_all_connections! # Return from owner mode
|
16
|
+
tables = Shinq.connection.query('show tables').flat_map(&:values)
|
17
|
+
tables.each do |table|
|
18
|
+
Shinq.connection.query("delete from #{table}")
|
19
|
+
end
|
20
|
+
Shinq.clear_all_connections!
|
17
21
|
end
|
18
22
|
|
19
23
|
describe "Shinq::Client.enqueue,dequeue" do
|
20
|
-
|
21
|
-
|
24
|
+
before do
|
25
|
+
Timecop.freeze
|
26
|
+
end
|
27
|
+
after do
|
28
|
+
Timecop.return
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with scheduled_at on table' do
|
32
|
+
let(:queue_table) { 'queue_test' }
|
33
|
+
let(:job_id) { SecureRandom.uuid }
|
22
34
|
|
23
35
|
before do
|
24
36
|
Shinq::Client.enqueue(
|
25
37
|
table_name: queue_table,
|
26
|
-
job_id:
|
27
|
-
args:
|
38
|
+
job_id: job_id,
|
39
|
+
args: { title: :foo },
|
40
|
+
scheduled_at: scheduled_at
|
28
41
|
)
|
42
|
+
end
|
29
43
|
|
30
|
-
|
31
|
-
|
44
|
+
context 'when scheduled_at is not specified' do
|
45
|
+
let(:scheduled_at) { nil }
|
46
|
+
|
47
|
+
it 'can dequeue immediately' do
|
48
|
+
expect(Shinq::Client.dequeue(table_name: queue_table)[:job_id]).to eq job_id
|
49
|
+
end
|
32
50
|
end
|
33
51
|
|
34
|
-
|
52
|
+
context 'when scheduled_at is specified' do
|
53
|
+
let(:scheduled_at) { 1.minute.since }
|
54
|
+
|
55
|
+
it 'can not dequeue job immediately' do
|
56
|
+
expect(Shinq::Client.dequeue(table_name: queue_table)).to be nil
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when specified time elapsed' do
|
60
|
+
before do
|
61
|
+
Timecop.travel(scheduled_at)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'can dequeue job' do
|
65
|
+
expect(Shinq::Client.dequeue(table_name: queue_table)[:job_id]).to eq job_id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
35
69
|
end
|
36
70
|
|
37
|
-
context
|
71
|
+
context 'without scheduled_at on table' do
|
72
|
+
let(:job_id) { SecureRandom.uuid }
|
73
|
+
let(:unschedulable_queue_table) { 'queue_test_without_scheduled_at' }
|
74
|
+
|
75
|
+
context 'when scheduled_at is not specified' do
|
76
|
+
before do
|
77
|
+
Shinq::Client.enqueue(
|
78
|
+
table_name: unschedulable_queue_table,
|
79
|
+
job_id: job_id,
|
80
|
+
args: { title: :foo },
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'can dequeue job' do
|
85
|
+
expect(Shinq::Client.dequeue(table_name: unschedulable_queue_table)[:job_id]).to eq job_id
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when scheduled_at is specified' do
|
90
|
+
it 'cannot enqueue job' do
|
91
|
+
expect {
|
92
|
+
Shinq::Client.enqueue(
|
93
|
+
table_name: unschedulable_queue_table,
|
94
|
+
job_id: job_id,
|
95
|
+
args: { title: :foo },
|
96
|
+
scheduled_at: 1.minute.since,
|
97
|
+
)
|
98
|
+
}.to raise_error ArgumentError
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
context "with invalid args" do
|
105
|
+
let(:queue_table) { 'queue_test' }
|
38
106
|
it {
|
39
107
|
expect {
|
40
108
|
Shinq::Client.enqueue(
|
@@ -48,6 +116,8 @@ describe "Integration", skip: ENV['TRAVIS'] do
|
|
48
116
|
end
|
49
117
|
|
50
118
|
describe "Shinq::Client.abort" do
|
119
|
+
let(:queue_table) { 'queue_test' }
|
120
|
+
|
51
121
|
context "When client has a queue" do
|
52
122
|
before do
|
53
123
|
Shinq::Client.enqueue(
|
@@ -77,6 +147,8 @@ describe "Integration", skip: ENV['TRAVIS'] do
|
|
77
147
|
end
|
78
148
|
|
79
149
|
describe "Shinq::Client.queue_stats" do
|
150
|
+
let(:queue_table) { 'queue_test' }
|
151
|
+
|
80
152
|
subject(:stats) {
|
81
153
|
Shinq::Client.queue_stats(table_name: queue_table)
|
82
154
|
}
|
data/spec/shinq/cli_spec.rb
CHANGED
@@ -2,9 +2,21 @@ require 'spec_helper'
|
|
2
2
|
require 'shinq/cli'
|
3
3
|
|
4
4
|
describe Shinq::CLI do
|
5
|
+
after do
|
6
|
+
Shinq.clear_all_connections!
|
7
|
+
end
|
8
|
+
|
5
9
|
describe '.new' do
|
6
|
-
context 'when there are
|
7
|
-
it
|
10
|
+
context 'when there are require statement' do
|
11
|
+
it 'requires and run the code' do
|
12
|
+
# NOTE: As CLI alters global process irreversibly, we only check the result
|
13
|
+
Shinq::CLI.new(%W[
|
14
|
+
--require my_worker
|
15
|
+
--db-config #{File.expand_path('../config/database.yml', __dir__)}
|
16
|
+
--worker my_worker
|
17
|
+
])
|
18
|
+
expect(defined? MyWorker).to eq 'constant'
|
19
|
+
end
|
8
20
|
end
|
9
21
|
end
|
10
22
|
|
@@ -13,8 +25,14 @@ describe Shinq::CLI do
|
|
13
25
|
allow_any_instance_of(ServerEngine::Daemon).to receive(:run).and_return(nil)
|
14
26
|
end
|
15
27
|
|
16
|
-
it 'launches Shinq::Launcher' do
|
17
|
-
|
28
|
+
it 'launches Shinq::Launcher backended by ServerEngine' do
|
29
|
+
expect {
|
30
|
+
Shinq::CLI.new(%W[
|
31
|
+
--require my_worker
|
32
|
+
--db-config #{File.expand_path('../config/database.yml', __dir__)}
|
33
|
+
--worker my_worker
|
34
|
+
]).run
|
35
|
+
}.not_to raise_error
|
18
36
|
end
|
19
37
|
end
|
20
38
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shinq'
|
3
|
+
require 'shinq/client'
|
4
|
+
|
5
|
+
describe Shinq::Client do
|
6
|
+
subject(:shinq_client) do
|
7
|
+
Shinq::Client.dup.tap do |client|
|
8
|
+
client.instance_variables.each do |variable|
|
9
|
+
client.remove_instance_variable(variable)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
Shinq.configuration = {
|
16
|
+
default_db: :test,
|
17
|
+
db_config: load_database_config
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
Shinq.clear_all_connections!
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '.schedulable?' do
|
26
|
+
context 'when target table have scheduled_at' do
|
27
|
+
it { expect(shinq_client.schedulable?(table_name: :queue_test)).to be true }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when target table does NOT have scheduled_at' do
|
31
|
+
it { expect(shinq_client.schedulable?(table_name: :queue_test_without_scheduled_at)).to be false }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.column_names' do
|
36
|
+
it 'fetches column_names' do
|
37
|
+
expect(shinq_client.column_names(table_name: :queue_test)).to eq(['job_id', 'title', 'scheduled_at', 'enqueued_at'])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'fetch_column_names' do
|
42
|
+
it 'fetches column_names' do
|
43
|
+
expect(shinq_client.fetch_column_names(table_name: :queue_test)).to eq(['job_id', 'title', 'scheduled_at', 'enqueued_at'])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -33,6 +33,21 @@ describe Shinq::Configuration do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
describe '#worker_class' do
|
37
|
+
context 'when worker_name is valid' do
|
38
|
+
let(:configuration) { Shinq::Configuration.new(worker_name: 'shinq') }
|
39
|
+
it 'constantizes worker_name to corresponding constant' do
|
40
|
+
expect(configuration.worker_class).to eq Shinq
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when worker_name is invalid' do
|
45
|
+
let(:configuration) { Shinq::Configuration.new(worker_name: 'invalid_shinq') }
|
46
|
+
|
47
|
+
it {expect { configuration.worker_class }.to raise_error(Shinq::ConfigurationError)}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
36
51
|
describe "#default_db_config" do
|
37
52
|
context "when default_db is present" do
|
38
53
|
let(:configuration) { Shinq::Configuration.new({}) }
|
data/spec/shinq_spec.rb
CHANGED
@@ -3,29 +3,32 @@ require 'shinq'
|
|
3
3
|
require 'shinq/configuration'
|
4
4
|
require 'logger'
|
5
5
|
|
6
|
-
def shinq_class
|
7
|
-
Shinq.dup
|
8
|
-
end
|
9
|
-
|
10
6
|
describe Shinq do
|
11
|
-
|
7
|
+
# remove instance variable deliberately or indeliberately defined by other specs
|
8
|
+
subject(:shinq) do
|
9
|
+
Shinq.dup.tap do |shinq|
|
10
|
+
shinq.instance_variables.each do |variable|
|
11
|
+
shinq.remove_instance_variable(variable)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
shinq.clear_all_connections!
|
18
|
+
end
|
12
19
|
|
13
20
|
it { is_expected.to respond_to(:configuration) }
|
14
21
|
it { is_expected.to respond_to(:configuration=) }
|
15
22
|
|
16
23
|
describe ".configuration" do
|
17
24
|
context "when configuration is not present" do
|
18
|
-
let(:shinq) { shinq_class }
|
19
|
-
|
20
25
|
it { expect(shinq.configuration).to be_a_kind_of(Shinq::Configuration) }
|
21
26
|
end
|
22
27
|
|
23
28
|
context "when configuration is present" do
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
}
|
28
|
-
}
|
29
|
+
before do
|
30
|
+
shinq.configuration = Hash.new
|
31
|
+
end
|
29
32
|
|
30
33
|
it { expect(shinq.configuration).to be_a_kind_of(Shinq::Configuration) }
|
31
34
|
end
|
@@ -33,7 +36,6 @@ describe Shinq do
|
|
33
36
|
|
34
37
|
describe ".configuration=" do
|
35
38
|
context "when specify args is Hash" do
|
36
|
-
let(:shinq) { shinq_class }
|
37
39
|
let(:args) { Hash.new }
|
38
40
|
|
39
41
|
it 'is expect to return specified args' do
|
@@ -42,7 +44,6 @@ describe Shinq do
|
|
42
44
|
end
|
43
45
|
|
44
46
|
context "when specify args is Shinq::Configuration" do
|
45
|
-
let(:shinq) { shinq_class }
|
46
47
|
let(:args) { Shinq::Configuration.new({}) }
|
47
48
|
|
48
49
|
it 'is expect to return specified args' do
|
@@ -52,43 +53,56 @@ describe Shinq do
|
|
52
53
|
end
|
53
54
|
|
54
55
|
describe ".connection" do
|
56
|
+
context "when db_config is not present" do
|
57
|
+
it { expect{ shinq.connection(db_name: :unknown) }.to raise_error(Shinq::ConfigurationError) }
|
58
|
+
end
|
59
|
+
|
55
60
|
context "when db_config is present" do
|
56
|
-
|
61
|
+
before do
|
62
|
+
shinq.configuration = { db_config: load_database_config, default_db: :test }
|
63
|
+
end
|
57
64
|
|
58
|
-
it
|
65
|
+
it do
|
66
|
+
shinq.connection(db_name: :test)
|
67
|
+
expect(shinq.connection(db_name: :test)).to be_a_kind_of(Mysql2::Client)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '.clear_all_connections!' do
|
73
|
+
before do
|
74
|
+
shinq.configuration = { db_config: load_database_config, default_db: :test }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when there are no connections' do
|
78
|
+
it { expect { shinq.clear_all_connections! }.not_to raise_error }
|
59
79
|
end
|
60
80
|
|
61
|
-
context
|
62
|
-
let(:shinq)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
81
|
+
context 'when there is a connection' do
|
82
|
+
let!(:connection) { shinq.connection(db_name: :test) }
|
83
|
+
|
84
|
+
it 'closes connection' do
|
85
|
+
shinq.clear_all_connections!
|
86
|
+
expect(connection.ping).to be false
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'clears connection cache' do
|
90
|
+
shinq.clear_all_connections!
|
91
|
+
expect(shinq.connection(db_name: :test)).not_to eq connection
|
92
|
+
end
|
72
93
|
end
|
73
94
|
end
|
74
95
|
|
75
96
|
describe ".logger" do
|
76
97
|
context "when logger is not present" do
|
77
|
-
let(:shinq) {
|
78
|
-
shinq_class.tap {|s|
|
79
|
-
s.logger = nil
|
80
|
-
}
|
81
|
-
}
|
82
98
|
it { expect(shinq.logger).to be nil }
|
83
99
|
end
|
84
100
|
|
85
101
|
context "when logger is present" do
|
86
102
|
let(:logger) { Logger.new(STDOUT) }
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
}
|
91
|
-
}
|
103
|
+
before do
|
104
|
+
shinq.logger = logger
|
105
|
+
end
|
92
106
|
|
93
107
|
it { expect(shinq.logger).to be logger }
|
94
108
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
ENV['RAILS_ENV'] ||= 'test'
|
2
|
+
$LOAD_PATH << File.expand_path('../helpers', __FILE__)
|
3
|
+
|
1
4
|
require 'rspec/mocks/standalone'
|
2
5
|
require 'simplecov'
|
6
|
+
require 'erb'
|
3
7
|
require 'yaml'
|
4
8
|
require 'active_support/core_ext/hash'
|
9
|
+
require 'mysql2'
|
10
|
+
require 'timecop'
|
5
11
|
|
6
12
|
def load_database_config
|
7
13
|
db_config = YAML.load_file(File.expand_path('./config/database.yml', __dir__)).symbolize_keys
|
@@ -25,8 +31,19 @@ RSpec.configure do |config|
|
|
25
31
|
end
|
26
32
|
|
27
33
|
config.before(:suite) do
|
34
|
+
# MySQL on Travis does not have Q4M plugins.
|
35
|
+
# We use QUEUE engine and run Q4M specific spec (integration_spec) only when ENV['TRAVIS'] is nil.
|
36
|
+
engine = ENV['TRAVIS'] ? 'InnoDB' : 'QUEUE' # Travis MySQL does not have Q4M plugins.
|
37
|
+
sql = ERB.new(File.read(File.expand_path('./db/structure.sql.erb', __dir__))).result(binding)
|
38
|
+
|
28
39
|
connection = Mysql2::Client.new(load_database_config[:test].merge(flags: Mysql2::Client::MULTI_STATEMENTS))
|
29
|
-
connection.query(
|
40
|
+
result = connection.query(sql)
|
41
|
+
|
42
|
+
while connection.next_result
|
43
|
+
connection.store_result
|
44
|
+
end
|
45
|
+
|
46
|
+
connection.close
|
30
47
|
end
|
31
48
|
|
32
49
|
config.order = :random
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shinq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryoichi SEKIGUCHI
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: timecop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: mysql2
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -214,9 +228,11 @@ files:
|
|
214
228
|
- lib/shinq/statistics.rb
|
215
229
|
- shinq.gemspec
|
216
230
|
- spec/config/database.yml
|
217
|
-
- spec/db/structure.sql
|
231
|
+
- spec/db/structure.sql.erb
|
232
|
+
- spec/helpers/my_worker.rb
|
218
233
|
- spec/integration_spec.rb
|
219
234
|
- spec/shinq/cli_spec.rb
|
235
|
+
- spec/shinq/client_spec.rb
|
220
236
|
- spec/shinq/configuration_spec.rb
|
221
237
|
- spec/shinq_spec.rb
|
222
238
|
- spec/spec_helper.rb
|
@@ -235,9 +251,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
235
251
|
version: '0'
|
236
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
237
253
|
requirements:
|
238
|
-
- - "
|
254
|
+
- - ">"
|
239
255
|
- !ruby/object:Gem::Version
|
240
|
-
version:
|
256
|
+
version: 1.3.1
|
241
257
|
requirements: []
|
242
258
|
rubyforge_project:
|
243
259
|
rubygems_version: 2.6.8
|
@@ -246,9 +262,11 @@ specification_version: 4
|
|
246
262
|
summary: Worker and enqueuer for Q4M using the interface of ActiveJob.
|
247
263
|
test_files:
|
248
264
|
- spec/config/database.yml
|
249
|
-
- spec/db/structure.sql
|
265
|
+
- spec/db/structure.sql.erb
|
266
|
+
- spec/helpers/my_worker.rb
|
250
267
|
- spec/integration_spec.rb
|
251
268
|
- spec/shinq/cli_spec.rb
|
269
|
+
- spec/shinq/client_spec.rb
|
252
270
|
- spec/shinq/configuration_spec.rb
|
253
271
|
- spec/shinq_spec.rb
|
254
272
|
- spec/spec_helper.rb
|