Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

* TODO

### 0.45.0

* Add before and after queue hooks

https://github.com/KnapsackPro/knapsack_pro-ruby/pull/46

https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v0.44.0...v0.45.0

### 0.44.0

* Add ability to set test_dir using an environment variable.
Expand Down
33 changes: 18 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1188,11 +1188,15 @@ Knapsack Pro Queue Mode runs subset of test files from the work queue many times
```ruby
# spec_helper.rb or rails_helper.rb

# executes before Queue Mode starts work
Percy::Capybara.initialize_build
KnapsackPro::Hooks::Queue.before_queue do |queue_id|
# executes before Queue Mode starts work
Percy::Capybara.initialize_build
end

# executes after Queue Mode finishes work
at_exit { Percy::Capybara.finalize_build }
KnapsackPro::Hooks::Queue.after_queue do |queue_id|
# executes after Queue Mode finishes work
Percy::Capybara.finalize_build
end
```

#### How to call `before(:suite)` and `after(:suite)` RSpec hooks only once in Queue Mode?
Expand All @@ -1202,18 +1206,17 @@ Knapsack Pro Queue Mode runs subset of test files from the work queue many times
```ruby
# spec_helper.rb or rails_helper.rb

RSpec.configure do |config|
config.before(:suite) do
unless ENV['KNAPSACK_PRO_RSPEC_BEFORE_SUITE_LOADED']
ENV['KNAPSACK_PRO_RSPEC_BEFORE_SUITE_LOADED'] = 'true'

# this will be called only once before the tests started on the CI node
end
end
KnapsackPro::Hooks::Queue.before_queue do |queue_id|
# This will be called only once before the tests started on the CI node.
# It will be run inside of the RSpec before(:suite) block only once.
# It means you will have access to whatever RSpec provides in the context of the before(:suite) block.
end

at_exit do
# this will be called only once at the end when the CI node finished tests
end
KnapsackPro::Hooks::Queue.after_queue do |queue_id|
# This will be called only once after test suite is completed.
# Note this hook won't be called inside of RSpec after(:suite) block because
# we are not able to determine which after(:suite) block will be called as the last one
# due to the fact the Knapsack Pro Queue Mode allocates tests in dynamic way.
end
```

Expand Down
5 changes: 5 additions & 0 deletions lib/knapsack_pro/adapters/base_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def bind

if KnapsackPro::Config::Env.queue_recording_enabled?
KnapsackPro.logger.debug('Test suite time execution queue recording enabled.')
bind_before_queue_hook
bind_time_tracker
bind_save_queue_report
end
Expand All @@ -35,6 +36,10 @@ def bind_save_report
def bind_save_queue_report
raise NotImplementedError
end

def bind_before_queue_hook
raise NotImplementedError
end
end
end
end
11 changes: 11 additions & 0 deletions lib/knapsack_pro/adapters/rspec_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ def bind_save_queue_report
end
end
end

def bind_before_queue_hook
::RSpec.configure do |config|
config.before(:suite) do
unless ENV['KNAPSACK_PRO_BEFORE_QUEUE_HOOK_CALLED']
KnapsackPro::Hooks::Queue.call_before_queue
ENV['KNAPSACK_PRO_BEFORE_QUEUE_HOOK_CALLED'] = 'true'
end
end
end
end
end

# This is added to provide backwards compatibility
Expand Down
34 changes: 33 additions & 1 deletion lib/knapsack_pro/hooks/queue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,55 @@ module KnapsackPro
module Hooks
class Queue
class << self
attr_reader :after_subset_queue
attr_reader :before_queue,
:after_subset_queue,
:after_queue

def reset_before_queue
@before_queue = nil
end

def reset_after_subset_queue
@after_subset_queue = nil
end

def reset_after_queue
@after_queue = nil
end

def before_queue(&block)
@before_queue ||= block
end

def after_subset_queue(&block)
@after_subset_queue ||= block
end

def after_queue(&block)
@after_queue ||= block
end

def call_before_queue
return unless before_queue
before_queue.call(
KnapsackPro::Config::Env.queue_id
)
end

def call_after_subset_queue
return unless after_subset_queue
after_subset_queue.call(
KnapsackPro::Config::Env.queue_id,
KnapsackPro::Config::Env.subset_queue_id
)
end

def call_after_queue
return unless after_queue
after_queue.call(
KnapsackPro::Config::Env.queue_id
)
end
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/knapsack_pro/runners/queue/rspec_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def self.run_tests(runner, can_initialize_queue, args, exitstatus, all_test_file
log_rspec_command(args, all_test_file_paths, :end_of_queue)
end

KnapsackPro::Hooks::Queue.call_after_queue

KnapsackPro::Report.save_node_queue_to_api
exit(exitstatus)
else
Expand Down
11 changes: 11 additions & 0 deletions spec/knapsack_pro/adapters/base_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
let(:queue_recording_enabled?) { true }

before do
allow(subject).to receive(:bind_before_queue_hook)
allow(subject).to receive(:bind_time_tracker)
allow(subject).to receive(:bind_save_queue_report)
end
Expand All @@ -57,6 +58,7 @@
expect(KnapsackPro).to receive(:logger).and_return(logger)
expect(logger).to receive(:debug).with('Test suite time execution queue recording enabled.')
end
it { expect(subject).to receive(:bind_before_queue_hook) }
it { expect(subject).to receive(:bind_time_tracker) }
it { expect(subject).to receive(:bind_save_queue_report) }
end
Expand All @@ -65,6 +67,7 @@
it { expect(subject).not_to receive(:bind_time_tracker) }
it { expect(subject).not_to receive(:bind_save_report) }
it { expect(subject).not_to receive(:bind_save_queue_report) }
it { expect(subject).not_to receive(:bind_before_queue_hook) }
end
end

Expand All @@ -91,4 +94,12 @@
}.to raise_error(NotImplementedError)
end
end

describe '#bind_before_queue_hook' do
it do
expect {
subject.bind_before_queue_hook
}.to raise_error(NotImplementedError)
end
end
end
11 changes: 11 additions & 0 deletions spec/knapsack_pro/adapters/rspec_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,16 @@
subject.bind_save_queue_report
end
end

describe '#bind_before_queue_hook' do
it do
expect(config).to receive(:before).with(:suite).and_yield
expect(::RSpec).to receive(:configure).and_yield(config)

expect(KnapsackPro::Hooks::Queue).to receive(:call_before_queue)

subject.bind_before_queue_hook
end
end
end
end
52 changes: 52 additions & 0 deletions spec/knapsack_pro/hooks/queue_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
describe KnapsackPro::Hooks::Queue do
describe '.call_before_queue' do
subject { described_class.call_before_queue }

context 'when callback is not set' do
before do
described_class.reset_before_queue
end

it { should be_nil }
end

context 'when callback is set' do
let(:queue_id) { double }

before do
expect(KnapsackPro::Config::Env).to receive(:queue_id).and_return(queue_id)

described_class.before_queue do |q_id|
[:fake_value, q_id]
end
end

it { should eq [:fake_value, queue_id] }
end
end

describe '.call_after_subset_queue' do
subject { described_class.call_after_subset_queue }

Expand Down Expand Up @@ -26,4 +52,30 @@
it { should eq [:fake_value, queue_id, subset_queue_id] }
end
end

describe '.call_after_queue' do
subject { described_class.call_after_queue }

context 'when callback is not set' do
before do
described_class.reset_after_queue
end

it { should be_nil }
end

context 'when callback is set' do
let(:queue_id) { double }

before do
expect(KnapsackPro::Config::Env).to receive(:queue_id).and_return(queue_id)

described_class.after_queue do |q_id|
[:fake_value, q_id]
end
end

it { should eq [:fake_value, queue_id] }
end
end
end
2 changes: 2 additions & 0 deletions spec/knapsack_pro/runners/queue/rspec_runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@
let(:test_file_paths) { [] }

it do
expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)

expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
expect(described_class).to receive(:exit).with(exitstatus)

Expand Down