rspeed 0.4.0 → 0.7.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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/README.md +10 -7
  4. data/lib/generators/rspeed/install_generator.rb +1 -1
  5. data/lib/rspeed.rb +10 -7
  6. data/lib/rspeed/database.rb +19 -0
  7. data/lib/rspeed/differ.rb +71 -0
  8. data/lib/rspeed/env.rb +39 -0
  9. data/lib/rspeed/extension.rb +3 -2
  10. data/lib/rspeed/logger.rb +13 -0
  11. data/lib/rspeed/observer.rb +19 -7
  12. data/lib/rspeed/redis.rb +78 -0
  13. data/lib/rspeed/reporter.rb +38 -0
  14. data/lib/rspeed/runner.rb +4 -15
  15. data/lib/rspeed/splitter.rb +25 -115
  16. data/lib/rspeed/variable.rb +34 -0
  17. data/lib/rspeed/version.rb +1 -1
  18. data/spec/common_helper.rb +10 -0
  19. data/spec/fixtures/empty.rb +4 -0
  20. data/spec/models/rspeed/database/list_spec.rb +15 -0
  21. data/spec/models/rspeed/database/previous_result_spec.rb +17 -0
  22. data/spec/models/rspeed/database/result_spec.rb +17 -0
  23. data/spec/models/rspeed/differ/actual_data_spec.rb +20 -0
  24. data/spec/models/rspeed/differ/actual_files_spec.rb +20 -0
  25. data/spec/models/rspeed/differ/added_data_spec.rb +19 -0
  26. data/spec/models/rspeed/differ/diff_spec.rb +77 -0
  27. data/spec/models/rspeed/differ/final_diff_spec.rb +46 -0
  28. data/spec/models/rspeed/differ/removed_data_spec.rb +20 -0
  29. data/spec/models/rspeed/differ/sum_time_spec.rb +19 -0
  30. data/spec/models/rspeed/env/app_spec.rb +17 -0
  31. data/spec/models/rspeed/env/db_spec.rb +17 -0
  32. data/spec/models/rspeed/env/host_spec.rb +17 -0
  33. data/spec/models/rspeed/env/pipe_spec.rb +19 -0
  34. data/spec/models/rspeed/env/pipes_spec.rb +19 -0
  35. data/spec/models/rspeed/env/port_spec.rb +17 -0
  36. data/spec/models/rspeed/env/rspeed_spec.rb +43 -0
  37. data/spec/models/rspeed/env/spec_path_spec.rb +19 -0
  38. data/spec/models/rspeed/observer/after_spec.rb +5 -5
  39. data/spec/models/rspeed/observer/after_suite_spec.rb +43 -0
  40. data/spec/models/rspeed/observer/before_spec.rb +0 -2
  41. data/spec/models/rspeed/observer/before_suite_spec.rb +18 -6
  42. data/spec/models/rspeed/redis/clean_spec.rb +20 -0
  43. data/spec/models/rspeed/redis/client_spec.rb +7 -0
  44. data/spec/models/rspeed/redis/destroy_spec.rb +21 -0
  45. data/spec/models/rspeed/redis/get_spec.rb +11 -0
  46. data/spec/models/rspeed/redis/keys_spec.rb +13 -0
  47. data/spec/models/rspeed/redis/list_spec.rb +19 -0
  48. data/spec/models/rspeed/redis/profiles_content_spec.rb +19 -0
  49. data/spec/models/rspeed/redis/result_spec.rb +13 -0
  50. data/spec/models/rspeed/redis/set_spec.rb +11 -0
  51. data/spec/models/rspeed/redis/specs_finished_spec.rb +19 -0
  52. data/spec/models/rspeed/redis/specs_initiated_spec.rb +13 -0
  53. data/spec/models/rspeed/redis/version_the_result_spec.rb +21 -0
  54. data/spec/models/rspeed/reporter/call_spec.rb +42 -0
  55. data/spec/models/rspeed/reporter/print_files_spec.rb +27 -0
  56. data/spec/models/rspeed/reporter/print_table_spec.rb +29 -0
  57. data/spec/models/rspeed/runner/run_spec.rb +73 -0
  58. data/spec/models/rspeed/splitter/append_spec.rb +8 -28
  59. data/spec/models/rspeed/splitter/consolidate_spec.rb +23 -0
  60. data/spec/models/rspeed/splitter/first_pipe_spec.rb +4 -8
  61. data/spec/models/rspeed/splitter/need_warm_question_spec.rb +35 -0
  62. data/spec/models/rspeed/splitter/pipe_files_spec.rb +30 -0
  63. data/spec/models/rspeed/splitter/split_spec.rb +85 -45
  64. data/spec/models/rspeed/variable/append_app_name_spec.rb +33 -0
  65. data/spec/models/rspeed/variable/key_spec.rb +15 -0
  66. data/spec/models/rspeed/variable/pipe_spec.rb +23 -0
  67. data/spec/models/rspeed/variable/pipes_pattern_spec.rb +5 -0
  68. data/spec/models/rspeed/variable/previous_result_spec.rb +19 -0
  69. data/spec/models/rspeed/variable/profile_pattern_spec.rb +5 -0
  70. data/spec/models/rspeed/variable/profile_spec.rb +23 -0
  71. data/spec/models/rspeed/variable/result_spec.rb +19 -0
  72. data/spec/spec_helper.rb +27 -0
  73. data/spec/support/common.rb +13 -0
  74. data/spec/support/coverage.rb +14 -0
  75. data/spec/support/env_mock.rb +3 -0
  76. data/spec/support/fakeredis.rb +3 -0
  77. metadata +187 -30
  78. data/spec/fixtures/new_spec.rb.csv +0 -1
  79. data/spec/models/rspeed/splitter/actual_examples_spec.rb +0 -22
  80. data/spec/models/rspeed/splitter/destroy_spec.rb +0 -33
  81. data/spec/models/rspeed/splitter/diff_spec.rb +0 -32
  82. data/spec/models/rspeed/splitter/get_spec.rb +0 -76
  83. data/spec/models/rspeed/splitter/keys_spec.rb +0 -33
  84. data/spec/models/rspeed/splitter/last_pipe_spec.rb +0 -21
  85. data/spec/models/rspeed/splitter/pipe_spec.rb +0 -21
  86. data/spec/models/rspeed/splitter/pipes_spec.rb +0 -27
  87. data/spec/models/rspeed/splitter/rename_spec.rb +0 -18
  88. data/spec/models/rspeed/splitter/result_spec.rb +0 -19
  89. data/spec/models/rspeed/splitter/save_spec.rb +0 -57
  90. data/spec/rails_helper.rb +0 -47
data/lib/rspeed/runner.rb CHANGED
@@ -5,24 +5,13 @@ module RSpeed
5
5
  module_function
6
6
 
7
7
  def run(shell)
8
- splitter = ::RSpeed::Splitter.new
9
-
10
- if splitter.first_pipe?
11
- # splitter.destroy "rspeed_*"
12
- splitter.destroy 'rspeed_tmp'
8
+ if RSpeed::Redis.result? || RSpeed::Splitter.first_pipe?
9
+ return shell.call(['bundle exec rspec', RSpeed::Splitter.pipe_files].compact.join(' '))
13
10
  end
14
11
 
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
12
+ RSpeed::Logger.log(self, __method__, 'Skipped! Only Pipe 1 can warm.')
24
13
 
25
- splitter.rename if splitter.last_pipe?
14
+ RSpeed::Observer.after_suite
26
15
  end
27
16
  end
28
17
  end
@@ -1,112 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpeed
4
- class Splitter
5
- DEFAULT_PATTERN = 'rspeed_*'
4
+ module Splitter
5
+ module_function
6
6
 
7
- def initialize(specs_path: './spec/**/*_spec.rb')
8
- @specs_path = specs_path
9
- end
10
-
11
- def actual_examples
12
- @actual_examples ||= begin
13
- [].tap do |examples|
14
- Dir[@specs_path].each do |file|
15
- data = File.open(file).read
16
- lines = data.split("\n")
7
+ require 'json'
17
8
 
18
- lines&.each.with_index do |item, index|
19
- examples << "#{file}:#{index + 1}" if item.gsub(/\s+/, '') =~ /^it/
20
- end
21
- end
9
+ require 'rspeed/differ'
22
10
 
23
- stream(:actual_examples, examples)
24
- end
25
- end
11
+ def append(items:, key:)
12
+ items.each { |item| RSpeed::Redis.client.rpush(key, item) }
26
13
  end
27
14
 
28
- def append(files = CSV.read('rspeed.csv'))
29
- files.each do |time, file|
30
- redis.lpush('rspeed_tmp', { file: file, time: time.to_f }.to_json)
31
- end
32
- end
15
+ def consolidate
16
+ RSpeed::Logger.log(self, __method__, 'Consolidating profiles.')
33
17
 
34
- def destroy(pattern = DEFAULT_PATTERN)
35
- keys(pattern).each { |key| redis.del key }
36
- end
18
+ RSpeed::Redis.destroy(pattern: RSpeed::Variable.result)
37
19
 
38
- def diff
39
- actual_data = rspeed_data.select { |item| actual_examples.include?(item[:file]) }
40
- added_data = added_examples.map { |item| { file: item, time: 0 } }
41
-
42
- removed_examples # called just for stream for now
43
-
44
- actual_data + added_data
20
+ append(items: RSpeed::Redis.profiles_content, key: RSpeed::Variable.result)
45
21
  end
46
22
 
47
23
  def first_pipe?
48
- pipe == 1
24
+ RSpeed::Env.pipe == 1
49
25
  end
50
26
 
51
- def get(pattern)
52
- @get ||= begin
53
- return redis.lrange(pattern, 0, -1) if %w[rspeed rspeed_tmp].include?(pattern)
54
-
55
- keys(pattern).map { |key| JSON.parse(redis.get(key)) }
56
- end
27
+ def need_warm?
28
+ first_pipe? && !RSpeed::Redis.result?
57
29
  end
58
30
 
59
- def keys(pattern = DEFAULT_PATTERN)
60
- cursor = 0
61
- result = []
31
+ def pipe_files
32
+ return unless RSpeed::Redis.result?
62
33
 
63
- loop do
64
- cursor, results = redis.scan(cursor, match: pattern)
65
- result += results
34
+ splitted = split(data: RSpeed::Differ.diff[:actual_files])
66
35
 
67
- break if cursor.to_i.zero?
68
- end
69
-
70
- result
71
- end
72
-
73
- def last_pipe?
74
- pipe == pipes
75
- end
76
-
77
- def pipe
78
- ENV.fetch('RSPEED_PIPE') { 1 }.to_i
36
+ splitted[RSpeed::Variable.key(RSpeed::Env.pipe)][:files].tap do |items|
37
+ RSpeed::Reporter.print_files(items)
38
+ end.map { |item| item[:file] }.join(' ')
79
39
  end
80
40
 
81
- def pipes
82
- result? ? ENV.fetch('RSPEED_PIPES') { 1 }.to_i : 1
83
- end
84
-
85
- def rename
86
- redis.rename('rspeed_tmp', 'rspeed')
87
- end
88
-
89
- def result?
90
- !keys('rspeed').empty?
91
- end
92
-
93
- def save(data = diff)
94
- split(data).each { |key, value| redis.set(key, value.to_json) }
95
- end
96
-
97
- def split(data)
41
+ def split(data:)
98
42
  json = {}
99
43
 
100
- pipes.times do |index|
101
- json["rspeed_#{index + 1}".to_sym] ||= []
102
- json["rspeed_#{index + 1}".to_sym] = { total: 0, files: [], number: index + 1 }
44
+ RSpeed::Env.pipes.times do |index|
45
+ json[RSpeed::Variable.key(index + 1)] ||= []
46
+ json[RSpeed::Variable.key(index + 1)] = { total: 0, files: [], number: index + 1 }
103
47
  end
104
48
 
105
- sorted_data = data.sort_by { |item| item[:time] }.reverse
49
+ sorted_data = data.sort_by { |item| item[:time] || 0.0 }.reverse
106
50
 
107
51
  sorted_data.each do |record|
108
52
  selected_pipe_data = json.min_by { |pipe| pipe[1][:total] }
109
- selected_pipe = json["rspeed_#{selected_pipe_data[1][:number]}".to_sym]
53
+ selected_pipe = json[RSpeed::Variable.key(selected_pipe_data[1][:number])]
110
54
  time = record[:time].to_f
111
55
 
112
56
  selected_pipe[:total] += time
@@ -115,39 +59,5 @@ module RSpeed
115
59
 
116
60
  json
117
61
  end
118
-
119
- private
120
-
121
- def added_examples
122
- @added_examples ||= begin
123
- (actual_examples - rspeed_examples).tap { |examples| stream(:added_examples, examples) }
124
- end
125
- end
126
-
127
- def redis
128
- @redis ||= ::Redis.new(db: ENV['RSPEED_DB'], host: ENV['RSPEED_HOST'], port: ENV.fetch('RSPEED_PORT') { 6379 })
129
- end
130
-
131
- def removed_examples
132
- @removed_examples ||= begin
133
- (rspeed_examples - actual_examples).tap { |examples| stream(:removed_examples, examples) }
134
- end
135
- end
136
-
137
- def removed_time
138
- removed_examples.map { |item| item[0].to_f }.sum
139
- end
140
-
141
- def rspeed_data
142
- @rspeed_data ||= get('rspeed').map { |item| JSON.parse(item, symbolize_names: true) }
143
- end
144
-
145
- def rspeed_examples
146
- rspeed_data.map { |item| item[:file] }
147
- end
148
-
149
- def stream(type, data)
150
- puts "PIPE: #{pipe} with #{type}: #{data}"
151
- end
152
62
  end
153
63
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpeed
4
+ module Variable
5
+ module_function
6
+
7
+ PIPES_PATTERN = 'rspeed:pipe_*'
8
+ PROFILE_PATTERN = 'rspeed:profile_*'
9
+
10
+ def append_app_name(value, plus: nil)
11
+ [value, RSpeed::Env.app, plus].compact.join('_')
12
+ end
13
+
14
+ def key(number)
15
+ append_app_name('rspeed', plus: number).to_sym
16
+ end
17
+
18
+ def result
19
+ append_app_name('rspeed')
20
+ end
21
+
22
+ def pipe
23
+ append_app_name('rspeed:pipe', plus: format('%02d', RSpeed::Env.pipe))
24
+ end
25
+
26
+ def previous_result
27
+ append_app_name('rspeed', plus: 'previous')
28
+ end
29
+
30
+ def profile
31
+ append_app_name('rspeed:profile', plus: format('%02d', RSpeed::Env.pipe))
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpeed
4
- VERSION = '0.4.0'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV['RAILS_ENV'] ||= 'test'
4
+
5
+ require 'support/coverage'
6
+
7
+ require 'pry-byebug'
8
+ require 'rspeed'
9
+ require 'support/common'
10
+ require 'support/fakeredis'
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe 'empty' do
4
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Database, '#list' do
4
+ before do
5
+ redis_object.rpush(RSpeed::Variable.result, { file: '1_spec.rb', time: 1.0 }.to_json)
6
+ redis_object.rpush(RSpeed::Variable.result, { file: '2_spec.rb', time: 2.0 }.to_json)
7
+ end
8
+
9
+ it 'list and parse the given key' do
10
+ expect(described_class.list(RSpeed::Variable.result)).to eq [
11
+ { file: '1_spec.rb', time: 1.0 },
12
+ { file: '2_spec.rb', time: 2.0 },
13
+ ]
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Database, '#previous_result' do
4
+ let!(:redis) { redis_object }
5
+
6
+ before do
7
+ redis.rpush(RSpeed::Variable.previous_result, { file: '1_spec.rb', time: 1.0 }.to_json)
8
+ redis.rpush(RSpeed::Variable.previous_result, { file: '2_spec.rb', time: 2.0 }.to_json)
9
+ end
10
+
11
+ it 'returns the previous results data as json' do
12
+ expect(described_class.previous_result).to eq [
13
+ { file: '1_spec.rb', time: 1.0 },
14
+ { file: '2_spec.rb', time: 2.0 },
15
+ ]
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Database, '#result' do
4
+ let!(:redis) { redis_object }
5
+
6
+ before do
7
+ redis.rpush('rspeed', { file: '1_spec.rb', time: 1.0 }.to_json)
8
+ redis.rpush('rspeed', { file: '2_spec.rb', time: 2.0 }.to_json)
9
+ end
10
+
11
+ it 'returns the results data as json' do
12
+ expect(described_class.result).to eq [
13
+ { file: '1_spec.rb', time: 1.0 },
14
+ { file: '2_spec.rb', time: 2.0 },
15
+ ]
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Differ, '#actual_data' do
4
+ let!(:files) { ['./spec/fixtures/1_spec.rb:4', './spec/fixtures/1_spec.rb:6', './spec/fixtures/new_spec.rb:1'] }
5
+
6
+ let!(:result) do
7
+ [
8
+ { file: './spec/fixtures/1_spec.rb:4', time: 1.4 },
9
+ { file: './spec/fixtures/1_spec.rb:6', time: 1.6 },
10
+ { file: './spec/fixtures/2_spec.rb:4', time: 2.4 },
11
+ ]
12
+ end
13
+
14
+ it 'returns only consolidated data still existent as spec' do
15
+ expect(described_class.actual_data(files: files, result: result)).to eq [
16
+ { file: './spec/fixtures/1_spec.rb:4', time: 1.4 },
17
+ { file: './spec/fixtures/1_spec.rb:6', time: 1.6 },
18
+ ]
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Differ, '#actual_files' do
4
+ it 'returns all examples' do
5
+ expect(described_class.actual_files(spec_path: './spec/fixtures/**/*_spec.rb')).to eq [
6
+ './spec/fixtures/1_spec.rb:4',
7
+ './spec/fixtures/1_spec.rb:6',
8
+ './spec/fixtures/1_spec.rb:8',
9
+ './spec/fixtures/2_spec.rb:4',
10
+ ]
11
+ end
12
+
13
+ it 'does not raise when no file match' do
14
+ expect(described_class.actual_files(spec_path: './spec/fixtures/**/*_missing.rb')).to eq []
15
+ end
16
+
17
+ it 'does not raise when file is empty' do
18
+ expect(described_class.actual_files(spec_path: './spec/fixtures/**/empty.rb')).to eq []
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Differ, '#added_data' do
4
+ let!(:files) { ['./spec/fixtures/1_spec.rb:4', './spec/fixtures/1_spec.rb:6', './spec/fixtures/new_spec.rb:4'] }
5
+
6
+ let!(:result) do
7
+ [
8
+ { file: './spec/fixtures/1_spec.rb:4', time: 1.4 },
9
+ { file: './spec/fixtures/1_spec.rb:6', time: 1.6 },
10
+ { file: './spec/fixtures/2_spec.rb:4', time: 2.4 },
11
+ ]
12
+ end
13
+
14
+ it 'returns the added data files' do
15
+ expect(described_class.added_data(files: files, result: result)).to eq [
16
+ { file: './spec/fixtures/new_spec.rb:4', time: nil },
17
+ ]
18
+ end
19
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'support/env_mock'
4
+
5
+ RSpec.describe RSpeed::Differ, '#diff' do
6
+ let!(:redis) { redis_object }
7
+
8
+ before do
9
+ redis.rpush('rspeed', { file: './spec/fixtures/1_spec.rb:4', time: 1.4 }.to_json)
10
+ redis.rpush('rspeed', { file: './spec/fixtures/1_spec.rb:6', time: 1.6 }.to_json)
11
+ redis.rpush('rspeed', { file: './spec/fixtures/1_spec.rb:8', time: 1.8 }.to_json)
12
+ redis.rpush('rspeed', { file: './spec/fixtures/2_spec.rb:4', time: 2.4 }.to_json)
13
+ redis.rpush('rspeed', { file: './spec/fixtures/x_spec.rb:1', time: 3 }.to_json)
14
+ redis.rpush('rspeed', { file: './spec/fixtures/2_spec.rb:666', time: 6 }.to_json)
15
+
16
+ File.open('spec/fixtures/new_spec.rb', 'a') { |file| file.write('it') }
17
+ end
18
+
19
+ after { delete_file('spec/fixtures/new_spec.rb') }
20
+
21
+ it 'removes removed specs and adds new spec and keeps keeped specs based on rspeed key values' do
22
+ EnvMock.mock(rspeed_spec_path: './spec/fixtures/*_spec.rb') do
23
+ expect(described_class.diff).to eq(
24
+ actual_files: [
25
+ { file: './spec/fixtures/1_spec.rb:4', time: 1.4 },
26
+ { file: './spec/fixtures/1_spec.rb:6', time: 1.6 },
27
+ { file: './spec/fixtures/1_spec.rb:8', time: 1.8 },
28
+ { file: './spec/fixtures/2_spec.rb:4', time: 2.4 },
29
+ { file: './spec/fixtures/new_spec.rb:1', time: nil },
30
+ ],
31
+
32
+ actual_time: 7.2,
33
+ added_files: [{ file: './spec/fixtures/new_spec.rb:1', time: nil }],
34
+ added_time: '?',
35
+
36
+ removed_files: [
37
+ { file: './spec/fixtures/x_spec.rb:1', time: 3 },
38
+ { file: './spec/fixtures/2_spec.rb:666', time: 6 },
39
+ ],
40
+
41
+ removed_time: 9.0
42
+ )
43
+ end
44
+ end
45
+
46
+ context 'when has duplicated example' do
47
+ before do
48
+ redis.rpush('rspeed', { file: './spec/fixtures/1_spec.rb:4', time: 1.4 }.to_json)
49
+ redis.rpush('rspeed', { file: './spec/fixtures/1_spec.rb:4', time: 1.4 }.to_json)
50
+ end
51
+
52
+ it 'is removed' do
53
+ EnvMock.mock(rspeed_spec_path: './spec/fixtures/*_spec.rb') do
54
+ expect(described_class.diff).to eq(
55
+ actual_files: [
56
+ { file: './spec/fixtures/1_spec.rb:4', time: 1.4 },
57
+ { file: './spec/fixtures/1_spec.rb:6', time: 1.6 },
58
+ { file: './spec/fixtures/1_spec.rb:8', time: 1.8 },
59
+ { file: './spec/fixtures/2_spec.rb:4', time: 2.4 },
60
+ { file: './spec/fixtures/new_spec.rb:1', time: nil },
61
+ ],
62
+
63
+ actual_time: 7.2,
64
+ added_files: [{ file: './spec/fixtures/new_spec.rb:1', time: nil }],
65
+ added_time: '?',
66
+
67
+ removed_files: [
68
+ { file: './spec/fixtures/x_spec.rb:1', time: 3 },
69
+ { file: './spec/fixtures/2_spec.rb:666', time: 6 },
70
+ ],
71
+
72
+ removed_time: 9.0
73
+ )
74
+ end
75
+ end
76
+ end
77
+ end