knapsack_pro 6.0.3 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +375 -28
  3. data/.github/pull_request_template.md +22 -0
  4. data/.gitignore +4 -0
  5. data/CHANGELOG.md +95 -0
  6. data/Gemfile +9 -0
  7. data/README.md +0 -7
  8. data/knapsack_pro.gemspec +2 -1
  9. data/lib/knapsack_pro/adapters/base_adapter.rb +7 -2
  10. data/lib/knapsack_pro/adapters/cucumber_adapter.rb +1 -3
  11. data/lib/knapsack_pro/adapters/rspec_adapter.rb +16 -9
  12. data/lib/knapsack_pro/config/env.rb +1 -9
  13. data/lib/knapsack_pro/extensions/rspec_extension.rb +137 -0
  14. data/lib/knapsack_pro/formatters/time_tracker.rb +10 -26
  15. data/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +8 -0
  16. data/lib/knapsack_pro/presenter.rb +1 -1
  17. data/lib/knapsack_pro/pure/queue/rspec_pure.rb +92 -0
  18. data/lib/knapsack_pro/runners/queue/base_runner.rb +6 -1
  19. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +6 -6
  20. data/lib/knapsack_pro/runners/queue/minitest_runner.rb +10 -6
  21. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +124 -173
  22. data/lib/knapsack_pro/urls.rb +2 -0
  23. data/lib/knapsack_pro/version.rb +1 -1
  24. data/lib/knapsack_pro.rb +1 -0
  25. data/spec/integration/runners/queue/rspec_runner.rb +80 -0
  26. data/spec/integration/runners/queue/rspec_runner_spec.rb +2232 -0
  27. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +17 -11
  28. data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +2 -5
  29. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +2 -24
  30. data/spec/knapsack_pro/config/env_spec.rb +1 -35
  31. data/spec/knapsack_pro/formatters/time_tracker_specs.rb +8 -37
  32. data/spec/knapsack_pro/hooks/queue_spec.rb +2 -2
  33. data/spec/knapsack_pro/presenter_spec.rb +1 -1
  34. data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +224 -0
  35. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +16 -16
  36. data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +14 -14
  37. data/spec/knapsack_pro_spec.rb +3 -3
  38. data/spec/spec_helper.rb +0 -1
  39. metadata +17 -12
  40. data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +0 -58
  41. data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +0 -145
  42. data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +0 -536
@@ -4,223 +4,174 @@ module KnapsackPro
4
4
  module Runners
5
5
  module Queue
6
6
  class RSpecRunner < BaseRunner
7
- @@used_seed = nil
8
-
9
- def self.run(args)
7
+ def self.run(args, stream_error = $stderr, stream_out = $stdout)
10
8
  require 'rspec/core'
9
+ require_relative '../../extensions/rspec_extension'
11
10
  require_relative '../../formatters/time_tracker'
12
11
  require_relative '../../formatters/time_tracker_fetcher'
13
- require_relative '../../formatters/rspec_queue_summary_formatter'
14
- require_relative '../../formatters/rspec_queue_profile_formatter_extension'
12
+
13
+ KnapsackPro::Extensions::RSpecExtension.setup!
15
14
 
16
15
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec
17
- ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED'] = 'true'
18
- ENV['KNAPSACK_PRO_QUEUE_ID'] = KnapsackPro::Config::EnvGenerator.set_queue_id
19
16
 
20
- KnapsackPro::Config::Env.set_test_runner_adapter(adapter_class)
21
- runner = new(adapter_class)
22
-
23
- cli_args = (args || '').split
24
- adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(cli_args)
25
-
26
- # when format option is not defined by user then use progress formatter to show tests execution progress
27
- cli_args += ['--format', 'progress'] unless adapter_class.has_format_option?(cli_args)
28
-
29
- cli_args += [
30
- # shows summary of all tests executed in Queue Mode at the very end
31
- '--format', KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s,
32
- '--format', KnapsackPro::Formatters::TimeTracker.to_s,
33
- '--default-path', runner.test_dir,
34
- ]
35
-
36
- accumulator = {
37
- status: :next,
38
- runner: runner,
39
- can_initialize_queue: true,
40
- args: cli_args,
41
- exitstatus: 0,
42
- all_test_file_paths: [],
43
- }
44
- while accumulator[:status] == :next
45
- handle_signal!
46
- accumulator = run_tests(accumulator)
47
- end
17
+ rspec_pure = KnapsackPro::Pure::Queue::RSpecPure.new
48
18
 
49
- Kernel.exit(accumulator[:exitstatus])
19
+ queue_runner = new(KnapsackPro::Adapters::RSpecAdapter, rspec_pure, args, stream_error, stream_out)
20
+ queue_runner.run
50
21
  end
51
22
 
52
- def self.run_tests(accumulator)
53
- runner = accumulator.fetch(:runner)
54
- can_initialize_queue = accumulator.fetch(:can_initialize_queue)
55
- args = accumulator.fetch(:args)
56
- exitstatus = accumulator.fetch(:exitstatus)
57
- all_test_file_paths = accumulator.fetch(:all_test_file_paths)
23
+ def initialize(adapter_class, rspec_pure, args, stream_error, stream_out)
24
+ super(adapter_class)
25
+ @adapter_class = adapter_class
26
+ @rspec_pure = rspec_pure
27
+ has_format_option = @adapter_class.has_format_option?((args || '').split)
28
+ @cli_args = rspec_pure.prepare_cli_args(args, has_format_option, test_dir)
29
+ @stream_error = stream_error
30
+ @stream_out = stream_out
31
+ @node_test_file_paths = []
32
+ @rspec_runner = nil # RSpec::Core::Runner is lazy initialized
33
+ end
58
34
 
59
- test_file_paths = runner.test_file_paths(
60
- can_initialize_queue: can_initialize_queue,
61
- executed_test_files: all_test_file_paths
62
- )
35
+ # Based on:
36
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/runner.rb#L85
37
+ #
38
+ # @return [Fixnum] exit status code.
39
+ # 0 if all specs passed,
40
+ # or the configured failure exit code (1 by default) if specs failed.
41
+ def run
42
+ pre_run_setup
43
+
44
+ if @rspec_runner.knapsack__wants_to_quit?
45
+ exit_code = @rspec_runner.knapsack__exit_early
46
+ Kernel.exit(exit_code)
47
+ end
48
+
49
+ begin
50
+ exit_code = @rspec_runner.knapsack__run_specs(self)
51
+ rescue KnapsackPro::Runners::Queue::BaseRunner::TerminationError
52
+ exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code)
53
+ Kernel.exit(exit_code)
54
+ rescue Exception => exception
55
+ KnapsackPro.logger.error("An unexpected exception happened. RSpec cannot handle it. The exception: #{exception.inspect}")
63
56
 
64
- if test_file_paths.empty?
65
- unless all_test_file_paths.empty?
66
- KnapsackPro::Adapters::RSpecAdapter.verify_bind_method_called
57
+ message = @rspec_pure.exit_summary(unexecuted_test_files)
58
+ KnapsackPro.logger.warn(message) if message
67
59
 
68
- KnapsackPro::Formatters::RSpecQueueSummaryFormatter.print_summary
69
- KnapsackPro::Formatters::RSpecQueueProfileFormatterExtension.print_summary
60
+ exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code)
61
+ Kernel.exit(exit_code)
62
+ end
70
63
 
71
- args += ['--seed', @@used_seed] if @@used_seed
64
+ post_run_tasks(exit_code)
65
+ end
72
66
 
73
- log_rspec_command(args, all_test_file_paths, :end_of_queue)
74
- end
67
+ def with_batch
68
+ can_initialize_queue = true
75
69
 
76
- KnapsackPro::Hooks::Queue.call_after_queue
70
+ loop do
71
+ handle_signal!
72
+ test_file_paths = pull_tests_from_queue(can_initialize_queue: can_initialize_queue)
73
+ can_initialize_queue = false
77
74
 
78
- time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call
79
- KnapsackPro::Report.save_node_queue_to_api(time_tracker&.queue(all_test_file_paths) || [])
75
+ break if test_file_paths.empty?
80
76
 
81
- return {
82
- status: :completed,
83
- exitstatus: exitstatus,
84
- }
85
- else
86
77
  subset_queue_id = KnapsackPro::Config::EnvGenerator.set_subset_queue_id
87
78
  ENV['KNAPSACK_PRO_SUBSET_QUEUE_ID'] = subset_queue_id
88
79
 
89
80
  KnapsackPro::Hooks::Queue.call_before_subset_queue
90
81
 
91
- all_test_file_paths += test_file_paths
92
- cli_args = args + test_file_paths
93
-
94
- ensure_spec_opts_have_knapsack_pro_formatters
95
- options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
96
- rspec_runner = ::RSpec::Core::Runner.new(options)
97
-
98
- begin
99
- exit_code = rspec_runner.run($stderr, $stdout)
100
- exitstatus = exit_code if exit_code != 0
101
- rescue Exception => exception
102
- KnapsackPro.logger.error("Having exception when running RSpec: #{exception.inspect}")
103
- KnapsackPro::Formatters::RSpecQueueSummaryFormatter.print_exit_summary(all_test_file_paths)
104
- KnapsackPro::Hooks::Queue.call_after_subset_queue
105
- KnapsackPro::Hooks::Queue.call_after_queue
106
- Kernel.exit(1)
107
- raise
108
- else
109
- if rspec_runner.world.wants_to_quit
110
- KnapsackPro.logger.warn('RSpec wants to quit.')
111
- set_terminate_process
112
- end
113
- if rspec_runner.world.respond_to?(:rspec_is_quitting) && rspec_runner.world.rspec_is_quitting
114
- KnapsackPro.logger.warn('RSpec is quitting.')
115
- set_terminate_process
116
- end
117
-
118
- printable_args = args_with_seed_option_added_when_viable(args, rspec_runner)
119
- log_rspec_command(printable_args, test_file_paths, :subset_queue)
120
-
121
- rspec_clear_examples
122
-
123
- KnapsackPro::Hooks::Queue.call_after_subset_queue
124
-
125
- return {
126
- status: :next,
127
- runner: runner,
128
- can_initialize_queue: false,
129
- args: args,
130
- exitstatus: exitstatus,
131
- all_test_file_paths: all_test_file_paths,
132
- }
133
- end
134
- end
135
- end
82
+ yield test_file_paths
136
83
 
137
- def self.ensure_spec_opts_have_knapsack_pro_formatters
138
- return unless ENV['SPEC_OPTS']
84
+ KnapsackPro::Hooks::Queue.call_after_subset_queue
139
85
 
140
- if [
141
- ENV['SPEC_OPTS'].include?(KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s),
142
- ENV['SPEC_OPTS'].include?(KnapsackPro::Formatters::TimeTracker.to_s),
143
- ].all?
144
- return
145
- end
86
+ if @rspec_runner.knapsack__wants_to_quit?
87
+ KnapsackPro.logger.warn('RSpec wants to quit.')
88
+ set_terminate_process
89
+ end
90
+ if @rspec_runner.knapsack__rspec_is_quitting?
91
+ KnapsackPro.logger.warn('RSpec is quitting.')
92
+ set_terminate_process
93
+ end
146
94
 
147
- unless ENV['SPEC_OPTS'].include?(KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s)
148
- ENV['SPEC_OPTS'] = "#{ENV['SPEC_OPTS']} --format #{KnapsackPro::Formatters::RSpecQueueSummaryFormatter}"
95
+ log_rspec_batch_command(test_file_paths)
149
96
  end
97
+ end
150
98
 
151
- unless ENV['SPEC_OPTS'].include?(KnapsackPro::Formatters::TimeTracker.to_s)
152
- ENV['SPEC_OPTS'] = "#{ENV['SPEC_OPTS']} --format #{KnapsackPro::Formatters::TimeTracker}"
153
- end
99
+ def handle_signal!
100
+ self.class.handle_signal!
101
+ end
102
+
103
+ def log_fail_fast_limit_met
104
+ KnapsackPro.logger.warn('Test execution has been canceled because the RSpec --fail-fast option is enabled. It will cause other CI nodes to run tests longer because they need to consume more tests from the Knapsack Pro Queue API.')
154
105
  end
155
106
 
156
107
  private
157
108
 
158
- def self.adapter_class
159
- KnapsackPro::Adapters::RSpecAdapter
109
+ def pre_run_setup
110
+ ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED'] = 'true'
111
+ ENV['KNAPSACK_PRO_QUEUE_ID'] = KnapsackPro::Config::EnvGenerator.set_queue_id
112
+
113
+ KnapsackPro::Config::Env.set_test_runner_adapter(@adapter_class)
114
+
115
+ ENV['SPEC_OPTS'] = @rspec_pure.add_knapsack_pro_formatters_to(ENV['SPEC_OPTS'])
116
+ @adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(@cli_args)
117
+
118
+ rspec_configuration_options = ::RSpec::Core::ConfigurationOptions.new(@cli_args)
119
+ @rspec_runner = ::RSpec::Core::Runner.new(rspec_configuration_options)
120
+ @rspec_runner.knapsack__setup(@stream_error, @stream_out)
121
+
122
+ ensure_no_deprecated_run_all_when_everything_filtered_option!
160
123
  end
161
124
 
162
- def self.log_rspec_command(cli_args, test_file_paths, type)
163
- case type
164
- when :subset_queue
165
- KnapsackPro.logger.info("To retry the last batch of tests fetched from the API Queue, please run the following command on your machine:")
166
- when :end_of_queue
167
- KnapsackPro.logger.info("To retry all the tests assigned to this CI node, please run the following command on your machine:")
168
- end
125
+ def post_run_tasks(exit_code)
126
+ @adapter_class.verify_bind_method_called
169
127
 
170
- stringified_cli_args = cli_args.join(' ')
171
- .sub(" --format #{KnapsackPro::Formatters::RSpecQueueSummaryFormatter}", '')
172
- .sub(" --format #{KnapsackPro::Formatters::TimeTracker}", '')
128
+ log_rspec_queue_command
173
129
 
174
- KnapsackPro.logger.info(
175
- "bundle exec rspec #{stringified_cli_args} " +
176
- KnapsackPro::TestFilePresenter.stringify_paths(test_file_paths)
177
- )
130
+ time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call
131
+ KnapsackPro::Report.save_node_queue_to_api(time_tracker&.queue(@node_test_file_paths))
132
+
133
+ Kernel.exit(exit_code)
178
134
  end
179
135
 
180
- # Clear rspec examples without the shared examples:
181
- # https://github.com/rspec/rspec-core/pull/2379
182
- #
183
- # Keep formatters and report to accumulate info about failed/pending tests
184
- def self.rspec_clear_examples
185
- if ::RSpec::ExampleGroups.respond_to?(:remove_all_constants)
186
- ::RSpec::ExampleGroups.remove_all_constants
187
- else
188
- ::RSpec::ExampleGroups.constants.each do |constant|
189
- ::RSpec::ExampleGroups.__send__(:remove_const, constant)
190
- end
191
- end
192
- ::RSpec.world.example_groups.clear
193
- ::RSpec.configuration.start_time = ::RSpec::Core::Time.now
194
-
195
- if KnapsackPro::Config::Env.rspec_split_by_test_examples?
196
- # Reset example group counts to ensure scoped example ids in metadata
197
- # have correct index (not increased by each subsequent run).
198
- # Solves this problem: https://github.com/rspec/rspec-core/issues/2721
199
- ::RSpec.world.instance_variable_set(:@example_group_counts_by_spec_file, Hash.new(0))
200
- end
136
+ def ensure_no_deprecated_run_all_when_everything_filtered_option!
137
+ return unless @rspec_runner.knapsack__deprecated_run_all_when_everything_filtered_enabled?
201
138
 
202
- # skip reset filters for old RSpec versions
203
- if ::RSpec.configuration.respond_to?(:reset_filters)
204
- ::RSpec.configuration.reset_filters
205
- end
139
+ error_message = "The run_all_when_everything_filtered option is deprecated. See: #{KnapsackPro::Urls::RSPEC__DEPRECATED_RUN_ALL_WHEN_EVERYTHING_FILTERED}"
140
+ KnapsackPro.logger.error(error_message)
141
+ raise error_message
206
142
  end
207
143
 
208
- def self.args_with_seed_option_added_when_viable(args, rspec_runner)
209
- order_option = adapter_class.order_option(args)
144
+ def pull_tests_from_queue(can_initialize_queue: false)
145
+ test_file_paths = test_file_paths(
146
+ can_initialize_queue: can_initialize_queue,
147
+ executed_test_files: @node_test_file_paths
148
+ )
149
+ @node_test_file_paths += test_file_paths
150
+ test_file_paths
151
+ end
210
152
 
211
- if order_option
212
- # Don't add the seed option for order other than random, e.g. `defined`
213
- return args unless order_option.include?('rand')
214
- # Don't add the seed option if the seed is already set in args, e.g. `rand:12345`
215
- return args if order_option.to_s.split(':')[1]
216
- end
153
+ def log_rspec_batch_command(test_file_paths)
154
+ order_option = @adapter_class.order_option(@cli_args)
155
+ printable_args = @rspec_pure.args_with_seed_option_added_when_viable(order_option, @rspec_runner.knapsack__seed, @cli_args)
156
+ messages = @rspec_pure.rspec_command(printable_args, test_file_paths, :batch_finished)
157
+ log_info_messages(messages)
158
+ end
217
159
 
218
- # Don't add the seed option if the seed was not used (i.e. a different order is being used, e.g. `defined`)
219
- return args unless rspec_runner.configuration.seed_used?
160
+ def log_rspec_queue_command
161
+ order_option = @adapter_class.order_option(@cli_args)
162
+ printable_args = @rspec_pure.args_with_seed_option_added_when_viable(order_option, @rspec_runner.knapsack__seed, @cli_args)
163
+ messages = @rspec_pure.rspec_command(printable_args, @node_test_file_paths, :queue_finished)
164
+ log_info_messages(messages)
165
+ end
220
166
 
221
- @@used_seed = rspec_runner.configuration.seed.to_s
167
+ def log_info_messages(messages)
168
+ messages.each do |message|
169
+ KnapsackPro.logger.info(message)
170
+ end
171
+ end
222
172
 
223
- args + ['--seed', @@used_seed]
173
+ def unexecuted_test_files
174
+ KnapsackPro::Formatters::TimeTrackerFetcher.unexecuted_test_files(@node_test_file_paths)
224
175
  end
225
176
  end
226
177
  end
@@ -28,6 +28,8 @@ module KnapsackPro
28
28
 
29
29
  REGULAR_MODE__CONNECTION_ERROR_WITH_FALLBACK_ENABLED_TRUE_AND_POSITIVE_RETRY_COUNT = "#{HOST}/perma/ruby/regular-mode-connection-error-with-fallback-enabled-true-and-positive-retry-count"
30
30
 
31
+ RSPEC__DEPRECATED_RUN_ALL_WHEN_EVERYTHING_FILTERED = "#{HOST}/perma/ruby/rspec-deprecated-run-all-when-everything-filtered"
32
+
31
33
  RSPEC__SKIPS_TESTS = "#{HOST}/perma/ruby/rspec-skips-tests"
32
34
 
33
35
  RSPEC__SPLIT_BY_TEST_EXAMPLES__TAG = "#{HOST}/perma/ruby/rspec-split-by-test-examples-tag"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KnapsackPro
4
- VERSION = '6.0.3'
4
+ VERSION = '7.0.0'
5
5
  end
data/lib/knapsack_pro.rb CHANGED
@@ -82,6 +82,7 @@ require_relative 'knapsack_pro/crypto/encryptor'
82
82
  require_relative 'knapsack_pro/crypto/branch_encryptor'
83
83
  require_relative 'knapsack_pro/crypto/decryptor'
84
84
  require_relative 'knapsack_pro/crypto/digestor'
85
+ require_relative 'knapsack_pro/pure/queue/rspec_pure'
85
86
 
86
87
  require 'knapsack_pro/railtie' if defined?(Rails::Railtie)
87
88
 
@@ -0,0 +1,80 @@
1
+ require 'knapsack_pro'
2
+ require 'json'
3
+
4
+ ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC'] = SecureRandom.hex
5
+ ENV['KNAPSACK_PRO_CI_NODE_BUILD_ID'] = SecureRandom.uuid
6
+ ENV['KNAPSACK_PRO_TEST_DIR'] = 'spec_integration'
7
+ ENV['KNAPSACK_PRO_TEST_FILE_PATTERN'] = "spec_integration/**{,/*/**}/*_spec.rb"
8
+
9
+ RSPEC_OPTIONS = ENV.fetch('TEST__RSPEC_OPTIONS')
10
+ SHOW_DEBUG_LOG = ENV['TEST__SHOW_DEBUG_LOG'] == 'true'
11
+ SPEC_BATCHES = JSON.load(ENV.fetch('TEST__SPEC_BATCHES'))
12
+
13
+ class IntegrationTestLogger
14
+ def self.log(message)
15
+ puts "[INTEGRATION TEST] #{message}"
16
+ end
17
+ end
18
+
19
+ module KnapsackProExtensions
20
+ module QueueAllocatorExtension
21
+ def test_file_paths(can_initialize_queue, executed_test_files)
22
+ @batch_index ||= 0
23
+ last_batch = []
24
+ batches = [*SPEC_BATCHES, last_batch]
25
+ tests = batches[@batch_index]
26
+ @batch_index += 1
27
+
28
+ if SHOW_DEBUG_LOG
29
+ IntegrationTestLogger.log("Mocked tests from the Queue API: #{tests.inspect}")
30
+ end
31
+
32
+ tests
33
+ end
34
+ end
35
+
36
+ module Report
37
+ def create_build_subset(test_files)
38
+ if ENV['TEST__LOG_EXECUTION_TIMES']
39
+ have_execution_time = test_files.all? { _1.fetch('time_execution') > 0 }
40
+ IntegrationTestLogger.log("test_files: #{test_files.size}, test files have execution time: #{have_execution_time}")
41
+ end
42
+
43
+ return unless SHOW_DEBUG_LOG
44
+ IntegrationTestLogger.log("Mocked the #{__method__} method")
45
+ end
46
+ end
47
+
48
+ module RSpecAdapter
49
+ def test_file_cases_for(slow_test_files)
50
+ IntegrationTestLogger.log("Mocked test file cases for slow test files: #{slow_test_files}")
51
+
52
+ test_file_paths = JSON.load(ENV.fetch('TEST__TEST_FILE_CASES_FOR_SLOW_TEST_FILES'))
53
+ test_file_paths.map do |path|
54
+ { 'path' => path }
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ KnapsackPro::QueueAllocator.prepend(KnapsackProExtensions::QueueAllocatorExtension)
61
+
62
+ module KnapsackPro
63
+ class Report
64
+ class << self
65
+ prepend KnapsackProExtensions::Report
66
+ end
67
+ end
68
+ end
69
+
70
+ module KnapsackPro
71
+ module Adapters
72
+ class RSpecAdapter
73
+ class << self
74
+ prepend KnapsackProExtensions::RSpecAdapter
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ KnapsackPro::Runners::Queue::RSpecRunner.run(RSPEC_OPTIONS)