minitest-distributed 0.2.10 → 0.2.12

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a59856c10fd7a252d95609f66242a4c9706f91d6e7fb57a226914a7e816e04ee
4
- data.tar.gz: 024e72b9de525b048dbdc0a6f97b7721a24fd39803030dec85cf080832dfcfd3
3
+ metadata.gz: 722ec2cc00da4f9c5f5efc0591e39c2becc2338ce7fe171c60339d284116242b
4
+ data.tar.gz: aa1d3c52afa3b16c649a0b12d27e83ccb19ae11dd80fb68d3e57a669e0a081e5
5
5
  SHA512:
6
- metadata.gz: 401e8fcb14acf32f0e3904038e30d15bbc801e1cf7672c93b16c09d506829c46dc58fff771766ddd508e46d8740748a5688a8c0125ce19bafa8fe2dd16a81909
7
- data.tar.gz: d0082e9f6d731b73651e26c6a6ea943ff782b93cca2c11de19308b1e97a415f06450770a858ea6e176153df5183710a6dd2f2bc327474dde930b1d8685f40c08
6
+ metadata.gz: c2cfc291aeb202bb680b04a6e579272fd907efe47ef1d5e5ea2b66ca5ffe23967ded9ea38458e485e1e9b42609d84a2058fd2df3250217cf76a60272f3b3255c
7
+ data.tar.gz: cb0934c54f7c3bdcc76abe8c0593b08e2e7ddfacd9cf2c4e7ce3a71e586b2e75170be91ebe3ac8b520fb7c8c7e4e961ae4a9a218c582bf1301dc916f41427847
data/.rubocop.yml CHANGED
@@ -9,7 +9,6 @@ require:
9
9
  - rubocop-minitest
10
10
 
11
11
  AllCops:
12
- TargetRubyVersion: 2.6
13
12
  UseCache: true
14
13
  CacheRootDirectory: tmp/rubocop
15
14
  Exclude:
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/README.md CHANGED
@@ -23,12 +23,6 @@ flakiness. To combat flakiness, minitest-distributed implements resiliency
23
23
  patterns, like re-running a test on a different worker on failure, and a
24
24
  circuit breaker for misbehaving workers.
25
25
 
26
- | | |
27
- |----------------|--------------------------------------------------------------------------------------------------------------------------------------|
28
- | Current status | Ongoing |
29
- | Owner | [@Shopify/test-infra](https://github.com/orgs/Shopify/teams/test-infra) |
30
- | Help | [#team-test-infra](https://shopify.slack.com/archives/team-test-infra) |
31
-
32
26
  ## Commands
33
27
  **Distributed invocation**
34
28
 
data/dev.yml CHANGED
@@ -3,5 +3,6 @@ name: minitest-distributed
3
3
  type: ruby
4
4
 
5
5
  up:
6
- - ruby: 3.2.0
6
+ - ruby
7
7
  - bundler
8
+ - redis
@@ -105,15 +105,17 @@ module Minitest
105
105
 
106
106
  sig { returns(Coordinators::CoordinatorInterface) }
107
107
  def coordinator
108
- @coordinator = T.let(@coordinator, T.nilable(Coordinators::CoordinatorInterface))
109
- @coordinator ||= case coordinator_uri.scheme
110
- when "redis"
111
- Coordinators::RedisCoordinator.new(configuration: self)
112
- when "memory"
113
- Coordinators::MemoryCoordinator.new(configuration: self)
114
- else
115
- raise NotImplementedError, "Unknown coordinator implementation: #{coordinator_uri.scheme}"
116
- end
108
+ @coordinator ||= T.let(
109
+ case coordinator_uri.scheme
110
+ when "redis"
111
+ Coordinators::RedisCoordinator.new(configuration: self)
112
+ when "memory"
113
+ Coordinators::MemoryCoordinator.new(configuration: self)
114
+ else
115
+ raise NotImplementedError, "Unknown coordinator implementation: #{coordinator_uri.scheme}"
116
+ end,
117
+ T.nilable(Coordinators::CoordinatorInterface),
118
+ )
117
119
  end
118
120
  end
119
121
  end
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "redis"
5
5
  require "set"
6
+ require "logger"
6
7
 
7
8
  module Minitest
8
9
  module Distributed
@@ -268,13 +269,30 @@ module Minitest
268
269
 
269
270
  sig { returns(Redis) }
270
271
  def redis
271
- @redis ||= Redis.new(url: configuration.coordinator_uri.to_s)
272
+ @redis ||= Redis.new(
273
+ url: configuration.coordinator_uri.to_s,
274
+ middlewares: custom_middlewares,
275
+ custom: custom_config,
276
+ timeout: 2,
277
+ )
278
+ end
279
+
280
+ sig { returns(T.nilable(T::Array[Module])) }
281
+ def custom_middlewares
282
+ return unless ENV.key?("MINITEST_DISTRIBUTED_REDIS_LOG")
283
+
284
+ require_relative "redis_instrumentation_middleware"
285
+ [RedisInstrumentationMiddleware]
286
+ end
287
+
288
+ sig { returns(T.nilable(T::Hash[Symbol, File])) }
289
+ def custom_config
290
+ { log_file: logger }.compact
272
291
  end
273
292
 
274
293
  sig { returns(String) }
275
294
  def register_consumergroup_script
276
- @register_consumergroup_script = T.let(@register_consumergroup_script, T.nilable(String))
277
- @register_consumergroup_script ||= redis.script(:load, <<~LUA)
295
+ @register_consumergroup_script ||= T.let(redis.script(:load, <<~LUA), T.nilable(String))
278
296
  -- Try to create the consumergroup. This will raise an error if the
279
297
  -- consumergroup has already been registered by somebody else, which
280
298
  -- means another worker will be acting as leader.
@@ -518,6 +536,13 @@ module Minitest
518
536
  adjust_combined_results(batch_result_aggregate)
519
537
  end
520
538
 
539
+ sig { returns(T.nilable(Logger)) }
540
+ def logger
541
+ return unless (log_path = ENV["MINITEST_DISTRIBUTED_REDIS_LOG"])
542
+
543
+ @logger ||= T.let(Logger.new(log_path), T.nilable(Logger))
544
+ end
545
+
521
546
  INITIAL_BACKOFF = 10 # milliseconds
522
547
  private_constant :INITIAL_BACKOFF
523
548
  end
@@ -0,0 +1,39 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "redis"
5
+
6
+ module Minitest
7
+ module Distributed
8
+ module Coordinators
9
+ # Redis middleware that logs all Redis commands to a file for debugging.
10
+ module RedisInstrumentationMiddleware
11
+ extend T::Sig
12
+
13
+ sig { params(command: T::Array[T.untyped], redis_config: T.untyped).returns(T.untyped) }
14
+ def call(command, redis_config)
15
+ log_file = redis_config.custom[:log_file]
16
+ log_file.info("EXEC: #{command.inspect}")
17
+ result = super
18
+ log_file.info("RESULT: #{result.inspect}")
19
+ result
20
+ rescue => e
21
+ log_file.info("ERROR: #{e.class}")
22
+ Kernel.raise
23
+ end
24
+
25
+ sig { params(commands: T::Array[T.untyped], redis_config: T.untyped).returns(T.untyped) }
26
+ def call_pipelined(commands, redis_config)
27
+ log_file = redis_config.custom[:log_file]
28
+ log_file.info("EXEC PIPELINED: #{commands.inspect}")
29
+ result = super
30
+ log_file.info("RESULT PIPELINED: #{result.inspect}")
31
+ result
32
+ rescue => e
33
+ log_file.info("ERROR PIPELINED: #{e.class}")
34
+ Kernel.raise
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -61,8 +61,7 @@ module Minitest
61
61
 
62
62
  sig { returns(T::Boolean) }
63
63
  def success?
64
- @success = T.let(@success, T.nilable(T::Boolean))
65
- @success ||= @block.call
64
+ @success ||= T.let(@block.call, T.nilable(T::Boolean))
66
65
  end
67
66
 
68
67
  sig { returns(T::Boolean) }
@@ -72,14 +71,12 @@ module Minitest
72
71
 
73
72
  sig { returns(Commit) }
74
73
  def self.success
75
- @success = T.let(@success, T.nilable(Commit))
76
- @success ||= new { true }
74
+ @success ||= T.let(new { true }, T.nilable(Commit))
77
75
  end
78
76
 
79
77
  sig { returns(Commit) }
80
78
  def self.failure
81
- @failure = T.let(@failure, T.nilable(Commit))
82
- @failure ||= new { false }
79
+ @failure ||= T.let(new { false }, T.nilable(Commit))
83
80
  end
84
81
  end
85
82
 
@@ -106,13 +103,18 @@ module Minitest
106
103
 
107
104
  sig { returns(Minitest::Result) }
108
105
  def committed_result
109
- @committed_result = T.let(@committed_result, T.nilable(Minitest::Result))
110
- @committed_result ||= if final? && commit.failure?
111
- # If a runnable result is final, but the acked failed, we will discard the result.
112
- Minitest::Discard.wrap(initial_result, test_timeout_seconds: enqueued_runnable.test_timeout_seconds)
113
- else
114
- initial_result
115
- end
106
+ @committed_result ||= T.let(
107
+ if final? && commit.failure?
108
+ # If a runnable result is final, but the acked failed, we will discard the result.
109
+ Minitest::Discard.wrap(
110
+ initial_result,
111
+ test_timeout_seconds: enqueued_runnable.test_timeout_seconds,
112
+ )
113
+ else
114
+ initial_result
115
+ end,
116
+ T.nilable(Minitest::Result),
117
+ )
116
118
  end
117
119
  end
118
120
 
@@ -67,14 +67,12 @@ module Minitest
67
67
 
68
68
  sig { returns(ResultAggregate) }
69
69
  def local_results
70
- @local_results = T.let(@local_results, T.nilable(ResultAggregate))
71
- @local_results ||= configuration.coordinator.local_results
70
+ @local_results ||= T.let(configuration.coordinator.local_results, T.nilable(ResultAggregate))
72
71
  end
73
72
 
74
73
  sig { returns(ResultAggregate) }
75
74
  def combined_results
76
- @combined_results = T.let(@combined_results, T.nilable(ResultAggregate))
77
- @combined_results ||= configuration.coordinator.combined_results
75
+ @combined_results ||= T.let(configuration.coordinator.combined_results, T.nilable(ResultAggregate))
78
76
  end
79
77
 
80
78
  sig { returns(Configuration) }
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Minitest
5
5
  module Distributed
6
- VERSION = "0.2.10"
6
+ VERSION = "0.2.12"
7
7
  end
8
8
  end
@@ -1,7 +1,7 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative "./distributed"
4
+ require_relative "distributed"
5
5
 
6
6
  module Minitest
7
7
  class << self
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.homepage = "https://github.com/Shopify/minitest-distributed"
29
29
  spec.license = "MIT"
30
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
30
+ spec.required_ruby_version = ">= 2.7.0"
31
31
 
32
32
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
33
33
 
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
38
38
  # Specify which files should be added to the gem when it is released.
39
39
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
40
40
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
41
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
41
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|.shopify-build|.github)/}) }
42
42
  end
43
43
  spec.bindir = "exe"
44
44
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -47,4 +47,5 @@ Gem::Specification.new do |spec|
47
47
  spec.add_dependency('minitest', '~> 5.12')
48
48
  spec.add_dependency('redis', '>= 5.0.6', '< 6')
49
49
  spec.add_dependency('sorbet-runtime')
50
+ spec.add_dependency('rexml')
50
51
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-distributed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.10
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Bergen
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2023-08-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: minitest
@@ -58,6 +57,20 @@ dependencies:
58
57
  - - ">="
59
58
  - !ruby/object:Gem::Version
60
59
  version: '0'
60
+ - !ruby/object:Gem::Dependency
61
+ name: rexml
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
61
74
  description: |
62
75
  minitest-distributed is a plugin for minitest for executing tests on a
63
76
  distributed set of unreliable workers.
@@ -80,12 +93,10 @@ executables: []
80
93
  extensions: []
81
94
  extra_rdoc_files: []
82
95
  files:
83
- - ".github/ISSUE_TEMPLATE/bug_report.md"
84
- - ".github/dependabot.yml"
85
- - ".github/workflows/ruby.yml"
86
96
  - ".gitignore"
87
97
  - ".rubocop.yml"
88
98
  - ".rubocop_todo.yml"
99
+ - ".ruby-version"
89
100
  - CODEOWNERS
90
101
  - CODE_OF_CONDUCT.md
91
102
  - Gemfile
@@ -104,6 +115,7 @@ files:
104
115
  - lib/minitest/distributed/coordinators/coordinator_interface.rb
105
116
  - lib/minitest/distributed/coordinators/memory_coordinator.rb
106
117
  - lib/minitest/distributed/coordinators/redis_coordinator.rb
118
+ - lib/minitest/distributed/coordinators/redis_instrumentation_middleware.rb
107
119
  - lib/minitest/distributed/enqueued_runnable.rb
108
120
  - lib/minitest/distributed/filters/exclude_file_filter.rb
109
121
  - lib/minitest/distributed/filters/exclude_filter.rb
@@ -157,7 +169,6 @@ metadata:
157
169
  allowed_push_host: https://rubygems.org
158
170
  homepage_uri: https://github.com/Shopify/minitest-distributed
159
171
  source_code_uri: https://github.com/Shopify/minitest-distributed
160
- post_install_message:
161
172
  rdoc_options: []
162
173
  require_paths:
163
174
  - lib
@@ -165,15 +176,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
165
176
  requirements:
166
177
  - - ">="
167
178
  - !ruby/object:Gem::Version
168
- version: 2.3.0
179
+ version: 2.7.0
169
180
  required_rubygems_version: !ruby/object:Gem::Requirement
170
181
  requirements:
171
182
  - - ">="
172
183
  - !ruby/object:Gem::Version
173
184
  version: '0'
174
185
  requirements: []
175
- rubygems_version: 3.4.18
176
- signing_key:
186
+ rubygems_version: 3.7.2
177
187
  specification_version: 4
178
188
  summary: Distributed test executor plugin for Minitest
179
189
  test_files: []
@@ -1,43 +0,0 @@
1
- ---
2
- name: Bug report
3
- about: Create a report to help us improve
4
- title: "[BUG]"
5
- labels: bug
6
- assignees: ''
7
-
8
- ---
9
-
10
- **Describe the issue**
11
- A clear and concise description of the issue you're facing.
12
-
13
- **To Reproduce**
14
- Steps to reproduce the behaviour:
15
- 1. Go to '...'
16
- 2. Click on '....'
17
- 3. Scroll down to '....'
18
- 4. See error
19
-
20
- **Expected behaviour**
21
- A clear and concise description of what you expected to happen.
22
-
23
- **Screenshots**
24
- If applicable, add screenshots to help explain your problem.
25
-
26
- **What team are you on?**
27
- Please provide the name of your team.
28
-
29
- **Helpful links (Logs, Link to Build, Repo, PR etc.)**
30
- Please provide any helpful links for investigating the issue.
31
-
32
- **Is there a Slack thread related to this bug?**
33
- After submitting this issue, you can use: @spy github issues create_comment repo=minitest-distributed issue_id=$NEW_ISSUE_ID on any relevant Slack threads to save that information here.
34
-
35
- **Additional context**
36
- Add any other context about the problem here.
37
-
38
- If possible, assign appropriate severity level, priority (high, medium, low) and difficulty (easy, normal, difficult) labels to the issue.
39
- SEV-1 <24-72h - Critical issue that actively impacts multiple users/products.
40
- SEV-2 <14 days - Limited impact app or major inconvenience to app users, workarounds available.
41
- SEV-3 <60 days - Minor issue requiring action, but not affecting a users ability to use the app.
42
- SEV-4 <180 days - Minimal impact but something the team wants to fix eventually.
43
- SEV-5 No timeline - Cosmetic issue or bugs, no effect on user's ability to use tooling.
@@ -1,20 +0,0 @@
1
- version: 2
2
- registries:
3
- rubygems-server-pkgs-shopify-io:
4
- type: rubygems-server
5
- url: https://pkgs.shopify.io
6
- username: ${{secrets.RUBYGEMS_SERVER_PKGS_SHOPIFY_IO_USERNAME}}
7
- password: ${{secrets.RUBYGEMS_SERVER_PKGS_SHOPIFY_IO_PASSWORD}}
8
- github-com:
9
- type: git
10
- url: https://github.com
11
- username: ${{secrets.DEPENDENCIES_GITHUB_USER}}
12
- password: ${{secrets.DEPENDENCIES_GITHUB_TOKEN}}
13
- updates:
14
- - package-ecosystem: bundler
15
- directory: "/"
16
- schedule:
17
- interval: daily
18
- open-pull-requests-limit: 100
19
- insecure-external-code-execution: allow
20
- registries: "*"
@@ -1,111 +0,0 @@
1
- # This workflow uses actions that are not certified by GitHub.
2
- # They are provided by a third-party and are governed by
3
- # separate terms of service, privacy policy, and support
4
- # documentation.
5
- # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
- # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
-
8
- name: Ruby
9
-
10
- on: push
11
-
12
- jobs:
13
- test_32:
14
- runs-on: shopify-ubuntu-latest
15
- container: ruby:3.2
16
-
17
- services:
18
- redis:
19
- image: redis
20
- toxiproxy:
21
- image: ghcr.io/shopify/toxiproxy:2.5.0
22
-
23
- steps:
24
- - uses: actions/checkout@v2
25
- - name: Install dependencies
26
- run: gem install bundler && bundle install
27
- - name: Run tests
28
- run: bin/rake test
29
- env:
30
- REDIS_URL: redis://toxiproxy:22220
31
- TOXIPROXY_HOST: http://toxiproxy:8474
32
-
33
- test_31:
34
- runs-on: shopify-ubuntu-latest
35
- container: ruby:3.1
36
-
37
- services:
38
- redis:
39
- image: redis
40
- toxiproxy:
41
- image: ghcr.io/shopify/toxiproxy:2.5.0
42
-
43
- steps:
44
- - uses: actions/checkout@v2
45
- - name: Install dependencies
46
- run: gem install bundler && bundle install
47
- - name: Run tests
48
- run: bin/rake test
49
- env:
50
- REDIS_URL: redis://toxiproxy:22220
51
- TOXIPROXY_HOST: http://toxiproxy:8474
52
-
53
- test_30:
54
- runs-on: shopify-ubuntu-latest
55
- container: ruby:3.0
56
-
57
- services:
58
- redis:
59
- image: redis
60
- toxiproxy:
61
- image: ghcr.io/shopify/toxiproxy:2.5.0
62
-
63
- steps:
64
- - uses: actions/checkout@v2
65
- - name: Install dependencies
66
- run: gem install bundler && bundle install
67
- - name: Run tests
68
- run: bin/rake test
69
- env:
70
- REDIS_URL: redis://toxiproxy:22220
71
- TOXIPROXY_HOST: http://toxiproxy:8474
72
-
73
- test_27:
74
- runs-on: shopify-ubuntu-latest
75
- container: ruby:2.7
76
-
77
- services:
78
- redis:
79
- image: redis
80
- toxiproxy:
81
- image: ghcr.io/shopify/toxiproxy:2.5.0
82
-
83
- steps:
84
- - uses: actions/checkout@v2
85
- - name: Install dependencies
86
- run: gem install bundler && bundle install
87
- - name: Run tests
88
- run: bin/rake test
89
- env:
90
- REDIS_URL: redis://toxiproxy:22220
91
- TOXIPROXY_HOST: http://toxiproxy:8474
92
-
93
- typecheck:
94
- runs-on: shopify-ubuntu-latest
95
- container: ruby:2.7
96
- steps:
97
- - uses: actions/checkout@v2
98
- - name: Install dependencies
99
- run: gem install bundler && bundle install
100
- - name: Typecheck Ruby code
101
- run: bin/srb tc
102
-
103
- lint:
104
- runs-on: shopify-ubuntu-latest
105
- container: ruby:3.2
106
- steps:
107
- - uses: actions/checkout@v2
108
- - name: Install dependencies
109
- run: gem install bundler && bundle install
110
- - name: Lint Ruby code
111
- run: bin/rubocop