knapsack_pro 1.20.1 → 1.22.2

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/README.md +42 -17
  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 +38 -16
  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/report.rb +1 -1
  17. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +10 -1
  18. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +7 -0
  19. data/lib/knapsack_pro/runners/rspec_runner.rb +5 -2
  20. data/lib/knapsack_pro/slow_test_file_determiner.rb +33 -0
  21. data/lib/knapsack_pro/slow_test_file_finder.rb +27 -0
  22. data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +26 -7
  23. data/lib/knapsack_pro/test_case_mergers/base_merger.rb +29 -0
  24. data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +34 -0
  25. data/lib/knapsack_pro/test_file_finder.rb +43 -5
  26. data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +22 -0
  27. data/lib/knapsack_pro/version.rb +1 -1
  28. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +55 -0
  29. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +61 -25
  30. data/spec/knapsack_pro/allocator_builder_spec.rb +7 -3
  31. data/spec/knapsack_pro/allocator_spec.rb +7 -5
  32. data/spec/knapsack_pro/base_allocator_builder_spec.rb +79 -27
  33. data/spec/knapsack_pro/build_distribution_fetcher_spec.rb +89 -0
  34. data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +31 -0
  35. data/spec/knapsack_pro/client/connection_spec.rb +235 -104
  36. data/spec/knapsack_pro/config/env_spec.rb +14 -0
  37. data/spec/knapsack_pro/queue_allocator_builder_spec.rb +7 -3
  38. data/spec/knapsack_pro/queue_allocator_spec.rb +7 -5
  39. data/spec/knapsack_pro/report_spec.rb +1 -1
  40. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +38 -25
  41. data/spec/knapsack_pro/runners/rspec_runner_spec.rb +4 -4
  42. data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +74 -0
  43. data/spec/knapsack_pro/slow_test_file_finder_spec.rb +43 -0
  44. data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +83 -37
  45. data/spec/knapsack_pro/test_case_mergers/base_merger_spec.rb +27 -0
  46. data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +59 -0
  47. data/spec/knapsack_pro/test_file_finder_spec.rb +105 -29
  48. data/spec/knapsack_pro/test_files_with_test_cases_composer_spec.rb +41 -0
  49. metadata +20 -2
@@ -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
@@ -1,3 +1,3 @@
1
1
  module KnapsackPro
2
- VERSION = '1.20.1'
2
+ VERSION = '1.22.2'
3
3
  end
@@ -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
- it do
122
- expect(config).to receive(:around).with(:each).and_yield(example)
123
- expect(config).to receive(:after).with(:suite).and_yield
124
- expect(::RSpec).to receive(:configure).and_yield(config)
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
- expect(example).to receive(:id).and_return(test_example_path)
124
+ it 'records time for example.id' do
125
+ expect(example).to receive(:id).and_return(test_example_path)
127
126
 
128
- allow(KnapsackPro).to receive(:tracker).and_return(tracker)
129
- expect(tracker).to receive(:current_test_path=).with(test_example_path)
130
- expect(tracker).to receive(:start_timer)
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
- expect(example).to receive(:run)
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
- expect(tracker).to receive(:stop_timer)
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
- expect(KnapsackPro::Presenter).to receive(:global_time).and_return(global_time)
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
- subject.bind_time_tracker
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
@@ -8,8 +8,11 @@ describe KnapsackPro::AllocatorBuilder 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)
@@ -20,7 +23,8 @@ describe KnapsackPro::AllocatorBuilder do
20
23
  expect(KnapsackPro::Config::Env).to receive(:ci_node_index).and_return(ci_node_index)
21
24
 
22
25
  expect(KnapsackPro::Allocator).to receive(:new).with(
23
- test_files: test_files,
26
+ fast_and_slow_test_files_to_run: fast_and_slow_test_files_to_run,
27
+ fallback_mode_test_files: fallback_mode_test_files,
24
28
  ci_node_total: ci_node_total,
25
29
  ci_node_index: ci_node_index,
26
30
  repository_adapter: repository_adapter,
@@ -1,12 +1,14 @@
1
1
  describe KnapsackPro::Allocator 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(:repository_adapter) { instance_double(KnapsackPro::RepositoryAdapters::EnvAdapter, commit_hash: double, branch: double) }
6
7
 
7
8
  let(:allocator) do
8
9
  described_class.new(
9
- test_files: test_files,
10
+ fast_and_slow_test_files_to_run: fast_and_slow_test_files_to_run,
11
+ fallback_mode_test_files: fallback_mode_test_files,
10
12
  ci_node_total: ci_node_total,
11
13
  ci_node_index: ci_node_index,
12
14
  repository_adapter: repository_adapter
@@ -20,7 +22,7 @@ describe KnapsackPro::Allocator do
20
22
 
21
23
  before do
22
24
  encrypted_test_files = double
23
- expect(KnapsackPro::Crypto::Encryptor).to receive(:call).with(test_files).and_return(encrypted_test_files)
25
+ expect(KnapsackPro::Crypto::Encryptor).to receive(:call).with(fast_and_slow_test_files_to_run).and_return(encrypted_test_files)
24
26
 
25
27
  encrypted_branch = double
26
28
  expect(KnapsackPro::Crypto::BranchEncryptor).to receive(:call).with(repository_adapter.branch).and_return(encrypted_branch)
@@ -64,7 +66,7 @@ describe KnapsackPro::Allocator do
64
66
  end
65
67
 
66
68
  before do
67
- expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(test_files, response['test_files']).and_call_original
69
+ expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(fast_and_slow_test_files_to_run, response['test_files']).and_call_original
68
70
  end
69
71
 
70
72
  it { should eq ['a_spec.rb', 'b_spec.rb'] }
@@ -114,7 +116,7 @@ describe KnapsackPro::Allocator do
114
116
  context 'when fallback mode started' do
115
117
  before do
116
118
  test_flat_distributor = instance_double(KnapsackPro::TestFlatDistributor)
117
- expect(KnapsackPro::TestFlatDistributor).to receive(:new).with(test_files, ci_node_total).and_return(test_flat_distributor)
119
+ expect(KnapsackPro::TestFlatDistributor).to receive(:new).with(fallback_mode_test_files, ci_node_total).and_return(test_flat_distributor)
118
120
  expect(test_flat_distributor).to receive(:test_files_for_node).with(ci_node_index).and_return([
119
121
  { 'path' => 'c_spec.rb' },
120
122
  { 'path' => 'd_spec.rb' },
@@ -100,8 +100,22 @@ describe KnapsackPro::BaseAllocatorBuilder do
100
100
  end
101
101
  end
102
102
 
103
- describe '#test_files' do
104
- subject { allocator_builder.test_files }
103
+ describe '#fallback_mode_test_files' do
104
+ subject { allocator_builder.fallback_mode_test_files }
105
+
106
+ it do
107
+ test_file_pattern = double
108
+ expect(KnapsackPro::TestFilePattern).to receive(:call).with(adapter_class).and_return(test_file_pattern)
109
+
110
+ test_files = double
111
+ expect(KnapsackPro::TestFileFinder).to receive(:call).with(test_file_pattern).and_return(test_files)
112
+
113
+ expect(subject).to eq test_files
114
+ end
115
+ end
116
+
117
+ describe '#fast_and_slow_test_files_to_run' do
118
+ subject { allocator_builder.fast_and_slow_test_files_to_run }
105
119
 
106
120
  context 'when looking for test files on disk by default' do
107
121
  it do
@@ -115,10 +129,10 @@ describe KnapsackPro::BaseAllocatorBuilder do
115
129
  end
116
130
  end
117
131
 
118
- context 'when RSpec adapter and rspec split by test examples is enabled' do
132
+ context 'when RSpec adapter AND rspec split by test examples is enabled' do
119
133
  let(:adapter_class) { KnapsackPro::Adapters::RSpecAdapter }
120
- let(:test_files) { double(size: 1000) }
121
- let(:cmd) { 'bundle exec rake knapsack_pro:rspec_test_example_detector' }
134
+ let(:test_files_to_run) { double }
135
+ let(:cmd) { 'RACK_ENV=test RAILS_ENV=test bundle exec rake knapsack_pro:rspec_test_example_detector' }
122
136
 
123
137
  before do
124
138
  expect(KnapsackPro::Config::Env).to receive(:rspec_split_by_test_examples?).and_return(true)
@@ -126,53 +140,91 @@ describe KnapsackPro::BaseAllocatorBuilder do
126
140
  test_file_pattern = double
127
141
  expect(KnapsackPro::TestFilePattern).to receive(:call).with(adapter_class).and_return(test_file_pattern)
128
142
 
129
- expect(KnapsackPro::TestFileFinder).to receive(:call).with(test_file_pattern).and_return(test_files)
143
+ expect(KnapsackPro::TestFileFinder).to receive(:call).with(test_file_pattern).and_return(test_files_to_run)
144
+ end
145
+
146
+ context 'when RSpec version < 3.3.0' do
147
+ before do
148
+ stub_const('RSpec::Core::Version::STRING', '3.2.0')
149
+ end
130
150
 
131
- expect(Kernel).to receive(:system).with(cmd).and_return(cmd_result)
151
+ it do
152
+ expect { subject }.to raise_error RuntimeError, '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'
153
+ end
132
154
  end
133
155
 
134
156
  context 'when rake task to detect RSpec test examples works' do
157
+ let(:slow_test_files) { double(size: 5) }
135
158
  let(:cmd_result) { true }
136
159
  let(:test_file_example_paths) { double }
137
160
  let(:logger) { instance_double(Logger) }
161
+ let(:test_files_with_test_cases) { double }
138
162
 
139
163
  before do
140
- rspec_test_example_detector = instance_double(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector)
141
- expect(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector).to receive(:new).and_return(rspec_test_example_detector)
142
- expect(rspec_test_example_detector).to receive(:test_file_example_paths).and_return(test_file_example_paths)
164
+ expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
143
165
 
144
- expect(KnapsackPro).to receive(:logger).at_least(1).and_return(logger)
145
- end
166
+ expect(KnapsackPro).to receive(:logger).and_return(logger)
146
167
 
147
- context 'when up to 1000 test files detected on disk' do
148
- let(:test_files) { double(size: 1000) }
168
+ expect(Kernel).to receive(:system).with(cmd).and_return(cmd_result)
149
169
 
150
- it do
151
- expect(logger).to receive(:warn).with("Generating RSpec test examples JSON report to prepare your test suite to be split by test examples (by individual 'it's. Thanks to that a single test file can be split across parallel CI nodes). Analyzing 1000 test files.")
170
+ rspec_test_example_detector = instance_double(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector)
171
+ expect(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector).to receive(:new).and_return(rspec_test_example_detector)
172
+ expect(rspec_test_example_detector).to receive(:test_file_example_paths).and_return(test_file_example_paths)
152
173
 
153
- expect(subject).to eq test_file_example_paths
154
- end
174
+ expect(KnapsackPro::TestFilesWithTestCasesComposer).to receive(:call).with(test_files_to_run, slow_test_files, test_file_example_paths).and_return(test_files_with_test_cases)
155
175
  end
156
176
 
157
- context 'when more than 1000 test files detected on disk' do
158
- let(:test_files) { double(size: 1001) }
159
-
160
- it do
161
- expect(logger).to receive(:warn).with("Generating RSpec test examples JSON report to prepare your test suite to be split by test examples (by individual 'it's. Thanks to that a single test file can be split across parallel CI nodes). Analyzing 1001 test files.")
162
- expect(logger).to receive(:warn).with('You have more than 1000 test files, it may take longer to generate test examples. Please wait...')
177
+ it do
178
+ expect(logger).to receive(:info).with("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 5 slow test files.")
163
179
 
164
- expect(subject).to eq test_file_example_paths
165
- end
180
+ expect(subject).to eq test_files_with_test_cases
166
181
  end
167
182
  end
168
183
 
169
184
  context 'when rake task to detect RSpec test examples failed' do
185
+ let(:slow_test_files) { double(size: 5) }
170
186
  let(:cmd_result) { false }
171
187
 
188
+ before do
189
+ expect(allocator_builder).to receive(:get_slow_test_files).and_return(slow_test_files)
190
+
191
+ expect(Kernel).to receive(:system).with(cmd).and_return(cmd_result)
192
+ end
193
+
172
194
  it do
173
- expect { subject }.to raise_error(RuntimeError, 'Could not generate JSON report for RSpec. Rake task failed when running bundle exec rake knapsack_pro:rspec_test_example_detector')
195
+ expect { subject }.to raise_error(RuntimeError, 'Could not generate JSON report for RSpec. Rake task failed when running RACK_ENV=test RAILS_ENV=test bundle exec rake knapsack_pro:rspec_test_example_detector')
174
196
  end
175
197
  end
176
198
  end
177
199
  end
200
+
201
+ describe 'private #get_slow_test_files' do
202
+ subject { allocator_builder.send(:get_slow_test_files) }
203
+
204
+ before do
205
+ expect(KnapsackPro::Config::Env).to receive(:slow_test_file_pattern).and_return(slow_test_file_pattern)
206
+ end
207
+
208
+ context 'when slow test file pattern is present' do
209
+ let(:slow_test_files) { double(:slow_test_files_based_on_pattern, size: 3) }
210
+ let(:slow_test_file_pattern) { double }
211
+
212
+ before do
213
+ expect(KnapsackPro::TestFileFinder).to receive(:slow_test_files_by_pattern).with(adapter_class).and_return(slow_test_files)
214
+ end
215
+
216
+ it { expect(subject).to eq slow_test_files }
217
+ end
218
+
219
+ context 'when slow test file pattern is not present' do
220
+ let(:slow_test_files) { double(:slow_test_files_based_on_api, size: 2) }
221
+ let(:slow_test_file_pattern) { nil }
222
+
223
+ before do
224
+ expect(KnapsackPro::SlowTestFileFinder).to receive(:call).with(adapter_class).and_return(slow_test_files)
225
+ end
226
+
227
+ it { expect(subject).to eq slow_test_files }
228
+ end
229
+ end
178
230
  end
@@ -0,0 +1,89 @@
1
+ describe KnapsackPro::BuildDistributionFetcher do
2
+ describe '.call' do
3
+ subject { described_class.call }
4
+
5
+ it do
6
+ build_distribution_fetcher = instance_double(described_class)
7
+ expect(described_class).to receive(:new).and_return(build_distribution_fetcher)
8
+ result = double
9
+ expect(build_distribution_fetcher).to receive(:call).and_return(result)
10
+
11
+ expect(subject).to eq result
12
+ end
13
+ end
14
+
15
+ describe '#call' do
16
+ let(:ci_node_total) { double }
17
+ let(:ci_node_index) { double }
18
+ let(:repository_adapter) { instance_double(KnapsackPro::RepositoryAdapters::EnvAdapter, commit_hash: double, branch: double) }
19
+
20
+ subject { described_class.new.call }
21
+
22
+ before do
23
+ expect(KnapsackPro::RepositoryAdapterInitiator).to receive(:call).and_return(repository_adapter)
24
+
25
+ expect(KnapsackPro::Config::Env).to receive(:ci_node_total).and_return(ci_node_total)
26
+ expect(KnapsackPro::Config::Env).to receive(:ci_node_index).and_return(ci_node_index)
27
+
28
+ action = double
29
+ expect(KnapsackPro::Client::API::V1::BuildDistributions).to receive(:last).with({
30
+ commit_hash: repository_adapter.commit_hash,
31
+ branch: repository_adapter.branch,
32
+ node_total: ci_node_total,
33
+ node_index: ci_node_index,
34
+ }).and_return(action)
35
+
36
+ connection = instance_double(KnapsackPro::Client::Connection,
37
+ call: response,
38
+ success?: success?,
39
+ errors?: errors?)
40
+ expect(KnapsackPro::Client::Connection).to receive(:new).with(action).and_return(connection)
41
+ end
42
+
43
+ context 'when successful request to API' do
44
+ let(:success?) { true }
45
+
46
+ context 'when response has errors' do
47
+ let(:errors?) { true }
48
+ let(:response) { 'fake error response' }
49
+
50
+ it do
51
+ expect { subject }.to raise_error(ArgumentError, response)
52
+ end
53
+ end
54
+
55
+ context 'when response has no errors' do
56
+ let(:errors?) { false }
57
+ let(:response) do
58
+ {
59
+ 'build_distribution_id' => 'be2b95b1-1b8b-43a3-9d66-cabebbf135b8',
60
+ 'time_execution' => 2.5,
61
+ 'test_files' => [
62
+ { 'path' => 'a_spec.rb', 'time_execution' => 1.5 },
63
+ { 'path' => 'b_spec.rb', 'time_execution' => 1.0 },
64
+ ]
65
+ }
66
+ end
67
+
68
+ it { expect(subject).to be_a described_class::BuildDistributionEntity }
69
+ it { expect(subject.time_execution).to eq 2.5 }
70
+ it do
71
+ expect(subject.test_files).to eq([
72
+ { 'path' => 'a_spec.rb', 'time_execution' => 1.5 },
73
+ { 'path' => 'b_spec.rb', 'time_execution' => 1.0 },
74
+ ])
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'when not successful request to API' do
80
+ let(:success?) { false }
81
+ let(:errors?) { false }
82
+ let(:response) { double }
83
+
84
+ it { expect(subject).to be_a described_class::BuildDistributionEntity }
85
+ it { expect(subject.time_execution).to eq 0.0 }
86
+ it { expect(subject.test_files).to eq([]) }
87
+ end
88
+ end
89
+ end