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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37630f2559997e8c9d0a8128030d60d58a47b419197bae4e5af03bd882961108
4
- data.tar.gz: ce15fb8fe3bd8617819e7b9735a1300e31fdac020d6b907ebef9abedfe0bee52
3
+ metadata.gz: fa530fc36a8a38f31b2f241cb0c322bd268f0928cb5929f89d4b939e54b740a3
4
+ data.tar.gz: 4228e7997bd6d4b51da7aa66ef10ddc25474a184cd3c42d42afd6077db777f8d
5
5
  SHA512:
6
- metadata.gz: 2ee677e609df2a543b75c14259ab1d878fdbf6f853e00bffb196b14fc76fb0f4f026df9ea7c2ce9ec56744a497418b271dc6c5e5ccb053a62a6c110d3e794613
7
- data.tar.gz: 92f1c09d0f251d4b5e7bffed57120c3d9fa56b16278dd8b5de2dd225218d1993d62db5f3a57b0b30a8bd47bccaada5a90969c713bb63a45590bb3c4d3c10bea9
6
+ metadata.gz: ce7fa5fe6f56cdf9b3f9a02cc040a8180d21e3c5ad1c08bcc792df3ee336c300c6fd5d8438cef908815a896dc961a5743910a63686653c6fdc91707ec24b4a6b
7
+ data.tar.gz: ae309883ef9f2f63792644583c1b9277e8c290e84172b59e7eecb0a961015d48b9411a798a6514d6dd3855a3553ce4d31e420634514f37025f4023a4c181e133
@@ -1,3 +1,7 @@
1
+ ## v0.1.0
2
+
3
+ - First release;
4
+
1
5
  ## v0.0.1
2
6
 
3
7
  - RubyGems namespace reservation.
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 Washington Botelho
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://travis-ci.org/wbotelhos/normalizy.svg)](https://travis-ci.org/wbotelhos/normalizy)
4
- [![Gem Version](https://badge.fury.io/rb/normalizy.svg)](https://badge.fury.io/rb/normalizy)
5
- [![LiberPay](https://img.shields.io/badge/donate-%3C3-brightgreen.svg)](https://liberapay.com/wbotelhos)
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
- ## Love it!
12
+ Add the following code on your `Gemfile` and run `bundle install`:
10
13
 
11
- Via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=X8HEP2878NDEG&item_name=rspeed) or [LiberPay](https://liberapay.com/wbotelhos). Thanks! (:
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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspeed'
4
+
5
+ namespace :rspeed do
6
+ task run: :environment do
7
+ ::RSpeed::Runner.run ->(command) { sh command }
8
+ end
9
+ end
@@ -1,4 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpeed
4
+ require 'csv'
5
+ require 'redis'
4
6
  end
7
+
8
+ require 'rspeed/extension'
9
+ require 'rspeed/runner'
10
+ require 'rspeed/splitter'
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpeed
4
- VERSION = '0.0.1'
4
+ VERSION = '0.1.0'
5
5
  end
@@ -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
@@ -2,8 +2,23 @@
2
2
 
3
3
  ENV['RAILS_ENV'] ||= 'test'
4
4
 
5
- require 'active_record/railtie'
6
- require 'rspeed'
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
- Dir[File.expand_path('support/**/*.rb', __dir__)].each { |file| require file }
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.1
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: 2017-12-31 00:00:00.000000000 Z
11
+ date: 2020-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: redis
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.1'
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: '4.1'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '6'
26
+ version: '0'
33
27
  - !ruby/object:Gem::Dependency
34
- name: pry-byebug
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: rspec-rails
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: rubocop
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: rubocop-rspec
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: sqlite3
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
- rubyforge_project:
136
- rubygems_version: 2.7.4
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/support/common.rb
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
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rspec/rails'
4
-
5
- RSpec.configure do |config|
6
- config.filter_run_when_matching :focus
7
-
8
- config.disable_monkey_patching!
9
-
10
- config.order = :random
11
- end