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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 013b8f719198d810d0b9928008308196c17f4000
4
- data.tar.gz: e48fca8300e77ad5f830c0c290f723cf89a0fc78
3
+ metadata.gz: 64209cd09dc412fa47ad5de740fdc48a1a4882a6
4
+ data.tar.gz: ac63880ed26db5f5c417d068a1a5ca6c71d76cd5
5
5
  SHA512:
6
- metadata.gz: 5d3dd629d17c5cd5865c3a7832f9cbf3c91437cc348a211a2abfb5063d776468cb8d511aede38acf8c4a811883a7fe469aa47308ccb0fcf048704084953bd12c
7
- data.tar.gz: fff06dcd8d212d653a8445c201e8a983222b96a718c11ba7a3a267b86c7191acb9e7edcd42f653be66be846829e8417b586b70587ed94946e9747aeb6c28e276
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
- sql = builder.insert(table_name, args.merge(
18
+ attributes = args.merge(
15
19
  job_id: job_id,
16
- enqueued_at: Time.now
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
- quoted = SQL::Maker::Quoting.quote(table_name)
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
@@ -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, :worker_class, :db_config, :queue_db, :default_db, :process, :graceful_kill_timeout, :queue_timeout, :daemonize, :statistics, :lifecycle, :abort_on_error
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]
@@ -3,6 +3,10 @@ require 'active_support/inflector'
3
3
 
4
4
  module Shinq
5
5
  module Launcher
6
+ def initialize
7
+ Shinq.clear_all_connections!
8
+ end
9
+
6
10
  # Wait configured queue and proceed each of them until stop.
7
11
  # @see Shinq::Configuration#abort_on_error
8
12
  def run
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.8.1'
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 %>;
@@ -0,0 +1,4 @@
1
+ require 'active_job'
2
+ class MyWorker < ActiveJob::Base
3
+ queue_as :my_workers
4
+ end
@@ -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.connection.query("delete from #{queue_table}")
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
- context "valid args" do
21
- let(:args) { {title: 'foo'} }
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: 'jobid',
27
- args: args
38
+ job_id: job_id,
39
+ args: { title: :foo },
40
+ scheduled_at: scheduled_at
28
41
  )
42
+ end
29
43
 
30
- @queue = Shinq::Client.dequeue(table_name: queue_table)
31
- Shinq::Client.done
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
- it { expect(@queue[:title]).to eq args[:title] }
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 "invalid args" do
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
  }
@@ -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 no arguments' do
7
- it { expect { Shinq::CLI.new(%w(--require shinq/cli)) }.not_to raise_error }
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
- Shinq::CLI.new(%w(--require shinq/cli)).run
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
- subject { shinq_class }
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
- let(:shinq) {
25
- shinq_class.tap {|s|
26
- s.configuration = Hash.new
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
- let(:shinq) { shinq_class }
61
+ before do
62
+ shinq.configuration = { db_config: load_database_config, default_db: :test }
63
+ end
57
64
 
58
- it { expect{ shinq.connection(db_name: :unknown) }.to raise_error(Shinq::ConfigurationError) }
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 "when db_config is not preset" do
62
- let(:shinq) {
63
- shinq_class.tap {|s|
64
- s.configuration = {
65
- db_config: load_database_config,
66
- default_db: :test,
67
- }
68
- }
69
- }
70
-
71
- it { expect(shinq.connection(db_name: :test)).to be_a_kind_of(Mysql2::Client) }
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
- let(:shinq) {
88
- shinq_class.tap {|s|
89
- s.logger = logger
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(File.read(File.expand_path('./db/structure.sql', __dir__)))
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.8.1
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-01 00:00:00.000000000 Z
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: '0'
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
@@ -1,6 +0,0 @@
1
- DROP TABLE IF EXISTS `queue_test`;
2
- CREATE TABLE `queue_test` (
3
- `job_id` varchar(255) NOT NULL,
4
- `title` varchar(255),
5
- `enqueued_at` datetime NOT NULL
6
- ) ENGINE=QUEUE;