shinq 0.8.1 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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;