knapsack_pro 1.20.2 → 1.21.0
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +24 -12
- data/lib/knapsack_pro.rb +6 -0
- data/lib/knapsack_pro/adapters/base_adapter.rb +16 -0
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +11 -9
- data/lib/knapsack_pro/allocator.rb +7 -5
- data/lib/knapsack_pro/allocator_builder.rb +2 -1
- data/lib/knapsack_pro/base_allocator_builder.rb +41 -10
- data/lib/knapsack_pro/build_distribution_fetcher.rb +57 -0
- data/lib/knapsack_pro/client/api/v1/build_distributions.rb +13 -0
- data/lib/knapsack_pro/client/connection.rb +30 -12
- data/lib/knapsack_pro/config/env.rb +4 -0
- data/lib/knapsack_pro/queue_allocator.rb +7 -5
- data/lib/knapsack_pro/queue_allocator_builder.rb +2 -1
- data/lib/knapsack_pro/runners/queue/rspec_runner.rb +7 -0
- data/lib/knapsack_pro/runners/rspec_runner.rb +5 -2
- data/lib/knapsack_pro/slow_test_file_determiner.rb +28 -0
- data/lib/knapsack_pro/slow_test_file_finder.rb +27 -0
- data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +18 -2
- data/lib/knapsack_pro/test_case_mergers/base_merger.rb +29 -0
- data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +34 -0
- data/lib/knapsack_pro/test_file_finder.rb +43 -5
- data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +22 -0
- data/lib/knapsack_pro/version.rb +1 -1
- data/spec/knapsack_pro/adapters/base_adapter_spec.rb +55 -0
- data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +61 -25
- data/spec/knapsack_pro/allocator_builder_spec.rb +7 -3
- data/spec/knapsack_pro/allocator_spec.rb +7 -5
- data/spec/knapsack_pro/base_allocator_builder_spec.rb +79 -27
- data/spec/knapsack_pro/build_distribution_fetcher_spec.rb +89 -0
- data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +31 -0
- data/spec/knapsack_pro/client/connection_spec.rb +165 -103
- data/spec/knapsack_pro/config/env_spec.rb +14 -0
- data/spec/knapsack_pro/queue_allocator_builder_spec.rb +7 -3
- data/spec/knapsack_pro/queue_allocator_spec.rb +7 -5
- data/spec/knapsack_pro/runners/rspec_runner_spec.rb +4 -4
- data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +74 -0
- data/spec/knapsack_pro/slow_test_file_finder_spec.rb +43 -0
- data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +81 -35
- data/spec/knapsack_pro/test_case_mergers/base_merger_spec.rb +27 -0
- data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +59 -0
- data/spec/knapsack_pro/test_file_finder_spec.rb +105 -29
- data/spec/knapsack_pro/test_files_with_test_cases_composer_spec.rb +41 -0
- metadata +27 -10
@@ -1,7 +1,8 @@
|
|
1
1
|
module KnapsackPro
|
2
2
|
class QueueAllocator
|
3
3
|
def initialize(args)
|
4
|
-
@
|
4
|
+
@fast_and_slow_test_files_to_run = args.fetch(:fast_and_slow_test_files_to_run)
|
5
|
+
@fallback_mode_test_files = args.fetch(:fallback_mode_test_files)
|
5
6
|
@ci_node_total = args.fetch(:ci_node_total)
|
6
7
|
@ci_node_index = args.fetch(:ci_node_index)
|
7
8
|
@ci_node_build_id = args.fetch(:ci_node_build_id)
|
@@ -36,14 +37,15 @@ module KnapsackPro
|
|
36
37
|
|
37
38
|
private
|
38
39
|
|
39
|
-
attr_reader :
|
40
|
+
attr_reader :fast_and_slow_test_files_to_run,
|
41
|
+
:fallback_mode_test_files,
|
40
42
|
:ci_node_total,
|
41
43
|
:ci_node_index,
|
42
44
|
:ci_node_build_id,
|
43
45
|
:repository_adapter
|
44
46
|
|
45
47
|
def encrypted_test_files
|
46
|
-
KnapsackPro::Crypto::Encryptor.call(
|
48
|
+
KnapsackPro::Crypto::Encryptor.call(fast_and_slow_test_files_to_run)
|
47
49
|
end
|
48
50
|
|
49
51
|
def encrypted_branch
|
@@ -63,12 +65,12 @@ module KnapsackPro
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def prepare_test_files(response)
|
66
|
-
decrypted_test_files = KnapsackPro::Crypto::Decryptor.call(
|
68
|
+
decrypted_test_files = KnapsackPro::Crypto::Decryptor.call(fast_and_slow_test_files_to_run, response['test_files'])
|
67
69
|
KnapsackPro::TestFilePresenter.paths(decrypted_test_files)
|
68
70
|
end
|
69
71
|
|
70
72
|
def fallback_test_files(executed_test_files)
|
71
|
-
test_flat_distributor = KnapsackPro::TestFlatDistributor.new(
|
73
|
+
test_flat_distributor = KnapsackPro::TestFlatDistributor.new(fallback_mode_test_files, ci_node_total)
|
72
74
|
test_files_for_node_index = test_flat_distributor.test_files_for_node(ci_node_index)
|
73
75
|
KnapsackPro::TestFilePresenter.paths(test_files_for_node_index) - executed_test_files
|
74
76
|
end
|
@@ -2,7 +2,8 @@ module KnapsackPro
|
|
2
2
|
class QueueAllocatorBuilder < BaseAllocatorBuilder
|
3
3
|
def allocator
|
4
4
|
KnapsackPro::QueueAllocator.new(
|
5
|
-
|
5
|
+
fast_and_slow_test_files_to_run: fast_and_slow_test_files_to_run,
|
6
|
+
fallback_mode_test_files: fallback_mode_test_files,
|
6
7
|
ci_node_total: env.ci_node_total,
|
7
8
|
ci_node_index: env.ci_node_index,
|
8
9
|
ci_node_build_id: env.ci_node_build_id,
|
@@ -134,6 +134,13 @@ module KnapsackPro
|
|
134
134
|
RSpec.world.example_groups.clear
|
135
135
|
RSpec.configuration.start_time = ::RSpec::Core::Time.now
|
136
136
|
|
137
|
+
if KnapsackPro::Config::Env.rspec_split_by_test_examples?
|
138
|
+
# Reset example group counts to ensure scoped example ids in metadata
|
139
|
+
# have correct index (not increased by each subsequent run).
|
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))
|
142
|
+
end
|
143
|
+
|
137
144
|
# skip reset filters for old RSpec versions
|
138
145
|
if RSpec.configuration.respond_to?(:reset_filters)
|
139
146
|
RSpec.configuration.reset_filters
|
@@ -16,8 +16,11 @@ module KnapsackPro
|
|
16
16
|
end
|
17
17
|
|
18
18
|
RSpec::Core::RakeTask.new(task_name) do |t|
|
19
|
-
|
20
|
-
|
19
|
+
# we cannot pass runner.test_file_paths array to t.pattern
|
20
|
+
# because pattern does not accept test example path like spec/a_spec.rb[1:2]
|
21
|
+
# instead we pass test files and test example paths to t.rspec_opts
|
22
|
+
t.pattern = []
|
23
|
+
t.rspec_opts = "#{args} --default-path #{runner.test_dir} #{runner.stringify_test_file_paths}"
|
21
24
|
end
|
22
25
|
Rake::Task[task_name].invoke
|
23
26
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class SlowTestFileDeterminer
|
3
|
+
TIME_THRESHOLD_PER_CI_NODE = 0.7 # 70%
|
4
|
+
REPORT_DIR = 'tmp/knapsack_pro/slow_test_file_determiner'
|
5
|
+
REPORT_PATH = "#{REPORT_DIR}/slow_test_files.json"
|
6
|
+
|
7
|
+
# test_files: { 'path' => 'a_spec.rb', 'time_execution' => 0.0 }
|
8
|
+
# time_execution: of build distribution (total time of CI build run)
|
9
|
+
def self.call(test_files, time_execution)
|
10
|
+
time_threshold = (time_execution / KnapsackPro::Config::Env.ci_node_total) * TIME_THRESHOLD_PER_CI_NODE
|
11
|
+
|
12
|
+
test_files.select do |test_file|
|
13
|
+
test_file.fetch('time_execution') >= time_threshold
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.save_to_json_report(test_files)
|
18
|
+
FileUtils.mkdir_p(REPORT_DIR)
|
19
|
+
File.write(REPORT_PATH, test_files.to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.read_from_json_report
|
23
|
+
raise 'Report with slow test files was not generated yet. If you have enabled split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases and you see this error it means that your tests accidentally cleaned up tmp/knapsack_pro directory. Please do not remove this directory during tests runtime!' unless File.exists?(REPORT_PATH)
|
24
|
+
slow_test_files_json_report = File.read(REPORT_PATH)
|
25
|
+
JSON.parse(slow_test_files_json_report)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class SlowTestFileFinder
|
3
|
+
# Get recorded test files from API.
|
4
|
+
# Find slow tests among them that are still present on the disk.
|
5
|
+
# Save slow test files in json file on the disk.
|
6
|
+
# Returns slow test files.
|
7
|
+
def self.call(adapter_class)
|
8
|
+
if KnapsackPro::Config::Env.test_files_encrypted?
|
9
|
+
raise 'Split by test cases is not possible when you have enabled test file names encryption ( https://github.com/KnapsackPro/knapsack_pro-ruby#test-file-names-encryption ). You need to disable encryption with KNAPSACK_PRO_TEST_FILES_ENCRYPTED=false in order to use split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases'
|
10
|
+
end
|
11
|
+
|
12
|
+
# get list of recorded test files for last CI Build
|
13
|
+
build_distribution_entity = KnapsackPro::BuildDistributionFetcher.call
|
14
|
+
test_files_from_api = build_distribution_entity.test_files
|
15
|
+
|
16
|
+
merged_test_files_from_api = KnapsackPro::TestCaseMergers::BaseMerger.call(adapter_class, test_files_from_api)
|
17
|
+
|
18
|
+
test_files_existing_on_disk = KnapsackPro::TestFileFinder.select_test_files_that_can_be_run(adapter_class, merged_test_files_from_api)
|
19
|
+
|
20
|
+
slow_test_files = KnapsackPro::SlowTestFileDeterminer.call(test_files_existing_on_disk, build_distribution_entity.time_execution)
|
21
|
+
|
22
|
+
KnapsackPro::SlowTestFileDeterminer.save_to_json_report(slow_test_files)
|
23
|
+
|
24
|
+
slow_test_files
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -18,13 +18,19 @@ module KnapsackPro
|
|
18
18
|
ensure_report_dir_exists
|
19
19
|
remove_old_json_report
|
20
20
|
|
21
|
-
|
21
|
+
test_file_entities = slow_test_files
|
22
|
+
|
23
|
+
if test_file_entities.empty?
|
24
|
+
no_examples_json = { examples: [] }.to_json
|
25
|
+
File.write(REPORT_PATH, no_examples_json)
|
26
|
+
return
|
27
|
+
end
|
22
28
|
|
23
29
|
cli_args = cli_format + [
|
24
30
|
'--dry-run',
|
25
31
|
'--out', REPORT_PATH,
|
26
32
|
'--default-path', test_dir,
|
27
|
-
] +
|
33
|
+
] + KnapsackPro::TestFilePresenter.paths(test_file_entities)
|
28
34
|
options = RSpec::Core::ConfigurationOptions.new(cli_args)
|
29
35
|
exit_code = RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
30
36
|
if exit_code != 0
|
@@ -43,6 +49,16 @@ module KnapsackPro
|
|
43
49
|
.map { |path_with_example_id| test_file_hash_for(path_with_example_id) }
|
44
50
|
end
|
45
51
|
|
52
|
+
def slow_test_files
|
53
|
+
if KnapsackPro::Config::Env.slow_test_file_pattern
|
54
|
+
KnapsackPro::TestFileFinder.slow_test_files_by_pattern(adapter_class)
|
55
|
+
else
|
56
|
+
# read slow test files from JSON file on disk that was generated
|
57
|
+
# by lib/knapsack_pro/base_allocator_builder.rb
|
58
|
+
KnapsackPro::SlowTestFileDeterminer.read_from_json_report
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
46
62
|
private
|
47
63
|
|
48
64
|
def adapter_class
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module TestCaseMergers
|
3
|
+
class BaseMerger
|
4
|
+
# values must be string to avoid circular dependency problem during loading files
|
5
|
+
ADAPTER_TO_MERGER_MAP = {
|
6
|
+
KnapsackPro::Adapters::RSpecAdapter => 'KnapsackPro::TestCaseMergers::RSpecMerger',
|
7
|
+
}
|
8
|
+
|
9
|
+
def self.call(adapter_class, test_files)
|
10
|
+
merger_class =
|
11
|
+
ADAPTER_TO_MERGER_MAP[adapter_class] ||
|
12
|
+
raise("Test case merger does not exist for adapter_class: #{adapter_class}")
|
13
|
+
Kernel.const_get(merger_class).new(test_files).call
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(test_files)
|
17
|
+
@test_files = test_files
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :test_files
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module TestCaseMergers
|
3
|
+
class RSpecMerger < BaseMerger
|
4
|
+
def call
|
5
|
+
merged_test_files_hash = {}
|
6
|
+
test_files.each do |test_file|
|
7
|
+
test_file_path = extract_test_file_path(test_file.fetch('path'))
|
8
|
+
|
9
|
+
# must be float (default type for time execution from API)
|
10
|
+
merged_test_files_hash[test_file_path] ||= 0.0
|
11
|
+
merged_test_files_hash[test_file_path] += test_file.fetch('time_execution')
|
12
|
+
end
|
13
|
+
|
14
|
+
merged_test_files = []
|
15
|
+
merged_test_files_hash.each do |path, time_execution|
|
16
|
+
merged_test_files << {
|
17
|
+
'path' => path,
|
18
|
+
'time_execution' => time_execution
|
19
|
+
}
|
20
|
+
end
|
21
|
+
merged_test_files
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# path - can be:
|
27
|
+
# test file path: spec/a_spec.rb
|
28
|
+
# or test example path: spec/a_spec.rb[1:1]
|
29
|
+
def extract_test_file_path(path)
|
30
|
+
path.gsub(/\.rb\[.+\]$/, '.rb')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,11 +1,49 @@
|
|
1
1
|
module KnapsackPro
|
2
2
|
class TestFileFinder
|
3
|
-
def self.call(test_file_pattern)
|
4
|
-
new(test_file_pattern).call
|
3
|
+
def self.call(test_file_pattern, test_file_list_enabled: true)
|
4
|
+
new(test_file_pattern, test_file_list_enabled).call
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
# finds slow test files on disk based on ENV patterns
|
8
|
+
# returns example: [{ 'path' => 'a_spec.rb' }]
|
9
|
+
def self.slow_test_files_by_pattern(adapter_class)
|
10
|
+
raise 'KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN is not defined' unless KnapsackPro::Config::Env.slow_test_file_pattern
|
11
|
+
|
12
|
+
test_file_pattern = KnapsackPro::TestFilePattern.call(adapter_class)
|
13
|
+
test_file_entities = call(test_file_pattern)
|
14
|
+
|
15
|
+
slow_test_file_entities = call(KnapsackPro::Config::Env.slow_test_file_pattern, test_file_list_enabled: false)
|
16
|
+
|
17
|
+
# slow test files (KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN)
|
18
|
+
# should be subset of test file pattern (KNAPSACK_PRO_TEST_FILE_PATTERN)
|
19
|
+
slow_test_file_entities & test_file_entities
|
20
|
+
end
|
21
|
+
|
22
|
+
# Args:
|
23
|
+
# test_file_entities_to_run - it can be list of slow test files that you want to run
|
24
|
+
# Return:
|
25
|
+
# subset of test_file_entities_to_run that are present on disk and it is subset of tests matching pattern KNAPSACK_PRO_TEST_FILE_PATTERN
|
26
|
+
# Thanks to that we can select only slow test files that are within list of test file pattern we want to run tests for
|
27
|
+
def self.select_test_files_that_can_be_run(adapter_class, test_file_entities_to_run)
|
28
|
+
test_file_pattern = KnapsackPro::TestFilePattern.call(adapter_class)
|
29
|
+
test_file_entities = call(test_file_pattern)
|
30
|
+
|
31
|
+
test_file_paths_existing_on_disk = KnapsackPro::TestFilePresenter.paths(test_file_entities)
|
32
|
+
|
33
|
+
selected_test_files = []
|
34
|
+
|
35
|
+
test_file_entities_to_run.each do |test_file_entity|
|
36
|
+
if test_file_paths_existing_on_disk.include?(test_file_entity.fetch('path'))
|
37
|
+
selected_test_files << test_file_entity
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
selected_test_files
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(test_file_pattern, test_file_list_enabled)
|
8
45
|
@test_file_pattern = test_file_pattern
|
46
|
+
@test_file_list_enabled = test_file_list_enabled
|
9
47
|
end
|
10
48
|
|
11
49
|
def call
|
@@ -18,10 +56,10 @@ module KnapsackPro
|
|
18
56
|
|
19
57
|
private
|
20
58
|
|
21
|
-
attr_reader :test_file_pattern
|
59
|
+
attr_reader :test_file_pattern, :test_file_list_enabled
|
22
60
|
|
23
61
|
def test_files
|
24
|
-
if KnapsackPro::Config::Env.test_file_list
|
62
|
+
if test_file_list_enabled && KnapsackPro::Config::Env.test_file_list
|
25
63
|
return KnapsackPro::Config::Env.test_file_list.split(',').map(&:strip)
|
26
64
|
end
|
27
65
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class TestFilesWithTestCasesComposer
|
3
|
+
# Args:
|
4
|
+
# All 3 arguments have structure: [{ 'path' => 'spec/a_spec.rb', 'time_execution' => 0.0 }]
|
5
|
+
# time_execution is not always present (but it's not relevant here)
|
6
|
+
#
|
7
|
+
# test_files - list of test files that you want to run tests for
|
8
|
+
# slow_test_files - list of slow test files that should be split by test cases
|
9
|
+
# test_file_cases - list of paths to test cases (test examples) inside of all slow test files (slow_test_files)
|
10
|
+
# Return:
|
11
|
+
# Test files and test cases paths (it excludes test files that should be split by test cases (test examples))
|
12
|
+
def self.call(test_files, slow_test_files, test_file_cases)
|
13
|
+
slow_test_file_paths = KnapsackPro::TestFilePresenter.paths(slow_test_files)
|
14
|
+
|
15
|
+
test_files_without_slow_test_files = test_files.reject do |test_file|
|
16
|
+
slow_test_file_paths.include?(test_file.fetch('path'))
|
17
|
+
end
|
18
|
+
|
19
|
+
test_files_without_slow_test_files + test_file_cases
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/knapsack_pro/version.rb
CHANGED
@@ -3,6 +3,61 @@ describe KnapsackPro::Adapters::BaseAdapter do
|
|
3
3
|
expect(described_class::TEST_DIR_PATTERN).to eq 'test/**{,/*/**}/*_test.rb'
|
4
4
|
end
|
5
5
|
|
6
|
+
shared_examples '.slow_test_file? method' do
|
7
|
+
context 'when test_file_path is in slow test file paths' do
|
8
|
+
# add ./ before path to ensure KnapsackPro::TestFileCleaner.clean will clean it
|
9
|
+
let(:test_file_path) { './spec/models/user_spec.rb' }
|
10
|
+
|
11
|
+
it do
|
12
|
+
expect(subject).to be true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when test_file_path is not in slow test file paths' do
|
17
|
+
let(:test_file_path) { './spec/models/article_spec.rb' }
|
18
|
+
|
19
|
+
it do
|
20
|
+
expect(subject).to be false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '.slow_test_file?' do
|
26
|
+
let(:adapter_class) { double }
|
27
|
+
let(:slow_test_files) do
|
28
|
+
[
|
29
|
+
{ 'path' => 'spec/models/user_spec.rb' },
|
30
|
+
{ 'path' => 'spec/controllers/users_spec.rb' },
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
subject { described_class.slow_test_file?(adapter_class, test_file_path) }
|
35
|
+
|
36
|
+
before do
|
37
|
+
# reset class variable
|
38
|
+
described_class.instance_variable_set(:@slow_test_file_paths, nil)
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when slow test file pattern is present' do
|
42
|
+
before do
|
43
|
+
stub_const('ENV', {
|
44
|
+
'KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN' => '{spec/models/*_spec.rb}',
|
45
|
+
})
|
46
|
+
expect(KnapsackPro::TestFileFinder).to receive(:slow_test_files_by_pattern).with(adapter_class).and_return(slow_test_files)
|
47
|
+
end
|
48
|
+
|
49
|
+
it_behaves_like '.slow_test_file? method'
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when slow test file pattern is not present' do
|
53
|
+
before do
|
54
|
+
expect(KnapsackPro::SlowTestFileDeterminer).to receive(:read_from_json_report).and_return(slow_test_files)
|
55
|
+
end
|
56
|
+
|
57
|
+
it_behaves_like '.slow_test_file? method'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
6
61
|
describe '.bind' do
|
7
62
|
let(:adapter) { instance_double(described_class) }
|
8
63
|
|
@@ -71,22 +71,21 @@ describe KnapsackPro::Adapters::RSpecAdapter do
|
|
71
71
|
let(:tracker) { instance_double(KnapsackPro::Tracker) }
|
72
72
|
let(:logger) { instance_double(Logger) }
|
73
73
|
let(:global_time) { 'Global time: 01m 05s' }
|
74
|
+
let(:test_path) { 'spec/a_spec.rb' }
|
75
|
+
let(:example) { double }
|
76
|
+
let(:example_group) { double }
|
77
|
+
let(:current_example) do
|
78
|
+
OpenStruct.new(metadata: {
|
79
|
+
example_group: example_group
|
80
|
+
})
|
81
|
+
end
|
74
82
|
|
75
83
|
context 'when rspec split by test examples is disabled' do
|
76
|
-
let(:test_path) { 'spec/a_spec.rb' }
|
77
|
-
let(:example) { double }
|
78
|
-
let(:example_group) { double }
|
79
|
-
let(:current_example) do
|
80
|
-
OpenStruct.new(metadata: {
|
81
|
-
example_group: example_group
|
82
|
-
})
|
83
|
-
end
|
84
|
-
|
85
84
|
before do
|
86
85
|
expect(KnapsackPro::Config::Env).to receive(:rspec_split_by_test_examples?).and_return(false)
|
87
86
|
end
|
88
87
|
|
89
|
-
it do
|
88
|
+
it 'records time for current test path' do
|
90
89
|
expect(config).to receive(:around).with(:each).and_yield(example)
|
91
90
|
expect(config).to receive(:after).with(:suite).and_yield
|
92
91
|
expect(::RSpec).to receive(:configure).and_yield(config)
|
@@ -112,32 +111,69 @@ describe KnapsackPro::Adapters::RSpecAdapter do
|
|
112
111
|
|
113
112
|
context 'when rspec split by test examples is enabled' do
|
114
113
|
let(:test_example_path) { 'spec/a_spec.rb[1:1]' }
|
115
|
-
let(:example) { double }
|
116
114
|
|
117
115
|
before do
|
118
116
|
expect(KnapsackPro::Config::Env).to receive(:rspec_split_by_test_examples?).and_return(true)
|
119
117
|
end
|
120
118
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
119
|
+
context 'when current test_path is a slow test file' do
|
120
|
+
before do
|
121
|
+
expect(described_class).to receive(:slow_test_file?).with(described_class, test_path).and_return(true)
|
122
|
+
end
|
125
123
|
|
126
|
-
|
124
|
+
it 'records time for example.id' do
|
125
|
+
expect(example).to receive(:id).and_return(test_example_path)
|
127
126
|
|
128
|
-
|
129
|
-
|
130
|
-
|
127
|
+
expect(config).to receive(:around).with(:each).and_yield(example)
|
128
|
+
expect(config).to receive(:after).with(:suite).and_yield
|
129
|
+
expect(::RSpec).to receive(:configure).and_yield(config)
|
131
130
|
|
132
|
-
|
131
|
+
expect(::RSpec).to receive(:current_example).twice.and_return(current_example)
|
132
|
+
expect(described_class).to receive(:test_path).with(example_group).and_return(test_path)
|
133
133
|
|
134
|
-
|
134
|
+
allow(KnapsackPro).to receive(:tracker).and_return(tracker)
|
135
|
+
expect(tracker).to receive(:current_test_path=).with(test_example_path)
|
136
|
+
expect(tracker).to receive(:start_timer)
|
135
137
|
|
136
|
-
|
137
|
-
expect(KnapsackPro).to receive(:logger).and_return(logger)
|
138
|
-
expect(logger).to receive(:debug).with(global_time)
|
138
|
+
expect(example).to receive(:run)
|
139
139
|
|
140
|
-
|
140
|
+
expect(tracker).to receive(:stop_timer)
|
141
|
+
|
142
|
+
expect(KnapsackPro::Presenter).to receive(:global_time).and_return(global_time)
|
143
|
+
expect(KnapsackPro).to receive(:logger).and_return(logger)
|
144
|
+
expect(logger).to receive(:debug).with(global_time)
|
145
|
+
|
146
|
+
subject.bind_time_tracker
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when current test_path is not a slow test file' do
|
151
|
+
before do
|
152
|
+
expect(described_class).to receive(:slow_test_file?).with(described_class, test_path).and_return(false)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'records time for current test path' do
|
156
|
+
expect(config).to receive(:around).with(:each).and_yield(example)
|
157
|
+
expect(config).to receive(:after).with(:suite).and_yield
|
158
|
+
expect(::RSpec).to receive(:configure).and_yield(config)
|
159
|
+
|
160
|
+
expect(::RSpec).to receive(:current_example).twice.and_return(current_example)
|
161
|
+
expect(described_class).to receive(:test_path).with(example_group).and_return(test_path)
|
162
|
+
|
163
|
+
allow(KnapsackPro).to receive(:tracker).and_return(tracker)
|
164
|
+
expect(tracker).to receive(:current_test_path=).with(test_path)
|
165
|
+
expect(tracker).to receive(:start_timer)
|
166
|
+
|
167
|
+
expect(example).to receive(:run)
|
168
|
+
|
169
|
+
expect(tracker).to receive(:stop_timer)
|
170
|
+
|
171
|
+
expect(KnapsackPro::Presenter).to receive(:global_time).and_return(global_time)
|
172
|
+
expect(KnapsackPro).to receive(:logger).and_return(logger)
|
173
|
+
expect(logger).to receive(:debug).with(global_time)
|
174
|
+
|
175
|
+
subject.bind_time_tracker
|
176
|
+
end
|
141
177
|
end
|
142
178
|
end
|
143
179
|
end
|