backup 3.0.27 → 3.1.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.
- data/LICENSE.md +1 -1
- data/README.md +139 -386
- data/bin/backup +1 -7
- data/lib/backup.rb +3 -9
- data/lib/backup/archive.rb +26 -20
- data/lib/backup/cleaner.rb +2 -2
- data/lib/backup/cli.rb +366 -0
- data/lib/backup/compressor/base.rb +2 -2
- data/lib/backup/compressor/gzip.rb +35 -1
- data/lib/backup/config.rb +1 -2
- data/lib/backup/database/base.rb +2 -2
- data/lib/backup/database/mongodb.rb +3 -3
- data/lib/backup/database/mysql.rb +3 -2
- data/lib/backup/database/postgresql.rb +3 -2
- data/lib/backup/database/riak.rb +18 -5
- data/lib/backup/dependency.rb +144 -93
- data/lib/backup/encryptor/base.rb +2 -2
- data/lib/backup/logger.rb +108 -110
- data/lib/backup/logger/console.rb +51 -0
- data/lib/backup/logger/logfile.rb +113 -0
- data/lib/backup/logger/syslog.rb +116 -0
- data/lib/backup/model.rb +67 -65
- data/lib/backup/notifier/base.rb +1 -1
- data/lib/backup/notifier/hipchat.rb +1 -1
- data/lib/backup/notifier/mail.rb +1 -1
- data/lib/backup/notifier/pushover.rb +6 -3
- data/lib/backup/packager.rb +4 -4
- data/lib/backup/pipeline.rb +17 -3
- data/lib/backup/splitter.rb +2 -2
- data/lib/backup/storage/base.rb +2 -2
- data/lib/backup/storage/cloudfiles.rb +2 -2
- data/lib/backup/storage/dropbox.rb +4 -4
- data/lib/backup/storage/ftp.rb +2 -2
- data/lib/backup/storage/local.rb +2 -2
- data/lib/backup/storage/ninefold.rb +2 -2
- data/lib/backup/storage/rsync.rb +3 -3
- data/lib/backup/storage/s3.rb +2 -2
- data/lib/backup/storage/scp.rb +2 -6
- data/lib/backup/storage/sftp.rb +2 -5
- data/lib/backup/syncer/base.rb +1 -1
- data/lib/backup/syncer/cloud/base.rb +15 -8
- data/lib/backup/syncer/rsync/local.rb +1 -1
- data/lib/backup/syncer/rsync/pull.rb +1 -1
- data/lib/backup/syncer/rsync/push.rb +1 -1
- data/lib/backup/utilities.rb +211 -0
- data/lib/backup/version.rb +1 -1
- data/templates/cli/{utility/archive → archive} +4 -8
- data/templates/cli/{utility/compressor → compressor}/bzip2 +0 -0
- data/templates/cli/{utility/compressor → compressor}/custom +0 -0
- data/templates/cli/{utility/compressor → compressor}/gzip +0 -0
- data/templates/cli/{utility/compressor → compressor}/lzma +0 -0
- data/templates/cli/{utility/compressor → compressor}/pbzip2 +0 -0
- data/templates/cli/config +68 -0
- data/templates/cli/{utility/database → database}/mongodb +1 -1
- data/templates/cli/{utility/database → database}/mysql +1 -1
- data/templates/cli/{utility/database → database}/postgresql +1 -1
- data/templates/cli/{utility/database → database}/redis +0 -0
- data/templates/cli/database/riak +20 -0
- data/templates/cli/{utility/encryptor → encryptor}/gpg +0 -0
- data/templates/cli/{utility/encryptor → encryptor}/openssl +0 -0
- data/templates/cli/{utility/model.erb → model.erb} +4 -4
- data/templates/cli/{utility/notifier → notifier}/campfire +0 -0
- data/templates/cli/{utility/notifier → notifier}/hipchat +0 -0
- data/templates/cli/{utility/notifier → notifier}/mail +0 -0
- data/templates/cli/{utility/notifier → notifier}/prowl +0 -0
- data/templates/cli/{utility/notifier → notifier}/pushover +0 -0
- data/templates/cli/{utility/notifier → notifier}/twitter +0 -0
- data/templates/cli/{utility/splitter → splitter} +0 -0
- data/templates/cli/{utility/storage → storage}/cloud_files +0 -0
- data/templates/cli/{utility/storage → storage}/dropbox +0 -0
- data/templates/cli/{utility/storage → storage}/ftp +0 -0
- data/templates/cli/{utility/storage → storage}/local +0 -0
- data/templates/cli/{utility/storage → storage}/ninefold +0 -0
- data/templates/cli/{utility/storage → storage}/rsync +0 -0
- data/templates/cli/{utility/storage → storage}/s3 +0 -0
- data/templates/cli/{utility/storage → storage}/scp +0 -0
- data/templates/cli/{utility/storage → storage}/sftp +0 -0
- data/templates/cli/{utility/syncer → syncer}/cloud_files +0 -0
- data/templates/cli/{utility/syncer → syncer}/rsync_local +0 -0
- data/templates/cli/{utility/syncer → syncer}/rsync_pull +0 -0
- data/templates/cli/{utility/syncer → syncer}/rsync_push +0 -0
- data/templates/cli/{utility/syncer → syncer}/s3 +0 -0
- metadata +55 -131
- data/.gitignore +0 -8
- data/.travis.yml +0 -10
- data/Gemfile +0 -28
- data/Guardfile +0 -23
- data/backup.gemspec +0 -32
- data/lib/backup/cli/helpers.rb +0 -93
- data/lib/backup/cli/utility.rb +0 -255
- data/spec-live/.gitignore +0 -6
- data/spec-live/README +0 -7
- data/spec-live/backups/config.rb +0 -83
- data/spec-live/backups/config.yml.template +0 -46
- data/spec-live/backups/models.rb +0 -184
- data/spec-live/compressor/custom_spec.rb +0 -30
- data/spec-live/compressor/gzip_spec.rb +0 -30
- data/spec-live/encryptor/gpg_keys.rb +0 -239
- data/spec-live/encryptor/gpg_spec.rb +0 -287
- data/spec-live/notifier/mail_spec.rb +0 -121
- data/spec-live/spec_helper.rb +0 -151
- data/spec-live/storage/dropbox_spec.rb +0 -151
- data/spec-live/storage/local_spec.rb +0 -83
- data/spec-live/storage/scp_spec.rb +0 -193
- data/spec-live/syncer/cloud/s3_spec.rb +0 -124
- data/spec/archive_spec.rb +0 -335
- data/spec/cleaner_spec.rb +0 -312
- data/spec/cli/helpers_spec.rb +0 -301
- data/spec/cli/utility_spec.rb +0 -411
- data/spec/compressor/base_spec.rb +0 -52
- data/spec/compressor/bzip2_spec.rb +0 -217
- data/spec/compressor/custom_spec.rb +0 -106
- data/spec/compressor/gzip_spec.rb +0 -217
- data/spec/compressor/lzma_spec.rb +0 -123
- data/spec/compressor/pbzip2_spec.rb +0 -165
- data/spec/config_spec.rb +0 -321
- data/spec/configuration/helpers_spec.rb +0 -247
- data/spec/configuration/store_spec.rb +0 -39
- data/spec/configuration_spec.rb +0 -62
- data/spec/database/base_spec.rb +0 -63
- data/spec/database/mongodb_spec.rb +0 -510
- data/spec/database/mysql_spec.rb +0 -411
- data/spec/database/postgresql_spec.rb +0 -353
- data/spec/database/redis_spec.rb +0 -334
- data/spec/database/riak_spec.rb +0 -176
- data/spec/dependency_spec.rb +0 -51
- data/spec/encryptor/base_spec.rb +0 -40
- data/spec/encryptor/gpg_spec.rb +0 -909
- data/spec/encryptor/open_ssl_spec.rb +0 -148
- data/spec/errors_spec.rb +0 -306
- data/spec/logger_spec.rb +0 -367
- data/spec/model_spec.rb +0 -666
- data/spec/notifier/base_spec.rb +0 -104
- data/spec/notifier/campfire_spec.rb +0 -217
- data/spec/notifier/hipchat_spec.rb +0 -211
- data/spec/notifier/mail_spec.rb +0 -316
- data/spec/notifier/prowl_spec.rb +0 -138
- data/spec/notifier/pushover_spec.rb +0 -123
- data/spec/notifier/twitter_spec.rb +0 -153
- data/spec/package_spec.rb +0 -61
- data/spec/packager_spec.rb +0 -213
- data/spec/pipeline_spec.rb +0 -259
- data/spec/spec_helper.rb +0 -60
- data/spec/splitter_spec.rb +0 -120
- data/spec/storage/base_spec.rb +0 -166
- data/spec/storage/cloudfiles_spec.rb +0 -254
- data/spec/storage/cycler_spec.rb +0 -247
- data/spec/storage/dropbox_spec.rb +0 -480
- data/spec/storage/ftp_spec.rb +0 -271
- data/spec/storage/local_spec.rb +0 -259
- data/spec/storage/ninefold_spec.rb +0 -343
- data/spec/storage/rsync_spec.rb +0 -362
- data/spec/storage/s3_spec.rb +0 -245
- data/spec/storage/scp_spec.rb +0 -233
- data/spec/storage/sftp_spec.rb +0 -244
- data/spec/syncer/base_spec.rb +0 -109
- data/spec/syncer/cloud/base_spec.rb +0 -515
- data/spec/syncer/cloud/cloud_files_spec.rb +0 -181
- data/spec/syncer/cloud/s3_spec.rb +0 -174
- data/spec/syncer/rsync/base_spec.rb +0 -98
- data/spec/syncer/rsync/local_spec.rb +0 -149
- data/spec/syncer/rsync/pull_spec.rb +0 -98
- data/spec/syncer/rsync/push_spec.rb +0 -333
- data/spec/version_spec.rb +0 -21
- data/templates/cli/utility/config +0 -32
- data/templates/cli/utility/database/riak +0 -11
data/spec/logger_spec.rb
DELETED
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
|
-
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
|
-
|
|
5
|
-
describe Backup::Logger do
|
|
6
|
-
let(:logger_time) { Time.now.strftime("%Y/%m/%d %H:%M:%S") }
|
|
7
|
-
let(:logfile_path) { File.join(Backup::Config.log_path, 'backup.log') }
|
|
8
|
-
let(:logfile_mock) { mock }
|
|
9
|
-
let(:s) { sequence '' }
|
|
10
|
-
|
|
11
|
-
before do
|
|
12
|
-
Timecop.freeze(Time.now)
|
|
13
|
-
|
|
14
|
-
# stubbed in spec_helper
|
|
15
|
-
[:message, :error, :warn, :normal, :silent].each do |message_type|
|
|
16
|
-
subject.unstub(message_type)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
subject.quiet = nil
|
|
20
|
-
subject.send(:remove_instance_variable, :@messages) rescue nil
|
|
21
|
-
subject.send(:remove_instance_variable, :@has_warnings) rescue nil
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe '#message' do
|
|
25
|
-
it 'sends a regular message to the console and log file' do
|
|
26
|
-
subject.expects(:loggify).in_sequence(s).
|
|
27
|
-
with('regular message', :message, :green).
|
|
28
|
-
returns(:green_regular_message)
|
|
29
|
-
subject.expects(:to_console).in_sequence(s).
|
|
30
|
-
with(:green_regular_message)
|
|
31
|
-
subject.expects(:loggify).in_sequence(s).
|
|
32
|
-
with('regular message', :message).
|
|
33
|
-
returns(:uncolored_regular_message)
|
|
34
|
-
subject.expects(:to_file).in_sequence(s).
|
|
35
|
-
with(:uncolored_regular_message)
|
|
36
|
-
|
|
37
|
-
subject.message('regular message')
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
describe '#error' do
|
|
42
|
-
it 'sends an error message to the console (stderr) and log file' do
|
|
43
|
-
subject.expects(:loggify).in_sequence(s).
|
|
44
|
-
with('error message', :error, :red).
|
|
45
|
-
returns(:red_error_message)
|
|
46
|
-
subject.expects(:to_console).in_sequence(s).
|
|
47
|
-
with(:red_error_message, true)
|
|
48
|
-
subject.expects(:loggify).in_sequence(s).
|
|
49
|
-
with('error message', :error).
|
|
50
|
-
returns(:uncolored_error_message)
|
|
51
|
-
subject.expects(:to_file).in_sequence(s).
|
|
52
|
-
with(:uncolored_error_message)
|
|
53
|
-
|
|
54
|
-
subject.error('error message')
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
describe '#warn' do
|
|
59
|
-
it 'sends a warning message to the console (stderr) and log file' do
|
|
60
|
-
subject.expects(:loggify).in_sequence(s).
|
|
61
|
-
with('warning message', :warning, :yellow).
|
|
62
|
-
returns(:yellow_warning_message)
|
|
63
|
-
subject.expects(:to_console).in_sequence(s).
|
|
64
|
-
with(:yellow_warning_message, true)
|
|
65
|
-
subject.expects(:loggify).in_sequence(s).
|
|
66
|
-
with('warning message', :warning).
|
|
67
|
-
returns(:uncolored_warning_message)
|
|
68
|
-
subject.expects(:to_file).in_sequence(s).
|
|
69
|
-
with(:uncolored_warning_message)
|
|
70
|
-
|
|
71
|
-
subject.warn('warning message')
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
it 'sets has_warnings? to true' do
|
|
75
|
-
subject.stubs(:to_console)
|
|
76
|
-
subject.stubs(:to_file)
|
|
77
|
-
expect { subject.warn('warning') }.
|
|
78
|
-
to change{ subject.has_warnings? }.from(false).to(true)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
describe '#normal' do
|
|
83
|
-
it 'sends a normal, unformatted message to the console and log file' do
|
|
84
|
-
subject.expects(:loggify).in_sequence(s).
|
|
85
|
-
with('normal message').
|
|
86
|
-
returns(:unformatted_message)
|
|
87
|
-
subject.expects(:to_console).in_sequence(s).
|
|
88
|
-
with(:unformatted_message)
|
|
89
|
-
subject.expects(:loggify).in_sequence(s).
|
|
90
|
-
with('normal message').
|
|
91
|
-
returns(:unformatted_message)
|
|
92
|
-
subject.expects(:to_file).in_sequence(s).
|
|
93
|
-
with(:unformatted_message)
|
|
94
|
-
|
|
95
|
-
subject.normal('normal message')
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
describe '#silent' do
|
|
100
|
-
it 'sends a silent message to the log file' do
|
|
101
|
-
subject.expects(:to_console).never
|
|
102
|
-
subject.expects(:loggify).in_sequence(s).
|
|
103
|
-
with('silent message', :silent).
|
|
104
|
-
returns(:silent_message)
|
|
105
|
-
subject.expects(:to_file).in_sequence(s).
|
|
106
|
-
with(:silent_message)
|
|
107
|
-
|
|
108
|
-
subject.silent('silent message')
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
describe '#messages' do
|
|
113
|
-
|
|
114
|
-
it 'returns an empty array if no messages have been sent' do
|
|
115
|
-
subject.messages.should == []
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it 'returns an array of all lines sent to the log file' do
|
|
119
|
-
File.stubs(:open).yields(stub(:puts))
|
|
120
|
-
strings = ['an array', 'of message', 'strings']
|
|
121
|
-
subject.send(:to_file, strings)
|
|
122
|
-
subject.messages.should == strings
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it 'does not track lines sent to the console' do
|
|
126
|
-
subject.stubs(:puts)
|
|
127
|
-
strings = ['an array', 'of message', 'strings']
|
|
128
|
-
subject.send(:to_console, strings)
|
|
129
|
-
subject.messages.should == []
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
end # describe '#messages'
|
|
133
|
-
|
|
134
|
-
describe '#clear!' do
|
|
135
|
-
it 'should clear the log and reset has_warnings?' do
|
|
136
|
-
subject.messages << 'foo'
|
|
137
|
-
subject.instance_variable_set(:@has_warnings, true)
|
|
138
|
-
subject.messages.count.should == 1
|
|
139
|
-
subject.has_warnings?.should be_true
|
|
140
|
-
|
|
141
|
-
subject.clear!
|
|
142
|
-
subject.messages.should be_empty
|
|
143
|
-
subject.has_warnings?.should be_false
|
|
144
|
-
end
|
|
145
|
-
end # describe '#clear!'
|
|
146
|
-
|
|
147
|
-
describe '#truncate!' do
|
|
148
|
-
context 'when log file does not exist' do
|
|
149
|
-
before { File.stubs(:exist?).returns(false) }
|
|
150
|
-
it 'should do nothing' do
|
|
151
|
-
File.expects(:stat).never
|
|
152
|
-
subject.truncate!
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
context 'when log file is <= max_bytes' do
|
|
157
|
-
before { File.stubs(:exist?).returns(true) }
|
|
158
|
-
it 'should do nothing' do
|
|
159
|
-
stat = mock
|
|
160
|
-
File.expects(:stat).twice.with(
|
|
161
|
-
File.join(Backup::Config.log_path, 'backup.log')
|
|
162
|
-
).returns(stat)
|
|
163
|
-
|
|
164
|
-
[1, 2].each do |size|
|
|
165
|
-
stat.expects(:size).returns(size)
|
|
166
|
-
|
|
167
|
-
FileUtils.expects(:mv).never
|
|
168
|
-
File.expects(:open).never
|
|
169
|
-
FileUtils.expects(:rm_f).never
|
|
170
|
-
|
|
171
|
-
subject.truncate!(2)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
context 'when log file is > max_bytes' do
|
|
177
|
-
before do
|
|
178
|
-
FileUtils.unstub(:mkdir_p)
|
|
179
|
-
FileUtils.unstub(:mv)
|
|
180
|
-
FileUtils.unstub(:rm)
|
|
181
|
-
FileUtils.unstub(:rm_f)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
after do
|
|
185
|
-
Backup::Config.send(:reset!)
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
it 'should truncate the file, removing older lines' do
|
|
189
|
-
max_bytes = 5_000
|
|
190
|
-
line_len = 120
|
|
191
|
-
Dir.mktmpdir do |dir|
|
|
192
|
-
Backup::Config.update(:root_path => dir)
|
|
193
|
-
FileUtils.mkdir_p(Backup::Config.log_path)
|
|
194
|
-
log_file = File.join(Backup::Config.log_path, 'backup.log')
|
|
195
|
-
|
|
196
|
-
lineno = 0
|
|
197
|
-
over_max = (max_bytes * 1.25).to_i
|
|
198
|
-
File.open(log_file, 'w') do |f|
|
|
199
|
-
until f.pos > over_max
|
|
200
|
-
f.puts "#{ lineno += 1 }: ".ljust(line_len, 'x')
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
File.stat(log_file).size.
|
|
204
|
-
should be_within(line_len + 2).of(over_max)
|
|
205
|
-
|
|
206
|
-
subject.truncate!(max_bytes)
|
|
207
|
-
|
|
208
|
-
File.stat(log_file).size.
|
|
209
|
-
should be_within(line_len + 2).of(max_bytes)
|
|
210
|
-
|
|
211
|
-
File.readlines(log_file).last.chomp.
|
|
212
|
-
should == "#{ lineno }: ".ljust(line_len, 'x')
|
|
213
|
-
|
|
214
|
-
File.exist?(log_file + '~').should be_false
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
end # describe '#truncate!'
|
|
220
|
-
|
|
221
|
-
describe '#loggify' do
|
|
222
|
-
|
|
223
|
-
it 'returns an array of strings split on newline separators' do
|
|
224
|
-
str_aa = "first line\nsecond line"
|
|
225
|
-
str_ab = "first line\nsecond line\n"
|
|
226
|
-
expected_a = ["[#{logger_time}][msg_type] first line",
|
|
227
|
-
"[#{logger_time}][msg_type] second line"]
|
|
228
|
-
|
|
229
|
-
str_b = 'string with no newline'
|
|
230
|
-
expected_b = ["[#{logger_time}][msg_type] string with no newline"]
|
|
231
|
-
|
|
232
|
-
subject.send(:loggify, str_aa, :msg_type).should == expected_a
|
|
233
|
-
subject.send(:loggify, str_ab, :msg_type).should == expected_a
|
|
234
|
-
subject.send(:loggify, str_b, :msg_type).should == expected_b
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it 'formats a string with color if color is given' do
|
|
238
|
-
green_type = ["[#{logger_time}][#{"\e[32mmsg_type\e[0m"}] foo"]
|
|
239
|
-
yellow_type = ["[#{logger_time}][#{"\e[33mmsg_type\e[0m"}] foo"]
|
|
240
|
-
red_type = ["[#{logger_time}][#{"\e[31mmsg_type\e[0m"}] foo"]
|
|
241
|
-
|
|
242
|
-
subject.send(:loggify, 'foo', :msg_type, :green ).should == green_type
|
|
243
|
-
subject.send(:loggify, 'foo', :msg_type, :yellow).should == yellow_type
|
|
244
|
-
subject.send(:loggify, 'foo', :msg_type, :red ).should == red_type
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
it 'does not colorize if no color given' do
|
|
248
|
-
no_color = ["[#{logger_time}][msg_type] foo"]
|
|
249
|
-
subject.send(:loggify, 'foo', :msg_type).should == no_color
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
it 'accepts blank lines in the message' do
|
|
253
|
-
str = "first line\n\nthird line"
|
|
254
|
-
expected = ["[#{logger_time}][msg_type] first line",
|
|
255
|
-
"[#{logger_time}][msg_type] ",
|
|
256
|
-
"[#{logger_time}][msg_type] third line"]
|
|
257
|
-
|
|
258
|
-
subject.send(:loggify, str, :msg_type).should == expected
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
it 'accepts an object responding to #to_s for the message' do
|
|
262
|
-
obj = StandardError.new("first line\nsecond line")
|
|
263
|
-
expected = ["[#{logger_time}][msg_type] first line",
|
|
264
|
-
"[#{logger_time}][msg_type] second line"]
|
|
265
|
-
|
|
266
|
-
subject.send(:loggify, obj, :msg_type).should == expected
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
it 'returns an unformatted lines if type is not given' do
|
|
270
|
-
str_a = 'single line'
|
|
271
|
-
str_b = "first line\n\nthird line"
|
|
272
|
-
expected_a = ['single line']
|
|
273
|
-
expected_b = ['first line', '', 'third line']
|
|
274
|
-
|
|
275
|
-
subject.send(:loggify, str_a).should == expected_a
|
|
276
|
-
subject.send(:loggify, str_b).should == expected_b
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
end # describe '#loggify'
|
|
280
|
-
|
|
281
|
-
describe '#to_console' do
|
|
282
|
-
|
|
283
|
-
context 'when +stderr+ is not set (false)' do
|
|
284
|
-
it 'writes an array of strings to stdout' do
|
|
285
|
-
lines = [ 'line one', 'line two', 'line three']
|
|
286
|
-
lines.each {|line| subject.expects(:puts).with(line).in_sequence(s) }
|
|
287
|
-
subject.send(:to_console, lines)
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
context 'when +stderr+ is set (true)' do
|
|
292
|
-
it 'writes an array of strings to stdout' do
|
|
293
|
-
lines = [ 'line one', 'line two', 'line three']
|
|
294
|
-
lines.each {|line| Kernel.expects(:warn).with(line).in_sequence(s) }
|
|
295
|
-
subject.send(:to_console, lines, true)
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
it 'returns nil if quiet? is true' do
|
|
300
|
-
subject.quiet = true
|
|
301
|
-
subject.expects(:puts).never
|
|
302
|
-
subject.send(:to_console, 'a string')
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
end # describe '#to_console'
|
|
306
|
-
|
|
307
|
-
describe '#to_file' do
|
|
308
|
-
|
|
309
|
-
it 'writes an array of strings to the log file' do
|
|
310
|
-
lines = ['line one', 'line two', 'line three']
|
|
311
|
-
File.stubs(:open).yields(logfile_mock)
|
|
312
|
-
lines.each {|line| logfile_mock.expects(:puts).with(line).in_sequence(s) }
|
|
313
|
-
subject.send(:to_file, lines)
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
it 'appends each line written to #messages' do
|
|
317
|
-
lines = ['line one', 'line two', 'line three']
|
|
318
|
-
File.stubs(:open)
|
|
319
|
-
a_mock = mock
|
|
320
|
-
subject.expects(:messages).returns(a_mock)
|
|
321
|
-
a_mock.expects(:push).with('line one', 'line two', 'line three')
|
|
322
|
-
subject.send(:to_file, lines)
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
it 'only opens the log file once to append multiple lines' do
|
|
326
|
-
lines = ['line one', 'line two', 'line three']
|
|
327
|
-
File.expects(:open).once.with(logfile_path, 'a').yields(logfile_mock)
|
|
328
|
-
logfile_mock.expects(:puts).times(3)
|
|
329
|
-
subject.send(:to_file, lines)
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
end # describe '#to_file'
|
|
333
|
-
|
|
334
|
-
describe 'color methods' do
|
|
335
|
-
|
|
336
|
-
it 'color methods send strings to #colorize with color codes' do
|
|
337
|
-
colors = [ [:green, 32], [:yellow, 33], [:red, 31] ]
|
|
338
|
-
colors.each do |color, code|
|
|
339
|
-
subject.expects(:colorize).with('foo', code).in_sequence(s)
|
|
340
|
-
end
|
|
341
|
-
colors.each {|color, code| subject.send(color, 'foo') }
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
it '#colorize adds the code to the string' do
|
|
345
|
-
[32, 33, 31].each do |code|
|
|
346
|
-
subject.send(:colorize, 'foo', code).
|
|
347
|
-
should == "\e[#{code}mfoo\e[0m"
|
|
348
|
-
end
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
end # color methods
|
|
352
|
-
|
|
353
|
-
describe '#quiet' do
|
|
354
|
-
it 'should be nil by default' do
|
|
355
|
-
# of course, 'before' is setting it to nil ;)
|
|
356
|
-
subject.quiet.should be_nil
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
it 'can be set true/false' do
|
|
360
|
-
subject.quiet = true
|
|
361
|
-
subject.quiet.should be_true
|
|
362
|
-
subject.quiet = false
|
|
363
|
-
subject.quiet.should be_false
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
end
|
data/spec/model_spec.rb
DELETED
|
@@ -1,666 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
|
-
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
|
-
|
|
5
|
-
describe 'Backup::Model' do
|
|
6
|
-
let(:model) { Backup::Model.new(:test_trigger, 'test label') }
|
|
7
|
-
let(:s) { sequence '' }
|
|
8
|
-
|
|
9
|
-
before do
|
|
10
|
-
Backup::Model.all.clear
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
describe '.all' do
|
|
14
|
-
it 'should be an empty array by default' do
|
|
15
|
-
Backup::Model.all.should == []
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
describe 'finder methods' do
|
|
20
|
-
before do
|
|
21
|
-
[:a, :b, :c, :b, :d].each_with_index do |sym, i|
|
|
22
|
-
Backup::Model.new("trigger_#{sym}", "label#{i}")
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
describe '.find' do
|
|
27
|
-
it 'should return the first matching model' do
|
|
28
|
-
Backup::Model.find('trigger_b').label.should == 'label1'
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it 'should accept symbols' do
|
|
32
|
-
Backup::Model.find(:trigger_b).label.should == 'label1'
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it 'should raise an error if trigger is not found' do
|
|
36
|
-
expect do
|
|
37
|
-
Backup::Model.find(:f)
|
|
38
|
-
end.to raise_error(
|
|
39
|
-
Backup::Errors::Model::MissingTriggerError,
|
|
40
|
-
"Model::MissingTriggerError: Could not find trigger 'f'."
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
describe '.find_matching' do
|
|
46
|
-
it 'should find all triggers matching a wildcard' do
|
|
47
|
-
Backup::Model.find_matching('tri*_b').count.should be(2)
|
|
48
|
-
Backup::Model.find_matching('trigg*').count.should be(5)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it 'should return an empty array if no matches are found' do
|
|
52
|
-
Backup::Model.find_matching('foo*').should == []
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
end # describe 'finder methods'
|
|
57
|
-
|
|
58
|
-
describe '#initialize' do
|
|
59
|
-
|
|
60
|
-
it 'should convert trigger to a string' do
|
|
61
|
-
Backup::Model.new(:foo, :bar).trigger.should == 'foo'
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'should convert label to a string' do
|
|
65
|
-
Backup::Model.new(:foo, :bar).label.should == 'bar'
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'should set all procedure variables to an empty array' do
|
|
69
|
-
model.send(:procedure_instance_variables).each do |var|
|
|
70
|
-
model.instance_variable_get(var).should == []
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
it 'should accept and instance_eval a block' do
|
|
75
|
-
block = lambda {|model| throw(:instance, model) }
|
|
76
|
-
caught = catch(:instance) do
|
|
77
|
-
Backup::Model.new('gotcha', '', &block)
|
|
78
|
-
end
|
|
79
|
-
caught.trigger.should == 'gotcha'
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it 'should add itself to Model.all' do
|
|
83
|
-
Backup::Model.all.should == [model]
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
end # describe '#initialize'
|
|
87
|
-
|
|
88
|
-
describe 'DSL Methods' do
|
|
89
|
-
|
|
90
|
-
module Fake
|
|
91
|
-
module NoArg
|
|
92
|
-
class Base
|
|
93
|
-
attr_accessor :block_arg
|
|
94
|
-
def initialize(&block)
|
|
95
|
-
instance_eval(&block) if block_given?
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
module OneArg
|
|
100
|
-
class Base
|
|
101
|
-
attr_accessor :arg1, :block_arg
|
|
102
|
-
def initialize(arg1, &block)
|
|
103
|
-
@arg1 = arg1
|
|
104
|
-
instance_eval(&block) if block_given?
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
module TwoArgs
|
|
109
|
-
class Base
|
|
110
|
-
attr_accessor :arg1, :arg2, :block_arg
|
|
111
|
-
def initialize(arg1, arg2, &block)
|
|
112
|
-
@arg1 = arg1
|
|
113
|
-
@arg2 = arg2
|
|
114
|
-
instance_eval(&block) if block_given?
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Set +const+ to +replacement+ for the calling block
|
|
121
|
-
def using_fake(const, replacement)
|
|
122
|
-
orig = Backup.const_get(const)
|
|
123
|
-
Backup.send(:remove_const, const)
|
|
124
|
-
Backup.const_set(const, replacement)
|
|
125
|
-
yield
|
|
126
|
-
Backup.send(:remove_const, const)
|
|
127
|
-
Backup.const_set(const, orig)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
describe '#archive' do
|
|
131
|
-
it 'should add archives' do
|
|
132
|
-
using_fake('Archive', Fake::TwoArgs::Base) do
|
|
133
|
-
model.archive('foo') {|a| a.block_arg = :foo }
|
|
134
|
-
model.archive('bar') {|a| a.block_arg = :bar }
|
|
135
|
-
model.archives.count.should == 2
|
|
136
|
-
a1, a2 = model.archives
|
|
137
|
-
a1.arg1.should be(model)
|
|
138
|
-
a1.arg2.should == 'foo'
|
|
139
|
-
a1.block_arg.should == :foo
|
|
140
|
-
a2.arg1.should be(model)
|
|
141
|
-
a2.arg2.should == 'bar'
|
|
142
|
-
a2.block_arg.should == :bar
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
describe '#database' do
|
|
148
|
-
it 'should add databases' do
|
|
149
|
-
using_fake('Database', Fake::OneArg) do
|
|
150
|
-
model.database('Base') {|a| a.block_arg = :foo }
|
|
151
|
-
model.database('Base') {|a| a.block_arg = :bar }
|
|
152
|
-
model.databases.count.should be(2)
|
|
153
|
-
d1, d2 = model.databases
|
|
154
|
-
d1.arg1.should be(model)
|
|
155
|
-
d1.block_arg.should == :foo
|
|
156
|
-
d2.arg1.should be(model)
|
|
157
|
-
d2.block_arg.should == :bar
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
it 'should accept a nested class name' do
|
|
162
|
-
using_fake('Database', Fake) do
|
|
163
|
-
model.database('OneArg::Base')
|
|
164
|
-
model.databases.first.should be_an_instance_of Fake::OneArg::Base
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
describe '#store_with' do
|
|
170
|
-
it 'should add storages' do
|
|
171
|
-
using_fake('Storage', Fake::TwoArgs) do
|
|
172
|
-
model.store_with('Base', 'foo') {|a| a.block_arg = :foo }
|
|
173
|
-
model.store_with('Base', 'bar') {|a| a.block_arg = :bar }
|
|
174
|
-
model.storages.count.should be(2)
|
|
175
|
-
s1, s2 = model.storages
|
|
176
|
-
s1.arg1.should be(model)
|
|
177
|
-
s1.arg2.should == 'foo'
|
|
178
|
-
s1.block_arg.should == :foo
|
|
179
|
-
s2.arg1.should be(model)
|
|
180
|
-
s2.arg2.should == 'bar'
|
|
181
|
-
s2.block_arg.should == :bar
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
it 'should accept a nested class name' do
|
|
186
|
-
using_fake('Storage', Fake) do
|
|
187
|
-
model.store_with('TwoArgs::Base')
|
|
188
|
-
model.storages.first.should be_an_instance_of Fake::TwoArgs::Base
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
describe '#sync_with' do
|
|
194
|
-
it 'should add syncers' do
|
|
195
|
-
using_fake('Syncer', Fake::NoArg) do
|
|
196
|
-
model.sync_with('Base') {|a| a.block_arg = :foo }
|
|
197
|
-
model.sync_with('Base') {|a| a.block_arg = :bar }
|
|
198
|
-
model.syncers.count.should be(2)
|
|
199
|
-
s1, s2 = model.syncers
|
|
200
|
-
s1.block_arg.should == :foo
|
|
201
|
-
s2.block_arg.should == :bar
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
it 'should accept a nested class name' do
|
|
206
|
-
using_fake('Syncer', Fake) do
|
|
207
|
-
model.sync_with('NoArg::Base')
|
|
208
|
-
model.syncers.first.should be_an_instance_of Fake::NoArg::Base
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
it 'should warn user of change from RSync to RSync::Push' do
|
|
213
|
-
Backup::Logger.expects(:warn)
|
|
214
|
-
model.sync_with('Backup::Config::RSync')
|
|
215
|
-
model.syncers.first.should
|
|
216
|
-
be_an_instance_of Backup::Syncer::RSync::Push
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
it 'should warn user of change from S3 to Cloud::S3' do
|
|
220
|
-
Backup::Logger.expects(:warn)
|
|
221
|
-
model.sync_with('Backup::Config::S3')
|
|
222
|
-
model.syncers.first.should
|
|
223
|
-
be_an_instance_of Backup::Syncer::Cloud::S3
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
it 'should warn user of change from CloudFiles to Cloud::CloudFiles' do
|
|
227
|
-
Backup::Logger.expects(:warn)
|
|
228
|
-
model.sync_with('Backup::Config::CloudFiles')
|
|
229
|
-
model.syncers.first.should
|
|
230
|
-
be_an_instance_of Backup::Syncer::Cloud::CloudFiles
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
describe '#notify_by' do
|
|
235
|
-
it 'should add notifiers' do
|
|
236
|
-
using_fake('Notifier', Fake::OneArg) do
|
|
237
|
-
model.notify_by('Base') {|a| a.block_arg = :foo }
|
|
238
|
-
model.notify_by('Base') {|a| a.block_arg = :bar }
|
|
239
|
-
model.notifiers.count.should be(2)
|
|
240
|
-
n1, n2 = model.notifiers
|
|
241
|
-
n1.arg1.should be(model)
|
|
242
|
-
n1.block_arg.should == :foo
|
|
243
|
-
n2.arg1.should be(model)
|
|
244
|
-
n2.block_arg.should == :bar
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
it 'should accept a nested class name' do
|
|
249
|
-
using_fake('Notifier', Fake) do
|
|
250
|
-
model.notify_by('OneArg::Base')
|
|
251
|
-
model.notifiers.first.should be_an_instance_of Fake::OneArg::Base
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
describe '#encrypt_with' do
|
|
257
|
-
it 'should add an encryptor' do
|
|
258
|
-
using_fake('Encryptor', Fake::NoArg) do
|
|
259
|
-
model.encrypt_with('Base') {|a| a.block_arg = :foo }
|
|
260
|
-
model.encryptor.should be_an_instance_of Fake::NoArg::Base
|
|
261
|
-
model.encryptor.block_arg.should == :foo
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
it 'should accept a nested class name' do
|
|
266
|
-
using_fake('Encryptor', Fake) do
|
|
267
|
-
model.encrypt_with('NoArg::Base')
|
|
268
|
-
model.encryptor.should be_an_instance_of Fake::NoArg::Base
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
describe '#compress_with' do
|
|
274
|
-
it 'should add a compressor' do
|
|
275
|
-
using_fake('Compressor', Fake::NoArg) do
|
|
276
|
-
model.compress_with('Base') {|a| a.block_arg = :foo }
|
|
277
|
-
model.compressor.should be_an_instance_of Fake::NoArg::Base
|
|
278
|
-
model.compressor.block_arg.should == :foo
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
it 'should accept a nested class name' do
|
|
283
|
-
using_fake('Compressor', Fake) do
|
|
284
|
-
model.compress_with('NoArg::Base')
|
|
285
|
-
model.compressor.should be_an_instance_of Fake::NoArg::Base
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
describe '#split_into_chunks_of' do
|
|
291
|
-
it 'should add a splitter' do
|
|
292
|
-
using_fake('Splitter', Fake::TwoArgs::Base) do
|
|
293
|
-
model.split_into_chunks_of(123)
|
|
294
|
-
model.splitter.should be_an_instance_of Fake::TwoArgs::Base
|
|
295
|
-
model.splitter.arg1.should be(model)
|
|
296
|
-
model.splitter.arg2.should == 123
|
|
297
|
-
end
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
it 'should raise an error if chunk_size is not an Integer' do
|
|
301
|
-
expect do
|
|
302
|
-
model.split_into_chunks_of('345')
|
|
303
|
-
end.to raise_error {|err|
|
|
304
|
-
err.should be_an_instance_of Backup::Errors::Model::ConfigurationError
|
|
305
|
-
err.message.should match(/must be an Integer/)
|
|
306
|
-
}
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
end # describe 'DSL Methods'
|
|
311
|
-
|
|
312
|
-
describe '#prepare!' do
|
|
313
|
-
it 'should prepare for the backup' do
|
|
314
|
-
FileUtils.expects(:mkdir_p).with(
|
|
315
|
-
File.join(Backup::Config.data_path, 'test_trigger')
|
|
316
|
-
)
|
|
317
|
-
Backup::Cleaner.expects(:prepare).with(model)
|
|
318
|
-
|
|
319
|
-
model.prepare!
|
|
320
|
-
end
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
describe '#perform!' do
|
|
324
|
-
let(:procedure_a) { lambda {} }
|
|
325
|
-
let(:procedure_b) { mock }
|
|
326
|
-
let(:procedure_c) { mock }
|
|
327
|
-
let(:procedure_d) { lambda {} }
|
|
328
|
-
let(:procedure_e) { lambda {} }
|
|
329
|
-
let(:procedure_f) { mock }
|
|
330
|
-
let(:procedures) do
|
|
331
|
-
[ procedure_a, [procedure_b, procedure_c],
|
|
332
|
-
procedure_d, procedure_e, [procedure_f] ]
|
|
333
|
-
end
|
|
334
|
-
let(:syncer_a) { mock }
|
|
335
|
-
let(:syncer_b) { mock }
|
|
336
|
-
let(:syncers) { [syncer_a, syncer_b] }
|
|
337
|
-
let(:notifier_a) { mock }
|
|
338
|
-
let(:notifier_b) { mock }
|
|
339
|
-
let(:notifiers) { [notifier_a, notifier_b] }
|
|
340
|
-
|
|
341
|
-
it 'should set the @time and @started_at variables' do
|
|
342
|
-
Timecop.freeze(Time.now)
|
|
343
|
-
started_at = Time.now
|
|
344
|
-
time = started_at.strftime("%Y.%m.%d.%H.%M.%S")
|
|
345
|
-
model.expects(:log!).with(:started)
|
|
346
|
-
model.expects(:log!).with(:finished)
|
|
347
|
-
|
|
348
|
-
model.perform!
|
|
349
|
-
model.time.should == time
|
|
350
|
-
model.instance_variable_get(:@started_at).should == started_at
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
context 'when no errors occur' do
|
|
354
|
-
before do
|
|
355
|
-
model.expects(:procedures).returns(procedures)
|
|
356
|
-
model.expects(:syncers).returns(syncers)
|
|
357
|
-
model.expects(:notifiers).returns(notifiers)
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
context 'when databases are configured' do
|
|
361
|
-
before do
|
|
362
|
-
model.instance_variable_set(:@databases, [true])
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
it 'should perform all procedures' do
|
|
366
|
-
model.expects(:log!).in_sequence(s).with(:started)
|
|
367
|
-
|
|
368
|
-
procedure_a.expects(:call).in_sequence(s)
|
|
369
|
-
procedure_b.expects(:perform!).in_sequence(s)
|
|
370
|
-
procedure_c.expects(:perform!).in_sequence(s)
|
|
371
|
-
procedure_d.expects(:call).in_sequence(s)
|
|
372
|
-
procedure_e.expects(:call).in_sequence(s)
|
|
373
|
-
procedure_f.expects(:perform!).in_sequence(s)
|
|
374
|
-
|
|
375
|
-
syncer_a.expects(:perform!).in_sequence(s)
|
|
376
|
-
syncer_b.expects(:perform!).in_sequence(s)
|
|
377
|
-
|
|
378
|
-
notifier_a.expects(:perform!).in_sequence(s)
|
|
379
|
-
notifier_b.expects(:perform!).in_sequence(s)
|
|
380
|
-
|
|
381
|
-
model.expects(:log!).in_sequence(s).with(:finished)
|
|
382
|
-
|
|
383
|
-
model.perform!
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
context 'when archives are configured' do
|
|
388
|
-
before do
|
|
389
|
-
model.instance_variable_set(:@archives, [true])
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
it 'should perform all procedures' do
|
|
393
|
-
model.expects(:log!).in_sequence(s).with(:started)
|
|
394
|
-
|
|
395
|
-
procedure_a.expects(:call).in_sequence(s)
|
|
396
|
-
procedure_b.expects(:perform!).in_sequence(s)
|
|
397
|
-
procedure_c.expects(:perform!).in_sequence(s)
|
|
398
|
-
procedure_d.expects(:call).in_sequence(s)
|
|
399
|
-
procedure_e.expects(:call).in_sequence(s)
|
|
400
|
-
procedure_f.expects(:perform!).in_sequence(s)
|
|
401
|
-
|
|
402
|
-
syncer_a.expects(:perform!).in_sequence(s)
|
|
403
|
-
syncer_b.expects(:perform!).in_sequence(s)
|
|
404
|
-
|
|
405
|
-
notifier_a.expects(:perform!).in_sequence(s)
|
|
406
|
-
notifier_b.expects(:perform!).in_sequence(s)
|
|
407
|
-
|
|
408
|
-
model.expects(:log!).in_sequence(s).with(:finished)
|
|
409
|
-
|
|
410
|
-
model.perform!
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
end # context 'when no errors occur'
|
|
415
|
-
|
|
416
|
-
# for the purposes of testing the error handling, we're just going to
|
|
417
|
-
# stub the first thing this method calls and raise an error
|
|
418
|
-
context 'when errors occur' do
|
|
419
|
-
let(:error_a) { mock }
|
|
420
|
-
let(:error_b) { mock }
|
|
421
|
-
let(:notifier) { mock }
|
|
422
|
-
|
|
423
|
-
before do
|
|
424
|
-
error_a.stubs(:backtrace).returns(['many', 'backtrace', 'lines'])
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
it 'logs, notifies and continues if a StandardError is rescued' do
|
|
428
|
-
Time.stubs(:now).raises(StandardError, 'non-fatal error')
|
|
429
|
-
|
|
430
|
-
Backup::Errors::ModelError.expects(:wrap).in_sequence(s).with do |err, msg|
|
|
431
|
-
err.message.should == 'non-fatal error'
|
|
432
|
-
msg.should match(/Backup for test label \(test_trigger\) Failed!/)
|
|
433
|
-
end.returns(error_a)
|
|
434
|
-
Backup::Logger.expects(:error).in_sequence(s).with(error_a)
|
|
435
|
-
Backup::Logger.expects(:error).in_sequence(s).with(
|
|
436
|
-
"\nBacktrace:\n\s\smany\n\s\sbacktrace\n\s\slines\n\n"
|
|
437
|
-
)
|
|
438
|
-
|
|
439
|
-
Backup::Cleaner.expects(:warnings).in_sequence(s).with(model)
|
|
440
|
-
|
|
441
|
-
Backup::Errors::ModelError.expects(:new).in_sequence(s).with do |msg|
|
|
442
|
-
msg.should match(/Backup will now attempt to continue/)
|
|
443
|
-
end.returns(error_b)
|
|
444
|
-
Backup::Logger.expects(:message).in_sequence(s).with(error_b)
|
|
445
|
-
|
|
446
|
-
# notifiers called, but any Exception is ignored
|
|
447
|
-
notifier.expects(:perform!).with(true).raises(Exception)
|
|
448
|
-
model.expects(:notifiers).returns([notifier])
|
|
449
|
-
|
|
450
|
-
# returns to allow next trigger to run
|
|
451
|
-
expect { model.perform! }.not_to raise_error
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
it 'logs, notifies and exits if an Exception is rescued' do
|
|
455
|
-
Time.stubs(:now).raises(Exception, 'fatal error')
|
|
456
|
-
|
|
457
|
-
Backup::Errors::ModelError.expects(:wrap).in_sequence(s).with do |err, msg|
|
|
458
|
-
err.message.should == 'fatal error'
|
|
459
|
-
msg.should match(/Backup for test label \(test_trigger\) Failed!/)
|
|
460
|
-
end.returns(error_a)
|
|
461
|
-
Backup::Logger.expects(:error).in_sequence(s).with(error_a)
|
|
462
|
-
Backup::Logger.expects(:error).in_sequence(s).with(
|
|
463
|
-
"\nBacktrace:\n\s\smany\n\s\sbacktrace\n\s\slines\n\n"
|
|
464
|
-
)
|
|
465
|
-
|
|
466
|
-
Backup::Cleaner.expects(:warnings).in_sequence(s).with(model)
|
|
467
|
-
|
|
468
|
-
Backup::Errors::ModelError.expects(:new).in_sequence(s).with do |msg|
|
|
469
|
-
msg.should match(/Backup will now exit/)
|
|
470
|
-
end.returns(error_b)
|
|
471
|
-
Backup::Logger.expects(:error).in_sequence(s).with(error_b)
|
|
472
|
-
|
|
473
|
-
expect do
|
|
474
|
-
# notifiers called, but any Exception is ignored
|
|
475
|
-
notifier = mock
|
|
476
|
-
notifier.expects(:perform!).with(true).raises(Exception)
|
|
477
|
-
model.expects(:notifiers).returns([notifier])
|
|
478
|
-
end.not_to raise_error
|
|
479
|
-
|
|
480
|
-
expect do
|
|
481
|
-
model.perform!
|
|
482
|
-
end.to raise_error(SystemExit) {|exit| exit.status.should be(1) }
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
end # context 'when errors occur'
|
|
486
|
-
|
|
487
|
-
end # describe '#perform!'
|
|
488
|
-
|
|
489
|
-
describe '#package!' do
|
|
490
|
-
it 'should package the backup' do
|
|
491
|
-
Backup::Packager.expects(:package!).in_sequence(s).with(model)
|
|
492
|
-
Backup::Cleaner.expects(:remove_packaging).in_sequence(s).with(model)
|
|
493
|
-
|
|
494
|
-
model.send(:package!)
|
|
495
|
-
model.package.should be_an_instance_of Backup::Package
|
|
496
|
-
end
|
|
497
|
-
end
|
|
498
|
-
|
|
499
|
-
describe '#clean' do
|
|
500
|
-
it 'should remove the final packaged files' do
|
|
501
|
-
package = mock
|
|
502
|
-
model.instance_variable_set(:@package, package)
|
|
503
|
-
Backup::Cleaner.expects(:remove_package).with(package)
|
|
504
|
-
|
|
505
|
-
model.send(:clean!)
|
|
506
|
-
end
|
|
507
|
-
end
|
|
508
|
-
|
|
509
|
-
describe '#procedures' do
|
|
510
|
-
it 'should return an array of specific, ordered procedures' do
|
|
511
|
-
model.stubs(:databases).returns(:databases)
|
|
512
|
-
model.stubs(:archives).returns(:archives)
|
|
513
|
-
model.stubs(:package!).returns(:package)
|
|
514
|
-
model.stubs(:storages).returns(:storages)
|
|
515
|
-
model.stubs(:clean!).returns(:clean)
|
|
516
|
-
|
|
517
|
-
one, two, three, four, five = model.send(:procedures)
|
|
518
|
-
one.should == :databases
|
|
519
|
-
two.should == :archives
|
|
520
|
-
three.call.should == :package
|
|
521
|
-
four.should == :storages
|
|
522
|
-
five.call.should == :clean
|
|
523
|
-
end
|
|
524
|
-
end
|
|
525
|
-
|
|
526
|
-
describe '#procedure_instance_variables' do
|
|
527
|
-
# these are all set to an empty Array in #initialize
|
|
528
|
-
it 'should return an array of Array holding instance variables' do
|
|
529
|
-
model.send(:procedure_instance_variables).should ==
|
|
530
|
-
[:@databases, :@archives, :@storages, :@notifiers, :@syncers]
|
|
531
|
-
end
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
describe '#get_class_from_scope' do
|
|
535
|
-
|
|
536
|
-
module Fake
|
|
537
|
-
module TestScope
|
|
538
|
-
class TestKlass; end
|
|
539
|
-
end
|
|
540
|
-
end
|
|
541
|
-
module TestScope
|
|
542
|
-
module TestKlass; end
|
|
543
|
-
end
|
|
544
|
-
|
|
545
|
-
context 'when name is given as a string' do
|
|
546
|
-
it 'should return the constant for the given scope and name' do
|
|
547
|
-
model.send(
|
|
548
|
-
:get_class_from_scope,
|
|
549
|
-
Fake,
|
|
550
|
-
'TestScope'
|
|
551
|
-
).should == Fake::TestScope
|
|
552
|
-
end
|
|
553
|
-
|
|
554
|
-
it 'should accept a nested class name' do
|
|
555
|
-
model.send(
|
|
556
|
-
:get_class_from_scope,
|
|
557
|
-
Fake,
|
|
558
|
-
'TestScope::TestKlass'
|
|
559
|
-
).should == Fake::TestScope::TestKlass
|
|
560
|
-
end
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
context 'when name is given as a module' do
|
|
564
|
-
it 'should return the constant for the given scope and name' do
|
|
565
|
-
model.send(
|
|
566
|
-
:get_class_from_scope,
|
|
567
|
-
Fake,
|
|
568
|
-
TestScope
|
|
569
|
-
).should == Fake::TestScope
|
|
570
|
-
end
|
|
571
|
-
|
|
572
|
-
it 'should accept a nested class name' do
|
|
573
|
-
model.send(
|
|
574
|
-
:get_class_from_scope,
|
|
575
|
-
Fake,
|
|
576
|
-
TestScope::TestKlass
|
|
577
|
-
).should == Fake::TestScope::TestKlass
|
|
578
|
-
end
|
|
579
|
-
end
|
|
580
|
-
|
|
581
|
-
context 'when name is given as a module defined under Backup::Config' do
|
|
582
|
-
# this is necessary since the specs in spec/config_spec.rb
|
|
583
|
-
# remove all the constants from Backup::Config as part of those tests.
|
|
584
|
-
before(:all) do
|
|
585
|
-
module Backup::Config
|
|
586
|
-
module TestScope
|
|
587
|
-
module TestKlass; end
|
|
588
|
-
end
|
|
589
|
-
end
|
|
590
|
-
end
|
|
591
|
-
|
|
592
|
-
it 'should return the constant for the given scope and name' do
|
|
593
|
-
model.send(
|
|
594
|
-
:get_class_from_scope,
|
|
595
|
-
Fake,
|
|
596
|
-
Backup::Config::TestScope
|
|
597
|
-
).should == Fake::TestScope
|
|
598
|
-
end
|
|
599
|
-
|
|
600
|
-
it 'should accept a nested class name' do
|
|
601
|
-
model.send(
|
|
602
|
-
:get_class_from_scope,
|
|
603
|
-
Fake,
|
|
604
|
-
Backup::Config::TestScope::TestKlass
|
|
605
|
-
).should == Fake::TestScope::TestKlass
|
|
606
|
-
end
|
|
607
|
-
end
|
|
608
|
-
|
|
609
|
-
end # describe '#get_class_from_scope'
|
|
610
|
-
|
|
611
|
-
describe '#log!' do
|
|
612
|
-
context 'when action is :started' do
|
|
613
|
-
it 'should log that the backup has started with the version' do
|
|
614
|
-
Backup::Logger.expects(:message).with(
|
|
615
|
-
"Performing Backup for 'test label (test_trigger)'!\n" +
|
|
616
|
-
"[ backup #{ Backup::Version.current } : #{ RUBY_DESCRIPTION } ]"
|
|
617
|
-
)
|
|
618
|
-
model.send(:log!, :started)
|
|
619
|
-
end
|
|
620
|
-
end
|
|
621
|
-
|
|
622
|
-
context 'when action is :finished' do
|
|
623
|
-
before { model.expects(:elapsed_time).returns('01:02:03') }
|
|
624
|
-
context 'when warnings were issued' do
|
|
625
|
-
before { Backup::Logger.expects(:has_warnings?).returns(true) }
|
|
626
|
-
it 'should log a warning that the backup has finished with warnings' do
|
|
627
|
-
Backup::Logger.expects(:warn).with(
|
|
628
|
-
"Backup for 'test label (test_trigger)' " +
|
|
629
|
-
"Completed Successfully (with Warnings) in 01:02:03"
|
|
630
|
-
)
|
|
631
|
-
model.send(:log!, :finished)
|
|
632
|
-
end
|
|
633
|
-
end
|
|
634
|
-
|
|
635
|
-
context 'when no warnings were issued' do
|
|
636
|
-
it 'should log that the backup has finished with the elapsed time' do
|
|
637
|
-
Backup::Logger.expects(:message).with(
|
|
638
|
-
"Backup for 'test label (test_trigger)' " +
|
|
639
|
-
"Completed Successfully in 01:02:03"
|
|
640
|
-
)
|
|
641
|
-
model.send(:log!, :finished)
|
|
642
|
-
end
|
|
643
|
-
end
|
|
644
|
-
end
|
|
645
|
-
end # describe '#log!'
|
|
646
|
-
|
|
647
|
-
describe '#elapsed_time' do
|
|
648
|
-
it 'should return a string representing the elapsed time' do
|
|
649
|
-
Timecop.freeze(Time.now)
|
|
650
|
-
{ 0 => '00:00:00', 1 => '00:00:01', 59 => '00:00:59',
|
|
651
|
-
60 => '00:01:00', 61 => '00:01:01', 119 => '00:01:59',
|
|
652
|
-
3540 => '00:59:00', 3541 => '00:59:01', 3599 => '00:59:59',
|
|
653
|
-
3600 => '01:00:00', 3601 => '01:00:01', 3659 => '01:00:59',
|
|
654
|
-
3660 => '01:01:00', 3661 => '01:01:01', 3719 => '01:01:59',
|
|
655
|
-
7140 => '01:59:00', 7141 => '01:59:01', 7199 => '01:59:59',
|
|
656
|
-
212400 => '59:00:00', 212401 => '59:00:01', 212459 => '59:00:59',
|
|
657
|
-
212460 => '59:01:00', 212461 => '59:01:01', 212519 => '59:01:59',
|
|
658
|
-
215940 => '59:59:00', 215941 => '59:59:01', 215999 => '59:59:59'
|
|
659
|
-
}.each do |duration, expected|
|
|
660
|
-
model.instance_variable_set(:@started_at, Time.now - duration)
|
|
661
|
-
model.send(:elapsed_time).should == expected
|
|
662
|
-
end
|
|
663
|
-
end
|
|
664
|
-
end
|
|
665
|
-
|
|
666
|
-
end
|