rspeed 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/LICENSE +1 -1
- data/README.md +84 -5
- data/lib/generators/rspeed/install_generator.rb +13 -0
- data/lib/generators/rspeed/templates/lib/tasks/rspeed.rb +9 -0
- data/lib/rspeed.rb +6 -0
- data/lib/rspeed/extension.rb +43 -0
- data/lib/rspeed/runner.rb +28 -0
- data/lib/rspeed/splitter.rb +137 -0
- data/lib/rspeed/version.rb +1 -1
- data/spec/models/rspeed/splitter/append_spec.rb +32 -0
- data/spec/models/rspeed/splitter/destroy_spec.rb +33 -0
- data/spec/models/rspeed/splitter/diff_spec.rb +29 -0
- data/spec/models/rspeed/splitter/first_pipe_spec.rb +19 -0
- data/spec/models/rspeed/splitter/get_spec.rb +76 -0
- data/spec/models/rspeed/splitter/keys_spec.rb +33 -0
- data/spec/models/rspeed/splitter/last_pipe_spec.rb +21 -0
- data/spec/models/rspeed/splitter/pipe_spec.rb +21 -0
- data/spec/models/rspeed/splitter/pipes_spec.rb +27 -0
- data/spec/models/rspeed/splitter/rename_spec.rb +18 -0
- data/spec/models/rspeed/splitter/result_spec.rb +19 -0
- data/spec/models/rspeed/splitter/save_spec.rb +55 -0
- data/spec/models/rspeed/splitter/split_spec.rb +53 -0
- data/spec/rails_helper.rb +18 -3
- metadata +51 -26
- data/spec/support/common.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa530fc36a8a38f31b2f241cb0c322bd268f0928cb5929f89d4b939e54b740a3
|
4
|
+
data.tar.gz: 4228e7997bd6d4b51da7aa66ef10ddc25474a184cd3c42d42afd6077db777f8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce7fa5fe6f56cdf9b3f9a02cc040a8180d21e3c5ad1c08bcc792df3ee336c300c6fd5d8438cef908815a896dc961a5743910a63686653c6fdc91707ec24b4a6b
|
7
|
+
data.tar.gz: ae309883ef9f2f63792644583c1b9277e8c290e84172b59e7eecb0a961015d48b9411a798a6514d6dd3855a3553ce4d31e420634514f37025f4023a4c181e133
|
data/CHANGELOG.md
CHANGED
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c)
|
3
|
+
Copyright (c) 2017-2020 Washington Botelho
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,11 +1,90 @@
|
|
1
1
|
# RSpeed
|
2
2
|
|
3
|
-
[![Build Status](https://
|
4
|
-
[![Gem Version](https://badge.fury.io/rb/
|
5
|
-
[![
|
3
|
+
[![Build Status](https://github.com/wbotelhos/rspeed/workflows/CI/badge.svg)](https://github.com/wbotelhos/rspeed/actions)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/rspeed.svg)](https://badge.fury.io/rb/rspeed)
|
5
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/cc5efe8b06bc1d5e9e8a/maintainability)](https://codeclimate.com/github/wbotelhos/rspeed/maintainability)
|
6
|
+
[![Patreon](https://img.shields.io/badge/donate-%3C3-brightgreen.svg)](https://www.patreon.com/wbotelhos)
|
6
7
|
|
8
|
+
RSpeed splits your specs to you run parallels tests.
|
7
9
|
|
10
|
+
## Install
|
8
11
|
|
9
|
-
|
12
|
+
Add the following code on your `Gemfile` and run `bundle install`:
|
10
13
|
|
11
|
-
|
14
|
+
```ruby
|
15
|
+
gem 'rspeed'
|
16
|
+
```
|
17
|
+
|
18
|
+
## Setup
|
19
|
+
|
20
|
+
We need to extract the rake that executes the split via `rspeed:run`.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
rake rspeed:install
|
24
|
+
```
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
- `RSPEED`: Enables RSpeed
|
29
|
+
- `RSPEED_PIPES`: Quantity of pipes
|
30
|
+
- `RSPEED_PIPE`: Current pipe
|
31
|
+
|
32
|
+
```sh
|
33
|
+
RSPEED=true RSPEED_PIPES=3 RSPEED_PIPE=1 bundle exec rake rspeed:run
|
34
|
+
```
|
35
|
+
|
36
|
+
## How it Works
|
37
|
+
|
38
|
+
### First run
|
39
|
+
|
40
|
+
1. Since we has no statistics on the first time, we run all specs and collect it;
|
41
|
+
|
42
|
+
```json
|
43
|
+
{ "file": "./spec/models/1_spec.rb", "time": 0.01 }
|
44
|
+
{ "file": "./spec/models/2_spec.rb", "time": 0.02 }
|
45
|
+
{ "file": "./spec/models/3_spec.rb", "time": 0.001 }
|
46
|
+
{ "file": "./spec/models/4_spec.rb", "time": 1 }
|
47
|
+
```
|
48
|
+
|
49
|
+
### Second and next runs
|
50
|
+
|
51
|
+
1. Previous statistics is balanced by times and distributed between pipes:
|
52
|
+
|
53
|
+
```json
|
54
|
+
{ "file": "./spec/models/4_spec.rb", "time": 1 }
|
55
|
+
```
|
56
|
+
|
57
|
+
```json
|
58
|
+
{ "file": "./spec/models/2_spec.rb", "time": 0.02 }
|
59
|
+
```
|
60
|
+
|
61
|
+
```json
|
62
|
+
{ "file": "./spec/models/3_spec.rb", "time": 0.001 }
|
63
|
+
{ "file": "./spec/models/1_spec.rb", "time": 0.01 }
|
64
|
+
```
|
65
|
+
|
66
|
+
2. Run the current pipe `1`:
|
67
|
+
|
68
|
+
```json
|
69
|
+
{ "file": "./spec/models/4_spec.rb", "time": 1 }
|
70
|
+
```
|
71
|
+
|
72
|
+
- Collects statistics and temporary save it;
|
73
|
+
|
74
|
+
4. Run the current pipe `2`:
|
75
|
+
|
76
|
+
```json
|
77
|
+
{ "file": "./spec/models/2_spec.rb", "time": 0.02 }
|
78
|
+
```
|
79
|
+
|
80
|
+
- Collects statistics and temporary save it;
|
81
|
+
|
82
|
+
5. Run the current pipe `3`:
|
83
|
+
|
84
|
+
```json
|
85
|
+
{ "file": "./spec/models/3_spec.rb", "time": 0.001 }
|
86
|
+
{ "file": "./spec/models/1_spec.rb", "time": 0.01 }
|
87
|
+
```
|
88
|
+
|
89
|
+
- Collects statistics and temporary save it;
|
90
|
+
- Sum all the last statistics and save it for the next run;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpeed
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path('templates', __dir__)
|
6
|
+
|
7
|
+
desc 'Creates RSpeed task'
|
8
|
+
|
9
|
+
def copy_initializer
|
10
|
+
copy_file 'lib/tasks/rspeed.rake', 'lib/tasks/rspeed.rake'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/rspeed.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if ENV['RSPEED'] == 'true'
|
4
|
+
require 'rspec/rails'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.before :suite do
|
8
|
+
File.open('rspeed.csv', 'w') { |file| file.truncate 0 }
|
9
|
+
end
|
10
|
+
|
11
|
+
config.before do |example|
|
12
|
+
example.update_inherited_metadata start_at: example.clock.now
|
13
|
+
end
|
14
|
+
|
15
|
+
config.after do |example|
|
16
|
+
file_path = example.metadata[:file_path]
|
17
|
+
time_difference = example.clock.now - example.metadata[:start_at]
|
18
|
+
|
19
|
+
File.open('rspeed.csv', 'a') do |file|
|
20
|
+
file.write "#{time_difference},#{file_path}\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
config.after :suite do |_example|
|
25
|
+
result = {}
|
26
|
+
|
27
|
+
CSV.read('rspeed.csv').each do |line|
|
28
|
+
result[line[1]] ||= 0
|
29
|
+
result[line[1]] += line[0].to_d
|
30
|
+
end
|
31
|
+
|
32
|
+
result = result.sort_by { |line| line[1] }.reverse
|
33
|
+
|
34
|
+
File.open('rspeed.csv', 'w') { |file| file.truncate 0 }
|
35
|
+
|
36
|
+
File.open('rspeed.csv', 'a') do |file|
|
37
|
+
result.each do |file_spec, time|
|
38
|
+
file.write "#{time},#{file_spec}\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpeed
|
4
|
+
module Runner
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def run(shell)
|
8
|
+
splitter = ::RSpeed::Splitter.new
|
9
|
+
|
10
|
+
if splitter.first_pipe?
|
11
|
+
# splitter.destroy "rspeed_*"
|
12
|
+
splitter.destroy 'rspeed_tmp'
|
13
|
+
end
|
14
|
+
|
15
|
+
if splitter.result?
|
16
|
+
splitter.save if splitter.first_pipe?
|
17
|
+
|
18
|
+
files = splitter.get("rspeed_#{splitter.pipe}")[0]['files'].map { |item| item['file'] }.join(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
shell.call ['bundle exec rspec', files].compact.join(' ')
|
22
|
+
|
23
|
+
splitter.append
|
24
|
+
|
25
|
+
splitter.rename if splitter.last_pipe?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpeed
|
4
|
+
class Splitter
|
5
|
+
DEFAULT_PATTERN = 'rspeed_*'
|
6
|
+
|
7
|
+
def append(files = file_data)
|
8
|
+
files.each do |time, file|
|
9
|
+
redis.lpush 'rspeed_tmp', { file: file, time: time.to_f }.to_json
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def destroy(pattern = DEFAULT_PATTERN)
|
14
|
+
keys(pattern).each { |key| redis.del key }
|
15
|
+
end
|
16
|
+
|
17
|
+
def diff
|
18
|
+
(actual_files + added_files).sort_by { |item| item[:time].to_f }.map do |item|
|
19
|
+
[item[:time], item[:file]]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def first_pipe?
|
24
|
+
pipe == 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(pattern)
|
28
|
+
@get ||= begin
|
29
|
+
return redis.lrange(pattern, 0, -1) if %w[rspeed rspeed_tmp].include?(pattern)
|
30
|
+
|
31
|
+
keys(pattern).map { |key| JSON.parse redis.get(key) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def keys(pattern = DEFAULT_PATTERN)
|
36
|
+
cursor = 0
|
37
|
+
result = []
|
38
|
+
|
39
|
+
loop do
|
40
|
+
cursor, results = redis.scan(cursor, match: pattern)
|
41
|
+
result += results
|
42
|
+
|
43
|
+
break if cursor.to_i.zero?
|
44
|
+
end
|
45
|
+
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
def last_pipe?
|
50
|
+
pipe == pipes
|
51
|
+
end
|
52
|
+
|
53
|
+
def pipe
|
54
|
+
ENV.fetch('RSPEED_PIPE') { 1 }.to_i
|
55
|
+
end
|
56
|
+
|
57
|
+
def pipes
|
58
|
+
result? ? ENV.fetch('RSPEED_PIPES') { 1 }.to_i : 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def rename
|
62
|
+
redis.rename 'rspeed_tmp', 'rspeed'
|
63
|
+
end
|
64
|
+
|
65
|
+
def result?
|
66
|
+
!keys('rspeed').empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
def save(data = rspeed_data)
|
70
|
+
split(data).each do |key, value|
|
71
|
+
redis.set key, value.to_json
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def split(data)
|
76
|
+
json = {}
|
77
|
+
|
78
|
+
pipes.times do |index|
|
79
|
+
json["rspeed_#{index + 1}".to_sym] ||= []
|
80
|
+
json["rspeed_#{index + 1}".to_sym] = { total: 0, files: [], number: index + 1 }
|
81
|
+
end
|
82
|
+
|
83
|
+
data.each do |record|
|
84
|
+
selected_pipe_data = json.min_by { |pipe| pipe[1][:total] }
|
85
|
+
selected_pipe = json["rspeed_#{selected_pipe_data[1][:number]}".to_sym]
|
86
|
+
time = record[:time].to_f
|
87
|
+
|
88
|
+
selected_pipe[:total] += time
|
89
|
+
selected_pipe[:files] << { file: record[:file], time: time }
|
90
|
+
end
|
91
|
+
|
92
|
+
json
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def actual_files
|
98
|
+
rspeed_data.select { |item| actual_specs.include?(item[:file]) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def actual_specs
|
102
|
+
Dir['./spec/**/*_spec.rb']
|
103
|
+
end
|
104
|
+
|
105
|
+
def added_files
|
106
|
+
added_specs.map { |item| { file: item, time: 0 } }
|
107
|
+
end
|
108
|
+
|
109
|
+
def added_specs
|
110
|
+
actual_specs - saved_specs
|
111
|
+
end
|
112
|
+
|
113
|
+
def file_data
|
114
|
+
CSV.read('rspeed.csv')
|
115
|
+
end
|
116
|
+
|
117
|
+
def redis
|
118
|
+
@redis ||= ::Redis.new(db: ENV['RSPEED_DB'], host: ENV['RSPEED_HOST'], port: ENV.fetch('RSPEED_PORT') { 6379 })
|
119
|
+
end
|
120
|
+
|
121
|
+
def removed_specs
|
122
|
+
saved_specs - actual_specs
|
123
|
+
end
|
124
|
+
|
125
|
+
def removed_time
|
126
|
+
removed_specs.map { |item| item[0].to_f }.sum
|
127
|
+
end
|
128
|
+
|
129
|
+
def rspeed_data
|
130
|
+
get('rspeed').map { |item| JSON.parse item, symbolize_names: true }
|
131
|
+
end
|
132
|
+
|
133
|
+
def saved_specs
|
134
|
+
rspeed_data.map { |item| item[:file] }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/rspeed/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#append' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
it 'appends file and time on rspeed key' do
|
9
|
+
splitter.append [[1, '1_spec.rb'], [2, '2_spec.rb']]
|
10
|
+
|
11
|
+
expect(splitter.get('rspeed_tmp')).to eq [
|
12
|
+
'{"file":"2_spec.rb","time":2.0}',
|
13
|
+
'{"file":"1_spec.rb","time":1.0}'
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when files is not given' do
|
18
|
+
it 'read csv and append file and time on rspeed key' do
|
19
|
+
splitter.append
|
20
|
+
|
21
|
+
expect(splitter.get('rspeed_tmp')).to eq [
|
22
|
+
'{"file":"./spec/0_2_spec.rb","time":0.2}',
|
23
|
+
'{"file":"./spec/0_3_spec.rb","time":0.3}',
|
24
|
+
'{"file":"./spec/0_4_spec.rb","time":0.4}',
|
25
|
+
'{"file":"./spec/0_7_spec.rb","time":0.7}',
|
26
|
+
'{"file":"./spec/1_1_spec.rb","time":1.1}',
|
27
|
+
'{"file":"./spec/1_5_spec.rb","time":1.5}',
|
28
|
+
'{"file":"./spec/2_0_spec.rb","time":2.0}',
|
29
|
+
]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#destroy' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:redis) { redis_object }
|
9
|
+
|
10
|
+
before do
|
11
|
+
redis.set 'rspeed', '{}'
|
12
|
+
redis.set 'rspeed_1', '{}'
|
13
|
+
redis.set 'rspeed_2', '{}'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'destroys via wildcard' do
|
17
|
+
splitter.destroy 'rspeed_*'
|
18
|
+
|
19
|
+
expect(splitter.keys('*')).to eq %w[rspeed]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'destroys via single name' do
|
23
|
+
splitter.destroy 'rspeed'
|
24
|
+
|
25
|
+
expect(splitter.keys('*')).to eq %w[rspeed_1 rspeed_2]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'destroys default partner when no pattern is given' do
|
29
|
+
splitter.destroy
|
30
|
+
|
31
|
+
expect(splitter.keys('*')).to eq %w[rspeed]
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#diff' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:redis) { redis_object }
|
9
|
+
|
10
|
+
before do
|
11
|
+
redis.lpush 'rspeed', { file: '1_spec.rb', time: 1 }.to_json
|
12
|
+
redis.lpush 'rspeed', { file: '2_spec.rb', time: 2 }.to_json
|
13
|
+
redis.lpush 'rspeed', { file: '3_spec.rb', time: 3 }.to_json
|
14
|
+
|
15
|
+
allow(Dir).to receive(:[]).with('./spec/**/*_spec.rb').and_return %w[
|
16
|
+
2_spec.rb
|
17
|
+
3_spec.rb
|
18
|
+
4_spec.rb
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'removes removed specs and adds new spec and keeps keeped specs based on rspeed key values' do
|
23
|
+
expect(splitter.diff).to eq [
|
24
|
+
[0, '4_spec.rb'],
|
25
|
+
[2, '2_spec.rb'],
|
26
|
+
[3, '3_spec.rb']
|
27
|
+
]
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '.first_pipe?' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
context 'when pipe env is 1' do
|
9
|
+
before { allow(splitter).to receive(:pipe).and_return 1 }
|
10
|
+
|
11
|
+
it { expect(splitter.first_pipe?).to eq true }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when pipe env is not 1' do
|
15
|
+
before { allow(splitter).to receive(:pipe).and_return 2 }
|
16
|
+
|
17
|
+
it { expect(splitter.first_pipe?).to eq false }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#get' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:redis) { redis_object }
|
9
|
+
|
10
|
+
context 'when wildcard pattern is given' do
|
11
|
+
before do
|
12
|
+
redis.set 'rspeed_1', { files: [[1, '1_spec.rb'], [2, '2_spec.rb']], number: 0, total: 3 }.to_json
|
13
|
+
redis.set 'rspeed_2', { files: [[3, '3_spec.rb']], number: 1, total: 3 }.to_json
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns all values' do
|
17
|
+
expect(splitter.get('rspeed_*')).to eq [
|
18
|
+
{
|
19
|
+
'files' => [[1, '1_spec.rb'], [2, '2_spec.rb']],
|
20
|
+
'number' => 0,
|
21
|
+
'total' => 3
|
22
|
+
},
|
23
|
+
|
24
|
+
{
|
25
|
+
'files' => [[3, '3_spec.rb']],
|
26
|
+
'number' => 1,
|
27
|
+
'total' => 3
|
28
|
+
}
|
29
|
+
]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when normal pattern is given' do
|
34
|
+
before do
|
35
|
+
redis.set 'pattern', { files: [[1, '1_spec.rb'], [2, '2_spec.rb']], number: 0, total: 3 }.to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns all values from that key' do
|
39
|
+
expect(splitter.get('pattern')).to eq [
|
40
|
+
{
|
41
|
+
'files' => [[1, '1_spec.rb'], [2, '2_spec.rb']],
|
42
|
+
'number' => 0,
|
43
|
+
'total' => 3
|
44
|
+
}
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when pattern is rspeed' do
|
50
|
+
before do
|
51
|
+
redis.lpush 'rspeed', { file: '1_spec.rb', time: 1 }.to_json
|
52
|
+
redis.lpush 'rspeed', { file: '2_spec.rb', time: 2 }.to_json
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'executes the right fetch method' do
|
56
|
+
expect(splitter.get('rspeed')).to eq [
|
57
|
+
'{"file":"2_spec.rb","time":2}',
|
58
|
+
'{"file":"1_spec.rb","time":1}'
|
59
|
+
]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when pattern is rspeed_tmp' do
|
64
|
+
before do
|
65
|
+
redis.lpush 'rspeed_tmp', { file: '1_spec.rb', time: 1 }.to_json
|
66
|
+
redis.lpush 'rspeed_tmp', { file: '2_spec.rb', time: 2 }.to_json
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'executes the right fetch method' do
|
70
|
+
expect(splitter.get('rspeed_tmp')).to eq [
|
71
|
+
'{"file":"2_spec.rb","time":2}',
|
72
|
+
'{"file":"1_spec.rb","time":1}'
|
73
|
+
]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '.keys' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:redis) { redis_object }
|
9
|
+
|
10
|
+
context 'with default config' do
|
11
|
+
before do
|
12
|
+
redis.set 'rspeed_1', 'value_1'
|
13
|
+
redis.set 'rspeed_2', 'value_2'
|
14
|
+
redis.set 'rspeed_3', 'value_3'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'shows keys' do
|
18
|
+
expect(splitter.keys).to eq %w[rspeed_1 rspeed_2 rspeed_3]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with custom key' do
|
23
|
+
before do
|
24
|
+
redis.set 'custom_key_1', 'value_1'
|
25
|
+
redis.set 'custom_key_2', 'value_2'
|
26
|
+
redis.set 'custom_key_3', 'value_3'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'shows keys' do
|
30
|
+
expect(splitter.keys('custom_key_*')).to eq %w[custom_key_1 custom_key_2 custom_key_3]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '.last_pipe?' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
before { allow(splitter).to receive(:pipes).and_return 3 }
|
9
|
+
|
10
|
+
context 'when pipe env is equal pipes env' do
|
11
|
+
before { allow(splitter).to receive(:pipe).and_return 3 }
|
12
|
+
|
13
|
+
it { expect(splitter.last_pipe?).to eq true }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when pipe env not equal pipes env' do
|
17
|
+
before { allow(splitter).to receive(:pipe).and_return 2 }
|
18
|
+
|
19
|
+
it { expect(splitter.last_pipe?).to eq false }
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#pipe' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
context 'when pipe env is given' do
|
9
|
+
before { ENV['RSPEED_PIPE'] = '2' }
|
10
|
+
|
11
|
+
it 'returns the number of the current pipe' do
|
12
|
+
expect(splitter.pipe).to eq 2
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when pipe env is not given' do
|
17
|
+
it 'returns 1' do
|
18
|
+
expect(splitter.pipe).to eq 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#pipes' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
context 'when has no result' do
|
9
|
+
before { allow(splitter).to receive(:result?).and_return(false) }
|
10
|
+
|
11
|
+
it 'the number of pipes is adjusted to one' do
|
12
|
+
expect(splitter.pipes).to eq 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when has result' do
|
17
|
+
before do
|
18
|
+
allow(splitter).to receive(:result?).and_return(true)
|
19
|
+
|
20
|
+
ENV['RSPEED_PIPES'] = '2'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'is used the given value on env' do
|
24
|
+
expect(splitter.pipes).to eq 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#rename' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:redis) { redis_object }
|
9
|
+
|
10
|
+
before { redis.lpush 'rspeed_tmp', { file: '1_spec.rb', time: 1.0 }.to_json }
|
11
|
+
|
12
|
+
it 'renames the key' do
|
13
|
+
splitter.rename
|
14
|
+
|
15
|
+
expect(redis.lrange('rspeed_tmp', 0, -1)).to eq []
|
16
|
+
expect(redis.lrange('rspeed', 0, -1)).to eq ['{"file":"1_spec.rb","time":1.0}']
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '#result?' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
context 'when has no key rspeed on redis' do
|
9
|
+
it { expect(splitter.result?).to eq false }
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when has no key rspeed on redis' do
|
13
|
+
let!(:redis) { redis_object }
|
14
|
+
|
15
|
+
before { redis.set 'rspeed', { files: [[1, '1_spec.rb']], number: 0, total: 1 }.to_json }
|
16
|
+
|
17
|
+
it { expect(splitter.result?).to eq true }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '.save' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:redis) { redis_object }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(splitter).to receive(:pipes).and_return(3)
|
12
|
+
|
13
|
+
redis.lpush 'rspeed', { file: "./spec/0_2_spec.rb", time: '0.2' }.to_json
|
14
|
+
redis.lpush 'rspeed', { file: "./spec/0_3_spec.rb", time: '0.3' }.to_json
|
15
|
+
redis.lpush 'rspeed', { file: "./spec/0_4_spec.rb", time: '0.4' }.to_json
|
16
|
+
redis.lpush 'rspeed', { file: "./spec/0_7_spec.rb", time: '0.7' }.to_json
|
17
|
+
redis.lpush 'rspeed', { file: "./spec/1_1_spec.rb", time: '1.1' }.to_json
|
18
|
+
redis.lpush 'rspeed', { file: "./spec/1_5_spec.rb", time: '1.5' }.to_json
|
19
|
+
redis.lpush 'rspeed', { file: "./spec/2_0_spec.rb", time: '2.0' }.to_json
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'saves the data on redis' do
|
23
|
+
splitter.save
|
24
|
+
|
25
|
+
expect(redis.keys('*')).to eq %w[rspeed rspeed_1 rspeed_2 rspeed_3]
|
26
|
+
|
27
|
+
expect(JSON.parse(redis.get('rspeed_1'), symbolize_names: true)).to eq(
|
28
|
+
files: [{ file: './spec/2_0_spec.rb', time: 2.0 }],
|
29
|
+
number: 1,
|
30
|
+
total: 2.0
|
31
|
+
)
|
32
|
+
|
33
|
+
expect(JSON.parse(redis.get('rspeed_2'), symbolize_names: true)).to eq(
|
34
|
+
files: [
|
35
|
+
{ file: './spec/1_5_spec.rb', time: 1.5 },
|
36
|
+
{ file: './spec/0_4_spec.rb', time: 0.4 },
|
37
|
+
{ file: './spec/0_2_spec.rb', time: 0.2 }
|
38
|
+
],
|
39
|
+
|
40
|
+
number: 2,
|
41
|
+
total: 1.5 + 0.4 + 0.2
|
42
|
+
)
|
43
|
+
|
44
|
+
expect(JSON.parse(redis.get('rspeed_3'), symbolize_names: true)).to eq(
|
45
|
+
files: [
|
46
|
+
{ file: './spec/1_1_spec.rb', time: 1.1 },
|
47
|
+
{ file: './spec/0_7_spec.rb', time: 0.7 },
|
48
|
+
{ file: './spec/0_3_spec.rb', time: 0.3 }
|
49
|
+
],
|
50
|
+
|
51
|
+
number: 3,
|
52
|
+
total: 1.1 + 0.7 + 0.3
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RSpeed::Splitter, '.split' do
|
6
|
+
subject(:splitter) { described_class.new }
|
7
|
+
|
8
|
+
let!(:data) do
|
9
|
+
[
|
10
|
+
{ file: './spec/2_0_spec.rb', time: '2.0' },
|
11
|
+
{ file: './spec/1_5_spec.rb', time: '1.5' },
|
12
|
+
{ file: './spec/1_1_spec.rb', time: '1.1' },
|
13
|
+
{ file: './spec/0_7_spec.rb', time: '0.7' },
|
14
|
+
{ file: './spec/0_4_spec.rb', time: '0.4' },
|
15
|
+
{ file: './spec/0_3_spec.rb', time: '0.3' },
|
16
|
+
{ file: './spec/0_2_spec.rb', time: '0.2' },
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
before { allow(splitter).to receive(:pipes).and_return 3 }
|
21
|
+
|
22
|
+
it 'splits the times between the pipes' do
|
23
|
+
expect(splitter.split(data)).to eq(
|
24
|
+
rspeed_1: {
|
25
|
+
files: [{ file: './spec/2_0_spec.rb', time: 2.0 }],
|
26
|
+
number: 1,
|
27
|
+
total: 2.0
|
28
|
+
},
|
29
|
+
|
30
|
+
rspeed_2: {
|
31
|
+
files: [
|
32
|
+
{ file: './spec/1_5_spec.rb', time: 1.5 },
|
33
|
+
{ file: './spec/0_4_spec.rb', time: 0.4 },
|
34
|
+
{ file: './spec/0_2_spec.rb', time: 0.2 }
|
35
|
+
],
|
36
|
+
|
37
|
+
number: 2,
|
38
|
+
total: 1.5 + 0.4 + 0.2 # 1.5 -> 1.9 -> 2.1
|
39
|
+
},
|
40
|
+
|
41
|
+
rspeed_3: {
|
42
|
+
files: [
|
43
|
+
{ file: './spec/1_1_spec.rb', time: 1.1 },
|
44
|
+
{ file: './spec/0_7_spec.rb', time: 0.7 },
|
45
|
+
{ file: './spec/0_3_spec.rb', time: 0.3 }
|
46
|
+
],
|
47
|
+
|
48
|
+
number: 3,
|
49
|
+
total: 1.1 + 0.7 + 0.3 # 1.1 -> 1.8 -> 2.1
|
50
|
+
}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
data/spec/rails_helper.rb
CHANGED
@@ -2,8 +2,23 @@
|
|
2
2
|
|
3
3
|
ENV['RAILS_ENV'] ||= 'test'
|
4
4
|
|
5
|
-
require '
|
6
|
-
require '
|
5
|
+
require 'fakeredis/rspec'
|
6
|
+
require 'json'
|
7
7
|
require 'pry-byebug'
|
8
|
+
require 'rspec'
|
9
|
+
require 'rspeed'
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.disable_monkey_patching!
|
13
|
+
|
14
|
+
config.order = :random
|
15
|
+
|
16
|
+
config.after do
|
17
|
+
ENV.delete 'RSPEED_PIPE'
|
18
|
+
ENV.delete 'RSPEED_PIPES'
|
19
|
+
end
|
20
|
+
end
|
8
21
|
|
9
|
-
|
22
|
+
def redis_object
|
23
|
+
@redis_object ||= Redis.new(db: ENV['RSPEED_DB'], host: ENV['RSPEED_HOST'])
|
24
|
+
end
|
metadata
CHANGED
@@ -1,37 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspeed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Washington Botelho
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: redis
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '6'
|
19
|
+
version: '0'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '6'
|
26
|
+
version: '0'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
28
|
+
name: fakeredis
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - ">="
|
@@ -45,7 +39,7 @@ dependencies:
|
|
45
39
|
- !ruby/object:Gem::Version
|
46
40
|
version: '0'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
42
|
+
name: pry-byebug
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
50
44
|
requirements:
|
51
45
|
- - ">="
|
@@ -59,7 +53,7 @@ dependencies:
|
|
59
53
|
- !ruby/object:Gem::Version
|
60
54
|
version: '0'
|
61
55
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
56
|
+
name: rake
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
64
58
|
requirements:
|
65
59
|
- - ">="
|
@@ -73,7 +67,7 @@ dependencies:
|
|
73
67
|
- !ruby/object:Gem::Version
|
74
68
|
version: '0'
|
75
69
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
70
|
+
name: rspec
|
77
71
|
requirement: !ruby/object:Gem::Requirement
|
78
72
|
requirements:
|
79
73
|
- - ">="
|
@@ -87,7 +81,7 @@ dependencies:
|
|
87
81
|
- !ruby/object:Gem::Version
|
88
82
|
version: '0'
|
89
83
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
84
|
+
name: rubocop-rspec
|
91
85
|
requirement: !ruby/object:Gem::Requirement
|
92
86
|
requirements:
|
93
87
|
- - ">="
|
@@ -100,24 +94,44 @@ dependencies:
|
|
100
94
|
- - ">="
|
101
95
|
- !ruby/object:Gem::Version
|
102
96
|
version: '0'
|
103
|
-
description:
|
97
|
+
description: Split and speed up your RSpec tests.
|
104
98
|
email: wbotelhos@gmail.com
|
105
99
|
executables: []
|
106
100
|
extensions: []
|
107
|
-
extra_rdoc_files:
|
101
|
+
extra_rdoc_files:
|
102
|
+
- CHANGELOG.md
|
103
|
+
- LICENSE
|
104
|
+
- README.md
|
108
105
|
files:
|
109
106
|
- CHANGELOG.md
|
110
107
|
- LICENSE
|
111
108
|
- README.md
|
109
|
+
- lib/generators/rspeed/install_generator.rb
|
110
|
+
- lib/generators/rspeed/templates/lib/tasks/rspeed.rb
|
112
111
|
- lib/rspeed.rb
|
112
|
+
- lib/rspeed/extension.rb
|
113
|
+
- lib/rspeed/runner.rb
|
114
|
+
- lib/rspeed/splitter.rb
|
113
115
|
- lib/rspeed/version.rb
|
116
|
+
- spec/models/rspeed/splitter/append_spec.rb
|
117
|
+
- spec/models/rspeed/splitter/destroy_spec.rb
|
118
|
+
- spec/models/rspeed/splitter/diff_spec.rb
|
119
|
+
- spec/models/rspeed/splitter/first_pipe_spec.rb
|
120
|
+
- spec/models/rspeed/splitter/get_spec.rb
|
121
|
+
- spec/models/rspeed/splitter/keys_spec.rb
|
122
|
+
- spec/models/rspeed/splitter/last_pipe_spec.rb
|
123
|
+
- spec/models/rspeed/splitter/pipe_spec.rb
|
124
|
+
- spec/models/rspeed/splitter/pipes_spec.rb
|
125
|
+
- spec/models/rspeed/splitter/rename_spec.rb
|
126
|
+
- spec/models/rspeed/splitter/result_spec.rb
|
127
|
+
- spec/models/rspeed/splitter/save_spec.rb
|
128
|
+
- spec/models/rspeed/splitter/split_spec.rb
|
114
129
|
- spec/rails_helper.rb
|
115
|
-
- spec/support/common.rb
|
116
130
|
homepage: https://github.com/wbotelhos/rspeed
|
117
131
|
licenses:
|
118
132
|
- MIT
|
119
133
|
metadata: {}
|
120
|
-
post_install_message:
|
134
|
+
post_install_message:
|
121
135
|
rdoc_options: []
|
122
136
|
require_paths:
|
123
137
|
- lib
|
@@ -132,11 +146,22 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
146
|
- !ruby/object:Gem::Version
|
133
147
|
version: '0'
|
134
148
|
requirements: []
|
135
|
-
|
136
|
-
|
137
|
-
signing_key:
|
149
|
+
rubygems_version: 3.0.8
|
150
|
+
signing_key:
|
138
151
|
specification_version: 4
|
139
|
-
summary:
|
152
|
+
summary: Split and speed up your RSpec tests.
|
140
153
|
test_files:
|
141
|
-
- spec/
|
154
|
+
- spec/models/rspeed/splitter/append_spec.rb
|
155
|
+
- spec/models/rspeed/splitter/destroy_spec.rb
|
156
|
+
- spec/models/rspeed/splitter/pipe_spec.rb
|
157
|
+
- spec/models/rspeed/splitter/get_spec.rb
|
158
|
+
- spec/models/rspeed/splitter/rename_spec.rb
|
159
|
+
- spec/models/rspeed/splitter/last_pipe_spec.rb
|
160
|
+
- spec/models/rspeed/splitter/first_pipe_spec.rb
|
161
|
+
- spec/models/rspeed/splitter/result_spec.rb
|
162
|
+
- spec/models/rspeed/splitter/save_spec.rb
|
163
|
+
- spec/models/rspeed/splitter/keys_spec.rb
|
164
|
+
- spec/models/rspeed/splitter/diff_spec.rb
|
165
|
+
- spec/models/rspeed/splitter/split_spec.rb
|
166
|
+
- spec/models/rspeed/splitter/pipes_spec.rb
|
142
167
|
- spec/rails_helper.rb
|