knapsack_pro 2.8.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +23 -35
  4. data/lib/knapsack_pro/adapters/base_adapter.rb +22 -0
  5. data/lib/knapsack_pro/client/api/v1/queues.rb +4 -1
  6. data/lib/knapsack_pro/client/connection.rb +5 -0
  7. data/lib/knapsack_pro/config/env.rb +1 -0
  8. data/lib/knapsack_pro/queue_allocator.rb +19 -3
  9. data/lib/knapsack_pro/report.rb +1 -1
  10. data/lib/knapsack_pro/runners/cucumber_runner.rb +4 -1
  11. data/lib/knapsack_pro/runners/minitest_runner.rb +4 -1
  12. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +4 -0
  13. data/lib/knapsack_pro/runners/queue/minitest_runner.rb +4 -0
  14. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +2 -0
  15. data/lib/knapsack_pro/runners/rspec_runner.rb +4 -1
  16. data/lib/knapsack_pro/runners/spinach_runner.rb +4 -1
  17. data/lib/knapsack_pro/runners/test_unit_runner.rb +4 -1
  18. data/lib/knapsack_pro/slow_test_file_determiner.rb +1 -1
  19. data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +1 -1
  20. data/lib/knapsack_pro/tracker.rb +2 -6
  21. data/lib/knapsack_pro/version.rb +1 -1
  22. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +51 -0
  23. data/spec/knapsack_pro/client/api/v1/queues_spec.rb +31 -2
  24. data/spec/knapsack_pro/queue_allocator_spec.rb +217 -60
  25. data/spec/knapsack_pro/runners/cucumber_runner_spec.rb +2 -0
  26. data/spec/knapsack_pro/runners/minitest_runner_spec.rb +4 -0
  27. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +27 -7
  28. data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +27 -7
  29. data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +2 -0
  30. data/spec/knapsack_pro/runners/rspec_runner_spec.rb +2 -0
  31. data/spec/knapsack_pro/runners/spinach_runner_spec.rb +2 -0
  32. data/spec/knapsack_pro/runners/test_unit_runner_spec.rb +2 -0
  33. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9d29bfab6d9abd18cc90777bf6fe0f12e0a9c5622ccdd7ba75ecaa503b5afe5
4
- data.tar.gz: 827c14d1cf91da82dea672ec71c53b7f966342ba1d85c1b1f0610ab2776d22b7
3
+ metadata.gz: e9730c18427b9bf5c5f8c6ef527135ee374192ac527f7a934202fc7d5061577e
4
+ data.tar.gz: e3a7c4cd3b751cdb0110b2846c61dfdef37c0bcce6e05967b40a209fd69f4f7e
5
5
  SHA512:
6
- metadata.gz: 785be65ef6709bbce2e2e302f55c7c9be5782c1dd5ede66d43c67119dd6342dd9e1d4d7851f426732ea61b986505d7a0ac08165782a11c0338c209bc4f4fc167
7
- data.tar.gz: c30bf1b7dc4ac778c34763a18aee465c3266ee366589999be11ae71ab73c8263cf0470e1ce8646260de6a41b0f749dd9cdaf1b7d5d326c20a758da0e2c7f4f8e
6
+ metadata.gz: 1a8ec2361a57993184c40fcfa8200e31ddfe70519bdbe266d96bbd8f9f9703fc41acbcfecf00f416aa0eefd3ee6e72b570f805411433a81f2c947c7853234f7b
7
+ data.tar.gz: 44b9a94233dc9a073a8a6d055b9d058c6b8e1e99407deab47cafdc444872db6c8f4c07e432a7bef4bcbaff07de4885ba2c833a983f957e40d8710f52a74cbd9d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # Change Log
2
2
 
3
+ ### 2.12.0
4
+
5
+ * Use 0 seconds as a default test file time execution instead of 0.1s because Knapsack Pro API already accepts 0 seconds value
6
+
7
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/140
8
+
9
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.11.0...v2.12.0
10
+
11
+ ### 2.11.0
12
+
13
+ * Verify test runner adapter bind method is called to track test files time execution and ensure `tmp/knapsack_pro` directory is not removed accidentally
14
+
15
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/137
16
+
17
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.10.1...v2.11.0
18
+
19
+ ### 2.10.1
20
+
21
+ * Fix RSpec split by test examples feature broken by lazy generating of JSON report with test example ids
22
+
23
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/135
24
+
25
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.10.0...v2.10.1
26
+
27
+ ### 2.10.0
28
+
29
+ * Add support for an attempt to connect to existing Queue on API side to reduce slow requests number
30
+
31
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/133
32
+
33
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.9.0...v2.10.0
34
+
35
+ ### 2.9.0
36
+
37
+ * Use `Process.clock_gettime` to measure track execution time
38
+
39
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/132
40
+
41
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v2.8.0...v2.9.0
42
+
3
43
  ### 2.8.0
4
44
 
5
45
  * More actionable error message when RSpec split by examples is not working due to RSpec dry-run failure
data/README.md CHANGED
@@ -50,7 +50,7 @@ We keep this old FAQ in README to not break old links spread across the web. You
50
50
 
51
51
  # Requirements
52
52
 
53
- `>= Ruby 2.0.0`
53
+ `>= Ruby 2.1.0`
54
54
 
55
55
  # Table of Contents
56
56
 
@@ -72,8 +72,9 @@ We keep this old FAQ in README to not break old links spread across the web. You
72
72
  - [Set API key token](#set-api-key-token)
73
73
  - [Set knapsack_pro command to execute tests](#set-knapsack_pro-command-to-execute-tests)
74
74
  - [Repository adapter (How to set up 3 of 3)](#repository-adapter-how-to-set-up-3-of-3)
75
- - [When you NOT set global variable `KNAPSACK_PRO_REPOSITORY_ADAPTER` (default)](#when-you-not-set-global-variable-knapsack_pro_repository_adapter-default)
76
- - [When should you set global variable `KNAPSACK_PRO_REPOSITORY_ADAPTER=git` (required when CI provider is not supported)](#when-should-you-set-global-variable-knapsack_pro_repository_adaptergit-required-when-ci-provider-is-not-supported)
75
+ - [By default `KNAPSACK_PRO_REPOSITORY_ADAPTER` environment variable is undefined](#by-default-knapsack_pro_repository_adapter-environment-variable-is-undefined)
76
+ - [When should you set global variable `KNAPSACK_PRO_REPOSITORY_ADAPTER=git` (when CI provider is not supported and you use git)](#when-should-you-set-global-variable-knapsack_pro_repository_adaptergit-when-ci-provider-is-not-supported-and-you-use-git)
77
+ - [When you don't use git](#when-you-dont-use-git)
77
78
  - [Queue Mode](#queue-mode)
78
79
  - [How does queue mode work?](#how-does-queue-mode-work)
79
80
  - [How to use queue mode?](#how-to-use-queue-mode)
@@ -84,7 +85,6 @@ We keep this old FAQ in README to not break old links spread across the web. You
84
85
  - [Supported test runners in queue mode](#supported-test-runners-in-queue-mode)
85
86
  - [Split test files by test cases](#split-test-files-by-test-cases)
86
87
  - [RSpec split test files by test examples (by individual `it`s)](#rspec-split-test-files-by-test-examples-by-individual-its)
87
- - [Why I see error: Don't know how to build task 'knapsack_pro:rspec_test_example_detector'?](#why-i-see-error-dont-know-how-to-build-task-knapsack_prorspec_test_example_detector)
88
88
  - [How to manually define a list of slow test files to be split by test cases](#how-to-manually-define-a-list-of-slow-test-files-to-be-split-by-test-cases)
89
89
  - [Extra configuration for CI server](#extra-configuration-for-ci-server)
90
90
  - [Info about ENV variables](#info-about-env-variables)
@@ -442,7 +442,7 @@ __Tip 2:__ If you use one of unsupported CI providers ([here is list of supporte
442
442
 
443
443
  ### Repository adapter (How to set up 3 of 3)
444
444
 
445
- #### When you NOT set global variable `KNAPSACK_PRO_REPOSITORY_ADAPTER` (default)
445
+ #### By default `KNAPSACK_PRO_REPOSITORY_ADAPTER` environment variable is undefined
446
446
 
447
447
  By default `KNAPSACK_PRO_REPOSITORY_ADAPTER` variable has no value so knapsack_pro will try to get info about branch name and commit hash from [supported CI](#supported-ci-providers) (CI providers have branch, commit, project directory stored as environment variables). In case when you use other CI provider like Jenkins then please set below variables on your own.
448
448
 
@@ -452,12 +452,20 @@ By default `KNAPSACK_PRO_REPOSITORY_ADAPTER` variable has no value so knapsack_p
452
452
 
453
453
  You can also use git as repository adapter to determine branch and commit hash, please see below section.
454
454
 
455
- #### When should you set global variable `KNAPSACK_PRO_REPOSITORY_ADAPTER=git` (required when CI provider is not supported)
455
+ #### When should you set global variable `KNAPSACK_PRO_REPOSITORY_ADAPTER=git` (when CI provider is not supported and you use git)
456
456
 
457
457
  `KNAPSACK_PRO_REPOSITORY_ADAPTER` - When it has the value `git`, your local version of git on CI server will be used to get the branch name and commit hash. You also need to set `KNAPSACK_PRO_PROJECT_DIR` with the project directory path.
458
458
 
459
459
  `KNAPSACK_PRO_PROJECT_DIR` - Path to the project on the CI node, for instance `/home/ubuntu/my-app-repository`. It should be the top-level directory of your repository.
460
460
 
461
+ #### When you don't use git
462
+
463
+ If your CI provider does not expose commit hash and branch name through environment variables, then `knapsack_pro` gem does not know these values.
464
+ You can manually set the values of the current commit hash and branch name in the environment variables:
465
+
466
+ * `KNAPSACK_PRO_COMMIT_HASH` - commit hash.
467
+ * `KNAPSACK_PRO_BRANCH` - branch name.
468
+
461
469
  ## Queue Mode
462
470
 
463
471
  knapsack_pro has a built-in queue mode designed to determine the optimal test suite split even when there is an unpredictably longer time execution of test files on one node (e.g. by
@@ -609,6 +617,8 @@ Knapsack Pro API provides recorded timing of test files from your previously rec
609
617
 
610
618
  ### RSpec split test files by test examples (by individual `it`s)
611
619
 
620
+ Read more about [this feature](https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it) and [common problems here](https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it#common-problems).
621
+
612
622
  > ❗ __RSpec requirement:__ You need `RSpec >= 3.3.0` in order to use this feature.
613
623
 
614
624
  In order to split RSpec slow test files by test examples across parallel CI nodes you need to set environment variable:
@@ -619,16 +629,6 @@ KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
619
629
 
620
630
  Thanks to that your CI build speed can be faster. We recommend using this feature with [Queue Mode](https://youtu.be/hUEB1XDKEFY) to ensure parallel CI nodes finish work at a similar time which gives you the shortest CI build time.
621
631
 
622
- #### Why I see error: Don't know how to build task 'knapsack_pro:rspec_test_example_detector'?
623
-
624
- If you will see error like:
625
-
626
- ```
627
- Don't know how to build task 'knapsack_pro:rspec_test_example_detector' (See the list of available tasks with `rake --tasks`)
628
- ```
629
-
630
- It probably means bundler can't find the rake task. You can try to remove the default prefix `bundle exec` used by knapsack_pro gem by setting `KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX=""`.
631
-
632
632
  ### How to manually define a list of slow test files to be split by test cases
633
633
 
634
634
  If you don't want to rely on a list of test files from Knapsack Pro API to determine slow test files that should be split by test cases then you can define your own list of slow test files.
@@ -857,6 +857,7 @@ Note: there are a few branch names that won't be encrypted because we use them a
857
857
  * dev
858
858
  * master
859
859
  * staging
860
+ * [see full list of encryption excluded branch names](https://github.com/KnapsackPro/knapsack_pro-ruby/blob/master/lib/knapsack_pro/crypto/branch_encryptor.rb#L4)
860
861
 
861
862
  #### How to debug branch names?
862
863
 
@@ -1600,12 +1601,12 @@ jobs:
1600
1601
  strategy:
1601
1602
  fail-fast: false
1602
1603
  matrix:
1603
- # Set N number of parallel jobs you want to run tests on.
1604
- # Use higher number if you have slow tests to split them on more parallel jobs.
1605
- # Remember to update ci_node_index below to 0..N-1
1604
+ # [n] - where the n is a number of parallel jobs you want to run your tests on.
1605
+ # Use a higher number if you have slow tests to split them between more parallel jobs.
1606
+ # Remember to update the value of the `ci_node_index` below to (0..n-1).
1606
1607
  ci_node_total: [2]
1607
- # set N-1 indexes for parallel jobs
1608
- # When you run 2 parallel jobs then first job will have index 0, the second job will have index 1 etc
1608
+ # Indexes for parallel jobs (starting from zero).
1609
+ # E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
1609
1610
  ci_node_index: [0, 1]
1610
1611
 
1611
1612
  steps:
@@ -2064,20 +2065,7 @@ If you go to [user dashboard](https://knapsackpro.com/dashboard) and open `Build
2064
2065
 
2065
2066
  ##### Why all test files have 0.1s time execution for my CI build in user dashboard?
2066
2067
 
2067
- If you go to [user dashboard](https://knapsackpro.com/dashboard) and open `Build metrics` for your API token and you open CI build for your last git commit you should see there info about collected time execution data from all CI nodes. If you see all test files have 0.1s time execution then please ensure:
2068
-
2069
- * you should not clean up `tmp` directory in your tests (for instance in RSpec hooks like `before` or `after`) so knapsack_pro can publish measured time execution data to Knapsack Pro API server. knapsack_pro Queue Mode saves temporary files with collected time execution data in `your_rails_project/tmp/knapsack_pro/queue/`.
2070
- * please ensure you have in your `rails_helper.rb` or `spec_helper.rb` line that allows to measure tests:
2071
-
2072
- ```ruby
2073
- require 'knapsack_pro'
2074
-
2075
- # CUSTOM_CONFIG_GOES_HERE
2076
-
2077
- KnapsackPro::Adapters::RSpecAdapter.bind
2078
- ```
2079
-
2080
- The 0.1s is a default time execution used when test file is an empty file or its content are all pending tests.
2068
+ https://knapsackpro.com/faq/question/why-all-test-files-have-01s-time-execution-for-my-ci-build-in-user-dashboard
2081
2069
 
2082
2070
  ##### Why when I use Queue Mode for RSpec and test fails then I see multiple times info about failed test in RSpec result?
2083
2071
 
@@ -4,6 +4,11 @@ module KnapsackPro
4
4
  # Just example, please overwrite constant in subclass
5
5
  TEST_DIR_PATTERN = 'test/**{,/*/**}/*_test.rb'
6
6
 
7
+ def self.adapter_bind_method_called_file
8
+ adapter_name = self.to_s.gsub('::', '-')
9
+ "#{KnapsackPro::Config::Env::TMP_DIR}/#{adapter_name}-bind_method_called_for_node_#{KnapsackPro::Config::Env.ci_node_index}.txt"
10
+ end
11
+
7
12
  def self.slow_test_file?(adapter_class, test_file_path)
8
13
  @slow_test_file_paths ||=
9
14
  begin
@@ -26,7 +31,24 @@ module KnapsackPro
26
31
  adapter
27
32
  end
28
33
 
34
+ def self.verify_bind_method_called
35
+ ::Kernel.at_exit do
36
+ if File.exists?(adapter_bind_method_called_file)
37
+ File.delete(adapter_bind_method_called_file)
38
+ else
39
+ puts "\n\n"
40
+ KnapsackPro.logger.error('-'*10 + ' Configuration error ' + '-'*50)
41
+ KnapsackPro.logger.error("You forgot to call #{self}.bind method in your test runner configuration file. It is needed to record test files time execution. Please follow the installation guide to configure your project properly https://docs.knapsackpro.com/knapsack_pro-ruby/guide/")
42
+ KnapsackPro.logger.error("If you already have #{self}.bind method added and you still see this error then one of your tests must had to delete tmp/knapsack_pro directory from the disk accidentally. Please ensure you do not remove tmp/knapsack_pro directory: https://knapsackpro.com/faq/question/why-all-test-files-have-01s-time-execution-for-my-ci-build-in-user-dashboard")
43
+ Kernel.exit(1)
44
+ end
45
+ end
46
+ end
47
+
29
48
  def bind
49
+ FileUtils.mkdir_p(KnapsackPro::Config::Env::TMP_DIR)
50
+ File.write(self.class.adapter_bind_method_called_file, nil)
51
+
30
52
  if KnapsackPro::Config::Env.recording_enabled?
31
53
  KnapsackPro.logger.debug('Test suite time execution recording enabled.')
32
54
  bind_time_tracker
@@ -3,11 +3,14 @@ module KnapsackPro
3
3
  module API
4
4
  module V1
5
5
  class Queues < Base
6
+ CODE_ATTEMPT_CONNECT_TO_QUEUE_FAILED = 'ATTEMPT_CONNECT_TO_QUEUE_FAILED'
7
+
6
8
  class << self
7
9
  def queue(args)
8
10
  request_hash = {
9
11
  :fixed_queue_split => KnapsackPro::Config::Env.fixed_queue_split,
10
12
  :can_initialize_queue => args.fetch(:can_initialize_queue),
13
+ :attempt_connect_to_queue => args.fetch(:attempt_connect_to_queue),
11
14
  :commit_hash => args.fetch(:commit_hash),
12
15
  :branch => args.fetch(:branch),
13
16
  :node_total => args.fetch(:node_total),
@@ -15,7 +18,7 @@ module KnapsackPro
15
18
  :node_build_id => KnapsackPro::Config::Env.ci_node_build_id,
16
19
  }
17
20
 
18
- if request_hash[:can_initialize_queue]
21
+ if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue]
19
22
  request_hash.merge!({
20
23
  :test_files => args.fetch(:test_files)
21
24
  })
@@ -25,6 +25,11 @@ module KnapsackPro
25
25
  !!(response_body && (response_body['errors'] || response_body['error']))
26
26
  end
27
27
 
28
+ def api_code
29
+ return unless response_body
30
+ response_body['code']
31
+ end
32
+
28
33
  def server_error?
29
34
  status = http_response.code.to_i
30
35
  status >= 500 && status < 600
@@ -8,6 +8,7 @@ module KnapsackPro
8
8
  'info' => ::Logger::INFO,
9
9
  'debug' => ::Logger::DEBUG,
10
10
  }
11
+ TMP_DIR = 'tmp/knapsack_pro'
11
12
 
12
13
  class << self
13
14
  def ci_node_total
@@ -11,9 +11,18 @@ module KnapsackPro
11
11
 
12
12
  def test_file_paths(can_initialize_queue, executed_test_files)
13
13
  return [] if @fallback_activated
14
- action = build_action(can_initialize_queue)
14
+ action = build_action(can_initialize_queue, attempt_connect_to_queue: can_initialize_queue)
15
15
  connection = KnapsackPro::Client::Connection.new(action)
16
16
  response = connection.call
17
+
18
+ # when attempt to connect to existing queue on API side failed because queue does not exist yet
19
+ if can_initialize_queue && connection.success? && connection.api_code == KnapsackPro::Client::API::V1::Queues::CODE_ATTEMPT_CONNECT_TO_QUEUE_FAILED
20
+ # make attempt to initalize a new queue on API side
21
+ action = build_action(can_initialize_queue, attempt_connect_to_queue: false)
22
+ connection = KnapsackPro::Client::Connection.new(action)
23
+ response = connection.call
24
+ end
25
+
17
26
  if connection.success?
18
27
  raise ArgumentError.new(response) if connection.errors?
19
28
  prepare_test_files(response)
@@ -52,15 +61,22 @@ module KnapsackPro
52
61
  KnapsackPro::Crypto::BranchEncryptor.call(repository_adapter.branch)
53
62
  end
54
63
 
55
- def build_action(can_initialize_queue)
64
+ def build_action(can_initialize_queue, attempt_connect_to_queue:)
65
+ # read test files from disk only when needed because it can be slow operation
66
+ test_files =
67
+ if can_initialize_queue && !attempt_connect_to_queue
68
+ encrypted_test_files
69
+ end
70
+
56
71
  KnapsackPro::Client::API::V1::Queues.queue(
57
72
  can_initialize_queue: can_initialize_queue,
73
+ attempt_connect_to_queue: attempt_connect_to_queue,
58
74
  commit_hash: repository_adapter.commit_hash,
59
75
  branch: encrypted_branch,
60
76
  node_total: ci_node_total,
61
77
  node_index: ci_node_index,
62
78
  node_build_id: ci_node_build_id,
63
- test_files: encrypted_test_files,
79
+ test_files: test_files,
64
80
  )
65
81
  end
66
82
 
@@ -80,7 +80,7 @@ module KnapsackPro
80
80
 
81
81
  def self.queue_path
82
82
  queue_id = KnapsackPro::Config::Env.queue_id
83
- "tmp/knapsack_pro/queue/#{queue_id}"
83
+ "#{KnapsackPro::Config::Env::TMP_DIR}/queue/#{queue_id}"
84
84
  end
85
85
  end
86
86
  end
@@ -5,9 +5,12 @@ module KnapsackPro
5
5
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_cucumber
6
6
  ENV['KNAPSACK_PRO_RECORDING_ENABLED'] = 'true'
7
7
 
8
- runner = new(KnapsackPro::Adapters::CucumberAdapter)
8
+ adapter_class = KnapsackPro::Adapters::CucumberAdapter
9
+ runner = new(adapter_class)
9
10
 
10
11
  if runner.test_files_to_execute_exist?
12
+ adapter_class.verify_bind_method_called
13
+
11
14
  require 'cucumber/rake/task'
12
15
 
13
16
  task_name = 'knapsack_pro:cucumber_run'
@@ -5,9 +5,12 @@ module KnapsackPro
5
5
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_minitest
6
6
  ENV['KNAPSACK_PRO_RECORDING_ENABLED'] = 'true'
7
7
 
8
- runner = new(KnapsackPro::Adapters::MinitestAdapter)
8
+ adapter_class = KnapsackPro::Adapters::MinitestAdapter
9
+ runner = new(adapter_class)
9
10
 
10
11
  if runner.test_files_to_execute_exist?
12
+ adapter_class.verify_bind_method_called
13
+
11
14
  task_name = 'knapsack_pro:minitest_run'
12
15
 
13
16
  if Rake::Task.task_defined?(task_name)
@@ -39,6 +39,10 @@ module KnapsackPro
39
39
  )
40
40
 
41
41
  if test_file_paths.empty?
42
+ unless all_test_file_paths.empty?
43
+ KnapsackPro::Adapters::CucumberAdapter.verify_bind_method_called
44
+ end
45
+
42
46
  KnapsackPro::Hooks::Queue.call_after_queue
43
47
 
44
48
  KnapsackPro::Report.save_node_queue_to_api
@@ -46,6 +46,10 @@ module KnapsackPro
46
46
  )
47
47
 
48
48
  if test_file_paths.empty?
49
+ unless all_test_file_paths.empty?
50
+ KnapsackPro::Adapters::MinitestAdapter.verify_bind_method_called
51
+ end
52
+
49
53
  KnapsackPro::Hooks::Queue.call_after_queue
50
54
 
51
55
  KnapsackPro::Report.save_node_queue_to_api
@@ -53,6 +53,8 @@ module KnapsackPro
53
53
 
54
54
  if test_file_paths.empty?
55
55
  unless all_test_file_paths.empty?
56
+ KnapsackPro::Adapters::RSpecAdapter.verify_bind_method_called
57
+
56
58
  KnapsackPro::Formatters::RSpecQueueSummaryFormatter.print_summary
57
59
  KnapsackPro::Formatters::RSpecQueueProfileFormatterExtension.print_summary
58
60
 
@@ -5,9 +5,12 @@ module KnapsackPro
5
5
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec
6
6
  ENV['KNAPSACK_PRO_RECORDING_ENABLED'] = 'true'
7
7
 
8
- runner = new(KnapsackPro::Adapters::RSpecAdapter)
8
+ adapter_class = KnapsackPro::Adapters::RSpecAdapter
9
+ runner = new(adapter_class)
9
10
 
10
11
  if runner.test_files_to_execute_exist?
12
+ adapter_class.verify_bind_method_called
13
+
11
14
  require 'rspec/core/rake_task'
12
15
 
13
16
  task_name = 'knapsack_pro:rspec_run'
@@ -4,9 +4,12 @@ module KnapsackPro
4
4
  def self.run(args)
5
5
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_spinach
6
6
 
7
- runner = new(KnapsackPro::Adapters::SpinachAdapter)
7
+ adapter_class = KnapsackPro::Adapters::SpinachAdapter
8
+ runner = new(adapter_class)
8
9
 
9
10
  if runner.test_files_to_execute_exist?
11
+ adapter_class.verify_bind_method_called
12
+
10
13
  cmd = %Q[KNAPSACK_PRO_RECORDING_ENABLED=true KNAPSACK_PRO_TEST_SUITE_TOKEN=#{ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN']} bundle exec spinach #{args} --features_path #{runner.test_dir} -- #{runner.stringify_test_file_paths}]
11
14
 
12
15
  Kernel.system(cmd)
@@ -5,9 +5,12 @@ module KnapsackPro
5
5
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_test_unit
6
6
  ENV['KNAPSACK_PRO_RECORDING_ENABLED'] = 'true'
7
7
 
8
- runner = new(KnapsackPro::Adapters::TestUnitAdapter)
8
+ adapter_class = KnapsackPro::Adapters::TestUnitAdapter
9
+ runner = new(adapter_class)
9
10
 
10
11
  if runner.test_files_to_execute_exist?
12
+ adapter_class.verify_bind_method_called
13
+
11
14
  require 'test/unit'
12
15
 
13
16
  cli_args =
@@ -1,7 +1,7 @@
1
1
  module KnapsackPro
2
2
  class SlowTestFileDeterminer
3
3
  TIME_THRESHOLD_PER_CI_NODE = 0.7 # 70%
4
- REPORT_DIR = 'tmp/knapsack_pro/slow_test_file_determiner'
4
+ REPORT_DIR = "#{KnapsackPro::Config::Env::TMP_DIR}/slow_test_file_determiner"
5
5
 
6
6
  # test_files: { 'path' => 'a_spec.rb', 'time_execution' => 0.0 }
7
7
  # time_execution: of build distribution (total time of CI build run)
@@ -1,7 +1,7 @@
1
1
  module KnapsackPro
2
2
  module TestCaseDetectors
3
3
  class RSpecTestExampleDetector
4
- REPORT_DIR = 'tmp/knapsack_pro/test_case_detectors/rspec'
4
+ REPORT_DIR = "#{KnapsackPro::Config::Env::TMP_DIR}/test_case_detectors/rspec"
5
5
 
6
6
  def generate_json_report
7
7
  require 'rspec/core'
@@ -4,7 +4,7 @@ module KnapsackPro
4
4
 
5
5
  # when test file is pending, empty with no tests or has syntax error then assume time execution
6
6
  # to better allocate it in Queue Mode for future CI build runs
7
- DEFAULT_TEST_FILE_TIME = 0.1 # seconds
7
+ DEFAULT_TEST_FILE_TIME = 0.0 # seconds
8
8
 
9
9
  attr_reader :global_time_since_beginning, :global_time, :test_files_with_time
10
10
  attr_writer :current_test_path
@@ -90,11 +90,7 @@ module KnapsackPro
90
90
  end
91
91
 
92
92
  def now_without_mock_time
93
- if defined?(Timecop)
94
- Time.now_without_mock_time
95
- else
96
- Time.raw_now
97
- end
93
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
98
94
  end
99
95
  end
100
96
  end
@@ -1,3 +1,3 @@
1
1
  module KnapsackPro
2
- VERSION = '2.8.0'
2
+ VERSION = '2.12.0'
3
3
  end
@@ -22,6 +22,27 @@ describe KnapsackPro::Adapters::BaseAdapter do
22
22
  end
23
23
  end
24
24
 
25
+ describe '.adapter_bind_method_called_file' do
26
+ subject { described_class.adapter_bind_method_called_file }
27
+
28
+ before do
29
+ expect(KnapsackPro::Config::Env).to receive(:ci_node_index).and_return(ci_node_index)
30
+ end
31
+
32
+ context 'when CI node index 0' do
33
+ let(:ci_node_index) { 0 }
34
+
35
+ it { expect(subject).to eq 'tmp/knapsack_pro/KnapsackPro-Adapters-BaseAdapter-bind_method_called_for_node_0.txt' }
36
+
37
+ end
38
+
39
+ context 'when CI node index 1' do
40
+ let(:ci_node_index) { 1 }
41
+
42
+ it { expect(subject).to eq 'tmp/knapsack_pro/KnapsackPro-Adapters-BaseAdapter-bind_method_called_for_node_1.txt' }
43
+ end
44
+ end
45
+
25
46
  describe '.slow_test_file?' do
26
47
  let(:adapter_class) { double }
27
48
  let(:slow_test_files) do
@@ -71,11 +92,41 @@ describe KnapsackPro::Adapters::BaseAdapter do
71
92
  it { should eql adapter }
72
93
  end
73
94
 
95
+ describe '.verify_bind_method_called' do
96
+ subject { described_class.verify_bind_method_called }
97
+
98
+ before do
99
+ expect(::Kernel).to receive(:at_exit).and_yield
100
+ expect(File).to receive(:exists?).with('tmp/knapsack_pro/KnapsackPro-Adapters-BaseAdapter-bind_method_called_for_node_0.txt').and_return(adapter_bind_method_called_file_exists)
101
+ end
102
+
103
+ context 'when adapter bind method called' do
104
+ let(:adapter_bind_method_called_file_exists) { true }
105
+
106
+ it do
107
+ expect(File).to receive(:delete).with('tmp/knapsack_pro/KnapsackPro-Adapters-BaseAdapter-bind_method_called_for_node_0.txt')
108
+ subject
109
+ end
110
+ end
111
+
112
+ context 'when adapter bind method was not call' do
113
+ let(:adapter_bind_method_called_file_exists) { false }
114
+
115
+ it do
116
+ expect(Kernel).to receive(:exit).with(1)
117
+ subject
118
+ end
119
+ end
120
+ end
121
+
74
122
  describe '#bind' do
75
123
  let(:recording_enabled?) { false }
76
124
  let(:queue_recording_enabled?) { false }
77
125
 
78
126
  before do
127
+ expect(FileUtils).to receive(:mkdir_p).with('tmp/knapsack_pro')
128
+ expect(File).to receive(:write).with('tmp/knapsack_pro/KnapsackPro-Adapters-BaseAdapter-bind_method_called_for_node_0.txt', nil)
129
+
79
130
  expect(KnapsackPro::Config::Env).to receive(:recording_enabled?).and_return(recording_enabled?)
80
131
  expect(KnapsackPro::Config::Env).to receive(:queue_recording_enabled?).and_return(queue_recording_enabled?)
81
132
  end
@@ -11,6 +11,7 @@ describe KnapsackPro::Client::API::V1::Queues do
11
11
  subject do
12
12
  described_class.queue(
13
13
  can_initialize_queue: can_initialize_queue,
14
+ attempt_connect_to_queue: attempt_connect_to_queue,
14
15
  commit_hash: commit_hash,
15
16
  branch: branch,
16
17
  node_total: node_total,
@@ -24,8 +25,33 @@ describe KnapsackPro::Client::API::V1::Queues do
24
25
  expect(KnapsackPro::Config::Env).to receive(:ci_node_build_id).and_return(node_build_id)
25
26
  end
26
27
 
27
- context 'when can_initialize_queue=true' do
28
+ context 'when can_initialize_queue=true and attempt_connect_to_queue=true' do
28
29
  let(:can_initialize_queue) { true }
30
+ let(:attempt_connect_to_queue) { true }
31
+
32
+ it 'does not send test_files among other params' do
33
+ action = double
34
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with({
35
+ endpoint_path: '/v1/queues/queue',
36
+ http_method: :post,
37
+ request_hash: {
38
+ fixed_queue_split: fixed_queue_split,
39
+ can_initialize_queue: can_initialize_queue,
40
+ attempt_connect_to_queue: attempt_connect_to_queue,
41
+ commit_hash: commit_hash,
42
+ branch: branch,
43
+ node_total: node_total,
44
+ node_index: node_index,
45
+ node_build_id: node_build_id,
46
+ }
47
+ }).and_return(action)
48
+ expect(subject).to eq action
49
+ end
50
+ end
51
+
52
+ context 'when can_initialize_queue=true and attempt_connect_to_queue=false' do
53
+ let(:can_initialize_queue) { true }
54
+ let(:attempt_connect_to_queue) { false }
29
55
 
30
56
  it 'sends test_files among other params' do
31
57
  action = double
@@ -35,6 +61,7 @@ describe KnapsackPro::Client::API::V1::Queues do
35
61
  request_hash: {
36
62
  fixed_queue_split: fixed_queue_split,
37
63
  can_initialize_queue: can_initialize_queue,
64
+ attempt_connect_to_queue: attempt_connect_to_queue,
38
65
  commit_hash: commit_hash,
39
66
  branch: branch,
40
67
  node_total: node_total,
@@ -47,8 +74,9 @@ describe KnapsackPro::Client::API::V1::Queues do
47
74
  end
48
75
  end
49
76
 
50
- context 'when can_initialize_queue=false' do
77
+ context 'when can_initialize_queue=false and attempt_connect_to_queue=false' do
51
78
  let(:can_initialize_queue) { false }
79
+ let(:attempt_connect_to_queue) { false }
52
80
 
53
81
  it 'does not send test_files among other params' do
54
82
  action = double
@@ -58,6 +86,7 @@ describe KnapsackPro::Client::API::V1::Queues do
58
86
  request_hash: {
59
87
  fixed_queue_split: fixed_queue_split,
60
88
  can_initialize_queue: can_initialize_queue,
89
+ attempt_connect_to_queue: attempt_connect_to_queue,
61
90
  commit_hash: commit_hash,
62
91
  branch: branch,
63
92
  node_total: node_total,
@@ -18,71 +18,13 @@ describe KnapsackPro::QueueAllocator do
18
18
  end
19
19
 
20
20
  describe '#test_file_paths' do
21
- let(:can_initialize_queue) { double }
22
21
  let(:executed_test_files) { [] }
23
22
  let(:response) { double }
23
+ let(:api_code) { nil }
24
24
 
25
25
  subject { queue_allocator.test_file_paths(can_initialize_queue, executed_test_files) }
26
26
 
27
- before do
28
- encrypted_test_files = double
29
- expect(KnapsackPro::Crypto::Encryptor).to receive(:call).with(fast_and_slow_test_files_to_run).and_return(encrypted_test_files)
30
-
31
- encrypted_branch = double
32
- expect(KnapsackPro::Crypto::BranchEncryptor).to receive(:call).with(repository_adapter.branch).and_return(encrypted_branch)
33
-
34
- action = double
35
- expect(KnapsackPro::Client::API::V1::Queues).to receive(:queue).with(
36
- can_initialize_queue: can_initialize_queue,
37
- commit_hash: repository_adapter.commit_hash,
38
- branch: encrypted_branch,
39
- node_total: ci_node_total,
40
- node_index: ci_node_index,
41
- node_build_id: ci_node_build_id,
42
- test_files: encrypted_test_files,
43
- ).and_return(action)
44
-
45
- connection = instance_double(KnapsackPro::Client::Connection,
46
- call: response,
47
- success?: success?,
48
- errors?: errors?)
49
- expect(KnapsackPro::Client::Connection).to receive(:new).with(action).and_return(connection)
50
- end
51
-
52
- context 'when successful request to API' do
53
- let(:success?) { true }
54
-
55
- context 'when response has errors' do
56
- let(:errors?) { true }
57
-
58
- it do
59
- expect { subject }.to raise_error(ArgumentError)
60
- end
61
- end
62
-
63
- context 'when response has no errors' do
64
- let(:errors?) { false }
65
- let(:response) do
66
- {
67
- 'test_files' => [
68
- { 'path' => 'a_spec.rb' },
69
- { 'path' => 'b_spec.rb' },
70
- ]
71
- }
72
- end
73
-
74
- before do
75
- expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(fast_and_slow_test_files_to_run, response['test_files']).and_call_original
76
- end
77
-
78
- it { should eq ['a_spec.rb', 'b_spec.rb'] }
79
- end
80
- end
81
-
82
- context 'when not successful request to API' do
83
- let(:success?) { false }
84
- let(:errors?) { false }
85
-
27
+ shared_examples_for 'when connection to API failed (fallback mode)' do
86
28
  context 'when fallback mode is disabled' do
87
29
  before do
88
30
  expect(KnapsackPro::Config::Env).to receive(:fallback_mode_enabled?).and_return(false)
@@ -146,5 +88,220 @@ describe KnapsackPro::QueueAllocator do
146
88
  end
147
89
  end
148
90
  end
91
+
92
+ context 'when can_initialize_queue=true' do
93
+ let(:can_initialize_queue) { true }
94
+
95
+ before do
96
+ encrypted_branch = double
97
+ expect(KnapsackPro::Crypto::BranchEncryptor).to receive(:call).with(repository_adapter.branch).and_return(encrypted_branch)
98
+
99
+ action = double
100
+ expect(KnapsackPro::Client::API::V1::Queues).to receive(:queue).with(
101
+ can_initialize_queue: can_initialize_queue,
102
+ attempt_connect_to_queue: true, # when can_initialize_queue=true then expect attempt_connect_to_queue=true
103
+ commit_hash: repository_adapter.commit_hash,
104
+ branch: encrypted_branch,
105
+ node_total: ci_node_total,
106
+ node_index: ci_node_index,
107
+ node_build_id: ci_node_build_id,
108
+ test_files: nil, # when attempt_connect_to_queue=true then expect test_files is nil to make fast request to API
109
+ ).and_return(action)
110
+
111
+ connection = instance_double(KnapsackPro::Client::Connection,
112
+ call: response,
113
+ success?: success?,
114
+ errors?: errors?,
115
+ api_code: api_code)
116
+ expect(KnapsackPro::Client::Connection).to receive(:new).with(action).and_return(connection)
117
+ end
118
+
119
+ context 'when successful request to API' do
120
+ let(:success?) { true }
121
+
122
+ context 'when response has errors' do
123
+ let(:errors?) { true }
124
+
125
+ it do
126
+ expect { subject }.to raise_error(ArgumentError)
127
+ end
128
+ end
129
+
130
+ context 'when response has no errors' do
131
+ let(:errors?) { false }
132
+
133
+ context 'when response returns test files (successful attempt to connect to queue already existing on the API side)' do
134
+ let(:response) do
135
+ {
136
+ 'test_files' => [
137
+ { 'path' => 'a_spec.rb' },
138
+ { 'path' => 'b_spec.rb' },
139
+ ]
140
+ }
141
+ end
142
+
143
+ before do
144
+ expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(fast_and_slow_test_files_to_run, response['test_files']).and_call_original
145
+ end
146
+
147
+ it { should eq ['a_spec.rb', 'b_spec.rb'] }
148
+ end
149
+
150
+ context 'when response has code=ATTEMPT_CONNECT_TO_QUEUE_FAILED' do
151
+ let(:response) do
152
+ { 'code' => 'ATTEMPT_CONNECT_TO_QUEUE_FAILED' }
153
+ end
154
+ let(:api_code) { 'ATTEMPT_CONNECT_TO_QUEUE_FAILED' }
155
+
156
+ before do
157
+ encrypted_branch = double
158
+ expect(KnapsackPro::Crypto::BranchEncryptor).to receive(:call).with(repository_adapter.branch).and_return(encrypted_branch)
159
+
160
+ encrypted_test_files = double
161
+ expect(KnapsackPro::Crypto::Encryptor).to receive(:call).with(fast_and_slow_test_files_to_run).and_return(encrypted_test_files)
162
+
163
+ # 2nd request is no more an attempt to connect to queue.
164
+ # We want to try to initalize a new queue so we will also send list of test files from disk.
165
+ action = double
166
+ expect(KnapsackPro::Client::API::V1::Queues).to receive(:queue).with(
167
+ can_initialize_queue: can_initialize_queue,
168
+ attempt_connect_to_queue: false,
169
+ commit_hash: repository_adapter.commit_hash,
170
+ branch: encrypted_branch,
171
+ node_total: ci_node_total,
172
+ node_index: ci_node_index,
173
+ node_build_id: ci_node_build_id,
174
+ test_files: encrypted_test_files,
175
+ ).and_return(action)
176
+
177
+ connection = instance_double(KnapsackPro::Client::Connection,
178
+ call: response2,
179
+ success?: response2_success?,
180
+ errors?: response2_errors?,
181
+ api_code: nil)
182
+ expect(KnapsackPro::Client::Connection).to receive(:new).with(action).and_return(connection)
183
+ end
184
+
185
+ context 'when successful 2nd request to API' do
186
+ let(:response2_success?) { true }
187
+
188
+ context 'when 2nd response has errors' do
189
+ let(:response2_errors?) { true }
190
+ let(:response2) { nil }
191
+
192
+ it do
193
+ expect { subject }.to raise_error(ArgumentError)
194
+ end
195
+ end
196
+
197
+ context 'when 2nd response has no errors' do
198
+ let(:response2_errors?) { false }
199
+
200
+ context 'when 2nd response returns test files (successful attempt to connect to queue already existing on the API side)' do
201
+ let(:response2) do
202
+ {
203
+ 'test_files' => [
204
+ { 'path' => 'a_spec.rb' },
205
+ { 'path' => 'b_spec.rb' },
206
+ ]
207
+ }
208
+ end
209
+
210
+ before do
211
+ expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(fast_and_slow_test_files_to_run, response2['test_files']).and_call_original
212
+ end
213
+
214
+ it { should eq ['a_spec.rb', 'b_spec.rb'] }
215
+ end
216
+ end
217
+ end
218
+
219
+ context 'when not successful 2nd request to API' do
220
+ let(:response2_success?) { false }
221
+ let(:response2_errors?) { false }
222
+ let(:response2) { nil }
223
+
224
+ it_behaves_like 'when connection to API failed (fallback mode)'
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ context 'when not successful request to API' do
231
+ let(:success?) { false }
232
+ let(:errors?) { false }
233
+
234
+ it_behaves_like 'when connection to API failed (fallback mode)'
235
+ end
236
+ end
237
+
238
+ context 'when can_initialize_queue=false' do
239
+ let(:can_initialize_queue) { false }
240
+ let(:api_code) { nil }
241
+
242
+ before do
243
+ encrypted_branch = double
244
+ expect(KnapsackPro::Crypto::BranchEncryptor).to receive(:call).with(repository_adapter.branch).and_return(encrypted_branch)
245
+
246
+ action = double
247
+ expect(KnapsackPro::Client::API::V1::Queues).to receive(:queue).with(
248
+ can_initialize_queue: can_initialize_queue,
249
+ attempt_connect_to_queue: false, # when can_initialize_queue=false then expect attempt_connect_to_queue=false
250
+ commit_hash: repository_adapter.commit_hash,
251
+ branch: encrypted_branch,
252
+ node_total: ci_node_total,
253
+ node_index: ci_node_index,
254
+ node_build_id: ci_node_build_id,
255
+ test_files: nil, # when can_initialize_queue=false then expect test_files is nil to make fast request to API
256
+ ).and_return(action)
257
+
258
+ connection = instance_double(KnapsackPro::Client::Connection,
259
+ call: response,
260
+ success?: success?,
261
+ errors?: errors?,
262
+ api_code: api_code)
263
+ expect(KnapsackPro::Client::Connection).to receive(:new).with(action).and_return(connection)
264
+ end
265
+
266
+ context 'when successful request to API' do
267
+ let(:success?) { true }
268
+
269
+ context 'when response has errors' do
270
+ let(:errors?) { true }
271
+
272
+ it do
273
+ expect { subject }.to raise_error(ArgumentError)
274
+ end
275
+ end
276
+
277
+ context 'when response has no errors' do
278
+ let(:errors?) { false }
279
+
280
+ context 'when response returns test files (successful attempt to connect to queue already existing on the API side)' do
281
+ let(:response) do
282
+ {
283
+ 'test_files' => [
284
+ { 'path' => 'a_spec.rb' },
285
+ { 'path' => 'b_spec.rb' },
286
+ ]
287
+ }
288
+ end
289
+
290
+ before do
291
+ expect(KnapsackPro::Crypto::Decryptor).to receive(:call).with(fast_and_slow_test_files_to_run, response['test_files']).and_call_original
292
+ end
293
+
294
+ it { should eq ['a_spec.rb', 'b_spec.rb'] }
295
+ end
296
+ end
297
+ end
298
+
299
+ context 'when not successful request to API' do
300
+ let(:success?) { false }
301
+ let(:errors?) { false }
302
+
303
+ it_behaves_like 'when connection to API failed (fallback mode)'
304
+ end
305
+ end
149
306
  end
150
307
  end
@@ -34,6 +34,8 @@ describe KnapsackPro::Runners::CucumberRunner do
34
34
  let(:task) { double }
35
35
 
36
36
  before do
37
+ expect(KnapsackPro::Adapters::CucumberAdapter).to receive(:verify_bind_method_called)
38
+
37
39
  expect(Rake::Task).to receive(:[]).with('knapsack_pro:cucumber_run').at_least(1).and_return(task)
38
40
 
39
41
  t = double
@@ -14,6 +14,10 @@ describe KnapsackPro::Runners::MinitestRunner do
14
14
  end
15
15
 
16
16
  context 'when test files were returned by Knapsack Pro API' do
17
+ before do
18
+ expect(KnapsackPro::Adapters::MinitestAdapter).to receive(:verify_bind_method_called)
19
+ end
20
+
17
21
  it 'runs tests' do
18
22
  test_file_paths = ['test_fake/a_test.rb', 'test_fake/b_test.rb']
19
23
  runner = instance_double(described_class,
@@ -167,14 +167,34 @@ describe KnapsackPro::Runners::Queue::CucumberRunner do
167
167
  context "when test files don't exist" do
168
168
  let(:test_file_paths) { [] }
169
169
 
170
- it 'returns exit code 0' do
171
- expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)
172
- expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
170
+ context 'when all_test_file_paths exist' do
171
+ let(:all_test_file_paths) { ['features/a.feature'] }
173
172
 
174
- expect(subject).to eq({
175
- status: :completed,
176
- exitstatus: exitstatus,
177
- })
173
+ it 'returns exit code 0' do
174
+ expect(KnapsackPro::Adapters::CucumberAdapter).to receive(:verify_bind_method_called)
175
+
176
+ expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)
177
+ expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
178
+
179
+ expect(subject).to eq({
180
+ status: :completed,
181
+ exitstatus: exitstatus,
182
+ })
183
+ end
184
+ end
185
+
186
+ context "when all_test_file_paths don't exist" do
187
+ let(:all_test_file_paths) { [] }
188
+
189
+ it 'returns exit code 0' do
190
+ expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)
191
+ expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
192
+
193
+ expect(subject).to eq({
194
+ status: :completed,
195
+ exitstatus: exitstatus,
196
+ })
197
+ end
178
198
  end
179
199
  end
180
200
  end
@@ -159,14 +159,34 @@ describe KnapsackPro::Runners::Queue::MinitestRunner do
159
159
  context "when test files don't exist" do
160
160
  let(:test_file_paths) { [] }
161
161
 
162
- it 'returns exit code 0' do
163
- expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)
164
- expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
162
+ context 'when all_test_file_paths exist' do
163
+ let(:all_test_file_paths) { ['a_test.rb'] }
165
164
 
166
- expect(subject).to eq({
167
- status: :completed,
168
- exitstatus: exitstatus,
169
- })
165
+ it 'returns exit code 0' do
166
+ expect(KnapsackPro::Adapters::MinitestAdapter).to receive(:verify_bind_method_called)
167
+
168
+ expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)
169
+ expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
170
+
171
+ expect(subject).to eq({
172
+ status: :completed,
173
+ exitstatus: exitstatus,
174
+ })
175
+ end
176
+ end
177
+
178
+ context "when all_test_file_paths don't exist" do
179
+ let(:all_test_file_paths) { [] }
180
+
181
+ it 'returns exit code 0' do
182
+ expect(KnapsackPro::Hooks::Queue).to receive(:call_after_queue)
183
+ expect(KnapsackPro::Report).to receive(:save_node_queue_to_api)
184
+
185
+ expect(subject).to eq({
186
+ status: :completed,
187
+ exitstatus: exitstatus,
188
+ })
189
+ end
170
190
  end
171
191
  end
172
192
  end
@@ -249,6 +249,8 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
249
249
  let(:all_test_file_paths) { ['a_spec.rb'] }
250
250
 
251
251
  it do
252
+ expect(KnapsackPro::Adapters::RSpecAdapter).to receive(:verify_bind_method_called)
253
+
252
254
  expect(KnapsackPro::Formatters::RSpecQueueSummaryFormatter).to receive(:print_summary)
253
255
  expect(KnapsackPro::Formatters::RSpecQueueProfileFormatterExtension).to receive(:print_summary)
254
256
 
@@ -34,6 +34,8 @@ describe KnapsackPro::Runners::RSpecRunner do
34
34
  let(:task) { double }
35
35
 
36
36
  before do
37
+ expect(KnapsackPro::Adapters::RSpecAdapter).to receive(:verify_bind_method_called)
38
+
37
39
  expect(Rake::Task).to receive(:[]).with('knapsack_pro:rspec_run').at_least(1).and_return(task)
38
40
 
39
41
  t = double
@@ -26,6 +26,8 @@ describe KnapsackPro::Runners::SpinachRunner do
26
26
  end
27
27
 
28
28
  before do
29
+ expect(KnapsackPro::Adapters::SpinachAdapter).to receive(:verify_bind_method_called)
30
+
29
31
  expect(Kernel).to receive(:system).with('KNAPSACK_PRO_RECORDING_ENABLED=true KNAPSACK_PRO_TEST_SUITE_TOKEN=spinach-token bundle exec spinach --custom-arg --features_path fake-test-dir -- features/a.feature features/b.feature')
30
32
  end
31
33
 
@@ -16,6 +16,8 @@ describe KnapsackPro::Runners::TestUnitRunner do
16
16
 
17
17
  context 'when test files were returned by Knapsack Pro API' do
18
18
  it 'runs tests' do
19
+ expect(KnapsackPro::Adapters::TestUnitAdapter).to receive(:verify_bind_method_called)
20
+
19
21
  test_file_paths = ['test-unit_fake/a_test.rb', 'test-unit_fake/b_test.rb']
20
22
  runner = instance_double(described_class,
21
23
  test_dir: 'test-unit_fake',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knapsack_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ArturT
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-06 00:00:00.000000000 Z
11
+ date: 2021-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -408,7 +408,7 @@ metadata:
408
408
  documentation_uri: https://docs.knapsackpro.com/integration/
409
409
  homepage_uri: https://knapsackpro.com
410
410
  source_code_uri: https://github.com/KnapsackPro/knapsack_pro-ruby
411
- post_install_message:
411
+ post_install_message:
412
412
  rdoc_options: []
413
413
  require_paths:
414
414
  - lib
@@ -424,7 +424,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
424
424
  version: '0'
425
425
  requirements: []
426
426
  rubygems_version: 3.0.6
427
- signing_key:
427
+ signing_key:
428
428
  specification_version: 4
429
429
  summary: Knapsack Pro splits tests across parallel CI nodes and ensures each parallel
430
430
  job finish work at a similar time.