rspecq 0.1.0 → 0.2.0
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +11 -8
- data/lib/rspecq/queue.rb +14 -0
- data/lib/rspecq/reporter.rb +30 -2
- data/lib/rspecq/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87f2cf8ea2c0b03bf491442902644d24dd001265b2550c0403073d3f34d99903
|
4
|
+
data.tar.gz: 646b803ece2861f4ac8faced44f620ea5608636be38033f6931c0550bf4d79bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 418cf064a63ff4ea790495f578bb02f7c76ce6c0536af7a8fbdd8d6a293182f75cc15c587f2bcf798175f1ca0c427a208d8db326d157eacfcc199b783ce00d26
|
7
|
+
data.tar.gz: c109a02fc2412f7bb412422d97ee8096d85795893904d7034bbf7928d9c4d8fc5492f279d3f8cfaa77a4065f2ec591ac23915a7d53c181340610c057558fa16f
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,15 @@ Breaking changes are prefixed with a "[BREAKING]" label.
|
|
4
4
|
|
5
5
|
## master (unreleased)
|
6
6
|
|
7
|
+
|
8
|
+
|
9
|
+
## 0.2.0 (2020-08-31)
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- Flaky jobs are now printed by the reporter in the final build output and also
|
14
|
+
emitted to Sentry (if the integration is enabled) [[#26](https://github.com/skroutz/rspecq/pull/26)]
|
15
|
+
|
7
16
|
## 0.1.0 (2020-08-27)
|
8
17
|
|
9
18
|
### Added
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ and [ci-queue](https://github.com/Shopify/ci-queue).
|
|
13
13
|
|
14
14
|
## Features
|
15
15
|
|
16
|
-
- Run an RSpec suite among many workers
|
16
|
+
- Run an RSpec suite among many workers
|
17
17
|
(potentially located in different hosts) in a distributed fashion,
|
18
18
|
facilitating faster CI builds.
|
19
19
|
- Consolidated, real-time reporting of a build's progress.
|
@@ -21,11 +21,11 @@ and [ci-queue](https://github.com/Shopify/ci-queue).
|
|
21
21
|
automatically scheduling slow spec files as individual examples. See
|
22
22
|
[*Spec file splitting*](#spec-file-splitting).
|
23
23
|
- Automatic retry of test failures before being considered legit, in order to
|
24
|
-
rule out flakiness.
|
24
|
+
rule out flakiness. Additionally, flaky tests are detected and provided to
|
25
|
+
the user. See [*Requeues*](#requeues).
|
25
26
|
- Handles intermittent worker failures (e.g. network hiccups, faulty hardware etc.)
|
26
27
|
by detecting non-responsive workers and requeing their jobs. See [*Worker failures*](#worker-failures)
|
27
|
-
-
|
28
|
-
RSpecQ-level events.
|
28
|
+
- Sentry integration for monitoring build-level events. See [*Sentry integration*](#sentry-integration).
|
29
29
|
- [PLANNED] StatsD integration for various build-level metrics and insights.
|
30
30
|
See [#2](https://github.com/skroutz/rspecq/issues/2).
|
31
31
|
|
@@ -124,10 +124,13 @@ dynamically (see #3).
|
|
124
124
|
|
125
125
|
As a mitigation technique against flaky tests, if an example fails it will be
|
126
126
|
put back to the queue to be picked up by another worker. This will be repeated
|
127
|
-
up to a certain number of times (set with the `--max-requeues` option), after
|
128
|
-
which the example will be considered a legit failure and printed as such in the
|
127
|
+
up to a certain number of times (set with the `--max-requeues` option), after
|
128
|
+
which the example will be considered a legit failure and printed as such in the
|
129
129
|
final report.
|
130
130
|
|
131
|
+
Flaky tests are also detected and printed as such in the final report. They are
|
132
|
+
also emitted to Sentry (see [Sentry integration](#sentry-integration)).
|
133
|
+
|
131
134
|
### Worker failures
|
132
135
|
|
133
136
|
It's not uncommon for CI processes to encounter unrecoverable failures for
|
@@ -173,8 +176,8 @@ rejects).
|
|
173
176
|
The downside of this design is that it's more complicated, since the scheduling
|
174
177
|
of spec files happens based on timings calculated from previous runs. This
|
175
178
|
means that RSpecQ maintains a key with the timing of each job and updates it
|
176
|
-
on every run (if the `--timings` option was used). Also, RSpecQ has a
|
177
|
-
file threshold" which, currently has to be set manually (but this can be
|
179
|
+
on every run (if the `--update-timings` option was used). Also, RSpecQ has a
|
180
|
+
"slow file threshold" which, currently has to be set manually (but this can be
|
178
181
|
improved in the future).
|
179
182
|
|
180
183
|
|
data/lib/rspecq/queue.rb
CHANGED
@@ -184,6 +184,7 @@ module RSpecQ
|
|
184
184
|
@redis.hgetall(key_errors)
|
185
185
|
end
|
186
186
|
|
187
|
+
# True if the build is complete, false otherwise
|
187
188
|
def exhausted?
|
188
189
|
return false if !published?
|
189
190
|
|
@@ -216,6 +217,19 @@ module RSpecQ
|
|
216
217
|
@redis.lrange(key_queue_unprocessed, 0, -1)
|
217
218
|
end
|
218
219
|
|
220
|
+
# Returns the jobs considered flaky (i.e. initially failed but passed
|
221
|
+
# after being retried). Must be called after the build is complete,
|
222
|
+
# otherwise an exception will be raised.
|
223
|
+
def flaky_jobs
|
224
|
+
raise "Queue is not yet exhausted" if !exhausted?
|
225
|
+
|
226
|
+
requeued = @redis.hkeys(key_requeues)
|
227
|
+
|
228
|
+
return [] if requeued.empty?
|
229
|
+
|
230
|
+
requeued - @redis.hkeys(key_failures)
|
231
|
+
end
|
232
|
+
|
219
233
|
# redis: STRING [STATUS_INITIALIZING, STATUS_READY]
|
220
234
|
def key_queue_status
|
221
235
|
key("queue", "status")
|
data/lib/rspecq/reporter.rb
CHANGED
@@ -45,8 +45,13 @@ module RSpecQ
|
|
45
45
|
raise "Build not finished after #{@timeout} seconds" if !finished
|
46
46
|
|
47
47
|
@queue.record_build_time(tests_duration)
|
48
|
+
|
49
|
+
flaky_jobs = @queue.flaky_jobs
|
50
|
+
|
48
51
|
puts summary(@queue.example_failures, @queue.non_example_errors,
|
49
|
-
|
52
|
+
flaky_jobs, humanize_duration(tests_duration))
|
53
|
+
|
54
|
+
flaky_jobs_to_sentry(flaky_jobs, tests_duration)
|
50
55
|
|
51
56
|
exit 1 if !@queue.build_successful?
|
52
57
|
end
|
@@ -60,7 +65,7 @@ module RSpecQ
|
|
60
65
|
end
|
61
66
|
|
62
67
|
# We try to keep this output consistent with RSpec's original output
|
63
|
-
def summary(failures, errors, duration)
|
68
|
+
def summary(failures, errors, flaky_jobs, duration)
|
64
69
|
failed_examples_section = "\nFailed examples:\n\n"
|
65
70
|
|
66
71
|
failures.each do |_job, msg|
|
@@ -81,6 +86,14 @@ module RSpecQ
|
|
81
86
|
"#{errors.count} errors"
|
82
87
|
summary << "\n\n"
|
83
88
|
summary << "Spec execution time: #{duration}"
|
89
|
+
|
90
|
+
if !flaky_jobs.empty?
|
91
|
+
summary << "\n\n"
|
92
|
+
summary << "Flaky jobs detected (count=#{flaky_jobs.count}):\n"
|
93
|
+
flaky_jobs.each { |j| summary << " #{j}\n" }
|
94
|
+
end
|
95
|
+
|
96
|
+
summary
|
84
97
|
end
|
85
98
|
|
86
99
|
def failure_formatted(rspec_output)
|
@@ -90,5 +103,20 @@ module RSpecQ
|
|
90
103
|
def humanize_duration(seconds)
|
91
104
|
Time.at(seconds).utc.strftime("%H:%M:%S")
|
92
105
|
end
|
106
|
+
|
107
|
+
def flaky_jobs_to_sentry(jobs, build_duration)
|
108
|
+
return if jobs.empty?
|
109
|
+
|
110
|
+
Raven.capture_message("Flaky jobs detected", level: "warning", extra: {
|
111
|
+
build: @build_id,
|
112
|
+
build_timeout: @timeout,
|
113
|
+
queue: @queue.inspect,
|
114
|
+
object: self.inspect,
|
115
|
+
pid: Process.pid,
|
116
|
+
flaky_jobs: jobs,
|
117
|
+
flaky_jobs_count: jobs.count,
|
118
|
+
build_duration: build_duration
|
119
|
+
})
|
120
|
+
end
|
93
121
|
end
|
94
122
|
end
|
data/lib/rspecq/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspecq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Agis Anastasopoulos
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-08-
|
11
|
+
date: 2020-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-core
|
@@ -148,7 +148,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
148
|
- !ruby/object:Gem::Version
|
149
149
|
version: '0'
|
150
150
|
requirements: []
|
151
|
-
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.7.6.2
|
152
153
|
signing_key:
|
153
154
|
specification_version: 4
|
154
155
|
summary: Optimally distribute and run RSpec suites among parallel workers; for faster
|