knapsack_pro 1.20.2 → 1.22.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/README.md +43 -18
  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/runners/queue/rspec_runner.rb +8 -1
  17. data/lib/knapsack_pro/runners/rspec_runner.rb +5 -2
  18. data/lib/knapsack_pro/slow_test_file_determiner.rb +33 -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 +26 -7
  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 +235 -104
  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/queue/rspec_runner_spec.rb +25 -0
  38. data/spec/knapsack_pro/runners/rspec_runner_spec.rb +4 -4
  39. data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +74 -0
  40. data/spec/knapsack_pro/slow_test_file_finder_spec.rb +43 -0
  41. data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +83 -37
  42. data/spec/knapsack_pro/test_case_mergers/base_merger_spec.rb +27 -0
  43. data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +59 -0
  44. data/spec/knapsack_pro/test_file_finder_spec.rb +105 -29
  45. data/spec/knapsack_pro/test_files_with_test_cases_composer_spec.rb +41 -0
  46. metadata +27 -10
@@ -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.2'
2
+ VERSION = '1.22.3'
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