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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +24 -12
  4. data/lib/knapsack_pro.rb +6 -0
  5. data/lib/knapsack_pro/adapters/base_adapter.rb +16 -0
  6. data/lib/knapsack_pro/adapters/rspec_adapter.rb +11 -9
  7. data/lib/knapsack_pro/allocator.rb +7 -5
  8. data/lib/knapsack_pro/allocator_builder.rb +2 -1
  9. data/lib/knapsack_pro/base_allocator_builder.rb +41 -10
  10. data/lib/knapsack_pro/build_distribution_fetcher.rb +57 -0
  11. data/lib/knapsack_pro/client/api/v1/build_distributions.rb +13 -0
  12. data/lib/knapsack_pro/client/connection.rb +30 -12
  13. data/lib/knapsack_pro/config/env.rb +4 -0
  14. data/lib/knapsack_pro/queue_allocator.rb +7 -5
  15. data/lib/knapsack_pro/queue_allocator_builder.rb +2 -1
  16. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +7 -0
  17. data/lib/knapsack_pro/runners/rspec_runner.rb +5 -2
  18. data/lib/knapsack_pro/slow_test_file_determiner.rb +28 -0
  19. data/lib/knapsack_pro/slow_test_file_finder.rb +27 -0
  20. data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +18 -2
  21. data/lib/knapsack_pro/test_case_mergers/base_merger.rb +29 -0
  22. data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +34 -0
  23. data/lib/knapsack_pro/test_file_finder.rb +43 -5
  24. data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +22 -0
  25. data/lib/knapsack_pro/version.rb +1 -1
  26. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +55 -0
  27. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +61 -25
  28. data/spec/knapsack_pro/allocator_builder_spec.rb +7 -3
  29. data/spec/knapsack_pro/allocator_spec.rb +7 -5
  30. data/spec/knapsack_pro/base_allocator_builder_spec.rb +79 -27
  31. data/spec/knapsack_pro/build_distribution_fetcher_spec.rb +89 -0
  32. data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +31 -0
  33. data/spec/knapsack_pro/client/connection_spec.rb +165 -103
  34. data/spec/knapsack_pro/config/env_spec.rb +14 -0
  35. data/spec/knapsack_pro/queue_allocator_builder_spec.rb +7 -3
  36. data/spec/knapsack_pro/queue_allocator_spec.rb +7 -5
  37. data/spec/knapsack_pro/runners/rspec_runner_spec.rb +4 -4
  38. data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +74 -0
  39. data/spec/knapsack_pro/slow_test_file_finder_spec.rb +43 -0
  40. data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +81 -35
  41. data/spec/knapsack_pro/test_case_mergers/base_merger_spec.rb +27 -0
  42. data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +59 -0
  43. data/spec/knapsack_pro/test_file_finder_spec.rb +105 -29
  44. data/spec/knapsack_pro/test_files_with_test_cases_composer_spec.rb +41 -0
  45. metadata +27 -10
@@ -183,6 +183,20 @@ describe KnapsackPro::Config::Env do
183
183
  end
184
184
  end
185
185
 
186
+ describe '.slow_test_file_pattern' do
187
+ subject { described_class.slow_test_file_pattern }
188
+
189
+ context 'when ENV exists' do
190
+ let(:slow_test_file_pattern) { 'spec/features/*_spec.rb' }
191
+ before { stub_const("ENV", { 'KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN' => slow_test_file_pattern }) }
192
+ it { should eq slow_test_file_pattern }
193
+ end
194
+
195
+ context "when ENV doesn't exist" do
196
+ it { should be_nil }
197
+ end
198
+ end
199
+
186
200
  describe '.test_file_exclude_pattern' do
187
201
  subject { described_class.test_file_exclude_pattern }
188
202
 
@@ -8,8 +8,11 @@ describe KnapsackPro::QueueAllocatorBuilder do
8
8
  subject { allocator_builder.allocator }
9
9
 
10
10
  before do
11
- test_files = double
12
- expect(allocator_builder).to receive(:test_files).and_return(test_files)
11
+ fast_and_slow_test_files_to_run = double
12
+ expect(allocator_builder).to receive(:fast_and_slow_test_files_to_run).and_return(fast_and_slow_test_files_to_run)
13
+
14
+ fallback_mode_test_files = double
15
+ expect(allocator_builder).to receive(:fallback_mode_test_files).and_return(fallback_mode_test_files)
13
16
 
14
17
  repository_adapter = double
15
18
  expect(KnapsackPro::RepositoryAdapterInitiator).to receive(:call).and_return(repository_adapter)
@@ -22,7 +25,8 @@ describe KnapsackPro::QueueAllocatorBuilder do
22
25
  expect(KnapsackPro::Config::Env).to receive(:ci_node_build_id).and_return(ci_node_build_id)
23
26
 
24
27
  expect(KnapsackPro::QueueAllocator).to receive(:new).with(
25
- test_files: test_files,
28
+ fast_and_slow_test_files_to_run: fast_and_slow_test_files_to_run,
29
+ fallback_mode_test_files: fallback_mode_test_files,
26
30
  ci_node_total: ci_node_total,
27
31
  ci_node_index: ci_node_index,
28
32
  ci_node_build_id: ci_node_build_id,
@@ -1,5 +1,6 @@
1
1
  describe KnapsackPro::QueueAllocator do
2
- let(:test_files) { double }
2
+ let(:fast_and_slow_test_files_to_run) { double }
3
+ let(:fallback_mode_test_files) { double }
3
4
  let(:ci_node_total) { double }
4
5
  let(:ci_node_index) { double }
5
6
  let(:ci_node_build_id) { double }
@@ -7,7 +8,8 @@ describe KnapsackPro::QueueAllocator do
7
8
 
8
9
  let(:queue_allocator) do
9
10
  described_class.new(
10
- test_files: test_files,
11
+ fast_and_slow_test_files_to_run: fast_and_slow_test_files_to_run,
12
+ fallback_mode_test_files: fallback_mode_test_files,
11
13
  ci_node_total: ci_node_total,
12
14
  ci_node_index: ci_node_index,
13
15
  ci_node_build_id: ci_node_build_id,
@@ -24,7 +26,7 @@ describe KnapsackPro::QueueAllocator do
24
26
 
25
27
  before do
26
28
  encrypted_test_files = double
27
- expect(KnapsackPro::Crypto::Encryptor).to receive(:call).with(test_files).and_return(encrypted_test_files)
29
+ expect(KnapsackPro::Crypto::Encryptor).to receive(:call).with(fast_and_slow_test_files_to_run).and_return(encrypted_test_files)
28
30
 
29
31
  encrypted_branch = double
30
32
  expect(KnapsackPro::Crypto::BranchEncryptor).to receive(:call).with(repository_adapter.branch).and_return(encrypted_branch)
@@ -70,7 +72,7 @@ describe KnapsackPro::QueueAllocator do
70
72
  end
71
73
 
72
74
  before do
73
- expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(test_files, response['test_files']).and_call_original
75
+ expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(fast_and_slow_test_files_to_run, response['test_files']).and_call_original
74
76
  end
75
77
 
76
78
  it { should eq ['a_spec.rb', 'b_spec.rb'] }
@@ -120,7 +122,7 @@ describe KnapsackPro::QueueAllocator do
120
122
  context 'when fallback mode started' do
121
123
  before do
122
124
  test_flat_distributor = instance_double(KnapsackPro::TestFlatDistributor)
123
- expect(KnapsackPro::TestFlatDistributor).to receive(:new).with(test_files, ci_node_total).and_return(test_flat_distributor)
125
+ expect(KnapsackPro::TestFlatDistributor).to receive(:new).with(fallback_mode_test_files, ci_node_total).and_return(test_flat_distributor)
124
126
  expect(test_flat_distributor).to receive(:test_files_for_node).with(ci_node_index).and_return([
125
127
  { 'path' => 'c_spec.rb' },
126
128
  { 'path' => 'd_spec.rb' },
@@ -24,11 +24,11 @@ describe KnapsackPro::Runners::RSpecRunner do
24
24
 
25
25
  context 'when test files were returned by Knapsack Pro API' do
26
26
  let(:test_dir) { 'fake-test-dir' }
27
- let(:test_file_paths) { double(:test_file_paths) }
27
+ let(:stringify_test_file_paths) { "spec/a_spec.rb spec/b_spec.rb[1:1]" }
28
28
  let(:runner) do
29
29
  instance_double(described_class,
30
30
  test_dir: test_dir,
31
- test_file_paths: test_file_paths,
31
+ stringify_test_file_paths: stringify_test_file_paths,
32
32
  test_files_to_execute_exist?: true)
33
33
  end
34
34
  let(:task) { double }
@@ -38,8 +38,8 @@ describe KnapsackPro::Runners::RSpecRunner do
38
38
 
39
39
  t = double
40
40
  expect(RSpec::Core::RakeTask).to receive(:new).with('knapsack_pro:rspec_run').and_yield(t)
41
- expect(t).to receive(:rspec_opts=).with('--profile --color --default-path fake-test-dir')
42
- expect(t).to receive(:pattern=).with(test_file_paths)
41
+ expect(t).to receive(:rspec_opts=).with('--profile --color --default-path fake-test-dir spec/a_spec.rb spec/b_spec.rb[1:1]')
42
+ expect(t).to receive(:pattern=).with([])
43
43
  end
44
44
 
45
45
  context 'when task already exists' do
@@ -0,0 +1,74 @@
1
+ describe KnapsackPro::SlowTestFileDeterminer do
2
+ describe '.call' do
3
+ let(:node_total) { 4 }
4
+ let(:time_execution) { 20.0 }
5
+ let(:test_files) do
6
+ [
7
+ { 'path' => 'a_spec.rb', 'time_execution' => 1.0 },
8
+ { 'path' => 'b_spec.rb', 'time_execution' => 3.4 },
9
+ # slow tests are above 3.5s threshold (20.0 / 4 * 0.7 = 3.5)
10
+ { 'path' => 'c_spec.rb', 'time_execution' => 3.5 },
11
+ { 'path' => 'd_spec.rb', 'time_execution' => 5.9 },
12
+ ]
13
+ end
14
+
15
+ before do
16
+ expect(KnapsackPro::Config::Env).to receive(:ci_node_total).and_return(node_total)
17
+ end
18
+
19
+ subject { described_class.call(test_files, time_execution) }
20
+
21
+ it do
22
+ expect(subject).to eq([
23
+ { 'path' => 'c_spec.rb', 'time_execution' => 3.5 },
24
+ { 'path' => 'd_spec.rb', 'time_execution' => 5.9 },
25
+ ])
26
+ end
27
+ end
28
+
29
+ describe '.save_to_json_report', :clear_tmp do
30
+ let(:json_report_path) { 'tmp/knapsack_pro/slow_test_file_determiner/slow_test_files.json' }
31
+ let(:test_files) do
32
+ [
33
+ { 'path' => 'a_spec.rb', 'time_execution' => 1.0 },
34
+ # unique path to ensure we saved on disk a completely new report
35
+ { 'path' => "#{SecureRandom.hex}_spec.rb", 'time_execution' => 3.4 },
36
+ ]
37
+ end
38
+
39
+ subject { described_class.save_to_json_report(test_files) }
40
+
41
+ it do
42
+ subject
43
+ expect(File.read(json_report_path)).to eq(test_files.to_json)
44
+ end
45
+ end
46
+
47
+ describe '.read_from_json_report', :clear_tmp do
48
+ let(:test_files) do
49
+ [
50
+ { 'path' => 'a_spec.rb', 'time_execution' => 1.0 },
51
+ # unique path to ensure we saved on disk a completely new report
52
+ { 'path' => "#{SecureRandom.hex}_spec.rb", 'time_execution' => 3.4 },
53
+ ]
54
+ end
55
+
56
+ subject { described_class.read_from_json_report }
57
+
58
+ context 'when json report exists' do
59
+ before do
60
+ described_class.save_to_json_report(test_files)
61
+ end
62
+
63
+ it do
64
+ expect(subject).to eq test_files
65
+ end
66
+ end
67
+
68
+ context 'when json report does not exist' do
69
+ it do
70
+ expect { subject }.to raise_error(RuntimeError, '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!')
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,43 @@
1
+ describe KnapsackPro::SlowTestFileFinder do
2
+ describe '.call' do
3
+ let(:adapter_class) { double }
4
+
5
+ subject { described_class.call(adapter_class) }
6
+
7
+ before do
8
+ expect(KnapsackPro::Config::Env).to receive(:test_files_encrypted?).and_return(test_files_encrypted?)
9
+ end
10
+
11
+ context 'when test files are not encrypted' do
12
+ let(:test_files_encrypted?) { false }
13
+
14
+ it do
15
+ test_files_from_api = double
16
+ time_execution = double
17
+ build_distribution_entity = instance_double(KnapsackPro::BuildDistributionFetcher::BuildDistributionEntity, test_files: test_files_from_api, time_execution: time_execution)
18
+ expect(KnapsackPro::BuildDistributionFetcher).to receive(:call).and_return(build_distribution_entity)
19
+
20
+ merged_test_files_from_api = double
21
+ expect(KnapsackPro::TestCaseMergers::BaseMerger).to receive(:call).with(adapter_class, test_files_from_api).and_return(merged_test_files_from_api)
22
+
23
+ test_files_existing_on_disk = double
24
+ expect(KnapsackPro::TestFileFinder).to receive(:select_test_files_that_can_be_run).with(adapter_class, merged_test_files_from_api).and_return(test_files_existing_on_disk)
25
+
26
+ slow_test_files = double
27
+ expect(KnapsackPro::SlowTestFileDeterminer).to receive(:call).with(test_files_existing_on_disk, time_execution).and_return(slow_test_files)
28
+
29
+ expect(KnapsackPro::SlowTestFileDeterminer).to receive(:save_to_json_report).with(slow_test_files)
30
+
31
+ expect(subject).to eq slow_test_files
32
+ end
33
+ end
34
+
35
+ context 'when test files are encrypted' do
36
+ let(:test_files_encrypted?) { true }
37
+
38
+ it do
39
+ expect { subject }.to raise_error RuntimeError, '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'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,9 +1,10 @@
1
1
  describe KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector do
2
2
  let(:report_dir) { 'tmp/knapsack_pro/test_case_detectors/rspec' }
3
3
  let(:report_path) { 'tmp/knapsack_pro/test_case_detectors/rspec/rspec_dry_run_json_report.json' }
4
+ let(:rspec_test_example_detector) { described_class.new }
4
5
 
5
6
  describe '#generate_json_report' do
6
- subject { described_class.new.generate_json_report }
7
+ subject { rspec_test_example_detector.generate_json_report }
7
8
 
8
9
  before do
9
10
  expect(FileUtils).to receive(:mkdir_p).with(report_dir)
@@ -11,48 +12,63 @@ describe KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector do
11
12
  expect(File).to receive(:exists?).with(report_path).and_return(true)
12
13
  expect(File).to receive(:delete).with(report_path)
13
14
 
14
- test_file_pattern = double
15
- adapter_class = KnapsackPro::Adapters::RSpecAdapter
16
- expect(KnapsackPro::TestFilePattern).to receive(:call).with(adapter_class).and_return(test_file_pattern)
17
-
18
- test_file_paths = [
19
- { 'path' => 'spec/a_spec.rb' },
20
- { 'path' => 'spec/b_spec.rb' },
21
- ]
22
- expect(KnapsackPro::TestFileFinder).to receive(:call).with(test_file_pattern).and_return(test_file_paths)
23
-
24
- test_dir = 'spec'
25
- expect(KnapsackPro::Config::Env).to receive(:test_dir).and_return(nil)
26
- expect(KnapsackPro::TestFilePattern).to receive(:test_dir).with(adapter_class).and_return(test_dir)
27
-
28
- options = double
29
- expect(RSpec::Core::ConfigurationOptions).to receive(:new).with([
30
- '--format', expected_format,
31
- '--dry-run',
32
- '--out', report_path,
33
- '--default-path', test_dir,
34
- 'spec/a_spec.rb', 'spec/b_spec.rb',
35
- ]).and_return(options)
36
-
37
- rspec_core_runner = double
38
- expect(RSpec::Core::Runner).to receive(:new).with(options).and_return(rspec_core_runner)
39
- expect(rspec_core_runner).to receive(:run).with($stderr, $stdout).and_return(exit_code)
15
+ expect(rspec_test_example_detector).to receive(:slow_test_files).and_return(test_file_entities)
40
16
  end
41
17
 
42
18
  shared_examples 'generate_json_report runs RSpec::Core::Runner' do
43
- context 'when exit code from RSpec::Core::Runner is 0' do
44
- let(:exit_code) { 0 }
19
+ context 'when there are no slow test files' do
20
+ let(:test_file_entities) { [] }
21
+
22
+ before do
23
+ expect(File).to receive(:write).with(report_path, { examples: [] }.to_json)
24
+ end
45
25
 
46
26
  it do
47
27
  expect(subject).to be_nil
48
28
  end
49
29
  end
50
30
 
51
- context 'when exit code from RSpec::Core::Runner is 1' do
52
- let(:exit_code) { 1 }
31
+ context 'when slow test files exist' do
32
+ let(:test_file_entities) do
33
+ [
34
+ { 'path' => 'spec/a_spec.rb' },
35
+ { 'path' => 'spec/b_spec.rb' },
36
+ ]
37
+ end
53
38
 
54
- it do
55
- expect { subject }.to raise_error(RuntimeError, 'There was problem to generate test examples for test suite')
39
+ before do
40
+ test_dir = 'spec'
41
+ expect(KnapsackPro::Config::Env).to receive(:test_dir).and_return(nil)
42
+ expect(KnapsackPro::TestFilePattern).to receive(:test_dir).with(KnapsackPro::Adapters::RSpecAdapter).and_return(test_dir)
43
+
44
+ options = double
45
+ expect(RSpec::Core::ConfigurationOptions).to receive(:new).with([
46
+ '--format', expected_format,
47
+ '--dry-run',
48
+ '--out', report_path,
49
+ '--default-path', test_dir,
50
+ 'spec/a_spec.rb', 'spec/b_spec.rb',
51
+ ]).and_return(options)
52
+
53
+ rspec_core_runner = double
54
+ expect(RSpec::Core::Runner).to receive(:new).with(options).and_return(rspec_core_runner)
55
+ expect(rspec_core_runner).to receive(:run).with($stderr, $stdout).and_return(exit_code)
56
+ end
57
+
58
+ context 'when exit code from RSpec::Core::Runner is 0' do
59
+ let(:exit_code) { 0 }
60
+
61
+ it do
62
+ expect(subject).to be_nil
63
+ end
64
+ end
65
+
66
+ context 'when exit code from RSpec::Core::Runner is 1' do
67
+ let(:exit_code) { 1 }
68
+
69
+ it do
70
+ expect { subject }.to raise_error(RuntimeError, 'There was problem to generate test examples for test suite')
71
+ end
56
72
  end
57
73
  end
58
74
  end
@@ -77,7 +93,7 @@ describe KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector do
77
93
  describe '#test_file_example_paths' do
78
94
  subject { described_class.new.test_file_example_paths }
79
95
 
80
- context 'when json report exists' do
96
+ context 'when JSON report exists' do
81
97
  it do
82
98
  expect(File).to receive(:exists?).with(report_path).and_return(true)
83
99
 
@@ -96,7 +112,7 @@ describe KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector do
96
112
  end
97
113
  end
98
114
 
99
- context 'when json report does not exist' do
115
+ context 'when JSON report does not exist' do
100
116
  it do
101
117
  expect(File).to receive(:exists?).with(report_path).and_return(false)
102
118
 
@@ -104,4 +120,34 @@ describe KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector do
104
120
  end
105
121
  end
106
122
  end
123
+
124
+ describe '#slow_test_files' do
125
+ subject { described_class.new.slow_test_files }
126
+
127
+ before do
128
+ expect(KnapsackPro::Config::Env).to receive(:slow_test_file_pattern).and_return(slow_test_file_pattern)
129
+ end
130
+
131
+ context 'when slow test file pattern is present' do
132
+ let(:slow_test_file_pattern) { double }
133
+
134
+ it do
135
+ expected_slow_test_files = double
136
+ expect(KnapsackPro::TestFileFinder).to receive(:slow_test_files_by_pattern).with(KnapsackPro::Adapters::RSpecAdapter).and_return(expected_slow_test_files)
137
+
138
+ expect(subject).to eq expected_slow_test_files
139
+ end
140
+ end
141
+
142
+ context 'when slow test file pattern is not present' do
143
+ let(:slow_test_file_pattern) { nil }
144
+
145
+ it do
146
+ expected_slow_test_files = double
147
+ expect(KnapsackPro::SlowTestFileDeterminer).to receive(:read_from_json_report).and_return(expected_slow_test_files)
148
+
149
+ expect(subject).to eq expected_slow_test_files
150
+ end
151
+ end
152
+ end
107
153
  end
@@ -0,0 +1,27 @@
1
+ describe KnapsackPro::TestCaseMergers::BaseMerger do
2
+ describe '.call' do
3
+ let(:test_files) { double }
4
+
5
+ subject { described_class.call(adapter_class, test_files) }
6
+
7
+ context 'when adapter_class is KnapsackPro::Adapters::RSpecAdapter' do
8
+ let(:adapter_class) { KnapsackPro::Adapters::RSpecAdapter }
9
+
10
+ it do
11
+ result = double
12
+ rspec_merger = instance_double(KnapsackPro::TestCaseMergers::RSpecMerger, call: result)
13
+ expect(KnapsackPro::TestCaseMergers::RSpecMerger).to receive(:new).with(test_files).and_return(rspec_merger)
14
+
15
+ expect(subject).to eq result
16
+ end
17
+ end
18
+
19
+ context 'when adapter_class is unknown' do
20
+ let(:adapter_class) { 'fake-adapter' }
21
+
22
+ it do
23
+ expect { subject }.to raise_error 'Test case merger does not exist for adapter_class: fake-adapter'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,59 @@
1
+ describe KnapsackPro::TestCaseMergers::RSpecMerger do
2
+ describe '#call' do
3
+ subject { described_class.new(test_files).call }
4
+
5
+ context 'when all test files are not test example paths' do
6
+ let(:test_files) do
7
+ [
8
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
9
+ { 'path' => 'spec/b_spec.rb', 'time_execution' => 2.2 },
10
+ ]
11
+ end
12
+
13
+ it do
14
+ expect(subject).to eq([
15
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
16
+ { 'path' => 'spec/b_spec.rb', 'time_execution' => 2.2 },
17
+ ])
18
+ end
19
+ end
20
+
21
+ context 'when test files have test example paths' do
22
+ let(:test_files) do
23
+ [
24
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
25
+ # test example paths
26
+ { 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
27
+ { 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
28
+ ]
29
+ end
30
+
31
+ it 'returns merged paths for test examples and sum of their time_execution' do
32
+ expect(subject).to eq([
33
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
34
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 3.0 },
35
+ ])
36
+ end
37
+ end
38
+
39
+ context 'when test files have test example paths and at the same time test file path for test example path is present as full test file path' do
40
+ let(:test_files) do
41
+ [
42
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
43
+ # full test file path is present despite existing test example paths
44
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 1.0 },
45
+ # test example paths
46
+ { 'path' => 'spec/test_case_spec.rb[1:1]', 'time_execution' => 2.2 },
47
+ { 'path' => 'spec/test_case_spec.rb[1:2]', 'time_execution' => 0.8 },
48
+ ]
49
+ end
50
+
51
+ it 'returns merged paths for test examples and sum of their time_execution' do
52
+ expect(subject).to eq([
53
+ { 'path' => 'spec/a_spec.rb', 'time_execution' => 1.1 },
54
+ { 'path' => 'spec/test_case_spec.rb', 'time_execution' => 4.0 },
55
+ ])
56
+ end
57
+ end
58
+ end
59
+ end