knapsack_pro 1.20.0 → 1.22.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) 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 +33 -15
  13. data/lib/knapsack_pro/config/env.rb +4 -0
  14. data/lib/knapsack_pro/formatters/rspec_json_formatter.rb +1 -1
  15. data/lib/knapsack_pro/queue_allocator.rb +7 -5
  16. data/lib/knapsack_pro/queue_allocator_builder.rb +2 -1
  17. data/lib/knapsack_pro/report.rb +1 -1
  18. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +10 -1
  19. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +7 -0
  20. data/lib/knapsack_pro/runners/rspec_runner.rb +5 -2
  21. data/lib/knapsack_pro/slow_test_file_determiner.rb +33 -0
  22. data/lib/knapsack_pro/slow_test_file_finder.rb +27 -0
  23. data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +26 -7
  24. data/lib/knapsack_pro/test_case_mergers/base_merger.rb +29 -0
  25. data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +34 -0
  26. data/lib/knapsack_pro/test_file_finder.rb +43 -5
  27. data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +22 -0
  28. data/lib/knapsack_pro/version.rb +1 -1
  29. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +55 -0
  30. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +61 -25
  31. data/spec/knapsack_pro/allocator_builder_spec.rb +7 -3
  32. data/spec/knapsack_pro/allocator_spec.rb +7 -5
  33. data/spec/knapsack_pro/base_allocator_builder_spec.rb +79 -27
  34. data/spec/knapsack_pro/build_distribution_fetcher_spec.rb +89 -0
  35. data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +31 -0
  36. data/spec/knapsack_pro/client/connection_spec.rb +202 -104
  37. data/spec/knapsack_pro/config/env_spec.rb +14 -0
  38. data/spec/knapsack_pro/queue_allocator_builder_spec.rb +7 -3
  39. data/spec/knapsack_pro/queue_allocator_spec.rb +7 -5
  40. data/spec/knapsack_pro/report_spec.rb +1 -1
  41. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +38 -25
  42. data/spec/knapsack_pro/runners/rspec_runner_spec.rb +4 -4
  43. data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +74 -0
  44. data/spec/knapsack_pro/slow_test_file_finder_spec.rb +43 -0
  45. data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +83 -37
  46. data/spec/knapsack_pro/test_case_mergers/base_merger_spec.rb +27 -0
  47. data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +59 -0
  48. data/spec/knapsack_pro/test_file_finder_spec.rb +105 -29
  49. data/spec/knapsack_pro/test_files_with_test_cases_composer_spec.rb +41 -0
  50. metadata +20 -2
@@ -4,8 +4,8 @@ module KnapsackPro
4
4
  class ServerError < StandardError; end
5
5
 
6
6
  TIMEOUT = 15
7
- MAX_RETRY = 3
8
- REQUEST_RETRY_TIMEBOX = 4
7
+ MAX_RETRY = -> { KnapsackPro::Config::Env.fallback_mode_enabled? ? 3 : 6 }
8
+ REQUEST_RETRY_TIMEBOX = 8
9
9
 
10
10
  def initialize(action)
11
11
  @action = action
@@ -48,11 +48,7 @@ module KnapsackPro
48
48
  end
49
49
 
50
50
  def request_hash
51
- action
52
- .request_hash
53
- .merge({
54
- test_suite_token: test_suite_token
55
- })
51
+ action.request_hash
56
52
  end
57
53
 
58
54
  def request_body
@@ -69,6 +65,7 @@ module KnapsackPro
69
65
  'Accept' => 'application/json',
70
66
  'KNAPSACK-PRO-CLIENT-NAME' => client_name,
71
67
  'KNAPSACK-PRO-CLIENT-VERSION' => KnapsackPro::VERSION,
68
+ 'KNAPSACK-PRO-TEST-SUITE-TOKEN' => test_suite_token,
72
69
  }
73
70
  end
74
71
 
@@ -95,19 +92,15 @@ module KnapsackPro
95
92
  !seed.nil?
96
93
  end
97
94
 
98
- def post
95
+ def make_request(&block)
99
96
  retries ||= 0
100
- uri = URI.parse(endpoint_url)
101
- http = Net::HTTP.new(uri.host, uri.port)
102
- http.use_ssl = (uri.scheme == 'https')
103
- http.open_timeout = TIMEOUT
104
- http.read_timeout = TIMEOUT
105
97
 
106
- @http_response = http.post(uri.path, request_body, json_headers)
98
+ @http_response = block.call
107
99
  @response_body = parse_response_body(http_response.body)
108
100
 
109
101
  request_uuid = http_response.header['X-Request-Id'] || 'N/A'
110
102
 
103
+ logger.debug("#{action.http_method.to_s.upcase} #{endpoint_url}")
111
104
  logger.debug("API request UUID: #{request_uuid}")
112
105
  logger.debug("Test suite split seed: #{seed}") if has_seed?
113
106
  logger.debug('API response:')
@@ -125,7 +118,7 @@ module KnapsackPro
125
118
  rescue ServerError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::EPIPE, EOFError, SocketError, Net::OpenTimeout, Net::ReadTimeout, OpenSSL::SSL::SSLError => e
126
119
  logger.warn(e.inspect)
127
120
  retries += 1
128
- if retries < MAX_RETRY
121
+ if retries < MAX_RETRY.call
129
122
  wait = retries * REQUEST_RETRY_TIMEBOX
130
123
  logger.warn("Wait #{wait}s and retry request to Knapsack Pro API.")
131
124
  Kernel.sleep(wait)
@@ -134,6 +127,31 @@ module KnapsackPro
134
127
  response_body
135
128
  end
136
129
  end
130
+
131
+ def build_http(uri)
132
+ http = Net::HTTP.new(uri.host, uri.port)
133
+ http.use_ssl = (uri.scheme == 'https')
134
+ http.open_timeout = TIMEOUT
135
+ http.read_timeout = TIMEOUT
136
+ http
137
+ end
138
+
139
+ def post
140
+ uri = URI.parse(endpoint_url)
141
+ http = build_http(uri)
142
+ make_request do
143
+ http.post(uri.path, request_body, json_headers)
144
+ end
145
+ end
146
+
147
+ def get
148
+ uri = URI.parse(endpoint_url)
149
+ uri.query = URI.encode_www_form(request_hash)
150
+ http = build_http(uri)
151
+ make_request do
152
+ http.get(uri, json_headers)
153
+ end
154
+ end
137
155
  end
138
156
  end
139
157
  end
@@ -55,6 +55,10 @@ module KnapsackPro
55
55
  ENV['KNAPSACK_PRO_TEST_FILE_PATTERN']
56
56
  end
57
57
 
58
+ def slow_test_file_pattern
59
+ ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN']
60
+ end
61
+
58
62
  def test_file_exclude_pattern
59
63
  ENV['KNAPSACK_PRO_TEST_FILE_EXCLUDE_PATTERN']
60
64
  end
@@ -4,7 +4,7 @@ RSpec::Support.require_rspec_core('formatters/json_formatter')
4
4
  module KnapsackPro
5
5
  module Formatters
6
6
  class RSpecJsonFormatter < RSpec::Core::Formatters::JsonFormatter
7
- RSpec::Core::Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :seed, :close
7
+ RSpec::Core::Formatters.register self
8
8
 
9
9
  private
10
10
 
@@ -1,7 +1,8 @@
1
1
  module KnapsackPro
2
2
  class QueueAllocator
3
3
  def initialize(args)
4
- @test_files = args.fetch(:test_files)
4
+ @fast_and_slow_test_files_to_run = args.fetch(:fast_and_slow_test_files_to_run)
5
+ @fallback_mode_test_files = args.fetch(:fallback_mode_test_files)
5
6
  @ci_node_total = args.fetch(:ci_node_total)
6
7
  @ci_node_index = args.fetch(:ci_node_index)
7
8
  @ci_node_build_id = args.fetch(:ci_node_build_id)
@@ -36,14 +37,15 @@ module KnapsackPro
36
37
 
37
38
  private
38
39
 
39
- attr_reader :test_files,
40
+ attr_reader :fast_and_slow_test_files_to_run,
41
+ :fallback_mode_test_files,
40
42
  :ci_node_total,
41
43
  :ci_node_index,
42
44
  :ci_node_build_id,
43
45
  :repository_adapter
44
46
 
45
47
  def encrypted_test_files
46
- KnapsackPro::Crypto::Encryptor.call(test_files)
48
+ KnapsackPro::Crypto::Encryptor.call(fast_and_slow_test_files_to_run)
47
49
  end
48
50
 
49
51
  def encrypted_branch
@@ -63,12 +65,12 @@ module KnapsackPro
63
65
  end
64
66
 
65
67
  def prepare_test_files(response)
66
- decrypted_test_files = KnapsackPro::Crypto::Decryptor.call(test_files, response['test_files'])
68
+ decrypted_test_files = KnapsackPro::Crypto::Decryptor.call(fast_and_slow_test_files_to_run, response['test_files'])
67
69
  KnapsackPro::TestFilePresenter.paths(decrypted_test_files)
68
70
  end
69
71
 
70
72
  def fallback_test_files(executed_test_files)
71
- test_flat_distributor = KnapsackPro::TestFlatDistributor.new(test_files, ci_node_total)
73
+ test_flat_distributor = KnapsackPro::TestFlatDistributor.new(fallback_mode_test_files, ci_node_total)
72
74
  test_files_for_node_index = test_flat_distributor.test_files_for_node(ci_node_index)
73
75
  KnapsackPro::TestFilePresenter.paths(test_files_for_node_index) - executed_test_files
74
76
  end
@@ -2,7 +2,8 @@ module KnapsackPro
2
2
  class QueueAllocatorBuilder < BaseAllocatorBuilder
3
3
  def allocator
4
4
  KnapsackPro::QueueAllocator.new(
5
- test_files: test_files,
5
+ fast_and_slow_test_files_to_run: fast_and_slow_test_files_to_run,
6
+ fallback_mode_test_files: fallback_mode_test_files,
6
7
  ci_node_total: env.ci_node_total,
7
8
  ci_node_index: env.ci_node_index,
8
9
  ci_node_build_id: env.ci_node_build_id,
@@ -37,7 +37,7 @@ module KnapsackPro
37
37
  if test_files.empty?
38
38
  KnapsackPro.logger.warn("No test files were executed on this CI node.")
39
39
  KnapsackPro.logger.debug("When you use knapsack_pro queue mode then probably reason might be that CI node was started after the test files from the queue were already executed by other CI nodes. That is why this CI node has no test files to execute.")
40
- KnapsackPro.logger.debug("Another reason might be when your CI node failed in a way that prevented knapsack_pro to save time execution data to Knapsack Pro API and you have just tried to retry failed CI node but instead you got no test files to execute. In that case knapsack_pro don't know what testes should be executed here.")
40
+ KnapsackPro.logger.debug("Another reason might be when your CI node failed in a way that prevented knapsack_pro to save time execution data to Knapsack Pro API and you have just tried to retry failed CI node but instead you got no test files to execute. In that case knapsack_pro don't know what tests should be executed here.")
41
41
  end
42
42
 
43
43
  measured_test_files = test_files
@@ -91,7 +91,16 @@ module KnapsackPro
91
91
  # which is defined in lib/knapsack_pro/adapters/cucumber_adapter.rb
92
92
  ENV['KNAPSACK_PRO_BEFORE_QUEUE_HOOK_CALLED'] = 'true'
93
93
 
94
- $?.exitstatus
94
+ process_status = $?
95
+
96
+ unless process_status.exited?
97
+ raise "Cucumber process execution failed. It's likely that your CI server has exceeded"\
98
+ " its available memory. Please try changing CI config or retrying the CI build.\n"\
99
+ "Failed command: #{cmd}\n"\
100
+ "Process status: #{process_status.inspect}"
101
+ end
102
+
103
+ process_status.exitstatus
95
104
  end
96
105
  end
97
106
  end
@@ -134,6 +134,13 @@ module KnapsackPro
134
134
  RSpec.world.example_groups.clear
135
135
  RSpec.configuration.start_time = ::RSpec::Core::Time.now
136
136
 
137
+ if KnapsackPro::Config::Env.rspec_split_by_test_examples?
138
+ # Reset example group counts to ensure scoped example ids in metadata
139
+ # have correct index (not increased by each subsequent run).
140
+ # Solves this problem: https://github.com/rspec/rspec-core/issues/2721
141
+ RSpec.world.instance_variable_set(:@example_group_counts_by_spec_file, Hash.new(0))
142
+ end
143
+
137
144
  # skip reset filters for old RSpec versions
138
145
  if RSpec.configuration.respond_to?(:reset_filters)
139
146
  RSpec.configuration.reset_filters
@@ -16,8 +16,11 @@ module KnapsackPro
16
16
  end
17
17
 
18
18
  RSpec::Core::RakeTask.new(task_name) do |t|
19
- t.rspec_opts = "#{args} --default-path #{runner.test_dir}"
20
- t.pattern = runner.test_file_paths
19
+ # we cannot pass runner.test_file_paths array to t.pattern
20
+ # because pattern does not accept test example path like spec/a_spec.rb[1:2]
21
+ # instead we pass test files and test example paths to t.rspec_opts
22
+ t.pattern = []
23
+ t.rspec_opts = "#{args} --default-path #{runner.test_dir} #{runner.stringify_test_file_paths}"
21
24
  end
22
25
  Rake::Task[task_name].invoke
23
26
  end
@@ -0,0 +1,33 @@
1
+ module KnapsackPro
2
+ class SlowTestFileDeterminer
3
+ TIME_THRESHOLD_PER_CI_NODE = 0.7 # 70%
4
+ REPORT_DIR = 'tmp/knapsack_pro/slow_test_file_determiner'
5
+
6
+ # test_files: { 'path' => 'a_spec.rb', 'time_execution' => 0.0 }
7
+ # time_execution: of build distribution (total time of CI build run)
8
+ def self.call(test_files, time_execution)
9
+ time_threshold = (time_execution / KnapsackPro::Config::Env.ci_node_total) * TIME_THRESHOLD_PER_CI_NODE
10
+
11
+ test_files.select do |test_file|
12
+ test_file.fetch('time_execution') >= time_threshold
13
+ end
14
+ end
15
+
16
+ def self.save_to_json_report(test_files)
17
+ FileUtils.mkdir_p(REPORT_DIR)
18
+ File.write(report_path, test_files.to_json)
19
+ end
20
+
21
+ def self.read_from_json_report
22
+ raise 'Report with slow test files was not generated yet. If you have enabled split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases and you see this error it means that your tests accidentally cleaned up tmp/knapsack_pro directory. Please do not remove this directory during tests runtime!' unless File.exists?(report_path)
23
+ slow_test_files_json_report = File.read(report_path)
24
+ JSON.parse(slow_test_files_json_report)
25
+ end
26
+
27
+ private
28
+
29
+ def self.report_path
30
+ "#{REPORT_DIR}/slow_test_files_node_#{KnapsackPro::Config::Env.ci_node_index}.json"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ module KnapsackPro
2
+ class SlowTestFileFinder
3
+ # Get recorded test files from API.
4
+ # Find slow tests among them that are still present on the disk.
5
+ # Save slow test files in json file on the disk.
6
+ # Returns slow test files.
7
+ def self.call(adapter_class)
8
+ if KnapsackPro::Config::Env.test_files_encrypted?
9
+ raise 'Split by test cases is not possible when you have enabled test file names encryption ( https://github.com/KnapsackPro/knapsack_pro-ruby#test-file-names-encryption ). You need to disable encryption with KNAPSACK_PRO_TEST_FILES_ENCRYPTED=false in order to use split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases'
10
+ end
11
+
12
+ # get list of recorded test files for last CI Build
13
+ build_distribution_entity = KnapsackPro::BuildDistributionFetcher.call
14
+ test_files_from_api = build_distribution_entity.test_files
15
+
16
+ merged_test_files_from_api = KnapsackPro::TestCaseMergers::BaseMerger.call(adapter_class, test_files_from_api)
17
+
18
+ test_files_existing_on_disk = KnapsackPro::TestFileFinder.select_test_files_that_can_be_run(adapter_class, merged_test_files_from_api)
19
+
20
+ slow_test_files = KnapsackPro::SlowTestFileDeterminer.call(test_files_existing_on_disk, build_distribution_entity.time_execution)
21
+
22
+ KnapsackPro::SlowTestFileDeterminer.save_to_json_report(slow_test_files)
23
+
24
+ slow_test_files
25
+ end
26
+ end
27
+ end
@@ -2,7 +2,6 @@ module KnapsackPro
2
2
  module TestCaseDetectors
3
3
  class RSpecTestExampleDetector
4
4
  REPORT_DIR = 'tmp/knapsack_pro/test_case_detectors/rspec'
5
- REPORT_PATH = "#{REPORT_DIR}/rspec_dry_run_json_report.json"
6
5
 
7
6
  def generate_json_report
8
7
  require 'rspec/core'
@@ -18,13 +17,19 @@ module KnapsackPro
18
17
  ensure_report_dir_exists
19
18
  remove_old_json_report
20
19
 
21
- test_file_paths = KnapsackPro::TestFileFinder.call(test_file_pattern)
20
+ test_file_entities = slow_test_files
21
+
22
+ if test_file_entities.empty?
23
+ no_examples_json = { examples: [] }.to_json
24
+ File.write(report_path, no_examples_json)
25
+ return
26
+ end
22
27
 
23
28
  cli_args = cli_format + [
24
29
  '--dry-run',
25
- '--out', REPORT_PATH,
30
+ '--out', report_path,
26
31
  '--default-path', test_dir,
27
- ] + test_file_paths.map { |t| t.fetch('path') }
32
+ ] + KnapsackPro::TestFilePresenter.paths(test_file_entities)
28
33
  options = RSpec::Core::ConfigurationOptions.new(cli_args)
29
34
  exit_code = RSpec::Core::Runner.new(options).run($stderr, $stdout)
30
35
  if exit_code != 0
@@ -33,9 +38,9 @@ module KnapsackPro
33
38
  end
34
39
 
35
40
  def test_file_example_paths
36
- raise "No report found at #{REPORT_PATH}" unless File.exists?(REPORT_PATH)
41
+ raise "No report found at #{report_path}" unless File.exists?(report_path)
37
42
 
38
- json_report = File.read(REPORT_PATH)
43
+ json_report = File.read(report_path)
39
44
  hash_report = JSON.parse(json_report)
40
45
  hash_report
41
46
  .fetch('examples')
@@ -43,8 +48,22 @@ module KnapsackPro
43
48
  .map { |path_with_example_id| test_file_hash_for(path_with_example_id) }
44
49
  end
45
50
 
51
+ def slow_test_files
52
+ if KnapsackPro::Config::Env.slow_test_file_pattern
53
+ KnapsackPro::TestFileFinder.slow_test_files_by_pattern(adapter_class)
54
+ else
55
+ # read slow test files from JSON file on disk that was generated
56
+ # by lib/knapsack_pro/base_allocator_builder.rb
57
+ KnapsackPro::SlowTestFileDeterminer.read_from_json_report
58
+ end
59
+ end
60
+
46
61
  private
47
62
 
63
+ def report_path
64
+ "#{REPORT_DIR}/rspec_dry_run_json_report_node_#{KnapsackPro::Config::Env.ci_node_index}.json"
65
+ end
66
+
48
67
  def adapter_class
49
68
  KnapsackPro::Adapters::RSpecAdapter
50
69
  end
@@ -62,7 +81,7 @@ module KnapsackPro
62
81
  end
63
82
 
64
83
  def remove_old_json_report
65
- File.delete(REPORT_PATH) if File.exists?(REPORT_PATH)
84
+ File.delete(report_path) if File.exists?(report_path)
66
85
  end
67
86
 
68
87
  def test_file_hash_for(test_file_path)
@@ -0,0 +1,29 @@
1
+ module KnapsackPro
2
+ module TestCaseMergers
3
+ class BaseMerger
4
+ # values must be string to avoid circular dependency problem during loading files
5
+ ADAPTER_TO_MERGER_MAP = {
6
+ KnapsackPro::Adapters::RSpecAdapter => 'KnapsackPro::TestCaseMergers::RSpecMerger',
7
+ }
8
+
9
+ def self.call(adapter_class, test_files)
10
+ merger_class =
11
+ ADAPTER_TO_MERGER_MAP[adapter_class] ||
12
+ raise("Test case merger does not exist for adapter_class: #{adapter_class}")
13
+ Kernel.const_get(merger_class).new(test_files).call
14
+ end
15
+
16
+ def initialize(test_files)
17
+ @test_files = test_files
18
+ end
19
+
20
+ def call
21
+ raise NotImplementedError
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :test_files
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module KnapsackPro
2
+ module TestCaseMergers
3
+ class RSpecMerger < BaseMerger
4
+ def call
5
+ merged_test_files_hash = {}
6
+ test_files.each do |test_file|
7
+ test_file_path = extract_test_file_path(test_file.fetch('path'))
8
+
9
+ # must be float (default type for time execution from API)
10
+ merged_test_files_hash[test_file_path] ||= 0.0
11
+ merged_test_files_hash[test_file_path] += test_file.fetch('time_execution')
12
+ end
13
+
14
+ merged_test_files = []
15
+ merged_test_files_hash.each do |path, time_execution|
16
+ merged_test_files << {
17
+ 'path' => path,
18
+ 'time_execution' => time_execution
19
+ }
20
+ end
21
+ merged_test_files
22
+ end
23
+
24
+ private
25
+
26
+ # path - can be:
27
+ # test file path: spec/a_spec.rb
28
+ # or test example path: spec/a_spec.rb[1:1]
29
+ def extract_test_file_path(path)
30
+ path.gsub(/\.rb\[.+\]$/, '.rb')
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,11 +1,49 @@
1
1
  module KnapsackPro
2
2
  class TestFileFinder
3
- def self.call(test_file_pattern)
4
- new(test_file_pattern).call
3
+ def self.call(test_file_pattern, test_file_list_enabled: true)
4
+ new(test_file_pattern, test_file_list_enabled).call
5
5
  end
6
6
 
7
- def initialize(test_file_pattern)
7
+ # finds slow test files on disk based on ENV patterns
8
+ # returns example: [{ 'path' => 'a_spec.rb' }]
9
+ def self.slow_test_files_by_pattern(adapter_class)
10
+ raise 'KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN is not defined' unless KnapsackPro::Config::Env.slow_test_file_pattern
11
+
12
+ test_file_pattern = KnapsackPro::TestFilePattern.call(adapter_class)
13
+ test_file_entities = call(test_file_pattern)
14
+
15
+ slow_test_file_entities = call(KnapsackPro::Config::Env.slow_test_file_pattern, test_file_list_enabled: false)
16
+
17
+ # slow test files (KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN)
18
+ # should be subset of test file pattern (KNAPSACK_PRO_TEST_FILE_PATTERN)
19
+ slow_test_file_entities & test_file_entities
20
+ end
21
+
22
+ # Args:
23
+ # test_file_entities_to_run - it can be list of slow test files that you want to run
24
+ # Return:
25
+ # subset of test_file_entities_to_run that are present on disk and it is subset of tests matching pattern KNAPSACK_PRO_TEST_FILE_PATTERN
26
+ # Thanks to that we can select only slow test files that are within list of test file pattern we want to run tests for
27
+ def self.select_test_files_that_can_be_run(adapter_class, test_file_entities_to_run)
28
+ test_file_pattern = KnapsackPro::TestFilePattern.call(adapter_class)
29
+ test_file_entities = call(test_file_pattern)
30
+
31
+ test_file_paths_existing_on_disk = KnapsackPro::TestFilePresenter.paths(test_file_entities)
32
+
33
+ selected_test_files = []
34
+
35
+ test_file_entities_to_run.each do |test_file_entity|
36
+ if test_file_paths_existing_on_disk.include?(test_file_entity.fetch('path'))
37
+ selected_test_files << test_file_entity
38
+ end
39
+ end
40
+
41
+ selected_test_files
42
+ end
43
+
44
+ def initialize(test_file_pattern, test_file_list_enabled)
8
45
  @test_file_pattern = test_file_pattern
46
+ @test_file_list_enabled = test_file_list_enabled
9
47
  end
10
48
 
11
49
  def call
@@ -18,10 +56,10 @@ module KnapsackPro
18
56
 
19
57
  private
20
58
 
21
- attr_reader :test_file_pattern
59
+ attr_reader :test_file_pattern, :test_file_list_enabled
22
60
 
23
61
  def test_files
24
- if KnapsackPro::Config::Env.test_file_list
62
+ if test_file_list_enabled && KnapsackPro::Config::Env.test_file_list
25
63
  return KnapsackPro::Config::Env.test_file_list.split(',').map(&:strip)
26
64
  end
27
65