quarantine 2.1.2 → 2.1.3

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: 5b572688cff1561139754374abf14bfc0fbbce203dd7ab8d0db5916b2c5b67ba
4
- data.tar.gz: 8dfc948827ad091c3424dd425ba157294340fff95ec603e76f1ffcc5059541bd
3
+ metadata.gz: 6ab8e4aa2ba3c2ab497cb3adfb08b6c14459eab525f26a00f4bc1fb9b27e1084
4
+ data.tar.gz: ffafe0bdf3508389ae614ab5b8946c4cb9b5303f7697ca4b378b6284f335375f
5
5
  SHA512:
6
- metadata.gz: 879da05b1135ab244f4246e8003418a0e5b50f68ac7ca408b7ead93ebc44b5b54676d84be4b6793166c84ddf4816f92c09664ad6d78cc02755c7bf4c0de181b9
7
- data.tar.gz: d7d9cc51559136896dde5ad0ebde281542cbe2ed4b0a42a7dfa508a264d070bab67d1ea9dfe1c213e50fa98308e85430791d69e57b301c1d1d11ce3883bcfeab
6
+ metadata.gz: c4d12718e41b13558f30add75b2a5d5e25f5d29d4e19b55704e7500c1980f7192ed1a8fa3e4fc83e45329486c94bae42bd56f99a718144f42c6884878b926faf
7
+ data.tar.gz: 283aa10d1dafe98d3e5ed08f1add97facdcfbe6f4a1761759e42677b7dd26fafbc323d958ab81965076a1d19e951e18c67e35e01679ad43e44d622876649641f
data/lib/quarantine.rb CHANGED
@@ -66,7 +66,7 @@ class Quarantine
66
66
 
67
67
  # Scans the test_statuses from the database and store their IDs in quarantined_ids
68
68
  sig { void }
69
- def fetch_test_statuses
69
+ def on_start
70
70
  begin
71
71
  test_statuses = database.fetch_items(@options[:test_statuses_table_name])
72
72
  rescue Quarantine::DatabaseError => e
@@ -103,24 +103,40 @@ class Quarantine
103
103
  end
104
104
 
105
105
  sig { void }
106
- def upload_tests
107
- return if @tests.empty? || @tests.values.count { |test| test.status == :quarantined } >= @options[:failsafe_limit]
106
+ def on_complete
107
+ quarantined_tests = @tests.values.select { |test| test.status == :quarantined }.sort_by(&:id)
108
108
 
109
- begin
110
- timestamp = Time.now.to_i / 1000 # Truncated millisecond from timestamp for reasons specific to Flexport
111
- database.write_items(
112
- @options[:test_statuses_table_name],
113
- @tests.values.map { |item| item.to_hash.merge('updated_at' => timestamp) }
114
- )
115
- rescue Quarantine::DatabaseError => e
116
- @database_failures << "#{e.cause&.class}: #{e.cause&.message}"
109
+ if !@options[:record_tests]
110
+ log('Recording tests disabled; skipping')
111
+ elsif @tests.empty?
112
+ log('No tests found; skipping recording')
113
+ elsif quarantined_tests.count { |test| old_tests[test.id]&.status != :quarantined } >= @options[:failsafe_limit]
114
+ log('Number of quarantined tests above failsafe limit; skipping recording')
115
+ else
116
+ begin
117
+ timestamp = Time.now.to_i / 1000 # Truncated millisecond from timestamp for reasons specific to Flexport
118
+ database.write_items(
119
+ @options[:test_statuses_table_name],
120
+ @tests.values.map { |item| item.to_hash.merge('updated_at' => timestamp) }
121
+ )
122
+ rescue Quarantine::DatabaseError => e
123
+ @database_failures << "#{e.cause&.class}: #{e.cause&.message}"
124
+ end
117
125
  end
126
+
127
+ log(<<~MESSAGE)
128
+ \n[quarantine] Quarantined tests:
129
+ #{quarantined_tests.map { |test| "#{test.id} #{test.full_description}" }.join("\n ")}
130
+
131
+ [quarantine] Database errors:
132
+ #{@database_failures.join("\n ")}
133
+ MESSAGE
118
134
  end
119
135
 
120
136
  # Param: RSpec::Core::Example
121
137
  # Add the example to the internal tests list
122
138
  sig { params(example: T.untyped, status: Symbol, passed: T::Boolean).void }
123
- def record_test(example, status, passed:)
139
+ def on_test(example, status, passed:)
124
140
  extra_attributes = @options[:extra_attributes] ? @options[:extra_attributes].call(example) : {}
125
141
 
126
142
  new_consecutive_passes = passed ? (@old_tests[example.id]&.consecutive_passes || 0) + 1 : 0
@@ -145,15 +161,8 @@ class Quarantine
145
161
  @old_tests[example.id]&.status == :quarantined
146
162
  end
147
163
 
148
- sig { returns(String) }
149
- def summary
150
- quarantined_tests = @tests.values.select { |test| test.status == :quarantined }.sort_by(&:id)
151
- <<~MESSAGE
152
- \n[quarantine] Quarantined tests:
153
- #{quarantined_tests.map { |test| "#{test.id} #{test.full_description}" }.join("\n ")}
154
-
155
- [quarantine] Database errors:
156
- #{@database_failures.join("\n ")}
157
- MESSAGE
164
+ sig { params(message: String).void }
165
+ def log(message)
166
+ @options[:log].call(message) if @options[:logging]
158
167
  end
159
168
  end
@@ -21,7 +21,7 @@ class Quarantine
21
21
  sig { override.params(table_name: String).returns(T::Enumerable[Item]) }
22
22
  def fetch_items(table_name)
23
23
  parse_rows(spreadsheet.worksheet_by_title(table_name))
24
- rescue GoogleDrive::Error
24
+ rescue GoogleDrive::Error, Google::Apis::Error
25
25
  raise Quarantine::DatabaseError
26
26
  end
27
27
 
@@ -56,7 +56,7 @@ class Quarantine
56
56
  # Insert any items whose IDs weren't found in existing rows at the end
57
57
  worksheet.insert_rows(parsed_rows.count + 2, new_rows)
58
58
  worksheet.save
59
- rescue GoogleDrive::Error
59
+ rescue GoogleDrive::Error, Google::Apis::Error
60
60
  raise Quarantine::DatabaseError
61
61
  end
62
62
 
@@ -4,16 +4,12 @@ class Quarantine
4
4
  module RSpecAdapter
5
5
  extend T::Sig
6
6
 
7
- # Purpose: create an instance of Quarantine which contains information
8
- # about the test suite (ie. quarantined tests) and binds RSpec configurations
9
- # and hooks onto the global RSpec class
10
7
  sig { void }
11
8
  def self.bind
12
- bind_rspec_configurations
13
- bind_fetch_test_statuses
14
- bind_record_tests
15
- bind_upload_tests
16
- bind_logger
9
+ register_rspec_configurations
10
+ bind_on_start
11
+ bind_on_test
12
+ bind_on_complete
17
13
  end
18
14
 
19
15
  sig { returns(Quarantine) }
@@ -25,12 +21,15 @@ class Quarantine
25
21
  extra_attributes: RSpec.configuration.quarantine_extra_attributes,
26
22
  failsafe_limit: RSpec.configuration.quarantine_failsafe_limit,
27
23
  release_at_consecutive_passes: RSpec.configuration.quarantine_release_at_consecutive_passes,
24
+ logging: RSpec.configuration.quarantine_logging,
25
+ log: method(:log),
26
+ record_tests: RSpec.configuration.quarantine_record_tests
28
27
  )
29
28
  end
30
29
 
31
30
  # Purpose: binds rspec configuration variables
32
31
  sig { void }
33
- def self.bind_rspec_configurations
32
+ def self.register_rspec_configurations
34
33
  ::RSpec.configure do |config|
35
34
  config.add_setting(:quarantine_database, default: { type: :dynamodb, region: 'us-west-1' })
36
35
  config.add_setting(:quarantine_test_statuses, { default: 'test_statuses' })
@@ -45,17 +44,17 @@ class Quarantine
45
44
 
46
45
  # Purpose: binds quarantine to fetch the test_statuses from dynamodb in the before suite
47
46
  sig { void }
48
- def self.bind_fetch_test_statuses
47
+ def self.bind_on_start
49
48
  ::RSpec.configure do |config|
50
49
  config.before(:suite) do
51
- Quarantine::RSpecAdapter.quarantine.fetch_test_statuses
50
+ Quarantine::RSpecAdapter.quarantine.on_start
52
51
  end
53
52
  end
54
53
  end
55
54
 
56
55
  # Purpose: binds quarantine to record test statuses
57
56
  sig { void }
58
- def self.bind_record_tests
57
+ def self.bind_on_test
59
58
  ::RSpec.configure do |config|
60
59
  config.after(:each) do |example|
61
60
  metadata = example.metadata
@@ -68,42 +67,35 @@ class Quarantine
68
67
  # will record the failed test if it's final retry from the rspec-retry gem
69
68
  if RSpec.configuration.skip_quarantined_tests && quarantined
70
69
  example.clear_exception!
71
- Quarantine::RSpecAdapter.quarantine.record_test(example, :quarantined, passed: false)
70
+ Quarantine::RSpecAdapter.quarantine.on_test(example, :quarantined, passed: false)
72
71
  else
73
- Quarantine::RSpecAdapter.quarantine.record_test(example, :failing, passed: false)
72
+ Quarantine::RSpecAdapter.quarantine.on_test(example, :failing, passed: false)
74
73
  end
75
74
  end
76
75
  elsif metadata[:retry_attempts] > 0
77
76
  # will record the flaky test if it failed the first run but passed a subsequent run
78
- Quarantine::RSpecAdapter.quarantine.record_test(example, :quarantined, passed: false)
77
+ Quarantine::RSpecAdapter.quarantine.on_test(example, :quarantined, passed: false)
79
78
  elsif quarantined
80
- Quarantine::RSpecAdapter.quarantine.record_test(example, :quarantined, passed: true)
79
+ Quarantine::RSpecAdapter.quarantine.on_test(example, :quarantined, passed: true)
81
80
  else
82
- Quarantine::RSpecAdapter.quarantine.record_test(example, :passing, passed: true)
81
+ Quarantine::RSpecAdapter.quarantine.on_test(example, :passing, passed: true)
83
82
  end
84
83
  end
85
84
  end
86
85
  end
87
86
 
88
87
  sig { void }
89
- def self.bind_upload_tests
88
+ def self.bind_on_complete
90
89
  ::RSpec.configure do |config|
91
90
  config.after(:suite) do
92
- Quarantine::RSpecAdapter.quarantine.upload_tests if RSpec.configuration.quarantine_record_tests
91
+ Quarantine::RSpecAdapter.quarantine.on_complete
93
92
  end
94
93
  end
95
94
  end
96
95
 
97
- # Purpose: binds quarantine logger to output test to RSpec formatter messages
98
- sig { void }
99
- def self.bind_logger
100
- ::RSpec.configure do |config|
101
- config.after(:suite) do
102
- if RSpec.configuration.quarantine_logging
103
- RSpec.configuration.reporter.message(Quarantine::RSpecAdapter.quarantine.summary)
104
- end
105
- end
106
- end
96
+ sig { params(message: String).void }
97
+ def self.log(message)
98
+ RSpec.configuration.reporter.message(message)
107
99
  end
108
100
  end
109
101
  end
@@ -1,3 +1,3 @@
1
1
  class Quarantine
2
- VERSION = '2.1.2'.freeze
2
+ VERSION = '2.1.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quarantine
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flexport Engineering, Eric Zhu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-14 00:00:00.000000000 Z
11
+ date: 2021-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec