ultra_marathon 0.0.1

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.
@@ -0,0 +1,244 @@
1
+ require 'spec_helper'
2
+
3
+ describe UltraMarathon::Callbacks do
4
+ let(:test_class) do
5
+ anonymous_test_class do
6
+ include UltraMarathon::Callbacks
7
+ attr_writer :bubble_count
8
+ callbacks :before_bubbles, :after_bubbles, :on_error
9
+
10
+ def bubbles(&block)
11
+ begin
12
+ invoke_before_bubbles_callbacks
13
+ instance_exec &block
14
+ invoke_after_bubbles_callbacks
15
+ rescue StandardError => error
16
+ invoke_on_error_callbacks(error)
17
+ end
18
+ end
19
+
20
+ def bubble_count
21
+ @bubble_count ||= 0
22
+ end
23
+
24
+ def increment_bubbles
25
+ self.bubble_count += 1
26
+ end
27
+
28
+ def triple_bubbles
29
+ self.bubble_count *= 3
30
+ end
31
+
32
+ def i_can_handle_errors!(error)
33
+ self.bubble_count += error.message.to_i
34
+ end
35
+ end
36
+ end
37
+
38
+ let(:test_instance) { test_class.new }
39
+
40
+ describe 'callback memoization' do
41
+ it 'should add getter method' do
42
+ test_class.should be_respond_to :before_bubbles_callbacks
43
+ test_class.should be_respond_to :after_bubbles_callbacks
44
+ end
45
+
46
+ it 'should memoize an empty array' do
47
+ test_class.before_bubbles_callbacks.should eq []
48
+ test_class.after_bubbles_callbacks.should eq []
49
+ end
50
+ end
51
+
52
+ describe 'invoking callbacks' do
53
+ describe 'with lambdas' do
54
+ describe 'that do not take arguments' do
55
+ before(:each) do
56
+ test_class.before_bubbles ->{ self.bubble_count = 12 }
57
+ test_class.after_bubbles ->{ self.bubble_count += 1 }
58
+ test_class.on_error ->{ self.bubble_count += 8 }
59
+ end
60
+
61
+ it 'should invoke the callbacks in order' do
62
+ test_instance.bubbles { self.bubble_count /= 2 }
63
+ test_instance.bubble_count.should be 7
64
+ end
65
+
66
+ it 'should not pass arguments if the lambda takes none' do
67
+ # use a lambda, which will raise for incorrect arity
68
+ test_instance.bubbles &->{ raise 'the roof!' }
69
+ test_instance.bubble_count.should be 20
70
+ end
71
+ end
72
+
73
+ describe 'with arguments' do
74
+ before(:each) do
75
+ test_class.on_error ->(e){ self.bubble_count = e.message.to_i }
76
+ end
77
+
78
+ it 'should pass the argument to the lambda' do
79
+ test_instance.bubbles { raise '9001' }
80
+ test_instance.bubble_count.should be 9001
81
+ end
82
+
83
+ it 'should throw an error if not enough arguments are passed' do
84
+ expect {
85
+ test_instance.send :invoke_on_error_callbacks
86
+ }.to raise_error ArgumentError
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'passing in symbols' do
92
+ describe 'that do not take arguments' do
93
+ before(:each) do
94
+ test_class.before_bubbles :increment_bubbles
95
+ test_class.after_bubbles :triple_bubbles
96
+ end
97
+
98
+ it 'should invoke the callbacks in order' do
99
+ test_instance.bubbles { self.bubble_count -= 2 }
100
+ test_instance.bubble_count.should be -3
101
+ end
102
+
103
+ it 'allows passing the same symbol twice' do
104
+ test_class.before_bubbles :increment_bubbles
105
+ test_instance.bubbles { self.bubble_count -= 10 }
106
+ test_instance.bubble_count.should be -24
107
+ end
108
+
109
+ describe 'when the callback passes arguments' do
110
+ before(:each) { test_class.on_error :triple_bubbles }
111
+
112
+ it 'calls the method successfully' do
113
+ test_instance.bubbles { raise '9001' }
114
+ test_instance.bubble_count.should be 3
115
+ end
116
+ end
117
+ end
118
+
119
+ describe 'with arguments' do
120
+ before(:each) do
121
+ test_class.on_error :i_can_handle_errors!
122
+ end
123
+
124
+ it 'should pass the argument to the lambda' do
125
+ test_instance.bubbles { raise '9001' }
126
+ test_instance.bubble_count.should be 9001
127
+ end
128
+ end
129
+ end
130
+
131
+ describe 'options' do
132
+ describe ':if' do
133
+ describe 'with a symbol' do
134
+ before(:each) do
135
+ test_class.before_bubbles :increment_bubbles, :if => :ready_to_party?
136
+ test_class.before_bubbles :increment_bubbles
137
+ end
138
+
139
+ it 'should call the callback if the method is truthy' do
140
+ test_instance.stub(:ready_to_party?).and_return true
141
+ test_instance.bubbles { self.bubble_count *= 10 }
142
+ test_instance.bubble_count.should be 20
143
+ end
144
+
145
+ it 'should not call the callback if the method is falsy' do
146
+ test_instance.stub(:ready_to_party?).and_return false
147
+ test_instance.bubbles { self.bubble_count *= 10 }
148
+ test_instance.bubble_count.should be 10
149
+ end
150
+ end
151
+
152
+ describe 'with a lambda' do
153
+ before(:each) do
154
+ test_class.before_bubbles :increment_bubbles, if: -> { ready_to_party? }
155
+ test_class.before_bubbles :increment_bubbles
156
+ end
157
+
158
+ it 'should call the callback if the method is truthy' do
159
+ test_instance.stub(:ready_to_party?).and_return true
160
+ test_instance.bubbles { self.bubble_count *= 10 }
161
+ test_instance.bubble_count.should be 20
162
+ end
163
+
164
+ it 'should not call the callback if the method is falsy' do
165
+ test_instance.stub(:ready_to_party?).and_return false
166
+ test_instance.bubbles { self.bubble_count *= 10 }
167
+ test_instance.bubble_count.should be 10
168
+ end
169
+ end
170
+ end
171
+
172
+ describe ':unless' do
173
+ describe 'with a symbol' do
174
+ before(:each) do
175
+ test_class.before_bubbles :increment_bubbles, :unless => :ready_to_party?
176
+ test_class.before_bubbles :increment_bubbles
177
+ end
178
+
179
+ it 'should call the callback if the method is falsy' do
180
+ test_instance.stub(:ready_to_party?).and_return true
181
+ test_instance.bubbles { self.bubble_count *= 10 }
182
+ test_instance.bubble_count.should be 10
183
+ end
184
+
185
+ it 'should not call the callback if the method is truthy' do
186
+ test_instance.stub(:ready_to_party?).and_return false
187
+ test_instance.bubbles { self.bubble_count *= 10 }
188
+ test_instance.bubble_count.should be 20
189
+ end
190
+ end
191
+
192
+ describe 'with a lambda' do
193
+ before(:each) do
194
+ test_class.before_bubbles :increment_bubbles, unless: ->{ ready_to_party? }
195
+ test_class.before_bubbles :increment_bubbles
196
+ end
197
+
198
+ it 'should call the callback if the method is falsey' do
199
+ test_instance.stub(:ready_to_party?).and_return true
200
+ test_instance.bubbles { self.bubble_count *= 10 }
201
+ test_instance.bubble_count.should be 10
202
+ end
203
+
204
+ it 'should not call the callback if the method is truthy' do
205
+ test_instance.stub(:ready_to_party?).and_return false
206
+ test_instance.bubbles { self.bubble_count *= 10 }
207
+ test_instance.bubble_count.should be 20
208
+ end
209
+ end
210
+ end
211
+
212
+ describe ':context' do
213
+ let(:other_walrus) { test_class.new }
214
+
215
+ describe 'with a symbol' do
216
+ before(:each) do
217
+ test_class.before_bubbles :increment_bubbles, context: other_walrus
218
+ test_class.before_bubbles :increment_bubbles
219
+ end
220
+
221
+ it 'should call the callback on the other object' do
222
+ test_instance.bubbles { self.bubble_count *= 10 }
223
+ test_instance.bubble_count.should be 10
224
+ other_walrus.bubble_count.should be 1
225
+ end
226
+ end
227
+
228
+ describe 'with a block' do
229
+ before(:each) do
230
+ test_class.before_bubbles(Proc.new { increment_bubbles; triple_bubbles }, context: other_walrus)
231
+ test_class.before_bubbles :increment_bubbles
232
+ end
233
+
234
+ it 'should call the block on the other object' do
235
+ test_instance.stub(:ready_to_party?).and_return true
236
+ test_instance.bubbles { self.bubble_count *= 10 }
237
+ test_instance.bubble_count.should be 10
238
+ other_walrus.bubble_count.should be 3
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe UltraMarathon::Instrumentation do
4
+ let(:test_class) do
5
+ anonymous_test_class do
6
+ include UltraMarathon::Instrumentation
7
+
8
+ def run(&block)
9
+ instrument { block.call }
10
+ end
11
+ end
12
+ end
13
+
14
+ let(:test_instance) { test_class.new }
15
+ let(:start_time) { Time.local(1991, 1, 31, 15, 15, 00) }
16
+ let(:end_time) { Time.local(1991, 1, 31, 16, 00, 20) }
17
+ let(:run_block) do
18
+ # This is going to be evaluated in context of the instance
19
+ # so we need to wrap in an IIF to access `end_time`
20
+ Proc.new do |end_time|
21
+ Proc.new do
22
+ Timecop.travel(end_time)
23
+ end
24
+ end.call(end_time)
25
+ end
26
+
27
+ subject(:run) { test_instance.run &run_block }
28
+
29
+ before(:each) { Timecop.freeze(start_time) }
30
+ after(:each) { Timecop.return }
31
+
32
+ describe '#instrument' do
33
+
34
+ describe 'method signature' do
35
+ let(:run_block) { Proc.new { 'Bubbles!' } }
36
+
37
+ it 'should return the result of the passed in block' do
38
+ run.should eq 'Bubbles!'
39
+ end
40
+ end
41
+
42
+ describe 'setting instance variables' do
43
+ before(:each) { run }
44
+
45
+ it 'should set the start_time' do
46
+ test_instance.start_time.should eq start_time
47
+ end
48
+
49
+ it 'should set the end_time' do
50
+ test_instance.end_time.to_i.should eq end_time.to_i
51
+ end
52
+ end
53
+ end
54
+
55
+ describe 'total_time' do
56
+ before(:each) { run }
57
+
58
+ it 'should return the total seconds elapsed' do
59
+ test_instance.total_time.should eq 2720
60
+ end
61
+ end
62
+
63
+ describe '#formatted_total_time' do
64
+ before(:each) { run }
65
+
66
+ it 'should return the total time, formatted' do
67
+ test_instance.formatted_total_time.should eq '00:45:20'
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe UltraMarathon::Logging do
4
+ let(:test_class) do
5
+ anonymous_test_class do
6
+ include UltraMarathon::Logging
7
+ end
8
+ end
9
+
10
+ let(:test_instance) { test_class.new }
11
+
12
+ before(:each) { test_class.instance_variable_set(:@log_class, nil) }
13
+
14
+ describe '.log_class' do
15
+ let(:log_class) { anonymous_test_class }
16
+
17
+ context 'passing a proc' do
18
+ it 'it returns an instance of that class on instantiation' do
19
+ test_class.send :log_class, ->{ log_class }
20
+ test_instance.logger.should be_a log_class
21
+ end
22
+ end
23
+
24
+ context 'passing a class' do
25
+ it 'instantiates the logger as that class' do
26
+ test_class.send :log_class, log_class
27
+ test_instance.logger.should be_a log_class
28
+ end
29
+ end
30
+ end
31
+
32
+ describe '.logger' do
33
+ it 'defaults to the UltraMarathon::Logger class' do
34
+ test_instance.logger.should be_a UltraMarathon::Logger
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+
3
+ describe UltraMarathon::Store do
4
+ let(:runner_class) do
5
+ anonymous_test_class do
6
+ attr_accessor :success, :name
7
+
8
+ def initialize(name)
9
+ @name = name.to_sym
10
+ end
11
+
12
+ # Helper methods for testing
13
+
14
+ def succeed!
15
+ self.success = true
16
+ self
17
+ end
18
+
19
+ def fail!
20
+ self.success = false
21
+ self
22
+ end
23
+ end
24
+ end
25
+
26
+ let(:test_instance) { described_class.new(maintenances) }
27
+ let(:maintenances) { [] }
28
+
29
+ describe '#initialize' do
30
+ let(:maintenances) do
31
+ [ runner_class.new(:frank), runner_class.new(:harold) ]
32
+ end
33
+
34
+ it 'should add them and regurgitate them' do
35
+ test_instance.sort_by(&:name).should eq maintenances
36
+ end
37
+ end
38
+
39
+ describe '#<<' do
40
+ it 'should add the maintenance to the storage' do
41
+ test_maintenance = runner_class.new(:heraldo)
42
+ test_instance << test_maintenance
43
+ test_instance[:heraldo].should be test_maintenance
44
+ end
45
+ end
46
+
47
+ describe '#add' do
48
+ it 'should add the maintenance to the storage' do
49
+ test_maintenance = runner_class.new(:heraldo)
50
+ test_instance.add test_maintenance
51
+ test_instance[:heraldo].should be test_maintenance
52
+ end
53
+ end
54
+
55
+ describe '#pluck' do
56
+ let(:maintenances) do
57
+ [ runner_class.new(:frank), runner_class.new(:harold) ]
58
+ end
59
+
60
+ it 'should return an array of calling the block on each instance' do
61
+ test_instance.pluck(&:name).sort.should eq [:frank, :harold]
62
+ end
63
+ end
64
+
65
+ describe '#failed?' do
66
+ let(:maintenances) { [ runner_class.new(:heraldo).fail! ] }
67
+
68
+ it 'returns true if the maintenance was not successful' do
69
+ test_instance.should be_failed :heraldo
70
+ end
71
+
72
+ it 'returns nil if the maintenance is not being stored' do
73
+ test_instance.failed?(:juanita).should be_nil
74
+ end
75
+ end
76
+
77
+ describe '#success?' do
78
+ let(:maintenances) { [ runner_class.new(:heraldo).succeed! ] }
79
+
80
+ it 'returns true if the maintenance was successful' do
81
+ test_instance.should be_success :heraldo
82
+ end
83
+
84
+ it 'returns nil if the maintenance is not being stored' do
85
+ test_instance.success?(:juanita).should be_nil
86
+ end
87
+ end
88
+
89
+ describe '==' do
90
+ let(:maintenances) { [ runner_class.new(:waldo), runner_class.new(:heraldo), runner_class.new(:geraldo) ] }
91
+ let(:other_instance) { described_class.new(other_maintenances) }
92
+
93
+ context 'when the names of the other maintenances are the same' do
94
+ # purposefully a different order
95
+ let(:other_maintenances) { [ runner_class.new(:heraldo), runner_class.new(:geraldo), runner_class.new(:waldo) ] }
96
+
97
+ it 'should return true' do
98
+ (other_instance == test_instance).should be true
99
+ end
100
+ end
101
+
102
+ context 'when the names of the other maintenances are a subset' do
103
+ let(:other_maintenances) { [ runner_class.new(:geraldo), runner_class.new(:waldo) ] }
104
+
105
+ it 'should return false' do
106
+ (other_instance == test_instance).should be false
107
+ end
108
+ end
109
+
110
+ context 'when they are both equal' do
111
+ let(:other_maintenances) { [] }
112
+
113
+ it 'should return false' do
114
+ (other_instance == test_instance).should be false
115
+ end
116
+ end
117
+ end
118
+
119
+ describe '!=' do
120
+ let(:maintenances) { [ runner_class.new(:waldo), runner_class.new(:heraldo), runner_class.new(:geraldo) ] }
121
+ let(:other_instance) { described_class.new(other_maintenances) }
122
+
123
+ context 'when the names of the other maintenances are the same' do
124
+ # purposefully a different order
125
+ let(:other_maintenances) { [ runner_class.new(:heraldo), runner_class.new(:geraldo), runner_class.new(:waldo) ] }
126
+
127
+ it 'should return false' do
128
+ (other_instance != test_instance).should be false
129
+ end
130
+ end
131
+
132
+ context 'when the names of the other maintenances are a subset' do
133
+ let(:other_maintenances) { [ runner_class.new(:geraldo), runner_class.new(:waldo) ] }
134
+
135
+ it 'should return true' do
136
+ (other_instance != test_instance).should be true
137
+ end
138
+ end
139
+
140
+ context 'when they are both equal' do
141
+ let(:other_maintenances) { [] }
142
+
143
+ it 'should return true' do
144
+ (other_instance != test_instance).should be true
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe UltraMarathon::SubRunner do
4
+ let(:test_class) do
5
+ anonymous_test_class do
6
+ attr_writer :bubble_count
7
+
8
+ def bubble_count
9
+ @bubble_count ||= 0
10
+ end
11
+
12
+ def increment_bubbles
13
+ self.bubble_count += 1
14
+ end
15
+
16
+ def triple_bubbles
17
+ self.bubble_count *= 3
18
+ end
19
+ end
20
+ end
21
+
22
+ let(:test_instance) { described_class.new(options, run_block) }
23
+ let(:options) do
24
+ { context: context, name: name }
25
+ end
26
+ let(:name) { :frank }
27
+ let(:context) { test_class.new }
28
+
29
+ context '#run' do
30
+ let(:run_block) { ->{ increment_bubbles } }
31
+ subject { test_instance.run! }
32
+
33
+ it 'runs in the context that was passed in' do
34
+ subject
35
+ context.bubble_count.should be 1
36
+ end
37
+
38
+ it 'starts the logs with its name' do
39
+ subject
40
+ test_instance.logger.contents.should be_start_with "Running '#{name}' SubRunner"
41
+ end
42
+
43
+ describe 'logging' do
44
+ let(:run_block) { ->{ logger.info('Draws those who are willing, drags those who are not.') } }
45
+
46
+ it 'logs to the sub maintenance' do
47
+ subject
48
+ test_instance.logger.contents.should include 'Draws those who are willing, drags those who are not.'
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ultra_marathon/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.authors = ['Chris Maddox']
8
+ spec.date = '2013-10-02'
9
+ spec.description = 'Managing long running processes.'
10
+ spec.email = 'tyre77@gmail.com'
11
+ spec.files = %w(LICENSE.md README.md ultra_marathon.gemspec)
12
+ spec.files += Dir.glob('lib/**/*.rb')
13
+ spec.files += Dir.glob('spec/**/*')
14
+ spec.homepage = 'https://github.com/tyre/ultra_marathon'
15
+ spec.licenses = ['MIT']
16
+ spec.name = 'ultra_marathon'
17
+ spec.summary = 'Managing ultra long running processes.'
18
+ spec.test_files += Dir.glob('spec/**/*')
19
+ spec.version = UltraMarathon::Version.to_s
20
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ultra_marathon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Maddox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Managing long running processes.
14
+ email: tyre77@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENSE.md
20
+ - README.md
21
+ - lib/ultra_marathon.rb
22
+ - lib/ultra_marathon/abstract_runner.rb
23
+ - lib/ultra_marathon/callbacks.rb
24
+ - lib/ultra_marathon/instrumentation.rb
25
+ - lib/ultra_marathon/logger.rb
26
+ - lib/ultra_marathon/logging.rb
27
+ - lib/ultra_marathon/store.rb
28
+ - lib/ultra_marathon/sub_runner.rb
29
+ - lib/ultra_marathon/version.rb
30
+ - spec/spec_helper.rb
31
+ - spec/support/file_mutexes.rb
32
+ - spec/support/test_helpers.rb
33
+ - spec/ultra_marathon/abstract_runner_spec.rb
34
+ - spec/ultra_marathon/callbacks_spec.rb
35
+ - spec/ultra_marathon/instrumentation_spec.rb
36
+ - spec/ultra_marathon/logging_spec.rb
37
+ - spec/ultra_marathon/store_spec.rb
38
+ - spec/ultra_marathon/sub_runner_spec.rb
39
+ - ultra_marathon.gemspec
40
+ homepage: https://github.com/tyre/ultra_marathon
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.2.1
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Managing ultra long running processes.
64
+ test_files:
65
+ - spec/spec_helper.rb
66
+ - spec/support/file_mutexes.rb
67
+ - spec/support/test_helpers.rb
68
+ - spec/ultra_marathon/abstract_runner_spec.rb
69
+ - spec/ultra_marathon/callbacks_spec.rb
70
+ - spec/ultra_marathon/instrumentation_spec.rb
71
+ - spec/ultra_marathon/logging_spec.rb
72
+ - spec/ultra_marathon/store_spec.rb
73
+ - spec/ultra_marathon/sub_runner_spec.rb