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
@@ -38,4 +38,35 @@ describe KnapsackPro::Client::API::V1::BuildDistributions do
38
38
  expect(subject).to eq action
39
39
  end
40
40
  end
41
+
42
+ describe '.last' do
43
+ let(:commit_hash) { double }
44
+ let(:branch) { double }
45
+ let(:node_total) { double }
46
+ let(:node_index) { double }
47
+
48
+ subject do
49
+ described_class.last(
50
+ commit_hash: commit_hash,
51
+ branch: branch,
52
+ node_total: node_total,
53
+ node_index: node_index,
54
+ )
55
+ end
56
+
57
+ it do
58
+ action = double
59
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with({
60
+ endpoint_path: '/v1/build_distributions/last',
61
+ http_method: :get,
62
+ request_hash: {
63
+ commit_hash: commit_hash,
64
+ branch: branch,
65
+ node_total: node_total,
66
+ node_index: node_index,
67
+ }
68
+ }).and_return(action)
69
+ expect(subject).to eq action
70
+ end
71
+ end
41
72
  end
@@ -1,167 +1,298 @@
1
+ shared_examples 'when request got response from API' do
2
+ context 'when body response is JSON and API response code is 400' do
3
+ let(:body) { '{"errors": "value"}' }
4
+ let(:code) { '400' } # it must be string code
5
+
6
+ before do
7
+ expect(KnapsackPro).to receive(:logger).exactly(4).and_return(logger)
8
+ expect(logger).to receive(:debug).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
9
+ expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
10
+ expect(logger).to receive(:debug).with('API response:')
11
+ end
12
+
13
+ it do
14
+ parsed_response = { 'errors' => 'value' }
15
+
16
+ expect(logger).to receive(:error).with(parsed_response)
17
+
18
+ expect(subject).to eq(parsed_response)
19
+ expect(connection.success?).to be true
20
+ expect(connection.errors?).to be true
21
+ end
22
+ end
23
+
24
+ context 'when body response is JSON with build_distribution_id' do
25
+ let(:body) { '{"build_distribution_id": "seed-uuid"}' }
26
+ let(:code) { '200' } # it must be string code
27
+
28
+ before do
29
+ expect(KnapsackPro).to receive(:logger).exactly(5).and_return(logger)
30
+ expect(logger).to receive(:debug).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
31
+ expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
32
+ expect(logger).to receive(:debug).with("Test suite split seed: seed-uuid")
33
+ expect(logger).to receive(:debug).with('API response:')
34
+ end
35
+
36
+ it do
37
+ parsed_response = { 'build_distribution_id' => 'seed-uuid' }
38
+
39
+ expect(logger).to receive(:debug).with(parsed_response)
40
+
41
+ expect(subject).to eq(parsed_response)
42
+ expect(connection.success?).to be true
43
+ expect(connection.errors?).to be false
44
+ end
45
+ end
46
+
47
+ context 'when body response is empty' do
48
+ let(:body) { '' }
49
+ let(:code) { '200' } # it must be string code
50
+
51
+ before do
52
+ expect(KnapsackPro).to receive(:logger).exactly(4).and_return(logger)
53
+ expect(logger).to receive(:debug).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
54
+ expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
55
+ expect(logger).to receive(:debug).with('API response:')
56
+ end
57
+
58
+ it do
59
+ expect(logger).to receive(:debug).with('')
60
+
61
+ expect(subject).to eq('')
62
+ expect(connection.success?).to be true
63
+ expect(connection.errors?).to be false
64
+ end
65
+ end
66
+ end
67
+
68
+ shared_examples 'when retry request' do
69
+ context 'when body response is JSON and API response code is 500' do
70
+ let(:body) { '{"error": "Internal Server Error"}' }
71
+ let(:code) { '500' } # it must be string code
72
+
73
+ before do
74
+ expect(KnapsackPro).to receive(:logger).at_least(1).and_return(logger)
75
+ end
76
+
77
+ it do
78
+ expect(logger).to receive(:debug).exactly(3).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
79
+ expect(logger).to receive(:debug).exactly(3).with('API request UUID: fake-uuid')
80
+ expect(logger).to receive(:debug).exactly(3).with('API response:')
81
+
82
+ parsed_response = { 'error' => 'Internal Server Error' }
83
+
84
+ expect(logger).to receive(:error).exactly(3).with(parsed_response)
85
+
86
+ server_error = described_class::ServerError.new(parsed_response)
87
+ expect(logger).to receive(:warn).exactly(3).with(server_error.inspect)
88
+
89
+ expect(logger).to receive(:warn).with("Wait 8s and retry request to Knapsack Pro API.")
90
+ expect(logger).to receive(:warn).with("Next request in 8s...")
91
+ expect(logger).to receive(:warn).with("Next request in 6s...")
92
+ expect(logger).to receive(:warn).with("Next request in 4s...")
93
+ expect(logger).to receive(:warn).with("Next request in 2s...")
94
+ expect(logger).to receive(:warn).with("Wait 16s and retry request to Knapsack Pro API.")
95
+ expect(logger).to receive(:warn).with("Next request in 16s...")
96
+ expect(logger).to receive(:warn).with("Next request in 14s...")
97
+ expect(logger).to receive(:warn).with("Next request in 12s...")
98
+ expect(logger).to receive(:warn).with("Next request in 10s...")
99
+ expect(logger).to receive(:warn).with("Next request in 8s...")
100
+ expect(logger).to receive(:warn).with("Next request in 6s...")
101
+ expect(logger).to receive(:warn).with("Next request in 4s...")
102
+ expect(logger).to receive(:warn).with("Next request in 2s...")
103
+ expect(Kernel).to receive(:sleep).exactly(12).with(2)
104
+
105
+ expect(subject).to eq(parsed_response)
106
+
107
+ expect(connection.success?).to be false
108
+ expect(connection.errors?).to be true
109
+ end
110
+
111
+ context 'when Fallback Mode is disabled' do
112
+ before do
113
+ expect(KnapsackPro::Config::Env).to receive(:fallback_mode_enabled?).at_least(1).and_return(false)
114
+ end
115
+
116
+ it do
117
+ expect(logger).to receive(:debug).exactly(6).with("#{expected_http_method} http://api.knapsackpro.test:3000/v1/fake_endpoint")
118
+ expect(logger).to receive(:debug).exactly(6).with('API request UUID: fake-uuid')
119
+ expect(logger).to receive(:debug).exactly(6).with('API response:')
120
+
121
+ parsed_response = { 'error' => 'Internal Server Error' }
122
+
123
+ expect(logger).to receive(:error).exactly(6).with(parsed_response)
124
+
125
+ server_error = described_class::ServerError.new(parsed_response)
126
+ expect(logger).to receive(:warn).exactly(6).with(server_error.inspect)
127
+
128
+ expect(logger).to receive(:warn).with("Wait 8s and retry request to Knapsack Pro API.")
129
+ expect(logger).to receive(:warn).with("Next request in 8s...")
130
+ expect(logger).to receive(:warn).with("Next request in 6s...")
131
+ expect(logger).to receive(:warn).with("Next request in 4s...")
132
+ expect(logger).to receive(:warn).with("Next request in 2s...")
133
+
134
+ expect(logger).to receive(:warn).with("Wait 16s and retry request to Knapsack Pro API.")
135
+ expect(logger).to receive(:warn).with("Next request in 16s...")
136
+ expect(logger).to receive(:warn).with("Next request in 14s...")
137
+ expect(logger).to receive(:warn).with("Next request in 12s...")
138
+ expect(logger).to receive(:warn).with("Next request in 10s...")
139
+ expect(logger).to receive(:warn).with("Next request in 8s...")
140
+ expect(logger).to receive(:warn).with("Next request in 6s...")
141
+ expect(logger).to receive(:warn).with("Next request in 4s...")
142
+ expect(logger).to receive(:warn).with("Next request in 2s...")
143
+
144
+ expect(logger).to receive(:warn).with("Wait 24s and retry request to Knapsack Pro API.")
145
+ 12.times do |i|
146
+ expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
147
+ end
148
+
149
+ expect(logger).to receive(:warn).with("Wait 32s and retry request to Knapsack Pro API.")
150
+ 16.times do |i|
151
+ expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
152
+ end
153
+
154
+ expect(logger).to receive(:warn).with("Wait 40s and retry request to Knapsack Pro API.")
155
+ 20.times do |i|
156
+ expect(logger).to receive(:warn).with("Next request in #{(i+1)*2}s...")
157
+ end
158
+
159
+ expect(Kernel).to receive(:sleep).exactly(60).with(2)
160
+
161
+ expect(subject).to eq(parsed_response)
162
+
163
+ expect(connection.success?).to be false
164
+ expect(connection.errors?).to be true
165
+ end
166
+ end
167
+ end
168
+ end
169
+
1
170
  describe KnapsackPro::Client::Connection do
2
171
  let(:endpoint_path) { '/v1/fake_endpoint' }
3
- let(:http_method) { :post }
4
172
  let(:request_hash) { { fake: 'hash' } }
173
+ let(:http_method) { :post }
5
174
  let(:action) do
6
175
  instance_double(KnapsackPro::Client::API::Action,
7
176
  endpoint_path: endpoint_path,
8
177
  http_method: http_method,
9
178
  request_hash: request_hash)
10
179
  end
180
+ let(:test_suite_token) { '3fa64859337f6e56409d49f865d13fd7' }
11
181
 
12
182
  let(:connection) { described_class.new(action) }
13
183
 
14
184
  before do
15
185
  stub_const('ENV', {
16
186
  'KNAPSACK_PRO_ENDPOINT' => 'http://api.knapsackpro.test:3000',
17
- 'KNAPSACK_PRO_TEST_SUITE_TOKEN' => '3fa64859337f6e56409d49f865d13fd7',
187
+ 'KNAPSACK_PRO_TEST_SUITE_TOKEN' => test_suite_token,
18
188
  })
19
189
  end
20
190
 
21
191
  describe '#call' do
22
192
  let(:logger) { instance_double(Logger) }
193
+ let(:http) { instance_double(Net::HTTP) }
194
+ let(:http_response) do
195
+ header = { 'X-Request-Id' => 'fake-uuid' }
196
+ instance_double(Net::HTTPOK, body: body, header: header, code: code)
197
+ end
23
198
 
24
199
  subject { connection.call }
25
200
 
26
- context 'when http method is POST' do
27
- before do
28
- http = instance_double(Net::HTTP)
201
+ before do
202
+ expect(Net::HTTP).to receive(:new).with('api.knapsackpro.test', 3000).and_return(http)
29
203
 
30
- expect(Net::HTTP).to receive(:new).with('api.knapsackpro.test', 3000).and_return(http)
204
+ expect(http).to receive(:use_ssl=).with(false)
205
+ expect(http).to receive(:open_timeout=).with(15)
206
+ expect(http).to receive(:read_timeout=).with(15)
207
+ end
31
208
 
32
- expect(http).to receive(:use_ssl=).with(false)
33
- expect(http).to receive(:open_timeout=).with(15)
34
- expect(http).to receive(:read_timeout=).with(15)
209
+ context 'when http method is POST' do
210
+ let(:http_method) { :post }
35
211
 
36
- header = { 'X-Request-Id' => 'fake-uuid' }
37
- http_response = instance_double(Net::HTTPOK, body: body, header: header, code: code)
212
+ before do
38
213
  expect(http).to receive(:post).with(
39
214
  endpoint_path,
40
- "{\"fake\":\"hash\",\"test_suite_token\":\"3fa64859337f6e56409d49f865d13fd7\"}",
215
+ request_hash.to_json,
41
216
  {
42
217
  'Content-Type' => 'application/json',
43
218
  'Accept' => 'application/json',
44
219
  'KNAPSACK-PRO-CLIENT-NAME' => 'knapsack_pro-ruby',
45
220
  'KNAPSACK-PRO-CLIENT-VERSION' => KnapsackPro::VERSION,
221
+ 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => test_suite_token,
46
222
  }
47
223
  ).and_return(http_response)
48
224
  end
49
225
 
50
- context 'when body response is json and API response code is 400' do
51
- let(:body) { '{"errors": "value"}' }
52
- let(:code) { '400' } # it must be string code
53
-
54
- before do
55
- expect(KnapsackPro).to receive(:logger).exactly(3).and_return(logger)
56
- expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
57
- expect(logger).to receive(:debug).with('API response:')
58
- end
59
-
60
- it do
61
- parsed_response = { 'errors' => 'value' }
62
-
63
- expect(logger).to receive(:error).with(parsed_response)
64
-
65
- expect(subject).to eq(parsed_response)
66
- expect(connection.success?).to be true
67
- expect(connection.errors?).to be true
68
- end
226
+ it_behaves_like 'when request got response from API' do
227
+ let(:expected_http_method) { 'POST' }
69
228
  end
229
+ end
70
230
 
71
- context 'when body response is json with build_distribution_id' do
72
- let(:body) { '{"build_distribution_id": "seed-uuid"}' }
73
- let(:code) { '200' } # it must be string code
74
-
75
- before do
76
- expect(KnapsackPro).to receive(:logger).exactly(4).and_return(logger)
77
- expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
78
- expect(logger).to receive(:debug).with("Test suite split seed: seed-uuid")
79
- expect(logger).to receive(:debug).with('API response:')
80
- end
81
-
82
- it do
83
- parsed_response = { 'build_distribution_id' => 'seed-uuid' }
84
-
85
- expect(logger).to receive(:debug).with(parsed_response)
231
+ context 'when http method is GET' do
232
+ let(:http_method) { :get }
86
233
 
87
- expect(subject).to eq(parsed_response)
88
- expect(connection.success?).to be true
89
- expect(connection.errors?).to be false
90
- end
234
+ before do
235
+ uri = URI.parse("http://api.knapsackpro.test:3000#{endpoint_path}")
236
+ uri.query = URI.encode_www_form(request_hash)
237
+ expect(http).to receive(:get).with(
238
+ uri,
239
+ {
240
+ 'Content-Type' => 'application/json',
241
+ 'Accept' => 'application/json',
242
+ 'KNAPSACK-PRO-CLIENT-NAME' => 'knapsack_pro-ruby',
243
+ 'KNAPSACK-PRO-CLIENT-VERSION' => KnapsackPro::VERSION,
244
+ 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => test_suite_token,
245
+ }
246
+ ).and_return(http_response)
91
247
  end
92
248
 
93
- context 'when body response is empty' do
94
- let(:body) { '' }
95
- let(:code) { '200' } # it must be string code
96
-
97
- before do
98
- expect(KnapsackPro).to receive(:logger).exactly(3).and_return(logger)
99
- expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
100
- expect(logger).to receive(:debug).with('API response:')
101
- end
102
-
103
- it do
104
- expect(logger).to receive(:debug).with('')
105
-
106
- expect(subject).to eq('')
107
- expect(connection.success?).to be true
108
- expect(connection.errors?).to be false
109
- end
249
+ it_behaves_like 'when request got response from API' do
250
+ let(:expected_http_method) { 'GET' }
110
251
  end
111
252
  end
112
253
 
113
254
  context 'when retry request for http method POST' do
114
- before do
115
- http = instance_double(Net::HTTP)
116
-
117
- expect(Net::HTTP).to receive(:new).exactly(3).with('api.knapsackpro.test', 3000).and_return(http)
255
+ let(:http_method) { :post }
118
256
 
119
- expect(http).to receive(:use_ssl=).exactly(3).with(false)
120
- expect(http).to receive(:open_timeout=).exactly(3).with(15)
121
- expect(http).to receive(:read_timeout=).exactly(3).with(15)
122
-
123
- header = { 'X-Request-Id' => 'fake-uuid' }
124
- http_response = instance_double(Net::HTTPOK, body: body, header: header, code: code)
125
- expect(http).to receive(:post).exactly(3).with(
257
+ before do
258
+ expect(http).to receive(:post).at_least(3).with(
126
259
  endpoint_path,
127
- "{\"fake\":\"hash\",\"test_suite_token\":\"3fa64859337f6e56409d49f865d13fd7\"}",
260
+ request_hash.to_json,
128
261
  {
129
262
  'Content-Type' => 'application/json',
130
263
  'Accept' => 'application/json',
131
264
  'KNAPSACK-PRO-CLIENT-NAME' => 'knapsack_pro-ruby',
132
265
  'KNAPSACK-PRO-CLIENT-VERSION' => KnapsackPro::VERSION,
266
+ 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => test_suite_token,
133
267
  }
134
268
  ).and_return(http_response)
135
269
  end
136
270
 
137
- context 'when body response is json and API response code is 500' do
138
- let(:body) { '{"error": "Internal Server Error"}' }
139
- let(:code) { '500' } # it must be string code
140
-
141
- before do
142
- expect(KnapsackPro).to receive(:logger).at_least(1).and_return(logger)
143
- expect(logger).to receive(:debug).exactly(3).with('API request UUID: fake-uuid')
144
- expect(logger).to receive(:debug).exactly(3).with('API response:')
145
- end
146
-
147
- it do
148
- parsed_response = { 'error' => 'Internal Server Error' }
149
-
150
- expect(logger).to receive(:error).exactly(3).with(parsed_response)
151
-
152
- server_error = described_class::ServerError.new(parsed_response)
153
- expect(logger).to receive(:warn).exactly(3).with(server_error.inspect)
271
+ it_behaves_like 'when retry request' do
272
+ let(:expected_http_method) { 'POST' }
273
+ end
274
+ end
154
275
 
155
- expect(logger).to receive(:warn).with("Wait 4s and retry request to Knapsack Pro API.")
156
- expect(logger).to receive(:warn).with("Wait 8s and retry request to Knapsack Pro API.")
157
- expect(Kernel).to receive(:sleep).with(4)
158
- expect(Kernel).to receive(:sleep).with(8)
276
+ context 'when retry request for http method GET' do
277
+ let(:http_method) { :get }
159
278
 
160
- expect(subject).to eq(parsed_response)
279
+ before do
280
+ uri = URI.parse("http://api.knapsackpro.test:3000#{endpoint_path}")
281
+ uri.query = URI.encode_www_form(request_hash)
282
+ expect(http).to receive(:get).at_least(3).with(
283
+ uri,
284
+ {
285
+ 'Content-Type' => 'application/json',
286
+ 'Accept' => 'application/json',
287
+ 'KNAPSACK-PRO-CLIENT-NAME' => 'knapsack_pro-ruby',
288
+ 'KNAPSACK-PRO-CLIENT-VERSION' => KnapsackPro::VERSION,
289
+ 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => test_suite_token,
290
+ }
291
+ ).and_return(http_response)
292
+ end
161
293
 
162
- expect(connection.success?).to be false
163
- expect(connection.errors?).to be true
164
- end
294
+ it_behaves_like 'when retry request' do
295
+ let(:expected_http_method) { 'GET' }
165
296
  end
166
297
  end
167
298
  end
@@ -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