bluepill 0.0.68 → 0.0.69
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -2
- data/bin/bluepill +19 -20
- data/bin/sample_forking_server +26 -13
- data/bluepill.gemspec +12 -18
- data/lib/bluepill.rb +12 -12
- data/lib/bluepill/application.rb +64 -71
- data/lib/bluepill/application/client.rb +0 -2
- data/lib/bluepill/application/server.rb +1 -3
- data/lib/bluepill/condition_watch.rb +12 -7
- data/lib/bluepill/controller.rb +37 -42
- data/lib/bluepill/dsl.rb +1 -2
- data/lib/bluepill/dsl/app_proxy.rb +3 -4
- data/lib/bluepill/dsl/process_factory.rb +40 -44
- data/lib/bluepill/dsl/process_proxy.rb +4 -5
- data/lib/bluepill/group.rb +15 -21
- data/lib/bluepill/logger.rb +4 -4
- data/lib/bluepill/process.rb +107 -109
- data/lib/bluepill/process_conditions.rb +1 -3
- data/lib/bluepill/process_conditions/always_true.rb +2 -3
- data/lib/bluepill/process_conditions/cpu_usage.rb +0 -1
- data/lib/bluepill/process_conditions/file_time.rb +5 -6
- data/lib/bluepill/process_conditions/http.rb +11 -9
- data/lib/bluepill/process_conditions/mem_usage.rb +6 -7
- data/lib/bluepill/process_conditions/process_condition.rb +4 -5
- data/lib/bluepill/process_conditions/running_time.rb +1 -2
- data/lib/bluepill/process_conditions/zombie_process.rb +1 -2
- data/lib/bluepill/process_journal.rb +18 -21
- data/lib/bluepill/process_statistics.rb +2 -4
- data/lib/bluepill/socket.rb +13 -16
- data/lib/bluepill/system.rb +57 -63
- data/lib/bluepill/trigger.rb +9 -11
- data/lib/bluepill/triggers/flapping.rb +12 -16
- data/lib/bluepill/util/rotational_array.rb +1 -2
- data/lib/bluepill/version.rb +1 -2
- metadata +4 -28
- data/.gitignore +0 -12
- data/.rspec +0 -1
- data/.travis.yml +0 -17
- data/Gemfile +0 -27
- data/Rakefile +0 -38
- data/examples/example.rb +0 -87
- data/examples/new_example.rb +0 -89
- data/examples/new_runit_example.rb +0 -29
- data/examples/runit_example.rb +0 -26
- data/local-bluepill +0 -130
- data/spec/lib/bluepill/application_spec.rb +0 -51
- data/spec/lib/bluepill/logger_spec.rb +0 -3
- data/spec/lib/bluepill/process_spec.rb +0 -135
- data/spec/lib/bluepill/process_statistics_spec.rb +0 -24
- data/spec/lib/bluepill/system_spec.rb +0 -45
- data/spec/spec_helper.rb +0 -26
@@ -1,29 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
require 'rubygems'
|
3
|
-
require 'bluepill'
|
4
|
-
require 'logger'
|
5
|
-
|
6
|
-
# ATTENTION:
|
7
|
-
# You must declare only one application per config when foreground mode specified
|
8
|
-
#
|
9
|
-
# http://github.com/Undev/runit-man used as example of monitored application.
|
10
|
-
|
11
|
-
# Note that this syntax supported from bluepill 0.0.50
|
12
|
-
|
13
|
-
Bluepill.application(:runit_man, :foreground => true) do
|
14
|
-
process("runit-man") do
|
15
|
-
pid_file "/etc/service/runit-man/supervise/pid"
|
16
|
-
|
17
|
-
start_command "/usr/bin/sv start runit-man"
|
18
|
-
stop_command "/usr/bin/sv stop runit-man"
|
19
|
-
restart_command "/usr/bin/sv restart runit-man"
|
20
|
-
|
21
|
-
start_grace_time 1.seconds
|
22
|
-
restart_grace_time 7.seconds
|
23
|
-
stop_grace_time 7.seconds
|
24
|
-
|
25
|
-
checks :http, :within => 30.seconds, :retry_in => 7.seconds, :every => 30.seconds,
|
26
|
-
:url => 'http://localhost:4567/', :kind => :success, :pattern => /html/, :timeout => 3.seconds
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
data/examples/runit_example.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
require 'rubygems'
|
3
|
-
require 'bluepill'
|
4
|
-
require 'logger'
|
5
|
-
|
6
|
-
# ATTENTION:
|
7
|
-
# You must declare only one application per config when foreground mode specified
|
8
|
-
#
|
9
|
-
# http://github.com/Undev/runit-man used as example of monitored application.
|
10
|
-
|
11
|
-
Bluepill.application(:runit_man, :foreground => true) do |app|
|
12
|
-
app.process("runit-man") do |process|
|
13
|
-
process.pid_file = "/etc/service/runit-man/supervise/pid"
|
14
|
-
|
15
|
-
process.start_command = "/usr/bin/sv start runit-man"
|
16
|
-
process.stop_command = "/usr/bin/sv stop runit-man"
|
17
|
-
process.restart_command = "/usr/bin/sv restart runit-man"
|
18
|
-
|
19
|
-
process.start_grace_time = 1.seconds
|
20
|
-
process.restart_grace_time = 7.seconds
|
21
|
-
process.stop_grace_time = 7.seconds
|
22
|
-
|
23
|
-
process.checks :http, :within => 30.seconds, :retry_in => 7.seconds, :every => 30.seconds,
|
24
|
-
:url => 'http://localhost:4567/', :kind => :success, :pattern => /html/, :timeout => 3.seconds
|
25
|
-
end
|
26
|
-
end
|
data/local-bluepill
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler/setup'
|
5
|
-
$LOAD_PATH.unshift(File.expand_path('lib', File.dirname(__FILE__)))
|
6
|
-
|
7
|
-
require 'optparse'
|
8
|
-
require 'bluepill'
|
9
|
-
|
10
|
-
begin
|
11
|
-
require 'rbconfig'
|
12
|
-
rescue LoadError
|
13
|
-
end
|
14
|
-
|
15
|
-
RbConfig = Config unless Object.const_defined?(:RbConfig)
|
16
|
-
|
17
|
-
# Default options
|
18
|
-
options = {
|
19
|
-
:log_file => "/var/log/bluepill.log",
|
20
|
-
:base_dir => ENV['BLUEPILL_BASE_DIR'] || (::Process.euid != 0 ? File.join(ENV['HOME'], '.bluepill') : "/var/run/bluepill"),
|
21
|
-
:privileged => true,
|
22
|
-
:timeout => 10,
|
23
|
-
:attempts => 1
|
24
|
-
}
|
25
|
-
|
26
|
-
OptionParser.new do |opts|
|
27
|
-
opts.banner = "Usage: bluepill [app] cmd [options]"
|
28
|
-
opts.on('-l', "--logfile LOGFILE", "Path to logfile, defaults to #{options[:log_file]}") do |file|
|
29
|
-
options[:log_file] = file
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on('-c', "--base-dir DIR", "Directory to store bluepill socket and pid files, defaults to #{options[:base_dir]}") do |base_dir|
|
33
|
-
options[:base_dir] = base_dir
|
34
|
-
end
|
35
|
-
|
36
|
-
opts.on("-v", "--version") do
|
37
|
-
puts "bluepill, version #{Bluepill::VERSION}"
|
38
|
-
exit
|
39
|
-
end
|
40
|
-
|
41
|
-
opts.on("--[no-]privileged", "Allow/disallow to run #{$0} as non-privileged process. disallowed by default") do |v|
|
42
|
-
options[:privileged] = v
|
43
|
-
end
|
44
|
-
|
45
|
-
opts.on('-t', '--timeout Seconds', Integer, "Timeout for commands sent to the daemon, in seconds. Defaults to 10.") do |timeout|
|
46
|
-
options[:timeout] = timeout
|
47
|
-
end
|
48
|
-
|
49
|
-
opts.on('--attempts Count', Integer, "Attempts for commands sent to the daemon, in seconds. Defaults to 1.") do |attempts|
|
50
|
-
options[:attempts] = attempts
|
51
|
-
end
|
52
|
-
|
53
|
-
help = proc do
|
54
|
-
puts opts
|
55
|
-
puts
|
56
|
-
puts "Commands:"
|
57
|
-
puts " load CONFIG_FILE\t\tLoads new instance of bluepill using the specified config file"
|
58
|
-
puts " status\t\t\tLists the status of the proceses for the specified app"
|
59
|
-
puts " start [TARGET]\t\tIssues the start command for the target process or group, defaults to all processes"
|
60
|
-
puts " stop [TARGET]\t\tIssues the stop command for the target process or group, defaults to all processes"
|
61
|
-
puts " restart [TARGET]\t\tIssues the restart command for the target process or group, defaults to all processes"
|
62
|
-
puts " unmonitor [TARGET]\t\tStop monitoring target process or group, defaults to all processes"
|
63
|
-
puts " log [TARGET]\t\tShow the log for the specified process or group, defaults to all for app"
|
64
|
-
puts " quit\t\t\tStop bluepill"
|
65
|
-
puts
|
66
|
-
puts "See http://github.com/bluepill-rb/bluepill#readme"
|
67
|
-
exit
|
68
|
-
end
|
69
|
-
|
70
|
-
opts.on_tail('-h','--help', 'Show this message', &help)
|
71
|
-
help.call if ARGV.empty?
|
72
|
-
end.parse!
|
73
|
-
|
74
|
-
# Check for root
|
75
|
-
if options[:privileged] && ::Process.euid != 0
|
76
|
-
$stderr.puts "You must run bluepill as root or use --no-privileged option."
|
77
|
-
exit(3)
|
78
|
-
end
|
79
|
-
|
80
|
-
APPLICATION_COMMANDS = %w(status start stop restart unmonitor quit log)
|
81
|
-
|
82
|
-
controller = Bluepill::Controller.new(options.slice(:base_dir, :log_file))
|
83
|
-
|
84
|
-
if controller.running_applications.include?(File.basename($0)) && File.symlink?($0)
|
85
|
-
# bluepill was called as a symlink with the name of the target application
|
86
|
-
options[:application] = File.basename($0)
|
87
|
-
elsif controller.running_applications.include?(ARGV.first)
|
88
|
-
# the first arg is the application name
|
89
|
-
options[:application] = ARGV.shift
|
90
|
-
elsif APPLICATION_COMMANDS.include?(ARGV.first)
|
91
|
-
if controller.running_applications.length == 1
|
92
|
-
# there is only one, let's just use that
|
93
|
-
options[:application] = controller.running_applications.first
|
94
|
-
elsif controller.running_applications.length > 1
|
95
|
-
# There is more than one, tell them the list and exit
|
96
|
-
$stderr.puts "You must specify an application name to run that command. Here's the list of running applications:"
|
97
|
-
controller.running_applications.each_with_index do |app, index|
|
98
|
-
$stderr.puts " #{index + 1}. #{app}"
|
99
|
-
end
|
100
|
-
$stderr.puts "Usage: bluepill [app] cmd [options]"
|
101
|
-
exit(1)
|
102
|
-
else
|
103
|
-
# There are none running AND they aren't trying to start one
|
104
|
-
$stderr.puts "Error: There are no running bluepill daemons.\nTo start a bluepill daemon, use: bluepill load <config file>"
|
105
|
-
exit(2)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
options[:command] = ARGV.shift
|
110
|
-
|
111
|
-
if options[:command] == "load"
|
112
|
-
file = ARGV.shift
|
113
|
-
if File.exists?(file)
|
114
|
-
# Restart the ruby interpreter for the config file so that anything loaded here
|
115
|
-
# does not stay in memory for the daemon
|
116
|
-
ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
117
|
-
load_path = File.expand_path("#{File.dirname(__FILE__)}/lib")
|
118
|
-
file_path = File.expand_path(file)
|
119
|
-
ENV['BLUEPILL_BASE_DIR'] = options[:base_dir]
|
120
|
-
|
121
|
-
exec(ruby, "-I#{load_path}", '-rbluepill', file_path)
|
122
|
-
|
123
|
-
else
|
124
|
-
$stderr.puts "Can't find file: #{file}"
|
125
|
-
end
|
126
|
-
else
|
127
|
-
target = ARGV.shift
|
128
|
-
controller.handle_command(options[:application], options[:command], target)
|
129
|
-
end
|
130
|
-
|
@@ -1,51 +0,0 @@
|
|
1
|
-
describe Bluepill::Application do
|
2
|
-
describe "#initialize" do
|
3
|
-
let(:options){ {} }
|
4
|
-
subject {described_class.new('test', options)}
|
5
|
-
before(:each) {expect_any_instance_of(described_class).to receive(:setup_pids_dir)}
|
6
|
-
|
7
|
-
context "when euid is not root" do
|
8
|
-
before(:each) {allow(::Process).to receive(:euid).and_return(1)}
|
9
|
-
|
10
|
-
describe '#base_dir' do
|
11
|
-
subject { super().base_dir }
|
12
|
-
it{ should eq(File.join(ENV['HOME'], '.bluepill')) }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
context "when euid is root" do
|
16
|
-
before(:each) {allow(::Process).to receive(:euid).and_return(0)}
|
17
|
-
|
18
|
-
describe '#base_dir' do
|
19
|
-
subject { super().base_dir }
|
20
|
-
it { should eq('/var/run/bluepill') }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context "when option base_dir is specified" do
|
25
|
-
let(:options) { {:base_dir=>'/var/bluepill'} }
|
26
|
-
|
27
|
-
describe '#base_dir' do
|
28
|
-
subject { super().base_dir }
|
29
|
-
it { should eq(options[:base_dir]) }
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context "when environment BLUEPILL_BASE_DIR is specified" do
|
34
|
-
before(:each) {ENV['BLUEPILL_BASE_DIR'] = '/bluepill'}
|
35
|
-
|
36
|
-
describe '#base_dir' do
|
37
|
-
subject { super().base_dir }
|
38
|
-
it { should eq(ENV['BLUEPILL_BASE_DIR']) }
|
39
|
-
end
|
40
|
-
|
41
|
-
context "and option base_dir is specified" do
|
42
|
-
let(:options) { {:base_dir=>'/var/bluepill'} }
|
43
|
-
|
44
|
-
describe '#base_dir' do
|
45
|
-
subject { super().base_dir }
|
46
|
-
it { should eq(options[:base_dir]) }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
describe Bluepill::Process do
|
2
|
-
before(:all) do
|
3
|
-
Bluepill::ProcessJournal.base_dir = './.bluepill'
|
4
|
-
Bluepill::ProcessJournal.logger = Bluepill::Logger.new(:log_file => 'bluepill.log', :stdout => false).prefix_with('rspec')
|
5
|
-
end
|
6
|
-
|
7
|
-
subject do
|
8
|
-
Bluepill::Process.new(:proc_name, [], :logger => Bluepill::Logger.new)
|
9
|
-
end
|
10
|
-
|
11
|
-
describe "#initialize" do
|
12
|
-
context "defaults" do
|
13
|
-
[
|
14
|
-
:start_command, :stop_command, :restart_command, :stdout, :stderr, :stdin,
|
15
|
-
:daemonize, :pid_file, :working_dir, :uid, :gid, :child_process_factory,
|
16
|
-
:pid_command, :auto_start, :supplementary_groups, :stop_signals
|
17
|
-
].each do |attr|
|
18
|
-
describe attr do
|
19
|
-
subject { super().send(attr) }
|
20
|
-
it { should be_nil }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#monitor_children' do
|
25
|
-
subject { super().monitor_children }
|
26
|
-
it { should be false }
|
27
|
-
end
|
28
|
-
|
29
|
-
describe '#cache_actual_pid' do
|
30
|
-
subject { super().cache_actual_pid }
|
31
|
-
it { should be true }
|
32
|
-
end
|
33
|
-
|
34
|
-
describe '#start_grace_time' do
|
35
|
-
subject { super().start_grace_time }
|
36
|
-
it { should eq 3 }
|
37
|
-
end
|
38
|
-
|
39
|
-
describe '#stop_grace_time' do
|
40
|
-
subject { super().stop_grace_time }
|
41
|
-
it { should eq 3 }
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '#restart_grace_time' do
|
45
|
-
subject { super().restart_grace_time }
|
46
|
-
it { should eq 3 }
|
47
|
-
end
|
48
|
-
|
49
|
-
describe '#on_start_timeout' do
|
50
|
-
subject { super().on_start_timeout }
|
51
|
-
it { should eq "start" }
|
52
|
-
end
|
53
|
-
|
54
|
-
describe '#environment' do
|
55
|
-
subject { super().environment }
|
56
|
-
it { should eq Hash[] }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context "overrides" do
|
61
|
-
subject { Bluepill::Process.new(:proc_name, [], :start_grace_time => 17) }
|
62
|
-
|
63
|
-
describe '#start_grace_time' do
|
64
|
-
subject { super().start_grace_time }
|
65
|
-
it { should eq 17 }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "#start_process" do
|
71
|
-
it "functions" do
|
72
|
-
allow(subject).to receive(:start_command) { "/etc/init.d/script start" }
|
73
|
-
allow(subject).to receive(:on_start_timeout) { "freakout" }
|
74
|
-
allow(subject.logger).to receive(:warning)
|
75
|
-
allow(subject).to receive(:daemonize?) { false }
|
76
|
-
|
77
|
-
expect(subject).to receive(:with_timeout).
|
78
|
-
with(3, "freakout").
|
79
|
-
and_yield
|
80
|
-
|
81
|
-
expect(Bluepill::System).to receive(:execute_blocking).
|
82
|
-
with("/etc/init.d/script start", subject.system_command_options).
|
83
|
-
and_return(:exit_code => 0)
|
84
|
-
|
85
|
-
subject.start_process
|
86
|
-
end
|
87
|
-
|
88
|
-
describe "#stop_process" do
|
89
|
-
it "functions" do
|
90
|
-
allow(subject).to receive(:stop_command) { "/etc/init.d/script stop" }
|
91
|
-
allow(subject.logger).to receive(:warning)
|
92
|
-
expect(subject).to receive(:with_timeout).
|
93
|
-
with(3, "stop").
|
94
|
-
and_yield
|
95
|
-
|
96
|
-
expect(Bluepill::System).to receive(:execute_blocking).
|
97
|
-
with("/etc/init.d/script stop", subject.system_command_options).
|
98
|
-
and_return(:exit_code => 0)
|
99
|
-
|
100
|
-
subject.stop_process
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "#restart_process" do
|
105
|
-
it "functions" do
|
106
|
-
allow(subject).to receive(:restart_command) { "/etc/init.d/script restart" }
|
107
|
-
allow(subject.logger).to receive(:warning)
|
108
|
-
expect(subject).to receive(:with_timeout).
|
109
|
-
with(3, "restart").
|
110
|
-
and_yield
|
111
|
-
|
112
|
-
expect(Bluepill::System).to receive(:execute_blocking).
|
113
|
-
with("/etc/init.d/script restart", subject.system_command_options).
|
114
|
-
and_return(:exit_code => 0)
|
115
|
-
|
116
|
-
subject.restart_process
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "#with_timeout" do
|
122
|
-
let(:block) { proc { nil } }
|
123
|
-
|
124
|
-
before(:each) do
|
125
|
-
allow(subject.logger).to receive(:err)
|
126
|
-
expect(Timeout).to receive(:timeout).with(3.to_f, &block).and_raise(Timeout::Error)
|
127
|
-
end
|
128
|
-
|
129
|
-
it "proceeds to next_state on timeout." do
|
130
|
-
expect(subject).to receive(:dispatch!).with("state_override")
|
131
|
-
subject.with_timeout(3, "state_override", &block)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
describe Bluepill::ProcessStatistics do
|
2
|
-
before(:each) do
|
3
|
-
@stats = Bluepill::ProcessStatistics.new
|
4
|
-
end
|
5
|
-
|
6
|
-
it "should record events" do
|
7
|
-
@stats.record_event('some event', 'some reason')
|
8
|
-
@stats.record_event('another event', 'another reason')
|
9
|
-
expect(@stats.events.size).to eq(2)
|
10
|
-
end
|
11
|
-
|
12
|
-
it "should record #EVENTS_TO_PERSIST events" do
|
13
|
-
(2 * Bluepill::ProcessStatistics::EVENTS_TO_PERSIST).times do
|
14
|
-
@stats.record_event('some event', 'some reason')
|
15
|
-
end
|
16
|
-
expect(@stats.events.size).to eq(Bluepill::ProcessStatistics::EVENTS_TO_PERSIST)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should return event history" do
|
20
|
-
@stats.record_event('some event', 'some reason')
|
21
|
-
expect(@stats.to_s).to match(/some reason/)
|
22
|
-
expect(@stats.to_s).to match(/event history/)
|
23
|
-
end
|
24
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
describe Bluepill::System do
|
2
|
-
describe :pid_alive? do
|
3
|
-
it "should be true if process responds to zero signal" do
|
4
|
-
expect(Process).to receive(:kill).with(0, 555).and_return(0)
|
5
|
-
expect(Bluepill::System).to be_pid_alive(555)
|
6
|
-
end
|
7
|
-
|
8
|
-
it "should be false if process throws exception on zero signal" do
|
9
|
-
expect(Process).to receive(:kill).with(0, 555).and_raise(Errno::ESRCH)
|
10
|
-
expect(Bluepill::System).not_to be_pid_alive(555)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe :store do
|
15
|
-
it "should be Hash" do
|
16
|
-
expect(Bluepill::System.store).to be_kind_of(Hash)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should return same Hash or every call" do
|
20
|
-
expect(Bluepill::System.store).to be_equal(Bluepill::System.store)
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should store assigned pairs" do
|
24
|
-
Bluepill::System.store[:somekey] = 10
|
25
|
-
expect(Bluepill::System.store[:somekey]).to be_eql(10)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe :reset_data do
|
30
|
-
it 'should clear the #store' do
|
31
|
-
Bluepill::System.store[:anotherkey] = Faker::Lorem.sentence
|
32
|
-
Bluepill::System.reset_data
|
33
|
-
expect(Bluepill::System.store).to be_empty
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe :parse_etime do
|
38
|
-
it "should parse etime format" do
|
39
|
-
expect(Bluepill::System.parse_elapsed_time("400-00:04:01")).to be_equal(34560241)
|
40
|
-
expect(Bluepill::System.parse_elapsed_time("02:04:02")).to be_equal(7442)
|
41
|
-
expect(Bluepill::System.parse_elapsed_time("20:03")).to be_equal(1203)
|
42
|
-
expect(Bluepill::System.parse_elapsed_time("invalid")).to be_equal(0)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|