backup 3.0.19 → 3.0.20
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.
- data/.gitignore +4 -0
- data/Gemfile +9 -8
- data/Gemfile.lock +19 -1
- data/Guardfile +13 -9
- data/README.md +93 -31
- data/backup.gemspec +3 -3
- data/bin/backup +6 -283
- data/lib/backup.rb +101 -72
- data/lib/backup/archive.rb +21 -9
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/cleaner.rb +36 -0
- data/lib/backup/cli/helpers.rb +103 -0
- data/lib/backup/cli/utility.rb +308 -0
- data/lib/backup/compressor/base.rb +2 -2
- data/lib/backup/compressor/pbzip2.rb +76 -0
- data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
- data/lib/backup/configuration/database/riak.rb +25 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +6 -0
- data/lib/backup/configuration/helpers.rb +5 -18
- data/lib/backup/configuration/notifier/base.rb +13 -0
- data/lib/backup/configuration/notifier/hipchat.rb +41 -0
- data/lib/backup/configuration/notifier/mail.rb +38 -0
- data/lib/backup/configuration/notifier/prowl.rb +23 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +4 -0
- data/lib/backup/configuration/storage/dropbox.rb +8 -4
- data/lib/backup/database/base.rb +10 -2
- data/lib/backup/database/mongodb.rb +16 -19
- data/lib/backup/database/mysql.rb +2 -2
- data/lib/backup/database/postgresql.rb +2 -2
- data/lib/backup/database/redis.rb +15 -7
- data/lib/backup/database/riak.rb +45 -0
- data/lib/backup/dependency.rb +21 -7
- data/lib/backup/encryptor/base.rb +1 -1
- data/lib/backup/encryptor/open_ssl.rb +20 -5
- data/lib/backup/errors.rb +124 -0
- data/lib/backup/finder.rb +11 -3
- data/lib/backup/logger.rb +121 -82
- data/lib/backup/model.rb +103 -44
- data/lib/backup/notifier/base.rb +50 -0
- data/lib/backup/notifier/campfire.rb +32 -52
- data/lib/backup/notifier/hipchat.rb +99 -0
- data/lib/backup/notifier/mail.rb +100 -61
- data/lib/backup/notifier/presently.rb +31 -40
- data/lib/backup/notifier/prowl.rb +73 -0
- data/lib/backup/notifier/twitter.rb +29 -39
- data/lib/backup/packager.rb +25 -0
- data/lib/backup/splitter.rb +62 -0
- data/lib/backup/storage/base.rb +178 -18
- data/lib/backup/storage/cloudfiles.rb +34 -28
- data/lib/backup/storage/dropbox.rb +64 -67
- data/lib/backup/storage/ftp.rb +48 -40
- data/lib/backup/storage/local.rb +33 -28
- data/lib/backup/storage/ninefold.rb +40 -26
- data/lib/backup/storage/object.rb +8 -6
- data/lib/backup/storage/rsync.rb +61 -51
- data/lib/backup/storage/s3.rb +29 -27
- data/lib/backup/storage/scp.rb +56 -36
- data/lib/backup/storage/sftp.rb +49 -33
- data/lib/backup/syncer/base.rb +1 -1
- data/lib/backup/syncer/rsync.rb +1 -1
- data/lib/backup/template.rb +46 -0
- data/lib/backup/version.rb +1 -1
- data/spec/archive_spec.rb +34 -9
- data/spec/backup_spec.rb +1 -1
- data/spec/cli/helpers_spec.rb +35 -0
- data/spec/cli/utility_spec.rb +38 -0
- data/spec/compressor/bzip2_spec.rb +1 -1
- data/spec/compressor/gzip_spec.rb +1 -1
- data/spec/compressor/lzma_spec.rb +1 -1
- data/spec/compressor/pbzip2_spec.rb +63 -0
- data/spec/configuration/base_spec.rb +1 -1
- data/spec/configuration/compressor/bzip2_spec.rb +1 -1
- data/spec/configuration/compressor/gzip_spec.rb +1 -1
- data/spec/configuration/compressor/lzma_spec.rb +1 -1
- data/spec/configuration/database/base_spec.rb +1 -1
- data/spec/configuration/database/mongodb_spec.rb +1 -1
- data/spec/configuration/database/mysql_spec.rb +1 -1
- data/spec/configuration/database/postgresql_spec.rb +1 -1
- data/spec/configuration/database/redis_spec.rb +1 -1
- data/spec/configuration/database/riak_spec.rb +31 -0
- data/spec/configuration/encryptor/gpg_spec.rb +1 -1
- data/spec/configuration/encryptor/open_ssl_spec.rb +4 -1
- data/spec/configuration/notifier/campfire_spec.rb +1 -1
- data/spec/configuration/notifier/hipchat_spec.rb +43 -0
- data/spec/configuration/notifier/mail_spec.rb +34 -22
- data/spec/configuration/notifier/presently_spec.rb +1 -1
- data/spec/configuration/notifier/prowl_spec.rb +28 -0
- data/spec/configuration/notifier/twitter_spec.rb +1 -1
- data/spec/configuration/storage/cloudfiles_spec.rb +19 -16
- data/spec/configuration/storage/dropbox_spec.rb +1 -1
- data/spec/configuration/storage/ftp_spec.rb +1 -1
- data/spec/configuration/storage/local_spec.rb +1 -1
- data/spec/configuration/storage/ninefold_spec.rb +1 -1
- data/spec/configuration/storage/rsync_spec.rb +1 -1
- data/spec/configuration/storage/s3_spec.rb +1 -1
- data/spec/configuration/storage/scp_spec.rb +1 -1
- data/spec/configuration/storage/sftp_spec.rb +1 -1
- data/spec/configuration/syncer/rsync_spec.rb +1 -1
- data/spec/configuration/syncer/s3_spec.rb +1 -1
- data/spec/database/base_spec.rb +10 -1
- data/spec/database/mongodb_spec.rb +34 -7
- data/spec/database/mysql_spec.rb +8 -7
- data/spec/database/postgresql_spec.rb +8 -7
- data/spec/database/redis_spec.rb +39 -9
- data/spec/database/riak_spec.rb +50 -0
- data/spec/encryptor/gpg_spec.rb +1 -1
- data/spec/encryptor/open_ssl_spec.rb +77 -20
- data/spec/errors_spec.rb +306 -0
- data/spec/finder_spec.rb +91 -0
- data/spec/logger_spec.rb +254 -33
- data/spec/model_spec.rb +120 -15
- data/spec/notifier/campfire_spec.rb +127 -52
- data/spec/notifier/hipchat_spec.rb +193 -0
- data/spec/notifier/mail_spec.rb +290 -74
- data/spec/notifier/presently_spec.rb +290 -73
- data/spec/notifier/prowl_spec.rb +149 -0
- data/spec/notifier/twitter_spec.rb +106 -41
- data/spec/spec_helper.rb +8 -2
- data/spec/splitter_spec.rb +71 -0
- data/spec/storage/base_spec.rb +280 -19
- data/spec/storage/cloudfiles_spec.rb +38 -22
- data/spec/storage/dropbox_spec.rb +17 -13
- data/spec/storage/ftp_spec.rb +145 -55
- data/spec/storage/local_spec.rb +6 -6
- data/spec/storage/ninefold_spec.rb +70 -29
- data/spec/storage/object_spec.rb +44 -44
- data/spec/storage/rsync_spec.rb +186 -63
- data/spec/storage/s3_spec.rb +23 -24
- data/spec/storage/scp_spec.rb +116 -41
- data/spec/storage/sftp_spec.rb +124 -46
- data/spec/syncer/rsync_spec.rb +3 -3
- data/spec/syncer/s3_spec.rb +1 -1
- data/spec/version_spec.rb +1 -1
- data/templates/cli/utility/archive +13 -0
- data/{lib/templates → templates/cli/utility}/compressor/bzip2 +1 -1
- data/{lib/templates → templates/cli/utility}/compressor/gzip +1 -1
- data/{lib/templates → templates/cli/utility}/compressor/lzma +0 -0
- data/templates/cli/utility/compressor/pbzip2 +7 -0
- data/templates/cli/utility/config +31 -0
- data/{lib/templates → templates/cli/utility}/database/mongodb +1 -1
- data/{lib/templates → templates/cli/utility}/database/mysql +1 -1
- data/{lib/templates → templates/cli/utility}/database/postgresql +1 -1
- data/{lib/templates → templates/cli/utility}/database/redis +1 -1
- data/templates/cli/utility/database/riak +8 -0
- data/{lib/templates → templates/cli/utility}/encryptor/gpg +1 -1
- data/templates/cli/utility/encryptor/openssl +9 -0
- data/templates/cli/utility/model.erb +23 -0
- data/{lib/templates → templates/cli/utility}/notifier/campfire +2 -1
- data/templates/cli/utility/notifier/hipchat +15 -0
- data/{lib/templates → templates/cli/utility}/notifier/mail +6 -1
- data/{lib/templates → templates/cli/utility}/notifier/presently +1 -0
- data/templates/cli/utility/notifier/prowl +11 -0
- data/{lib/templates → templates/cli/utility}/notifier/twitter +2 -1
- data/templates/cli/utility/splitter +7 -0
- data/templates/cli/utility/storage/cloudfiles +12 -0
- data/{lib/templates → templates/cli/utility}/storage/dropbox +1 -1
- data/{lib/templates → templates/cli/utility}/storage/ftp +0 -0
- data/templates/cli/utility/storage/local +7 -0
- data/{lib/templates → templates/cli/utility}/storage/ninefold +1 -1
- data/templates/cli/utility/storage/rsync +11 -0
- data/{lib/templates → templates/cli/utility}/storage/s3 +0 -2
- data/templates/cli/utility/storage/scp +11 -0
- data/templates/cli/utility/storage/sftp +11 -0
- data/{lib/templates → templates/cli/utility}/syncer/rsync +1 -1
- data/{lib/templates → templates/cli/utility}/syncer/s3 +1 -1
- data/templates/general/links +11 -0
- data/templates/general/version.erb +2 -0
- data/templates/notifier/mail/failure.erb +9 -0
- data/templates/notifier/mail/success.erb +7 -0
- data/templates/notifier/mail/warning.erb +9 -0
- data/templates/storage/dropbox/authorization_url.erb +6 -0
- data/templates/storage/dropbox/authorized.erb +4 -0
- data/templates/storage/dropbox/cache_file_written.erb +10 -0
- metadata +81 -45
- data/lib/backup/cli.rb +0 -110
- data/lib/backup/exception/command_failed.rb +0 -8
- data/lib/backup/exception/command_not_found.rb +0 -8
- data/lib/backup/notifier/binder.rb +0 -32
- data/lib/backup/notifier/templates/notify_failure.erb +0 -33
- data/lib/backup/notifier/templates/notify_success.erb +0 -16
- data/lib/templates/archive +0 -7
- data/lib/templates/encryptor/openssl +0 -8
- data/lib/templates/readme +0 -15
- data/lib/templates/storage/cloudfiles +0 -11
- data/lib/templates/storage/local +0 -7
- data/lib/templates/storage/rsync +0 -11
- data/lib/templates/storage/scp +0 -11
- data/lib/templates/storage/sftp +0 -11
data/spec/finder_spec.rb
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe Backup::Finder do
|
|
6
|
+
|
|
7
|
+
describe '#find' do
|
|
8
|
+
let(:finder) { Backup::Finder.new('test_trigger', 'foo') }
|
|
9
|
+
|
|
10
|
+
before do
|
|
11
|
+
finder.stubs(:load_config!)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'should return the first model that matches the trigger' do
|
|
15
|
+
models = %w{ foo1 test_trigger foo2 test_trigger }.map do |trigger|
|
|
16
|
+
stub(:trigger => trigger.to_sym)
|
|
17
|
+
end
|
|
18
|
+
Backup::Model.expects(:all).returns(models)
|
|
19
|
+
Backup::Model.expects(:current=).with(models[1])
|
|
20
|
+
|
|
21
|
+
expect do
|
|
22
|
+
finder.find.should == models[1]
|
|
23
|
+
end.not_to raise_error
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should raise an error when no models match the trigger' do
|
|
27
|
+
models = %w{ foo1 foo2 foo3 }.map do |trigger|
|
|
28
|
+
stub(:trigger => trigger.to_sym)
|
|
29
|
+
end
|
|
30
|
+
Backup::Model.expects(:all).returns(models)
|
|
31
|
+
Backup::Model.expects(:current=).never
|
|
32
|
+
|
|
33
|
+
expect do
|
|
34
|
+
finder.find
|
|
35
|
+
end.to raise_error(
|
|
36
|
+
Backup::Errors::Finder::MissingTriggerError,
|
|
37
|
+
"Finder::MissingTriggerError: Could not find trigger 'test_trigger' in 'foo'."
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end # describe '#find'
|
|
42
|
+
|
|
43
|
+
describe '#load_config!' do
|
|
44
|
+
let(:finder) { Backup::Finder.new('foo', 'config_file') }
|
|
45
|
+
|
|
46
|
+
context 'when given a valid config file' do
|
|
47
|
+
|
|
48
|
+
before do
|
|
49
|
+
File.expects(:exist?).with('config_file').returns(true)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should load the config file' do
|
|
53
|
+
File.expects(:read).with('config_file').returns(:file_contents)
|
|
54
|
+
Backup.expects(:module_eval).with(:file_contents, 'config_file', 1)
|
|
55
|
+
|
|
56
|
+
finder.send(:load_config!)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'should reset Model.all' do
|
|
60
|
+
File.stubs(:read)
|
|
61
|
+
Backup.stubs(:module_eval)
|
|
62
|
+
Backup::Model.expects(:all=).with([])
|
|
63
|
+
|
|
64
|
+
finder.send(:load_config!)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end # context 'when given a valid config file'
|
|
68
|
+
|
|
69
|
+
context 'when given a config file that does not exist' do
|
|
70
|
+
|
|
71
|
+
before do
|
|
72
|
+
File.expects(:exist?).with('config_file').returns(false)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'should raise an error' do
|
|
76
|
+
Backup::Model.expects(:all=).never
|
|
77
|
+
File.expects(:read).never
|
|
78
|
+
Backup.expects(:module_eval).never
|
|
79
|
+
|
|
80
|
+
expect do
|
|
81
|
+
finder.send(:load_config!)
|
|
82
|
+
end.to raise_error(
|
|
83
|
+
Backup::Errors::Finder::MissingConfigError,
|
|
84
|
+
"Finder::MissingConfigError: Could not find configuration file: 'config_file'."
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end # context 'when given a config file that does not exist'
|
|
89
|
+
|
|
90
|
+
end # describe '#find'
|
|
91
|
+
end
|
data/spec/logger_spec.rb
CHANGED
|
@@ -1,66 +1,287 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
require File.
|
|
3
|
+
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
4
|
require 'timecop'
|
|
5
5
|
|
|
6
6
|
describe Backup::Logger do
|
|
7
|
+
let(:logger_time) { Time.now.strftime("%Y/%m/%d %H:%M:%S") }
|
|
8
|
+
let(:logfile_path) { File.join(Backup::LOG_PATH, 'backup.log') }
|
|
9
|
+
let(:logfile_mock) { mock }
|
|
10
|
+
let(:s) { sequence '' }
|
|
11
|
+
|
|
7
12
|
before do
|
|
8
13
|
Timecop.freeze(Time.now)
|
|
9
14
|
|
|
15
|
+
# stubbed in spec_helper
|
|
10
16
|
[:message, :error, :warn, :normal, :silent].each do |message_type|
|
|
11
|
-
|
|
17
|
+
subject.unstub(message_type)
|
|
12
18
|
end
|
|
19
|
+
|
|
20
|
+
subject.send(:remove_const, :QUIET) rescue nil
|
|
21
|
+
subject.send(:remove_instance_variable, :@messages) rescue nil
|
|
22
|
+
subject.send(:remove_instance_variable, :@has_warnings) rescue nil
|
|
13
23
|
end
|
|
14
24
|
|
|
15
|
-
describe '
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
describe '#message' do
|
|
26
|
+
it 'sends a regular message to the console and log file' do
|
|
27
|
+
subject.expects(:loggify).in_sequence(s).
|
|
28
|
+
with('regular message', :message, :green).
|
|
29
|
+
returns(:green_regular_message)
|
|
30
|
+
subject.expects(:to_console).in_sequence(s).
|
|
31
|
+
with(:green_regular_message)
|
|
32
|
+
subject.expects(:loggify).in_sequence(s).
|
|
33
|
+
with('regular message', :message).
|
|
34
|
+
returns(:uncolored_regular_message)
|
|
35
|
+
subject.expects(:to_file).in_sequence(s).
|
|
36
|
+
with(:uncolored_regular_message)
|
|
37
|
+
|
|
38
|
+
subject.message('regular message')
|
|
18
39
|
end
|
|
40
|
+
end
|
|
19
41
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
42
|
+
describe '#error' do
|
|
43
|
+
it 'sends an error message to the console (stderr) and log file' do
|
|
44
|
+
subject.expects(:loggify).in_sequence(s).
|
|
45
|
+
with('error message', :error, :red).
|
|
46
|
+
returns(:red_error_message)
|
|
47
|
+
subject.expects(:to_console).in_sequence(s).
|
|
48
|
+
with(:red_error_message, true)
|
|
49
|
+
subject.expects(:loggify).in_sequence(s).
|
|
50
|
+
with('error message', :error).
|
|
51
|
+
returns(:uncolored_error_message)
|
|
52
|
+
subject.expects(:to_file).in_sequence(s).
|
|
53
|
+
with(:uncolored_error_message)
|
|
23
54
|
|
|
24
|
-
|
|
25
|
-
end
|
|
55
|
+
subject.error('error message')
|
|
26
56
|
end
|
|
57
|
+
end
|
|
27
58
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
59
|
+
describe '#warn' do
|
|
60
|
+
it 'sends a warning message to the console (stderr) and log file' do
|
|
61
|
+
subject.expects(:loggify).in_sequence(s).
|
|
62
|
+
with('warning message', :warning, :yellow).
|
|
63
|
+
returns(:yellow_warning_message)
|
|
64
|
+
subject.expects(:to_console).in_sequence(s).
|
|
65
|
+
with(:yellow_warning_message, true)
|
|
66
|
+
subject.expects(:loggify).in_sequence(s).
|
|
67
|
+
with('warning message', :warning).
|
|
68
|
+
returns(:uncolored_warning_message)
|
|
69
|
+
subject.expects(:to_file).in_sequence(s).
|
|
70
|
+
with(:uncolored_warning_message)
|
|
31
71
|
|
|
32
|
-
|
|
33
|
-
|
|
72
|
+
subject.warn('warning message')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'sets has_warnings? to true' do
|
|
76
|
+
subject.stubs(:to_console)
|
|
77
|
+
subject.stubs(:to_file)
|
|
78
|
+
expect { subject.warn('warning') }.to
|
|
79
|
+
change{ subject.has_warnings? }.from(false).to(true)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe '#normal' do
|
|
84
|
+
it 'sends a normal, unformatted message to the console and log file' do
|
|
85
|
+
subject.expects(:loggify).in_sequence(s).
|
|
86
|
+
with('normal message').
|
|
87
|
+
returns(:unformatted_message)
|
|
88
|
+
subject.expects(:to_console).in_sequence(s).
|
|
89
|
+
with(:unformatted_message)
|
|
90
|
+
subject.expects(:loggify).in_sequence(s).
|
|
91
|
+
with('normal message').
|
|
92
|
+
returns(:unformatted_message)
|
|
93
|
+
subject.expects(:to_file).in_sequence(s).
|
|
94
|
+
with(:unformatted_message)
|
|
95
|
+
|
|
96
|
+
subject.normal('normal message')
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe '#silent' do
|
|
101
|
+
it 'sends a silent message to the log file' do
|
|
102
|
+
subject.expects(:to_console).never
|
|
103
|
+
subject.expects(:loggify).in_sequence(s).
|
|
104
|
+
with('silent message', :silent).
|
|
105
|
+
returns(:silent_message)
|
|
106
|
+
subject.expects(:to_file).in_sequence(s).
|
|
107
|
+
with(:silent_message)
|
|
108
|
+
|
|
109
|
+
subject.silent('silent message')
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe '#messages' do
|
|
114
|
+
|
|
115
|
+
it 'returns an empty array if no messages have been sent' do
|
|
116
|
+
subject.messages.should == []
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'returns an array of all lines sent to the log file' do
|
|
120
|
+
File.stubs(:open).yields(stub(:puts))
|
|
121
|
+
strings = ['an array', 'of message', 'strings']
|
|
122
|
+
subject.send(:to_file, strings)
|
|
123
|
+
subject.messages.should == strings
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'does not track lines sent to the console' do
|
|
127
|
+
subject.stubs(:puts)
|
|
128
|
+
strings = ['an array', 'of message', 'strings']
|
|
129
|
+
subject.send(:to_console, strings)
|
|
130
|
+
subject.messages.should == []
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end # describe '#messages'
|
|
134
|
+
|
|
135
|
+
describe '#clear!' do
|
|
136
|
+
it 'should clear the log and reset has_warnings?' do
|
|
137
|
+
subject.messages << 'foo'
|
|
138
|
+
subject.instance_variable_set(:@has_warnings, true)
|
|
139
|
+
subject.messages.count.should == 1
|
|
140
|
+
subject.has_warnings?.should be_true
|
|
141
|
+
|
|
142
|
+
subject.clear!
|
|
143
|
+
subject.messages.should be_empty
|
|
144
|
+
subject.has_warnings?.should be_false
|
|
145
|
+
end
|
|
146
|
+
end # describe '#clear!'
|
|
147
|
+
|
|
148
|
+
describe '#loggify' do
|
|
149
|
+
|
|
150
|
+
it 'returns an array of strings split on newline separators' do
|
|
151
|
+
str_aa = "first line\nsecond line"
|
|
152
|
+
str_ab = "first line\nsecond line\n"
|
|
153
|
+
expected_a = ["[#{logger_time}][msg_type] first line",
|
|
154
|
+
"[#{logger_time}][msg_type] second line"]
|
|
155
|
+
|
|
156
|
+
str_b = 'string with no newline'
|
|
157
|
+
expected_b = ["[#{logger_time}][msg_type] string with no newline"]
|
|
158
|
+
|
|
159
|
+
subject.send(:loggify, str_aa, :msg_type).should == expected_a
|
|
160
|
+
subject.send(:loggify, str_ab, :msg_type).should == expected_a
|
|
161
|
+
subject.send(:loggify, str_b, :msg_type).should == expected_b
|
|
34
162
|
end
|
|
35
163
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
164
|
+
it 'formats a string with color if color is given' do
|
|
165
|
+
green_type = ["[#{logger_time}][#{"\e[32mmsg_type\e[0m"}] foo"]
|
|
166
|
+
yellow_type = ["[#{logger_time}][#{"\e[33mmsg_type\e[0m"}] foo"]
|
|
167
|
+
red_type = ["[#{logger_time}][#{"\e[31mmsg_type\e[0m"}] foo"]
|
|
39
168
|
|
|
40
|
-
|
|
169
|
+
subject.send(:loggify, 'foo', :msg_type, :green ).should == green_type
|
|
170
|
+
subject.send(:loggify, 'foo', :msg_type, :yellow).should == yellow_type
|
|
171
|
+
subject.send(:loggify, 'foo', :msg_type, :red ).should == red_type
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'does not colorize if no color given' do
|
|
175
|
+
no_color = ["[#{logger_time}][msg_type] foo"]
|
|
176
|
+
subject.send(:loggify, 'foo', :msg_type).should == no_color
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'accepts blank lines in the message' do
|
|
180
|
+
str = "first line\n\nthird line"
|
|
181
|
+
expected = ["[#{logger_time}][msg_type] first line",
|
|
182
|
+
"[#{logger_time}][msg_type] ",
|
|
183
|
+
"[#{logger_time}][msg_type] third line"]
|
|
184
|
+
|
|
185
|
+
subject.send(:loggify, str, :msg_type).should == expected
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it 'accepts an object responding to #to_s for the message' do
|
|
189
|
+
obj = StandardError.new("first line\nsecond line")
|
|
190
|
+
expected = ["[#{logger_time}][msg_type] first line",
|
|
191
|
+
"[#{logger_time}][msg_type] second line"]
|
|
192
|
+
|
|
193
|
+
subject.send(:loggify, obj, :msg_type).should == expected
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it 'returns an unformatted lines if type is not given' do
|
|
197
|
+
str_a = 'single line'
|
|
198
|
+
str_b = "first line\n\nthird line"
|
|
199
|
+
expected_a = ['single line']
|
|
200
|
+
expected_b = ['first line', '', 'third line']
|
|
201
|
+
|
|
202
|
+
subject.send(:loggify, str_a).should == expected_a
|
|
203
|
+
subject.send(:loggify, str_b).should == expected_b
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end # describe '#loggify'
|
|
207
|
+
|
|
208
|
+
describe '#to_console' do
|
|
209
|
+
|
|
210
|
+
context 'when +stderr+ is not set (false)' do
|
|
211
|
+
it 'writes an array of strings to stdout' do
|
|
212
|
+
lines = [ 'line one', 'line two', 'line three']
|
|
213
|
+
lines.each {|line| subject.expects(:puts).with(line).in_sequence(s) }
|
|
214
|
+
subject.send(:to_console, lines)
|
|
41
215
|
end
|
|
42
216
|
end
|
|
43
217
|
|
|
44
|
-
context 'when
|
|
45
|
-
it do
|
|
46
|
-
|
|
218
|
+
context 'when +stderr+ is set (true)' do
|
|
219
|
+
it 'writes an array of strings to stdout' do
|
|
220
|
+
lines = [ 'line one', 'line two', 'line three']
|
|
221
|
+
lines.each {|line| Kernel.expects(:warn).with(line).in_sequence(s) }
|
|
222
|
+
subject.send(:to_console, lines, true)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
47
225
|
|
|
48
|
-
|
|
226
|
+
it 'returns nil if quiet? is true' do
|
|
227
|
+
subject.send(:const_set, :QUIET, true)
|
|
228
|
+
subject.expects(:puts).never
|
|
229
|
+
subject.send(:to_console, 'a string')
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
end # describe '#to_console'
|
|
233
|
+
|
|
234
|
+
describe '#to_file' do
|
|
235
|
+
|
|
236
|
+
it 'writes an array of strings to the log file' do
|
|
237
|
+
lines = ['line one', 'line two', 'line three']
|
|
238
|
+
File.stubs(:open).yields(logfile_mock)
|
|
239
|
+
lines.each {|line| logfile_mock.expects(:puts).with(line).in_sequence(s) }
|
|
240
|
+
subject.send(:to_file, lines)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it 'appends each line written to #messages' do
|
|
244
|
+
lines = ['line one', 'line two', 'line three']
|
|
245
|
+
File.stubs(:open)
|
|
246
|
+
a_mock = mock
|
|
247
|
+
subject.expects(:messages).returns(a_mock)
|
|
248
|
+
a_mock.expects(:push).with('line one', 'line two', 'line three')
|
|
249
|
+
subject.send(:to_file, lines)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'only opens the log file once to append multiple lines' do
|
|
253
|
+
lines = ['line one', 'line two', 'line three']
|
|
254
|
+
File.expects(:open).once.with(logfile_path, 'a').yields(logfile_mock)
|
|
255
|
+
logfile_mock.expects(:puts).times(3)
|
|
256
|
+
subject.send(:to_file, lines)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
end # describe '#to_file'
|
|
260
|
+
|
|
261
|
+
describe 'color methods' do
|
|
262
|
+
|
|
263
|
+
it 'color methods send strings to #colorize with color codes' do
|
|
264
|
+
colors = [ [:green, 32], [:yellow, 33], [:red, 31] ]
|
|
265
|
+
colors.each do |color, code|
|
|
266
|
+
subject.expects(:colorize).with('foo', code).in_sequence(s)
|
|
49
267
|
end
|
|
268
|
+
colors.each {|color, code| subject.send(color, 'foo') }
|
|
50
269
|
end
|
|
51
|
-
end
|
|
52
270
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
271
|
+
it '#colorize adds the code to the string' do
|
|
272
|
+
[32, 33, 31].each do |code|
|
|
273
|
+
subject.send(:colorize, 'foo', code).
|
|
274
|
+
should == "\e[#{code}mfoo\e[0m"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
56
277
|
|
|
57
|
-
|
|
58
|
-
File.expects(:open).times(4).with(File.join(Backup::LOG_PATH, 'backup.log'), 'a')
|
|
278
|
+
end # color methods
|
|
59
279
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
280
|
+
describe '#quiet?' do
|
|
281
|
+
it 'reports if the QUIET constant has been set' do
|
|
282
|
+
expect { subject.send(:const_set, :QUIET, true) }.to
|
|
283
|
+
change{ subject.send(:quiet?) }.from(false).to(true)
|
|
64
284
|
end
|
|
65
285
|
end
|
|
286
|
+
|
|
66
287
|
end
|
data/spec/model_spec.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
require File.
|
|
3
|
+
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
4
|
|
|
5
5
|
describe Backup::Model do
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ describe Backup::Model do
|
|
|
13
13
|
def initialize(&block); end
|
|
14
14
|
end
|
|
15
15
|
class Backup::Storage::TestStorage
|
|
16
|
-
def initialize(&block); end
|
|
16
|
+
def initialize(storage_id = nil, &block); end
|
|
17
17
|
end
|
|
18
18
|
class Backup::Compressor::TestGzip
|
|
19
19
|
def initialize(&block); end
|
|
@@ -121,6 +121,15 @@ describe Backup::Model do
|
|
|
121
121
|
|
|
122
122
|
model.storages.count.should == 2
|
|
123
123
|
end
|
|
124
|
+
|
|
125
|
+
it 'should accept an optional storage_id parameter' do
|
|
126
|
+
model = Backup::Model.new('mysql-s3', 'MySQL S3 Backup for MyApp') do
|
|
127
|
+
store_with('TestStorage', 'test storage_id')
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
model.storages.count.should == 1
|
|
131
|
+
end
|
|
132
|
+
|
|
124
133
|
end
|
|
125
134
|
|
|
126
135
|
describe 'archives' do
|
|
@@ -200,37 +209,133 @@ describe Backup::Model do
|
|
|
200
209
|
end
|
|
201
210
|
|
|
202
211
|
describe '#package!' do
|
|
212
|
+
let(:packager) { Backup::Packager.new(model) }
|
|
213
|
+
|
|
203
214
|
before do
|
|
204
215
|
[:utility, :run].each { |method| model.stubs(method) }
|
|
205
216
|
end
|
|
206
217
|
|
|
207
218
|
it 'should package the folder' do
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
it 'should log' do
|
|
214
|
-
Backup::Logger.expects(:message).with("Backup started packaging everything to a single archive file.")
|
|
215
|
-
model.send(:package!)
|
|
219
|
+
packager.expects(:utility).with(:tar).returns(:tar)
|
|
220
|
+
packager.expects(:run).with(%|tar -c -f '#{ File.join( Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar" ) }' -C '#{ Backup::TMP_PATH }' '#{ Backup::TRIGGER }'|)
|
|
221
|
+
Backup::Logger.expects(:message).with("Backup::Packager started packaging the backup files.")
|
|
222
|
+
packager.package!
|
|
216
223
|
end
|
|
217
224
|
end
|
|
218
225
|
|
|
219
226
|
describe '#clean!' do
|
|
227
|
+
let(:cleaner) { Backup::Cleaner.new(model) }
|
|
228
|
+
|
|
220
229
|
before do
|
|
221
230
|
[:utility, :run, :rm].each { |method| model.stubs(method) }
|
|
222
231
|
end
|
|
223
232
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
233
|
+
context 'when the backup archive is not chunked' do
|
|
234
|
+
it 'should remove the temporary files and folders that were created' do
|
|
235
|
+
cleaner.expects(:utility).with(:rm).returns(:rm)
|
|
236
|
+
Backup::Model.chunk_suffixes = []
|
|
237
|
+
cleaner.expects(:run).with "rm -rf '#{ File.join(Backup::TMP_PATH, Backup::TRIGGER) }' " +
|
|
238
|
+
"'#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }'"
|
|
239
|
+
cleaner.clean!
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
context 'when the backup archive is chunked' do
|
|
244
|
+
it 'should remove the temporary files and folders that were created' do
|
|
245
|
+
cleaner.expects(:utility).with(:rm).returns(:rm)
|
|
246
|
+
Backup::Model.chunk_suffixes = ["aa", "ab", "ac"]
|
|
247
|
+
cleaner.expects(:run).with "rm -rf '#{ File.join(Backup::TMP_PATH, Backup::TRIGGER) }' " +
|
|
248
|
+
"'#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }' " +
|
|
249
|
+
"'#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar-aa") }' " +
|
|
250
|
+
"'#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar-ab") }' " +
|
|
251
|
+
"'#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar-ac") }'"
|
|
252
|
+
cleaner.clean!
|
|
253
|
+
end
|
|
228
254
|
end
|
|
229
255
|
|
|
230
256
|
it do
|
|
231
|
-
Backup::Logger.expects(:message).with("Backup started cleaning up the temporary files.")
|
|
257
|
+
Backup::Logger.expects(:message).with("Backup::Cleaner started cleaning up the temporary files.")
|
|
232
258
|
model.send(:clean!)
|
|
233
259
|
end
|
|
234
260
|
end
|
|
235
261
|
|
|
262
|
+
describe '#split_into_chunks_of' do
|
|
263
|
+
it do
|
|
264
|
+
model.should respond_to(:split_into_chunks_of)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it do
|
|
268
|
+
model.split_into_chunks_of(500)
|
|
269
|
+
model.chunk_size.should == 500
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it do
|
|
273
|
+
model.chunk_size.should == nil
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
describe '#perform!' do
|
|
278
|
+
|
|
279
|
+
# for the purposes of testing the error handling, we're just going to
|
|
280
|
+
# stub the first thing this method calls and raise an error
|
|
281
|
+
describe 'when errors occur' do
|
|
282
|
+
let(:model) { Backup::Model.new('foo', 'foo') {} }
|
|
283
|
+
|
|
284
|
+
before do
|
|
285
|
+
# method ensures that #clean! is always run before exiting
|
|
286
|
+
model.expects(:clean!)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it 'logs, notifies and continues if a StandardError is rescued' do
|
|
290
|
+
model.stubs(:databases).raises(StandardError, 'non-fatal error')
|
|
291
|
+
|
|
292
|
+
Backup::Logger.expects(:error).twice
|
|
293
|
+
Backup::Logger.expects(:message).once
|
|
294
|
+
|
|
295
|
+
Backup::Errors::ModelError.expects(:wrap).with do |err, msg|
|
|
296
|
+
err.message.should == 'non-fatal error'
|
|
297
|
+
msg.should match(/Backup for foo \(foo\) Failed!/)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
Backup::Errors::ModelError.expects(:new).with do |msg|
|
|
301
|
+
msg.should match(/Backup will now attempt to continue/)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# notifiers called, but any Exception is ignored
|
|
305
|
+
notifier = mock
|
|
306
|
+
notifier.expects(:perform!).raises(Exception)
|
|
307
|
+
model.expects(:notifiers).returns([notifier])
|
|
308
|
+
|
|
309
|
+
# returns to allow next trigger to run
|
|
310
|
+
expect { model.perform! }.not_to raise_error
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it 'logs, notifies and exits if an Exception is rescued' do
|
|
314
|
+
model.stubs(:databases).raises(Exception, 'fatal error')
|
|
315
|
+
|
|
316
|
+
Backup::Logger.expects(:error).times(3)
|
|
317
|
+
Backup::Logger.expects(:message).never
|
|
318
|
+
|
|
319
|
+
Backup::Errors::ModelError.expects(:wrap).with do |err, msg|
|
|
320
|
+
err.message.should == 'fatal error'
|
|
321
|
+
msg.should match(/Backup for foo \(foo\) Failed!/)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
Backup::Errors::ModelError.expects(:new).with do |msg|
|
|
325
|
+
msg.should match(/Backup will now exit/)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
expect do
|
|
329
|
+
# notifiers called, but any Exception is ignored
|
|
330
|
+
notifier = mock
|
|
331
|
+
notifier.expects(:perform!).raises(Exception)
|
|
332
|
+
model.expects(:notifiers).returns([notifier])
|
|
333
|
+
end.not_to raise_error
|
|
334
|
+
|
|
335
|
+
expect { model.perform! }.to raise_error(SystemExit)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
end # context 'when errors occur'
|
|
339
|
+
|
|
340
|
+
end # describe '#perform!'
|
|
236
341
|
end
|