knapsack_pro 2.0.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +23 -2
- data/lib/knapsack_pro/adapters/cucumber_adapter.rb +1 -1
- data/lib/knapsack_pro/adapters/minitest_adapter.rb +3 -3
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +1 -1
- data/lib/knapsack_pro/adapters/test_unit_adapter.rb +25 -5
- data/lib/knapsack_pro/base_allocator_builder.rb +7 -2
- data/lib/knapsack_pro/client/connection.rb +17 -2
- data/lib/knapsack_pro/config/env.rb +15 -0
- data/lib/knapsack_pro/formatters/rspec_json_formatter.rb +2 -2
- data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +1 -1
- data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +2 -2
- data/lib/knapsack_pro/hooks/queue.rb +31 -22
- data/lib/knapsack_pro/runners/cucumber_runner.rb +1 -1
- data/lib/knapsack_pro/runners/queue/minitest_runner.rb +2 -2
- data/lib/knapsack_pro/runners/queue/rspec_runner.rb +11 -11
- data/lib/knapsack_pro/runners/rspec_runner.rb +1 -1
- data/lib/knapsack_pro/runners/test_unit_runner.rb +1 -1
- data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +3 -3
- data/lib/knapsack_pro/version.rb +1 -1
- data/spec/knapsack_pro/adapters/test_unit_adapter_spec.rb +1 -2
- data/spec/knapsack_pro/client/connection_spec.rb +104 -0
- data/spec/knapsack_pro/config/env_spec.rb +46 -0
- data/spec/knapsack_pro/hooks/queue_spec.rb +49 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a36ff1388dd1ad1c95c0fd5041fc771d27f28b36c0d02773fa8205ae4812818b
|
4
|
+
data.tar.gz: c07a145c9d4f62d9901cb1bb2122662ca57c69a75d8dd500771799af215204a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8aeb03d459916e73d5281fc28293300acc6e375747954afd070ef34cc062e08d603dee4bea5e614850ca723f15f3e926a69e7f0efee1399c02320baee0d18100
|
7
|
+
data.tar.gz: 1ac8483c14d798c0b4f8f163846e2f3e922223dad285516674568998ada15a917633a34b243b571b5f2e11f3d2a8d1086390ac1c39abd3205cb3c17aedf26c4f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,47 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
### 2.3.0
|
4
|
+
|
5
|
+
* When you use Regular Mode then try 6 attempts to connect to the API instead of 3 attempts
|
6
|
+
|
7
|
+
Add `KNAPSACK_PRO_MAX_REQUEST_RETRIES` environment variable to let user define their own number of request retries to the API. It is useful to set it to `0` for [forked repos](https://knapsackpro.com/faq/question/how-to-make-knapsack_pro-works-for-forked-repositories-of-my-project) when you want to relay on Fallback Mode.
|
8
|
+
|
9
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/124
|
10
|
+
|
11
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.2.1...v2.3.0
|
12
|
+
|
13
|
+
### 2.2.1
|
14
|
+
|
15
|
+
* Improve detection of test file path in test-unit runner for test files with shared examples
|
16
|
+
|
17
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/123
|
18
|
+
|
19
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.2.0...v2.2.1
|
20
|
+
|
21
|
+
### 2.2.0
|
22
|
+
|
23
|
+
* Allow defining Queue Mode hooks multiple times (`KnapsackPro::Hooks::Queue.before_queue`, `KnapsackPro::Hooks::Queue.after_subset_queue`, `KnapsackPro::Hooks::Queue.after_queue`)
|
24
|
+
|
25
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/122
|
26
|
+
|
27
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.1.1...v2.2.0
|
28
|
+
|
29
|
+
### 2.1.1
|
30
|
+
|
31
|
+
* Explicitly call root test runner class to avoid a confusing error when test runner gem is not loaded
|
32
|
+
|
33
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/120
|
34
|
+
|
35
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.1.0...v2.1.1
|
36
|
+
|
37
|
+
### 2.1.0
|
38
|
+
|
39
|
+
* Add `KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX` to customize prefix for generating test examples report when using RSpec split by test examples
|
40
|
+
|
41
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/118
|
42
|
+
|
43
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.0.0...v2.1.0
|
44
|
+
|
3
45
|
### 2.0.0
|
4
46
|
|
5
47
|
* Add support for CI build ID for Github Actions
|
data/README.md
CHANGED
@@ -84,6 +84,7 @@ We keep this old FAQ in README to not break old links spread across the web. You
|
|
84
84
|
- [Supported test runners in queue mode](#supported-test-runners-in-queue-mode)
|
85
85
|
- [Split test files by test cases](#split-test-files-by-test-cases)
|
86
86
|
- [RSpec split test files by test examples (by individual `it`s)](#rspec-split-test-files-by-test-examples-by-individual-its)
|
87
|
+
- [Why I see error: Don't know how to build task 'knapsack_pro:rspec_test_example_detector'?](#why-i-see-error-dont-know-how-to-build-task-knapsack_prorspec_test_example_detector)
|
87
88
|
- [How to manually define a list of slow test files to be split by test cases](#how-to-manually-define-a-list-of-slow-test-files-to-be-split-by-test-cases)
|
88
89
|
- [Extra configuration for CI server](#extra-configuration-for-ci-server)
|
89
90
|
- [Info about ENV variables](#info-about-env-variables)
|
@@ -618,6 +619,16 @@ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
|
|
618
619
|
|
619
620
|
Thanks to that your CI build speed can be faster. We recommend using this feature with [Queue Mode](https://youtu.be/hUEB1XDKEFY) to ensure parallel CI nodes finish work at a similar time which gives you the shortest CI build time.
|
620
621
|
|
622
|
+
#### Why I see error: Don't know how to build task 'knapsack_pro:rspec_test_example_detector'?
|
623
|
+
|
624
|
+
If you will see error like:
|
625
|
+
|
626
|
+
```
|
627
|
+
Don't know how to build task 'knapsack_pro:rspec_test_example_detector' (See the list of available tasks with `rake --tasks`)
|
628
|
+
```
|
629
|
+
|
630
|
+
It probably means bundler can't find the rake task. You can try to remove the default prefix `bundle exec` used by knapsack_pro gem by setting `KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX=""`.
|
631
|
+
|
621
632
|
### How to manually define a list of slow test files to be split by test cases
|
622
633
|
|
623
634
|
If you don't want to rely on a list of test files from Knapsack Pro API to determine slow test files that should be split by test cases then you can define your own list of slow test files.
|
@@ -2309,11 +2320,19 @@ There are a few ways to reproduce tests executed on CI node in your development
|
|
2309
2320
|
|
2310
2321
|
##### for knapsack_pro regular mode
|
2311
2322
|
|
2312
|
-
knapsack_pro gem will retry requests to Knapsack Pro API multiple times every few seconds
|
2323
|
+
knapsack_pro gem will retry requests to Knapsack Pro API multiple times every few seconds till it switchs to fallback behavior (Fallback Mode) and it will split test files across CI nodes based on popular test directory names. When knapsack_pro starts Fallback Mode then you will see a warning in the output.
|
2324
|
+
|
2325
|
+
Note there is an unlikely scenario when some of the CI nodes may start in Fallback Mode but others don't and then it could happen that some of test files might be skipped. You should [read this to learn more](https://github.com/KnapsackPro/knapsack_pro-ruby/pull/124) and decide if you like to use Fallback Mode when running tests with knapsack_pro Regular Mode.
|
2326
|
+
|
2327
|
+
If your CI provider allows to retry only one of parallel CI nodes then please [read about this edge case as well](#required-ci-configuration-if-you-use-retry-single-failed-ci-node-feature-on-your-ci-server-when-knapsack_pro_fixed_queue_splittrue-in-queue-mode-or-knapsack_pro_fixed_test_suite_splittrue-in-regular-mode).
|
2313
2328
|
|
2314
2329
|
##### for knapsack_pro queue mode
|
2315
2330
|
|
2316
|
-
knapsack_pro gem will retry requests to Knapsack Pro API multiple times every few seconds till it switches to fallback behavior and it will split test files across CI nodes based on popular test directory names.
|
2331
|
+
knapsack_pro gem will retry requests to Knapsack Pro API multiple times every few seconds till it switches to fallback behavior (Fallback Mode) and it will split test files across CI nodes based on popular test directory names.
|
2332
|
+
|
2333
|
+
Note that if one of the CI nodes will lose connection to Knapsack Pro API but other not then you may see that some of the test files will be executed on multiple CI nodes. **Fallback Mode guarantees each of the test files is run at least once across CI nodes when you use knapsack_pro in Queue Mode.** Thanks to that we know if the whole test suite is green or not. When knapsack_pro starts Fallback Mode then you will see a warning in the output.
|
2334
|
+
|
2335
|
+
If your CI provider allows to retry only one of parallel CI nodes then please [read about this edge case as well](#required-ci-configuration-if-you-use-retry-single-failed-ci-node-feature-on-your-ci-server-when-knapsack_pro_fixed_queue_splittrue-in-queue-mode-or-knapsack_pro_fixed_test_suite_splittrue-in-regular-mode).
|
2317
2336
|
|
2318
2337
|
#### How can I change log level?
|
2319
2338
|
|
@@ -2726,6 +2745,8 @@ end
|
|
2726
2745
|
|
2727
2746
|
#### What hooks are supported in Queue Mode?
|
2728
2747
|
|
2748
|
+
Note: Each hook type can be defined multiple times. For instance, if you define `KnapsackPro::Hooks::Queue.before_queue` twice then both block of code will be called when running your tests.
|
2749
|
+
|
2729
2750
|
* RSpec in knapsack_pro Queue Mode supports hooks:
|
2730
2751
|
|
2731
2752
|
```ruby
|
@@ -85,10 +85,10 @@ module KnapsackPro
|
|
85
85
|
private
|
86
86
|
|
87
87
|
def add_post_run_callback(&block)
|
88
|
-
if Minitest.respond_to?(:after_run)
|
89
|
-
Minitest.after_run { block.call }
|
88
|
+
if ::Minitest.respond_to?(:after_run)
|
89
|
+
::Minitest.after_run { block.call }
|
90
90
|
else
|
91
|
-
Minitest::Unit.after_tests { block.call }
|
91
|
+
::Minitest::Unit.after_tests { block.call }
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
@@ -4,7 +4,7 @@ module KnapsackPro
|
|
4
4
|
TEST_DIR_PATTERN = 'spec/**{,/*/**}/*_spec.rb'
|
5
5
|
|
6
6
|
def self.test_path(example_group)
|
7
|
-
if defined?(Turnip) && Turnip::VERSION.to_i < 2
|
7
|
+
if defined?(::Turnip) && ::Turnip::VERSION.to_i < 2
|
8
8
|
unless example_group[:turnip]
|
9
9
|
until example_group[:parent_example_group].nil?
|
10
10
|
example_group = example_group[:parent_example_group]
|
@@ -5,9 +5,29 @@ module KnapsackPro
|
|
5
5
|
@@parent_of_test_dir = nil
|
6
6
|
|
7
7
|
def self.test_path(obj)
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
full_test_path = nil
|
9
|
+
found_valid_test_file_path = false
|
10
|
+
|
11
|
+
obj.tests.each do |test_obj|
|
12
|
+
method = test_obj.method_name
|
13
|
+
full_test_path = test_obj.method(method).source_location.first
|
14
|
+
# if we find a test file path that is a valid test file path within test suite directory
|
15
|
+
# then break to stop looking further.
|
16
|
+
# If we won't find a valid test file path then the last found path will be used as full_test_path
|
17
|
+
# For instance if test file contains only shared examples then it's not possible to properly detect test file path
|
18
|
+
# so the wrong path can be used like:
|
19
|
+
# /Users/artur/.rvm/gems/ruby-2.6.5/gems/shared_should-0.10.0/lib/shared_should/shared_context.rb
|
20
|
+
if full_test_path.include?(@@parent_of_test_dir)
|
21
|
+
found_valid_test_file_path = true
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
unless found_valid_test_file_path
|
27
|
+
KnapsackPro.logger.warn('cannot detect a valid test file path. Probably the test file contains only shared examples. Please add test cases to your test file. Read more at https://github.com/KnapsackPro/knapsack_pro-ruby/pull/123')
|
28
|
+
KnapsackPro.logger.warn("See test file for #{obj.inspect}")
|
29
|
+
end
|
30
|
+
|
11
31
|
parent_of_test_dir_regexp = Regexp.new("^#{@@parent_of_test_dir}")
|
12
32
|
test_path = full_test_path.gsub(parent_of_test_dir_regexp, '.')
|
13
33
|
# test_path will look like ./test/dir/unit_test.rb
|
@@ -42,7 +62,7 @@ module KnapsackPro
|
|
42
62
|
end
|
43
63
|
|
44
64
|
def bind_time_tracker
|
45
|
-
Test::Unit::TestSuite.send(:prepend, BindTimeTrackerTestUnitPlugin)
|
65
|
+
::Test::Unit::TestSuite.send(:prepend, BindTimeTrackerTestUnitPlugin)
|
46
66
|
|
47
67
|
add_post_run_callback do
|
48
68
|
KnapsackPro.logger.debug(KnapsackPro::Presenter.global_time)
|
@@ -63,7 +83,7 @@ module KnapsackPro
|
|
63
83
|
private
|
64
84
|
|
65
85
|
def add_post_run_callback(&block)
|
66
|
-
Test::Unit.at_exit do
|
86
|
+
::Test::Unit.at_exit do
|
67
87
|
block.call
|
68
88
|
end
|
69
89
|
end
|
@@ -34,7 +34,7 @@ module KnapsackPro
|
|
34
34
|
test_files_to_run = all_test_files_to_run
|
35
35
|
|
36
36
|
if adapter_class == KnapsackPro::Adapters::RSpecAdapter && KnapsackPro::Config::Env.rspec_split_by_test_examples?
|
37
|
-
unless Gem::Version.new(RSpec::Core::Version::STRING) >= Gem::Version.new('3.3.0')
|
37
|
+
unless Gem::Version.new(::RSpec::Core::Version::STRING) >= Gem::Version.new('3.3.0')
|
38
38
|
raise 'RSpec >= 3.3.0 is required to split test files by test examples. Learn more: https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases'
|
39
39
|
end
|
40
40
|
|
@@ -43,7 +43,12 @@ module KnapsackPro
|
|
43
43
|
KnapsackPro.logger.info("Generating RSpec test examples JSON report for slow test files to prepare it to be split by test examples (by individual 'it's. Thanks to that a single slow test file can be split across parallel CI nodes). Analyzing #{slow_test_files.size} slow test files.")
|
44
44
|
|
45
45
|
# generate RSpec JSON report in separate process to not pollute RSpec state
|
46
|
-
cmd =
|
46
|
+
cmd = [
|
47
|
+
'RACK_ENV=test',
|
48
|
+
'RAILS_ENV=test',
|
49
|
+
KnapsackPro::Config::Env.rspec_test_example_detector_prefix,
|
50
|
+
'rake knapsack_pro:rspec_test_example_detector',
|
51
|
+
].join(' ')
|
47
52
|
unless Kernel.system(cmd)
|
48
53
|
raise "Could not generate JSON report for RSpec. Rake task failed when running #{cmd}"
|
49
54
|
end
|
@@ -4,7 +4,6 @@ module KnapsackPro
|
|
4
4
|
class ServerError < StandardError; end
|
5
5
|
|
6
6
|
TIMEOUT = 15
|
7
|
-
MAX_RETRY = -> { KnapsackPro::Config::Env.fallback_mode_enabled? ? 3 : 6 }
|
8
7
|
REQUEST_RETRY_TIMEBOX = 8
|
9
8
|
|
10
9
|
def initialize(action)
|
@@ -118,7 +117,7 @@ module KnapsackPro
|
|
118
117
|
rescue ServerError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::EPIPE, EOFError, SocketError, Net::OpenTimeout, Net::ReadTimeout, OpenSSL::SSL::SSLError => e
|
119
118
|
logger.warn(e.inspect)
|
120
119
|
retries += 1
|
121
|
-
if retries <
|
120
|
+
if retries < max_request_retries
|
122
121
|
wait = retries * REQUEST_RETRY_TIMEBOX
|
123
122
|
logger.warn("Wait #{wait}s and retry request to Knapsack Pro API.")
|
124
123
|
print_every = 2 # seconds
|
@@ -156,6 +155,22 @@ module KnapsackPro
|
|
156
155
|
http.get(uri, json_headers)
|
157
156
|
end
|
158
157
|
end
|
158
|
+
|
159
|
+
def max_request_retries
|
160
|
+
# when user defined max request retries
|
161
|
+
return KnapsackPro::Config::Env.max_request_retries if KnapsackPro::Config::Env.max_request_retries
|
162
|
+
|
163
|
+
# when Fallback Mode is disabled then try more attempts to connect to the API
|
164
|
+
return 6 unless KnapsackPro::Config::Env.fallback_mode_enabled?
|
165
|
+
|
166
|
+
# when Regular Mode then try more attempts to connect to the API
|
167
|
+
# if only one CI node starts Fallback Mode instead of all then we can't guarantee all test files will be run
|
168
|
+
# https://github.com/KnapsackPro/knapsack_pro-ruby/pull/124
|
169
|
+
return 6 if KnapsackPro::Config::Env.regular_mode?
|
170
|
+
|
171
|
+
# default number of attempts
|
172
|
+
3
|
173
|
+
end
|
159
174
|
end
|
160
175
|
end
|
161
176
|
end
|
@@ -36,6 +36,13 @@ module KnapsackPro
|
|
36
36
|
).to_i
|
37
37
|
end
|
38
38
|
|
39
|
+
def max_request_retries
|
40
|
+
number = ENV['KNAPSACK_PRO_MAX_REQUEST_RETRIES']
|
41
|
+
if number
|
42
|
+
number.to_i
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
39
46
|
def commit_hash
|
40
47
|
ENV['KNAPSACK_PRO_COMMIT_HASH'] ||
|
41
48
|
ci_env_for(:commit_hash)
|
@@ -83,6 +90,10 @@ module KnapsackPro
|
|
83
90
|
recording_enabled == 'true'
|
84
91
|
end
|
85
92
|
|
93
|
+
def regular_mode?
|
94
|
+
recording_enabled?
|
95
|
+
end
|
96
|
+
|
86
97
|
def queue_recording_enabled
|
87
98
|
ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED']
|
88
99
|
end
|
@@ -179,6 +190,10 @@ module KnapsackPro
|
|
179
190
|
rspec_split_by_test_examples.to_s == 'true'
|
180
191
|
end
|
181
192
|
|
193
|
+
def rspec_test_example_detector_prefix
|
194
|
+
ENV.fetch('KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX', 'bundle exec')
|
195
|
+
end
|
196
|
+
|
182
197
|
def test_suite_token
|
183
198
|
env_name = 'KNAPSACK_PRO_TEST_SUITE_TOKEN'
|
184
199
|
ENV[env_name] || raise("Missing environment variable #{env_name}. You should set environment variable like #{env_name}_RSPEC (note there is suffix _RSPEC at the end). knapsack_pro gem will set #{env_name} based on #{env_name}_RSPEC value. If you use other test runner than RSpec then use proper suffix.")
|
@@ -3,8 +3,8 @@ RSpec::Support.require_rspec_core('formatters/json_formatter')
|
|
3
3
|
# based on https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/formatters/json_formatter.rb
|
4
4
|
module KnapsackPro
|
5
5
|
module Formatters
|
6
|
-
class RSpecJsonFormatter < RSpec::Core::Formatters::JsonFormatter
|
7
|
-
RSpec::Core::Formatters.register self
|
6
|
+
class RSpecJsonFormatter < ::RSpec::Core::Formatters::JsonFormatter
|
7
|
+
::RSpec::Core::Formatters.register self
|
8
8
|
|
9
9
|
private
|
10
10
|
|
@@ -5,7 +5,7 @@ module KnapsackPro
|
|
5
5
|
module RSpecQueueProfileFormatterExtension
|
6
6
|
def self.print_summary
|
7
7
|
return unless KnapsackPro::Config::Env.modify_default_rspec_formatters?
|
8
|
-
RSpec::Core::Formatters::ProfileFormatter.print_profile_summary
|
8
|
+
::RSpec::Core::Formatters::ProfileFormatter.print_profile_summary
|
9
9
|
end
|
10
10
|
|
11
11
|
def initialize(output)
|
@@ -9,8 +9,8 @@ module KnapsackPro
|
|
9
9
|
def dump_summary(summary); end
|
10
10
|
end
|
11
11
|
|
12
|
-
class RSpecQueueSummaryFormatter < RSpec::Core::Formatters::BaseFormatter
|
13
|
-
RSpec::Core::Formatters.register self, :dump_summary, :dump_failures, :dump_pending
|
12
|
+
class RSpecQueueSummaryFormatter < ::RSpec::Core::Formatters::BaseFormatter
|
13
|
+
::RSpec::Core::Formatters.register self, :dump_summary, :dump_failures, :dump_pending
|
14
14
|
|
15
15
|
def self.registered_output=(output)
|
16
16
|
@registered_output = {
|
@@ -2,54 +2,63 @@ module KnapsackPro
|
|
2
2
|
module Hooks
|
3
3
|
class Queue
|
4
4
|
class << self
|
5
|
-
attr_reader :
|
6
|
-
:
|
7
|
-
:
|
5
|
+
attr_reader :before_queue_store,
|
6
|
+
:after_subset_queue_store,
|
7
|
+
:after_queue_store
|
8
8
|
|
9
9
|
def reset_before_queue
|
10
|
-
@
|
10
|
+
@before_queue_store = nil
|
11
11
|
end
|
12
12
|
|
13
13
|
def reset_after_subset_queue
|
14
|
-
@
|
14
|
+
@after_subset_queue_store = nil
|
15
15
|
end
|
16
16
|
|
17
17
|
def reset_after_queue
|
18
|
-
@
|
18
|
+
@after_queue_store = nil
|
19
19
|
end
|
20
20
|
|
21
21
|
def before_queue(&block)
|
22
|
-
@
|
22
|
+
@before_queue_store ||= []
|
23
|
+
@before_queue_store << block
|
23
24
|
end
|
24
25
|
|
25
26
|
def after_subset_queue(&block)
|
26
|
-
@
|
27
|
+
@after_subset_queue_store ||= []
|
28
|
+
@after_subset_queue_store << block
|
27
29
|
end
|
28
30
|
|
29
31
|
def after_queue(&block)
|
30
|
-
@
|
32
|
+
@after_queue_store ||= []
|
33
|
+
@after_queue_store << block
|
31
34
|
end
|
32
35
|
|
33
36
|
def call_before_queue
|
34
|
-
return unless
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
return unless before_queue_store
|
38
|
+
before_queue_store.each do |block|
|
39
|
+
block.call(
|
40
|
+
KnapsackPro::Config::Env.queue_id
|
41
|
+
)
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
def call_after_subset_queue
|
41
|
-
return unless
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
return unless after_subset_queue_store
|
47
|
+
after_subset_queue_store.each do |block|
|
48
|
+
block.call(
|
49
|
+
KnapsackPro::Config::Env.queue_id,
|
50
|
+
KnapsackPro::Config::Env.subset_queue_id
|
51
|
+
)
|
52
|
+
end
|
46
53
|
end
|
47
54
|
|
48
55
|
def call_after_queue
|
49
|
-
return unless
|
50
|
-
|
51
|
-
|
52
|
-
|
56
|
+
return unless after_queue_store
|
57
|
+
after_queue_store.each do |block|
|
58
|
+
block.call(
|
59
|
+
KnapsackPro::Config::Env.queue_id
|
60
|
+
)
|
61
|
+
end
|
53
62
|
end
|
54
63
|
end
|
55
64
|
end
|
@@ -15,7 +15,7 @@ module KnapsackPro
|
|
15
15
|
Rake::Task[task_name].clear
|
16
16
|
end
|
17
17
|
|
18
|
-
Cucumber::Rake::Task.new(task_name) do |t|
|
18
|
+
::Cucumber::Rake::Task.new(task_name) do |t|
|
19
19
|
t.cucumber_opts = "#{args} --require #{runner.test_dir} -- #{runner.stringify_test_file_paths}"
|
20
20
|
end
|
21
21
|
Rake::Task[task_name].invoke
|
@@ -79,8 +79,8 @@ module KnapsackPro
|
|
79
79
|
|
80
80
|
log_rspec_command(args, test_file_paths, :subset_queue)
|
81
81
|
|
82
|
-
options = RSpec::Core::ConfigurationOptions.new(cli_args)
|
83
|
-
exit_code = RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
82
|
+
options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
|
83
|
+
exit_code = ::RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
84
84
|
exitstatus = exit_code if exit_code != 0
|
85
85
|
|
86
86
|
rspec_clear_examples
|
@@ -124,26 +124,26 @@ module KnapsackPro
|
|
124
124
|
#
|
125
125
|
# Keep formatters and report to accumulate info about failed/pending tests
|
126
126
|
def self.rspec_clear_examples
|
127
|
-
if RSpec::ExampleGroups.respond_to?(:remove_all_constants)
|
128
|
-
RSpec::ExampleGroups.remove_all_constants
|
127
|
+
if ::RSpec::ExampleGroups.respond_to?(:remove_all_constants)
|
128
|
+
::RSpec::ExampleGroups.remove_all_constants
|
129
129
|
else
|
130
|
-
RSpec::ExampleGroups.constants.each do |constant|
|
131
|
-
RSpec::ExampleGroups.__send__(:remove_const, constant)
|
130
|
+
::RSpec::ExampleGroups.constants.each do |constant|
|
131
|
+
::RSpec::ExampleGroups.__send__(:remove_const, constant)
|
132
132
|
end
|
133
133
|
end
|
134
|
-
RSpec.world.example_groups.clear
|
135
|
-
RSpec.configuration.start_time = ::RSpec::Core::Time.now
|
134
|
+
::RSpec.world.example_groups.clear
|
135
|
+
::RSpec.configuration.start_time = ::RSpec::Core::Time.now
|
136
136
|
|
137
137
|
if KnapsackPro::Config::Env.rspec_split_by_test_examples?
|
138
138
|
# Reset example group counts to ensure scoped example ids in metadata
|
139
139
|
# have correct index (not increased by each subsequent run).
|
140
140
|
# Solves this problem: https://github.com/rspec/rspec-core/issues/2721
|
141
|
-
RSpec.world.instance_variable_set(:@example_group_counts_by_spec_file, Hash.new(0))
|
141
|
+
::RSpec.world.instance_variable_set(:@example_group_counts_by_spec_file, Hash.new(0))
|
142
142
|
end
|
143
143
|
|
144
144
|
# skip reset filters for old RSpec versions
|
145
|
-
if RSpec.configuration.respond_to?(:reset_filters)
|
146
|
-
RSpec.configuration.reset_filters
|
145
|
+
if ::RSpec.configuration.respond_to?(:reset_filters)
|
146
|
+
::RSpec.configuration.reset_filters
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
@@ -15,7 +15,7 @@ module KnapsackPro
|
|
15
15
|
Rake::Task[task_name].clear
|
16
16
|
end
|
17
17
|
|
18
|
-
RSpec::Core::RakeTask.new(task_name) do |t|
|
18
|
+
::RSpec::Core::RakeTask.new(task_name) do |t|
|
19
19
|
# we cannot pass runner.test_file_paths array to t.pattern
|
20
20
|
# because pattern does not accept test example path like spec/a_spec.rb[1:2]
|
21
21
|
# instead we pass test files and test example paths to t.rspec_opts
|
@@ -7,7 +7,7 @@ module KnapsackPro
|
|
7
7
|
require 'rspec/core'
|
8
8
|
|
9
9
|
cli_format =
|
10
|
-
if Gem::Version.new(RSpec::Core::Version::STRING) < Gem::Version.new('3.6.0')
|
10
|
+
if Gem::Version.new(::RSpec::Core::Version::STRING) < Gem::Version.new('3.6.0')
|
11
11
|
require_relative '../formatters/rspec_json_formatter'
|
12
12
|
['--format', KnapsackPro::Formatters::RSpecJsonFormatter.to_s]
|
13
13
|
else
|
@@ -30,8 +30,8 @@ module KnapsackPro
|
|
30
30
|
'--out', report_path,
|
31
31
|
'--default-path', test_dir,
|
32
32
|
] + KnapsackPro::TestFilePresenter.paths(test_file_entities)
|
33
|
-
options = RSpec::Core::ConfigurationOptions.new(cli_args)
|
34
|
-
exit_code = RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
33
|
+
options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
|
34
|
+
exit_code = ::RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
35
35
|
if exit_code != 0
|
36
36
|
raise 'There was problem to generate test examples for test suite'
|
37
37
|
end
|
data/lib/knapsack_pro/version.rb
CHANGED
@@ -10,8 +10,7 @@ describe KnapsackPro::Adapters::TestUnitAdapter do
|
|
10
10
|
|
11
11
|
before do
|
12
12
|
parent_of_test_dir = File.expand_path('../../../', File.dirname(__FILE__))
|
13
|
-
|
14
|
-
described_class.class_variable_set(:@@parent_of_test_dir, parent_of_test_dir_regexp)
|
13
|
+
described_class.class_variable_set(:@@parent_of_test_dir, parent_of_test_dir)
|
15
14
|
end
|
16
15
|
|
17
16
|
context 'when regular test' do
|
@@ -108,6 +108,53 @@ shared_examples 'when retry request' do
|
|
108
108
|
expect(connection.errors?).to be true
|
109
109
|
end
|
110
110
|
|
111
|
+
context 'when max request retries defined' do
|
112
|
+
before do
|
113
|
+
expect(KnapsackPro::Config::Env).to receive(:max_request_retries).at_least(1).and_return(4)
|
114
|
+
end
|
115
|
+
|
116
|
+
it do
|
117
|
+
expect(logger).to receive(:debug).exactly(4).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
|
118
|
+
expect(logger).to receive(:debug).exactly(4).with('API request UUID: fake-uuid')
|
119
|
+
expect(logger).to receive(:debug).exactly(4).with('API response:')
|
120
|
+
|
121
|
+
parsed_response = { 'error' => 'Internal Server Error' }
|
122
|
+
|
123
|
+
expect(logger).to receive(:error).exactly(4).with(parsed_response)
|
124
|
+
|
125
|
+
server_error = described_class::ServerError.new(parsed_response)
|
126
|
+
expect(logger).to receive(:warn).exactly(4).with(server_error.inspect)
|
127
|
+
|
128
|
+
expect(logger).to receive(:warn).with("Wait 8s and retry request to Knapsack Pro API.")
|
129
|
+
expect(logger).to receive(:warn).with("Next request in 8s...")
|
130
|
+
expect(logger).to receive(:warn).with("Next request in 6s...")
|
131
|
+
expect(logger).to receive(:warn).with("Next request in 4s...")
|
132
|
+
expect(logger).to receive(:warn).with("Next request in 2s...")
|
133
|
+
|
134
|
+
expect(logger).to receive(:warn).with("Wait 16s and retry request to Knapsack Pro API.")
|
135
|
+
expect(logger).to receive(:warn).with("Next request in 16s...")
|
136
|
+
expect(logger).to receive(:warn).with("Next request in 14s...")
|
137
|
+
expect(logger).to receive(:warn).with("Next request in 12s...")
|
138
|
+
expect(logger).to receive(:warn).with("Next request in 10s...")
|
139
|
+
expect(logger).to receive(:warn).with("Next request in 8s...")
|
140
|
+
expect(logger).to receive(:warn).with("Next request in 6s...")
|
141
|
+
expect(logger).to receive(:warn).with("Next request in 4s...")
|
142
|
+
expect(logger).to receive(:warn).with("Next request in 2s...")
|
143
|
+
|
144
|
+
expect(logger).to receive(:warn).with("Wait 24s and retry request to Knapsack Pro API.")
|
145
|
+
12.times do |i|
|
146
|
+
expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
|
147
|
+
end
|
148
|
+
|
149
|
+
expect(Kernel).to receive(:sleep).exactly(4+8+12).with(2)
|
150
|
+
|
151
|
+
expect(subject).to eq(parsed_response)
|
152
|
+
|
153
|
+
expect(connection.success?).to be false
|
154
|
+
expect(connection.errors?).to be true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
111
158
|
context 'when Fallback Mode is disabled' do
|
112
159
|
before do
|
113
160
|
expect(KnapsackPro::Config::Env).to receive(:fallback_mode_enabled?).at_least(1).and_return(false)
|
@@ -164,6 +211,63 @@ shared_examples 'when retry request' do
|
|
164
211
|
expect(connection.errors?).to be true
|
165
212
|
end
|
166
213
|
end
|
214
|
+
|
215
|
+
context 'when Regular Mode' do
|
216
|
+
before do
|
217
|
+
expect(KnapsackPro::Config::Env).to receive(:regular_mode?).at_least(1).and_return(true)
|
218
|
+
end
|
219
|
+
|
220
|
+
it do
|
221
|
+
expect(logger).to receive(:debug).exactly(6).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
|
222
|
+
expect(logger).to receive(:debug).exactly(6).with('API request UUID: fake-uuid')
|
223
|
+
expect(logger).to receive(:debug).exactly(6).with('API response:')
|
224
|
+
|
225
|
+
parsed_response = { 'error' => 'Internal Server Error' }
|
226
|
+
|
227
|
+
expect(logger).to receive(:error).exactly(6).with(parsed_response)
|
228
|
+
|
229
|
+
server_error = described_class::ServerError.new(parsed_response)
|
230
|
+
expect(logger).to receive(:warn).exactly(6).with(server_error.inspect)
|
231
|
+
|
232
|
+
expect(logger).to receive(:warn).with("Wait 8s and retry request to Knapsack Pro API.")
|
233
|
+
expect(logger).to receive(:warn).with("Next request in 8s...")
|
234
|
+
expect(logger).to receive(:warn).with("Next request in 6s...")
|
235
|
+
expect(logger).to receive(:warn).with("Next request in 4s...")
|
236
|
+
expect(logger).to receive(:warn).with("Next request in 2s...")
|
237
|
+
|
238
|
+
expect(logger).to receive(:warn).with("Wait 16s and retry request to Knapsack Pro API.")
|
239
|
+
expect(logger).to receive(:warn).with("Next request in 16s...")
|
240
|
+
expect(logger).to receive(:warn).with("Next request in 14s...")
|
241
|
+
expect(logger).to receive(:warn).with("Next request in 12s...")
|
242
|
+
expect(logger).to receive(:warn).with("Next request in 10s...")
|
243
|
+
expect(logger).to receive(:warn).with("Next request in 8s...")
|
244
|
+
expect(logger).to receive(:warn).with("Next request in 6s...")
|
245
|
+
expect(logger).to receive(:warn).with("Next request in 4s...")
|
246
|
+
expect(logger).to receive(:warn).with("Next request in 2s...")
|
247
|
+
|
248
|
+
expect(logger).to receive(:warn).with("Wait 24s and retry request to Knapsack Pro API.")
|
249
|
+
12.times do |i|
|
250
|
+
expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
|
251
|
+
end
|
252
|
+
|
253
|
+
expect(logger).to receive(:warn).with("Wait 32s and retry request to Knapsack Pro API.")
|
254
|
+
16.times do |i|
|
255
|
+
expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
|
256
|
+
end
|
257
|
+
|
258
|
+
expect(logger).to receive(:warn).with("Wait 40s and retry request to Knapsack Pro API.")
|
259
|
+
20.times do |i|
|
260
|
+
expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
|
261
|
+
end
|
262
|
+
|
263
|
+
expect(Kernel).to receive(:sleep).exactly(60).with(2)
|
264
|
+
|
265
|
+
expect(subject).to eq(parsed_response)
|
266
|
+
|
267
|
+
expect(connection.success?).to be false
|
268
|
+
expect(connection.errors?).to be true
|
269
|
+
end
|
270
|
+
end
|
167
271
|
end
|
168
272
|
end
|
169
273
|
|
@@ -100,6 +100,19 @@ describe KnapsackPro::Config::Env do
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
+
describe '.max_request_retries' do
|
104
|
+
subject { described_class.max_request_retries }
|
105
|
+
|
106
|
+
context 'when ENV exists' do
|
107
|
+
before { stub_const("ENV", { 'KNAPSACK_PRO_MAX_REQUEST_RETRIES' => '2' }) }
|
108
|
+
it { should eq 2 }
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when ENV doesn't exist" do
|
112
|
+
it { should be_nil }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
103
116
|
describe '.commit_hash' do
|
104
117
|
subject { described_class.commit_hash }
|
105
118
|
|
@@ -267,6 +280,25 @@ describe KnapsackPro::Config::Env do
|
|
267
280
|
end
|
268
281
|
end
|
269
282
|
|
283
|
+
|
284
|
+
describe '.regular_mode?' do
|
285
|
+
subject { described_class.regular_mode? }
|
286
|
+
|
287
|
+
before do
|
288
|
+
expect(described_class).to receive(:recording_enabled?).and_return(recording_enabled)
|
289
|
+
end
|
290
|
+
|
291
|
+
context 'when recording is enabled' do
|
292
|
+
let(:recording_enabled) { true }
|
293
|
+
it { should be true }
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'when recording is not enabled' do
|
297
|
+
let(:recording_enabled) { false }
|
298
|
+
it { should be false }
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
270
302
|
describe '.recording_enabled?' do
|
271
303
|
subject { described_class.recording_enabled? }
|
272
304
|
|
@@ -658,6 +690,20 @@ describe KnapsackPro::Config::Env do
|
|
658
690
|
end
|
659
691
|
end
|
660
692
|
|
693
|
+
describe '.rspec_test_example_detector_prefix' do
|
694
|
+
subject { described_class.rspec_test_example_detector_prefix }
|
695
|
+
|
696
|
+
context 'when ENV exists' do
|
697
|
+
before { stub_const("ENV", { 'KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX' => '' }) }
|
698
|
+
it { should eq '' }
|
699
|
+
end
|
700
|
+
|
701
|
+
context "when ENV doesn't exist" do
|
702
|
+
before { stub_const("ENV", {}) }
|
703
|
+
it { should eq 'bundle exec' }
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
661
707
|
describe '.test_suite_token' do
|
662
708
|
subject { described_class.test_suite_token }
|
663
709
|
|
@@ -10,18 +10,30 @@ describe KnapsackPro::Hooks::Queue do
|
|
10
10
|
it { should be_nil }
|
11
11
|
end
|
12
12
|
|
13
|
-
context 'when callback is set' do
|
13
|
+
context 'when callback is set multiple times' do
|
14
14
|
let(:queue_id) { double }
|
15
15
|
|
16
16
|
before do
|
17
|
-
expect(KnapsackPro::Config::Env).to receive(:queue_id).and_return(queue_id)
|
17
|
+
expect(KnapsackPro::Config::Env).to receive(:queue_id).twice.and_return(queue_id)
|
18
18
|
|
19
|
+
$expected_called_blocks = []
|
20
|
+
|
21
|
+
described_class.before_queue do |q_id|
|
22
|
+
$expected_called_blocks << [:block_1_called, q_id]
|
23
|
+
end
|
19
24
|
described_class.before_queue do |q_id|
|
20
|
-
[:
|
25
|
+
$expected_called_blocks << [:block_2_called, q_id]
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
24
|
-
it
|
29
|
+
it 'each block is called' do
|
30
|
+
subject
|
31
|
+
|
32
|
+
expect($expected_called_blocks).to eq([
|
33
|
+
[:block_1_called, queue_id],
|
34
|
+
[:block_2_called, queue_id],
|
35
|
+
])
|
36
|
+
end
|
25
37
|
end
|
26
38
|
end
|
27
39
|
|
@@ -36,20 +48,32 @@ describe KnapsackPro::Hooks::Queue do
|
|
36
48
|
it { should be_nil }
|
37
49
|
end
|
38
50
|
|
39
|
-
context 'when callback is set' do
|
51
|
+
context 'when callback is set multiple times' do
|
40
52
|
let(:queue_id) { double }
|
41
53
|
let(:subset_queue_id) { double }
|
42
54
|
|
43
55
|
before do
|
44
|
-
expect(KnapsackPro::Config::Env).to receive(:queue_id).and_return(queue_id)
|
45
|
-
expect(KnapsackPro::Config::Env).to receive(:subset_queue_id).and_return(subset_queue_id)
|
56
|
+
expect(KnapsackPro::Config::Env).to receive(:queue_id).twice.and_return(queue_id)
|
57
|
+
expect(KnapsackPro::Config::Env).to receive(:subset_queue_id).twice.and_return(subset_queue_id)
|
58
|
+
|
59
|
+
$expected_called_blocks = []
|
46
60
|
|
47
61
|
described_class.after_subset_queue do |q_id, subset_q_id|
|
48
|
-
[:
|
62
|
+
$expected_called_blocks << [:block_1_called, q_id, subset_q_id]
|
63
|
+
end
|
64
|
+
described_class.after_subset_queue do |q_id, subset_q_id|
|
65
|
+
$expected_called_blocks << [:block_2_called, q_id, subset_q_id]
|
49
66
|
end
|
50
67
|
end
|
51
68
|
|
52
|
-
it
|
69
|
+
it 'each block is called' do
|
70
|
+
subject
|
71
|
+
|
72
|
+
expect($expected_called_blocks).to eq([
|
73
|
+
[:block_1_called, queue_id, subset_queue_id],
|
74
|
+
[:block_2_called, queue_id, subset_queue_id],
|
75
|
+
])
|
76
|
+
end
|
53
77
|
end
|
54
78
|
end
|
55
79
|
|
@@ -64,18 +88,30 @@ describe KnapsackPro::Hooks::Queue do
|
|
64
88
|
it { should be_nil }
|
65
89
|
end
|
66
90
|
|
67
|
-
context 'when callback is set' do
|
91
|
+
context 'when callback is set multiple times' do
|
68
92
|
let(:queue_id) { double }
|
69
93
|
|
70
94
|
before do
|
71
|
-
expect(KnapsackPro::Config::Env).to receive(:queue_id).and_return(queue_id)
|
95
|
+
expect(KnapsackPro::Config::Env).to receive(:queue_id).twice.and_return(queue_id)
|
96
|
+
|
97
|
+
$expected_called_blocks = []
|
72
98
|
|
73
99
|
described_class.after_queue do |q_id|
|
74
|
-
[:
|
100
|
+
$expected_called_blocks << [:block_1_called, q_id]
|
101
|
+
end
|
102
|
+
described_class.after_queue do |q_id|
|
103
|
+
$expected_called_blocks << [:block_2_called, q_id]
|
75
104
|
end
|
76
105
|
end
|
77
106
|
|
78
|
-
it
|
107
|
+
it 'each block is called' do
|
108
|
+
subject
|
109
|
+
|
110
|
+
expect($expected_called_blocks).to eq([
|
111
|
+
[:block_1_called, queue_id],
|
112
|
+
[:block_2_called, queue_id],
|
113
|
+
])
|
114
|
+
end
|
79
115
|
end
|
80
116
|
end
|
81
117
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knapsack_pro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ArturT
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|