specwrk 0.4.5 → 0.4.7
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/.circleci/config.yml +155 -0
- data/CHANGELOG.md +39 -2
- data/README.md +38 -3
- data/config.ru +3 -0
- data/docker/Dockerfile.server +10 -0
- data/docker/entrypoint.server.sh +3 -1
- data/lib/specwrk/cli.rb +9 -1
- data/lib/specwrk/client.rb +2 -2
- data/lib/specwrk/version.rb +1 -1
- data/lib/specwrk/web/app.rb +1 -1
- data/lib/specwrk/web/endpoints.rb +1 -3
- data/lib/specwrk/web/logger.rb +6 -2
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed8dbd2952f7e8caf1de7903bb7a03b02ddaba8a735246e347b2f56e7770b22e
|
4
|
+
data.tar.gz: a4a8403a07f36363e9a7d8239f824f7d33bffed98478540a044d6f8d293b130f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa9f2687d4009ee526037b19155225d24a9746b124101962dce1ecde652ea5c0f1bc788933f4bf5c7713f7983d018b7d5a2ddf2684361b6d5c0a951518010391
|
7
|
+
data.tar.gz: 77dd8e7ea504a2e02905f7dd6b5a1d13ece46a72653af791cea40bc6e3dbf9788c9238c28b1ee70cdcc0f8bab59c5dc235012cbe8d8ddf43541db3c5ddf06f7c
|
@@ -0,0 +1,155 @@
|
|
1
|
+
version: 2.1
|
2
|
+
|
3
|
+
workflows:
|
4
|
+
test_workflow:
|
5
|
+
jobs:
|
6
|
+
- test
|
7
|
+
- specwrk-single-node
|
8
|
+
- specwrk-multi-node-prepare
|
9
|
+
- specwrk-multi-node:
|
10
|
+
requires:
|
11
|
+
- specwrk-multi-node-prepare
|
12
|
+
|
13
|
+
jobs:
|
14
|
+
test:
|
15
|
+
docker:
|
16
|
+
- image: cimg/ruby:3.4.4
|
17
|
+
working_directory: ~/project
|
18
|
+
steps:
|
19
|
+
- checkout
|
20
|
+
|
21
|
+
- restore_cache:
|
22
|
+
keys:
|
23
|
+
- v1-deps-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
24
|
+
- v1-deps-{{ checksum "Gemfile" }}
|
25
|
+
- v1-deps-
|
26
|
+
|
27
|
+
- run:
|
28
|
+
name: Install Gems
|
29
|
+
command: |
|
30
|
+
bundle config path vendor/bundle
|
31
|
+
bundle install --jobs 4 --retry 2
|
32
|
+
|
33
|
+
- save_cache:
|
34
|
+
paths:
|
35
|
+
- vendor/bundle
|
36
|
+
key: v1-deps-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
37
|
+
|
38
|
+
- run:
|
39
|
+
name: Run RSpec
|
40
|
+
command: bundle exec rspec
|
41
|
+
|
42
|
+
specwrk-single-node:
|
43
|
+
docker:
|
44
|
+
- image: cimg/ruby:3.4.4
|
45
|
+
working_directory: ~/project
|
46
|
+
steps:
|
47
|
+
- checkout
|
48
|
+
|
49
|
+
- restore_cache:
|
50
|
+
keys:
|
51
|
+
- v1-deps-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
52
|
+
- v1-deps-{{ checksum "Gemfile" }}
|
53
|
+
- v1-deps-
|
54
|
+
|
55
|
+
## SPECWRK STEP ##
|
56
|
+
- restore_cache:
|
57
|
+
keys:
|
58
|
+
- specwrk-{{ .Branch }}
|
59
|
+
- specwrk-
|
60
|
+
## /SPECWRK STEP ##
|
61
|
+
|
62
|
+
- run:
|
63
|
+
name: Install Gems
|
64
|
+
command: |
|
65
|
+
bundle config path vendor/bundle
|
66
|
+
bundle install --jobs 4 --retry 2
|
67
|
+
|
68
|
+
- save_cache:
|
69
|
+
paths:
|
70
|
+
- vendor/bundle
|
71
|
+
key: v1-deps-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
72
|
+
|
73
|
+
## SPECWRK STEP ##
|
74
|
+
- run:
|
75
|
+
name: Run tests via specwrk start
|
76
|
+
command: bundle exec specwrk start --count 2 spec/
|
77
|
+
## /SPECWRK STEP ##
|
78
|
+
|
79
|
+
## SPECWRK STEP ##
|
80
|
+
- save_cache:
|
81
|
+
paths:
|
82
|
+
- .specwrk/report.json
|
83
|
+
key: specwrk-{{ .Branch }}
|
84
|
+
## /SPECWRK STEP ##
|
85
|
+
|
86
|
+
specwrk-multi-node-prepare:
|
87
|
+
docker:
|
88
|
+
- image: cimg/ruby:3.4.4
|
89
|
+
steps:
|
90
|
+
- checkout
|
91
|
+
|
92
|
+
- restore_cache:
|
93
|
+
keys:
|
94
|
+
- gem-cache-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
95
|
+
- gem-cache-{{ checksum "Gemfile" }}
|
96
|
+
- gem-cache-
|
97
|
+
|
98
|
+
- run:
|
99
|
+
name: bundle install
|
100
|
+
command: |
|
101
|
+
bundle config path vendor/bundle
|
102
|
+
bundle install --jobs 4 --retry 2
|
103
|
+
|
104
|
+
- save_cache:
|
105
|
+
paths:
|
106
|
+
- vendor/bundle
|
107
|
+
key: gem-cache-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
108
|
+
|
109
|
+
## SPECWRK STEP ##
|
110
|
+
- run:
|
111
|
+
name: Seed examples to specwrk server
|
112
|
+
command: |
|
113
|
+
bundle exec specwrk seed \
|
114
|
+
--uri "$SPECWRK_URI" \
|
115
|
+
--key "$SPECWRK_KEY" \
|
116
|
+
--run "$CIRCLE_WORKFLOW_ID" \
|
117
|
+
spec/
|
118
|
+
|
119
|
+
## /SPECWRK STEP ##
|
120
|
+
|
121
|
+
specwrk-multi-node:
|
122
|
+
parallelism: 2
|
123
|
+
docker:
|
124
|
+
- image: cimg/ruby:3.4.4
|
125
|
+
working_directory: ~/project
|
126
|
+
steps:
|
127
|
+
- checkout
|
128
|
+
|
129
|
+
- restore_cache:
|
130
|
+
keys:
|
131
|
+
- v1-deps-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
132
|
+
- v1-deps-{{ checksum "Gemfile" }}
|
133
|
+
- v1-deps-
|
134
|
+
|
135
|
+
- run:
|
136
|
+
name: Install Gems
|
137
|
+
command: |
|
138
|
+
bundle config path vendor/bundle
|
139
|
+
bundle install --jobs 4 --retry 2
|
140
|
+
|
141
|
+
- save_cache:
|
142
|
+
paths:
|
143
|
+
- vendor/bundle
|
144
|
+
key: v1-deps-{{ checksum "Gemfile" }}-{{ checksum "specwrk.gemspec" }}
|
145
|
+
|
146
|
+
## SPECWRK STEP ##
|
147
|
+
- run:
|
148
|
+
name: Run tests via specwrk work
|
149
|
+
command: |
|
150
|
+
bundle exec specwrk work \
|
151
|
+
--uri "$SPECWRK_URI" \
|
152
|
+
--key "$SPECWRK_KEY" \
|
153
|
+
--run "$CIRCLE_WORKFLOW_ID" \
|
154
|
+
--count 2
|
155
|
+
## /SPECWRK STEP ##
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,42 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
##
|
3
|
+
## v0.4.5
|
4
4
|
|
5
|
-
-
|
5
|
+
- Set ENV var when generating seed examples [#47](https://github.com/danielwestendorf/specwrk/issues/47). by @danielwestendorf
|
6
|
+
## v0.4.4
|
7
|
+
|
8
|
+
- Don’t dump the completed queue if it’s empty [#45](https://github.com/danielwestendorf/specwrk/issues/45). by @danielwestendorf
|
9
|
+
- Move single-run CLI option to only be an option for the `serve` command [#41](https://github.com/danielwestendorf/specwrk/issues/41). by @danielwestendorf
|
10
|
+
- Don’t complete examples which are not in the processing queue [#44](https://github.com/danielwestendorf/specwrk/issues/44). by @danielwestendorf
|
11
|
+
|
12
|
+
## v0.4.3
|
13
|
+
|
14
|
+
- Fix CLI’s `--uri` option description. by @danielwestendorf
|
15
|
+
- Add an unauthenticated `/health` endpoint to the server [#40](https://github.com/danielwestendorf/specwrk/issues/40). by @danielwestendorf
|
16
|
+
- Add support excluding server paths from authentication [#39](https://github.com/danielwestendorf/specwrk/issues/39). by @danielwestendorf
|
17
|
+
|
18
|
+
## v0.4.2
|
19
|
+
|
20
|
+
- Add specwrk variations to CI [#38](https://github.com/danielwestendorf/specwrk/issues/38). by @danielwestendorf
|
21
|
+
- Support specifying if subsequent seeds should be ignored for a run [#37](https://github.com/danielwestendorf/specwrk/issues/37). by @danielwestendorf
|
22
|
+
|
23
|
+
## v0.4.1
|
24
|
+
|
25
|
+
- Make the number of seed waits configurable [#35](https://github.com/danielwestendorf/specwrk/issues/35). by @danielwestendorf
|
26
|
+
|
27
|
+
## v0.4.0
|
28
|
+
|
29
|
+
- Worker wait for seeding [#32](https://github.com/danielwestendorf/specwrk/issues/32). by @danielwestendorf
|
30
|
+
- Track if the worker has processed *any* examples [#31](https://github.com/danielwestendorf/specwrk/issues/31). by @danielwestendorf
|
31
|
+
|
32
|
+
## v0.3.0
|
33
|
+
|
34
|
+
- Assign `Specwrk.net_http` to `Net::HTTP` before WebMock can mock it [#22](https://github.com/danielwestendorf/specwrk/issues/22). by @danielwestendorf
|
35
|
+
- Worker PIDs representative exit status [#20](https://github.com/danielwestendorf/specwrk/issues/20). by @danielwestendorf
|
36
|
+
- Track an individual worker’s failures [#19](https://github.com/danielwestendorf/specwrk/issues/19). by @danielwestendorf
|
37
|
+
- Default localhost server URI is not SSL. by @danielwestendorf
|
38
|
+
- Handle SSL-protected srv endpoints [#18](https://github.com/danielwestendorf/specwrk/issues/18). by @danielwestendorf
|
39
|
+
|
40
|
+
## v0.2.0
|
41
|
+
|
42
|
+
- Tag v0.2.0 by @danielwestendorf
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ One CLI command to:
|
|
8
8
|
3. Execute
|
9
9
|
|
10
10
|
## Install
|
11
|
-
Start by adding specwrk to your project or installing it.
|
11
|
+
Start by adding `specwrk` to your project or installing it.
|
12
12
|
```sh
|
13
13
|
$ bundle add specwrk -g development,test
|
14
14
|
```
|
@@ -30,7 +30,7 @@ Commands:
|
|
30
30
|
```
|
31
31
|
|
32
32
|
### `specwrk start -c 8 spec/`
|
33
|
-
|
33
|
+
Intended for quick ad-hoc local host development or single-node CI runs. This command starts a queue server, seeds it with examples from the `spec/` directory, and starts `8` worker processes. It will report the ultimate success or failure.
|
34
34
|
|
35
35
|
```sh
|
36
36
|
$ start --help
|
@@ -158,14 +158,49 @@ Rails has had easy multi-process test setup for a while now by creating unique t
|
|
158
158
|
-- Capybara.server_port = 5550
|
159
159
|
++ Capybara.server_port = 5550 + ENV.fetch("TEST_ENV_NUMBER", "1").to_i
|
160
160
|
++ Capybara.always_include_port = true
|
161
|
+
-- ActiveRecord::Migration.maintain_test_schema!
|
162
|
+
++ ActiveRecord::Migration.maintain_test_schema! unless ENV["SPECWRK_SEED"]
|
161
163
|
```
|
162
164
|
|
165
|
+
YMMV, but please submit an issue if your setup required more configuration.
|
166
|
+
|
163
167
|
## CI
|
164
168
|
Run `specwrk` in CI in either a single-node or multi-node configuration.
|
165
169
|
|
166
170
|
### Single-node, multi-process
|
167
|
-
Single-node
|
171
|
+
Single-node, multi-process works best when you only have a single node running tests, but that node has many unused CPUs. This is similar to running `specwrk` locally with `bundle exec specwrk start spec/` which spins up a local server, seeds the server with examples that need to be run, and then spawns child worker processes which execute those examples in parallel.
|
172
|
+
|
173
|
+
Make sure to persist `$SPECWRK_OUT/report.json` between runs so that subsequent run queues can be optimized.
|
174
|
+
|
175
|
+
[GitHub Actions Example](https://github.com/danielwestendorf/specwrk/blob/main/.github/workflows/specwrk-single-node.yml)
|
176
|
+
|
177
|
+
[CircleCI Example](https://github.com/danielwestendorf/specwrk/blob/main/.circleci/config.yml) (specwrk-single-node job)
|
178
|
+
|
179
|
+
### Multi-node, multi-process
|
180
|
+
Multi-node, multi-process works best when have many nodes running tests. This distributes the test execution across the nodes until the queue is for the run is empty, optimizing for slowest specs first. This distributes test execution across all nodes evenly(-ish).
|
181
|
+
|
182
|
+
To accomplish this, a central queue server is required, examples must be explicitly seeded, and workers explicitly started.
|
183
|
+
|
184
|
+
1. Start a centralized queue server (see [Running a persistent Queue Server](#running-a-persistent-queue-server))
|
185
|
+
2. Seed the server with the specs for the current `SPECWWRK_RUN` pointed at your central server
|
186
|
+
3. Execute `specwrk work` for the given process count, for the current `SPECWRK_RUN`, pointed at your central server
|
187
|
+
|
188
|
+
[GitHub Actions Example](https://github.com/danielwestendorf/specwrk/blob/main/.github/workflows/specwrk-multi-node.yml)
|
189
|
+
|
190
|
+
[CircleCI Example](https://github.com/danielwestendorf/specwrk/blob/main/.circleci/config.yml) (see specwrk-multi-node-prepare, specwrk-multi-node jobs)
|
191
|
+
|
192
|
+
|
193
|
+
## Running a persistent Queue Server
|
194
|
+
Start a persistent Queue Server given one of the following methods
|
195
|
+
- The explicit ruby command `bundle exec specwrk serve --port $PORT`
|
196
|
+
- Via [docker image](https://hub.docker.com/repository/docker/danielwestendorf/specwrk-server/general): `docker run -e PORT=5139 -p 5139:5139 docker.io/danielwestendorf/specwrk-server:latest`
|
197
|
+
- By mounting the app as an Rack app (see `config.ru`)
|
198
|
+
|
199
|
+
### Configuring your Queue Server
|
200
|
+
- Secure your server with a key either with the `SPECWRK_SRV_KEY` environment variable or `--key` CLI option
|
201
|
+
- Configure the server output to be a persisted volume so your timings survive between restarts with the `SPECWRK_OUT` environment variable or `--out` CLI option
|
168
202
|
|
203
|
+
See [specwrk serve --help](#specwrk-serve) for all possible configuration options.
|
169
204
|
|
170
205
|
## Contributing
|
171
206
|
|
data/config.ru
ADDED
data/docker/Dockerfile.server
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
FROM ruby:3.4-alpine
|
2
2
|
|
3
|
+
RUN apk add --no-cache \
|
4
|
+
build-base \
|
5
|
+
ruby-dev \
|
6
|
+
linux-headers \
|
7
|
+
zlib-dev \
|
8
|
+
libffi-dev
|
9
|
+
|
3
10
|
WORKDIR /app
|
4
11
|
|
5
12
|
RUN mkdir .specwrk/
|
@@ -12,6 +19,9 @@ COPY $GEMFILE ./
|
|
12
19
|
RUN gem install ./$GEMFILE --no-document
|
13
20
|
RUN rm ./$GEMFILE
|
14
21
|
|
22
|
+
RUN gem install puma
|
23
|
+
COPY config.ru ./
|
24
|
+
|
15
25
|
COPY docker/entrypoint.server.sh /usr/local/bin/entrypoint
|
16
26
|
RUN chmod +x /usr/local/bin/entrypoint
|
17
27
|
|
data/docker/entrypoint.server.sh
CHANGED
data/lib/specwrk/cli.rb
CHANGED
@@ -122,8 +122,10 @@ module Specwrk
|
|
122
122
|
Client.new.seed(examples)
|
123
123
|
rescue Errno::ECONNREFUSED
|
124
124
|
puts "Server at #{ENV.fetch("SPECWRK_SRV_URI", "http://localhost:5138")} is refusing connections, exiting...#{ENV["SPECWRK_FLUSH_DELIMINATOR"]}"
|
125
|
+
exit 1
|
125
126
|
rescue Errno::ECONNRESET
|
126
127
|
puts "Server at #{ENV.fetch("SPECWRK_SRV_URI", "http://localhost:5138")} stopped responding to connections, exiting...#{ENV["SPECWRK_FLUSH_DELIMINATOR"]}"
|
128
|
+
exit 1
|
127
129
|
end
|
128
130
|
end
|
129
131
|
|
@@ -184,6 +186,9 @@ module Specwrk
|
|
184
186
|
self.class.setup(**args)
|
185
187
|
$stdout.sync = true
|
186
188
|
|
189
|
+
# nil this env var if it exists to prevent never-ending workers
|
190
|
+
ENV["SPECWRK_SRV_URI"] = nil
|
191
|
+
|
187
192
|
web_pid = Process.fork do
|
188
193
|
require "specwrk/web"
|
189
194
|
require "specwrk/web/app"
|
@@ -210,7 +215,10 @@ module Specwrk
|
|
210
215
|
status "Samples seeded ✓"
|
211
216
|
end
|
212
217
|
|
213
|
-
Specwrk.wait_for_pids_exit([seed_pid])
|
218
|
+
if Specwrk.wait_for_pids_exit([seed_pid]).value?(1)
|
219
|
+
Process.kill("INT", web_pid)
|
220
|
+
exit(1)
|
221
|
+
end
|
214
222
|
|
215
223
|
return if Specwrk.force_quit
|
216
224
|
status "Starting #{worker_count} workers..."
|
data/lib/specwrk/client.rb
CHANGED
@@ -102,13 +102,13 @@ module Specwrk
|
|
102
102
|
def complete_examples(examples)
|
103
103
|
response = post "/complete", body: examples.to_json
|
104
104
|
|
105
|
-
(response.code == "200") ? true : UnhandledResponseError.new("#{response.code}: #{response.body}")
|
105
|
+
(response.code == "200") ? true : raise(UnhandledResponseError.new("#{response.code}: #{response.body}"))
|
106
106
|
end
|
107
107
|
|
108
108
|
def seed(examples)
|
109
109
|
response = post "/seed", body: examples.to_json
|
110
110
|
|
111
|
-
(response.code == "200") ? true : UnhandledResponseError.new("#{response.code}: #{response.body}")
|
111
|
+
(response.code == "200") ? true : raise(UnhandledResponseError.new("#{response.code}: #{response.body}"))
|
112
112
|
end
|
113
113
|
|
114
114
|
private
|
data/lib/specwrk/version.rb
CHANGED
data/lib/specwrk/web/app.rb
CHANGED
@@ -49,7 +49,7 @@ module Specwrk
|
|
49
49
|
def rackup
|
50
50
|
Rack::Builder.new do
|
51
51
|
use Rack::Runtime
|
52
|
-
use Specwrk::Web::Logger, $stdout
|
52
|
+
use Specwrk::Web::Logger, $stdout, %w[/health]
|
53
53
|
use Specwrk::Web::Auth, %w[/health] # global auth check
|
54
54
|
run Specwrk::Web::App.new # your router
|
55
55
|
end
|
@@ -82,9 +82,7 @@ module Specwrk
|
|
82
82
|
def response
|
83
83
|
processing_queue.synchronize do |processing_queue_hash|
|
84
84
|
payload.each do |example|
|
85
|
-
next unless processing_queue_hash.
|
86
|
-
|
87
|
-
processing_queue_hash.delete(example[:id])
|
85
|
+
next unless processing_queue_hash.delete(example[:id])
|
88
86
|
completed_queue[example[:id]] = example
|
89
87
|
end
|
90
88
|
end
|
data/lib/specwrk/web/logger.rb
CHANGED
@@ -3,11 +3,15 @@
|
|
3
3
|
module Specwrk
|
4
4
|
class Web
|
5
5
|
class Logger
|
6
|
-
def initialize(app, out = $stdout)
|
7
|
-
@app
|
6
|
+
def initialize(app, out = $stdout, ignored_paths = [])
|
7
|
+
@app = app
|
8
|
+
@out = out
|
9
|
+
@ignored_paths = ignored_paths
|
8
10
|
end
|
9
11
|
|
10
12
|
def call(env)
|
13
|
+
return @app.call(env) if @ignored_paths.include? env["PATH_INFO"]
|
14
|
+
|
11
15
|
start_time = Time.now
|
12
16
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
13
17
|
status, headers, body = @app.call(env)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: specwrk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Westendorf
|
@@ -142,12 +142,14 @@ executables:
|
|
142
142
|
extensions: []
|
143
143
|
extra_rdoc_files: []
|
144
144
|
files:
|
145
|
+
- ".circleci/config.yml"
|
145
146
|
- ".rspec"
|
146
147
|
- ".standard.yml"
|
147
148
|
- CHANGELOG.md
|
148
149
|
- LICENSE.txt
|
149
150
|
- README.md
|
150
151
|
- Rakefile
|
152
|
+
- config.ru
|
151
153
|
- docker/Dockerfile.server
|
152
154
|
- docker/entrypoint.server.sh
|
153
155
|
- exe/specwrk
|