backup_checksum 3.0.23
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 +7 -0
- data/.travis.yml +10 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +130 -0
- data/Guardfile +21 -0
- data/LICENSE.md +24 -0
- data/README.md +476 -0
- data/backup_checksum.gemspec +32 -0
- data/bin/backup +11 -0
- data/lib/backup.rb +217 -0
- data/lib/backup/archive.rb +117 -0
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/checksum/base.rb +44 -0
- data/lib/backup/checksum/shasum.rb +16 -0
- data/lib/backup/cleaner.rb +121 -0
- data/lib/backup/cli/helpers.rb +88 -0
- data/lib/backup/cli/utility.rb +247 -0
- data/lib/backup/compressor/base.rb +29 -0
- data/lib/backup/compressor/bzip2.rb +50 -0
- data/lib/backup/compressor/gzip.rb +47 -0
- data/lib/backup/compressor/lzma.rb +50 -0
- data/lib/backup/compressor/pbzip2.rb +56 -0
- data/lib/backup/config.rb +173 -0
- data/lib/backup/configuration/base.rb +15 -0
- data/lib/backup/configuration/checksum/base.rb +9 -0
- data/lib/backup/configuration/checksum/shasum.rb +9 -0
- data/lib/backup/configuration/compressor/base.rb +9 -0
- data/lib/backup/configuration/compressor/bzip2.rb +23 -0
- data/lib/backup/configuration/compressor/gzip.rb +23 -0
- data/lib/backup/configuration/compressor/lzma.rb +23 -0
- data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
- data/lib/backup/configuration/database/base.rb +19 -0
- data/lib/backup/configuration/database/mongodb.rb +49 -0
- data/lib/backup/configuration/database/mysql.rb +42 -0
- data/lib/backup/configuration/database/postgresql.rb +41 -0
- data/lib/backup/configuration/database/redis.rb +39 -0
- data/lib/backup/configuration/database/riak.rb +29 -0
- data/lib/backup/configuration/encryptor/base.rb +9 -0
- data/lib/backup/configuration/encryptor/gpg.rb +17 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +32 -0
- data/lib/backup/configuration/helpers.rb +52 -0
- data/lib/backup/configuration/notifier/base.rb +28 -0
- data/lib/backup/configuration/notifier/campfire.rb +25 -0
- data/lib/backup/configuration/notifier/hipchat.rb +41 -0
- data/lib/backup/configuration/notifier/mail.rb +112 -0
- data/lib/backup/configuration/notifier/presently.rb +25 -0
- data/lib/backup/configuration/notifier/prowl.rb +23 -0
- data/lib/backup/configuration/notifier/twitter.rb +21 -0
- data/lib/backup/configuration/storage/base.rb +18 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +25 -0
- data/lib/backup/configuration/storage/dropbox.rb +58 -0
- data/lib/backup/configuration/storage/ftp.rb +29 -0
- data/lib/backup/configuration/storage/local.rb +17 -0
- data/lib/backup/configuration/storage/ninefold.rb +20 -0
- data/lib/backup/configuration/storage/rsync.rb +29 -0
- data/lib/backup/configuration/storage/s3.rb +25 -0
- data/lib/backup/configuration/storage/scp.rb +25 -0
- data/lib/backup/configuration/storage/sftp.rb +25 -0
- data/lib/backup/configuration/syncer/base.rb +10 -0
- data/lib/backup/configuration/syncer/cloud.rb +23 -0
- data/lib/backup/configuration/syncer/cloud_files.rb +30 -0
- data/lib/backup/configuration/syncer/rsync/base.rb +28 -0
- data/lib/backup/configuration/syncer/rsync/local.rb +11 -0
- data/lib/backup/configuration/syncer/rsync/pull.rb +11 -0
- data/lib/backup/configuration/syncer/rsync/push.rb +31 -0
- data/lib/backup/configuration/syncer/s3.rb +23 -0
- data/lib/backup/database/base.rb +59 -0
- data/lib/backup/database/mongodb.rb +232 -0
- data/lib/backup/database/mysql.rb +163 -0
- data/lib/backup/database/postgresql.rb +146 -0
- data/lib/backup/database/redis.rb +139 -0
- data/lib/backup/database/riak.rb +69 -0
- data/lib/backup/dependency.rb +114 -0
- data/lib/backup/encryptor/base.rb +29 -0
- data/lib/backup/encryptor/gpg.rb +80 -0
- data/lib/backup/encryptor/open_ssl.rb +72 -0
- data/lib/backup/errors.rb +124 -0
- data/lib/backup/logger.rb +152 -0
- data/lib/backup/model.rb +386 -0
- data/lib/backup/notifier/base.rb +81 -0
- data/lib/backup/notifier/campfire.rb +168 -0
- data/lib/backup/notifier/hipchat.rb +99 -0
- data/lib/backup/notifier/mail.rb +206 -0
- data/lib/backup/notifier/presently.rb +88 -0
- data/lib/backup/notifier/prowl.rb +65 -0
- data/lib/backup/notifier/twitter.rb +70 -0
- data/lib/backup/package.rb +51 -0
- data/lib/backup/packager.rb +108 -0
- data/lib/backup/pipeline.rb +107 -0
- data/lib/backup/splitter.rb +75 -0
- data/lib/backup/storage/base.rb +119 -0
- data/lib/backup/storage/cloudfiles.rb +87 -0
- data/lib/backup/storage/cycler.rb +117 -0
- data/lib/backup/storage/dropbox.rb +181 -0
- data/lib/backup/storage/ftp.rb +119 -0
- data/lib/backup/storage/local.rb +82 -0
- data/lib/backup/storage/ninefold.rb +116 -0
- data/lib/backup/storage/rsync.rb +149 -0
- data/lib/backup/storage/s3.rb +94 -0
- data/lib/backup/storage/scp.rb +99 -0
- data/lib/backup/storage/sftp.rb +108 -0
- data/lib/backup/syncer/base.rb +42 -0
- data/lib/backup/syncer/cloud.rb +190 -0
- data/lib/backup/syncer/cloud_files.rb +56 -0
- data/lib/backup/syncer/rsync/base.rb +52 -0
- data/lib/backup/syncer/rsync/local.rb +53 -0
- data/lib/backup/syncer/rsync/pull.rb +38 -0
- data/lib/backup/syncer/rsync/push.rb +113 -0
- data/lib/backup/syncer/s3.rb +47 -0
- data/lib/backup/template.rb +46 -0
- data/lib/backup/version.rb +43 -0
- data/spec/archive_spec.rb +335 -0
- data/spec/cleaner_spec.rb +304 -0
- data/spec/cli/helpers_spec.rb +176 -0
- data/spec/cli/utility_spec.rb +363 -0
- data/spec/compressor/base_spec.rb +31 -0
- data/spec/compressor/bzip2_spec.rb +83 -0
- data/spec/compressor/gzip_spec.rb +83 -0
- data/spec/compressor/lzma_spec.rb +83 -0
- data/spec/compressor/pbzip2_spec.rb +124 -0
- data/spec/config_spec.rb +321 -0
- data/spec/configuration/base_spec.rb +35 -0
- data/spec/configuration/compressor/bzip2_spec.rb +29 -0
- data/spec/configuration/compressor/gzip_spec.rb +29 -0
- data/spec/configuration/compressor/lzma_spec.rb +29 -0
- data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
- data/spec/configuration/database/base_spec.rb +17 -0
- data/spec/configuration/database/mongodb_spec.rb +56 -0
- data/spec/configuration/database/mysql_spec.rb +53 -0
- data/spec/configuration/database/postgresql_spec.rb +53 -0
- data/spec/configuration/database/redis_spec.rb +50 -0
- data/spec/configuration/database/riak_spec.rb +35 -0
- data/spec/configuration/encryptor/gpg_spec.rb +26 -0
- data/spec/configuration/encryptor/open_ssl_spec.rb +35 -0
- data/spec/configuration/notifier/base_spec.rb +32 -0
- data/spec/configuration/notifier/campfire_spec.rb +32 -0
- data/spec/configuration/notifier/hipchat_spec.rb +44 -0
- data/spec/configuration/notifier/mail_spec.rb +71 -0
- data/spec/configuration/notifier/presently_spec.rb +35 -0
- data/spec/configuration/notifier/prowl_spec.rb +29 -0
- data/spec/configuration/notifier/twitter_spec.rb +35 -0
- data/spec/configuration/storage/cloudfiles_spec.rb +41 -0
- data/spec/configuration/storage/dropbox_spec.rb +38 -0
- data/spec/configuration/storage/ftp_spec.rb +44 -0
- data/spec/configuration/storage/local_spec.rb +29 -0
- data/spec/configuration/storage/ninefold_spec.rb +32 -0
- data/spec/configuration/storage/rsync_spec.rb +41 -0
- data/spec/configuration/storage/s3_spec.rb +38 -0
- data/spec/configuration/storage/scp_spec.rb +41 -0
- data/spec/configuration/storage/sftp_spec.rb +41 -0
- data/spec/configuration/syncer/cloud_files_spec.rb +44 -0
- data/spec/configuration/syncer/rsync/base_spec.rb +33 -0
- data/spec/configuration/syncer/rsync/local_spec.rb +10 -0
- data/spec/configuration/syncer/rsync/pull_spec.rb +10 -0
- data/spec/configuration/syncer/rsync/push_spec.rb +43 -0
- data/spec/configuration/syncer/s3_spec.rb +38 -0
- data/spec/database/base_spec.rb +54 -0
- data/spec/database/mongodb_spec.rb +428 -0
- data/spec/database/mysql_spec.rb +335 -0
- data/spec/database/postgresql_spec.rb +278 -0
- data/spec/database/redis_spec.rb +260 -0
- data/spec/database/riak_spec.rb +108 -0
- data/spec/dependency_spec.rb +49 -0
- data/spec/encryptor/base_spec.rb +30 -0
- data/spec/encryptor/gpg_spec.rb +134 -0
- data/spec/encryptor/open_ssl_spec.rb +129 -0
- data/spec/errors_spec.rb +306 -0
- data/spec/logger_spec.rb +363 -0
- data/spec/model_spec.rb +649 -0
- data/spec/notifier/base_spec.rb +89 -0
- data/spec/notifier/campfire_spec.rb +199 -0
- data/spec/notifier/hipchat_spec.rb +188 -0
- data/spec/notifier/mail_spec.rb +280 -0
- data/spec/notifier/presently_spec.rb +181 -0
- data/spec/notifier/prowl_spec.rb +117 -0
- data/spec/notifier/twitter_spec.rb +132 -0
- data/spec/package_spec.rb +61 -0
- data/spec/packager_spec.rb +225 -0
- data/spec/pipeline_spec.rb +257 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/splitter_spec.rb +120 -0
- data/spec/storage/base_spec.rb +160 -0
- data/spec/storage/cloudfiles_spec.rb +230 -0
- data/spec/storage/cycler_spec.rb +239 -0
- data/spec/storage/dropbox_spec.rb +370 -0
- data/spec/storage/ftp_spec.rb +247 -0
- data/spec/storage/local_spec.rb +235 -0
- data/spec/storage/ninefold_spec.rb +319 -0
- data/spec/storage/rsync_spec.rb +345 -0
- data/spec/storage/s3_spec.rb +221 -0
- data/spec/storage/scp_spec.rb +209 -0
- data/spec/storage/sftp_spec.rb +220 -0
- data/spec/syncer/base_spec.rb +22 -0
- data/spec/syncer/cloud_files_spec.rb +192 -0
- data/spec/syncer/rsync/base_spec.rb +118 -0
- data/spec/syncer/rsync/local_spec.rb +121 -0
- data/spec/syncer/rsync/pull_spec.rb +90 -0
- data/spec/syncer/rsync/push_spec.rb +327 -0
- data/spec/syncer/s3_spec.rb +192 -0
- data/spec/version_spec.rb +21 -0
- data/templates/cli/utility/archive +25 -0
- data/templates/cli/utility/compressor/bzip2 +7 -0
- data/templates/cli/utility/compressor/gzip +7 -0
- data/templates/cli/utility/compressor/lzma +7 -0
- data/templates/cli/utility/compressor/pbzip2 +7 -0
- data/templates/cli/utility/config +31 -0
- data/templates/cli/utility/database/mongodb +18 -0
- data/templates/cli/utility/database/mysql +21 -0
- data/templates/cli/utility/database/postgresql +17 -0
- data/templates/cli/utility/database/redis +16 -0
- data/templates/cli/utility/database/riak +11 -0
- data/templates/cli/utility/encryptor/gpg +12 -0
- data/templates/cli/utility/encryptor/openssl +9 -0
- data/templates/cli/utility/model.erb +23 -0
- data/templates/cli/utility/notifier/campfire +12 -0
- data/templates/cli/utility/notifier/hipchat +15 -0
- data/templates/cli/utility/notifier/mail +22 -0
- data/templates/cli/utility/notifier/presently +13 -0
- data/templates/cli/utility/notifier/prowl +11 -0
- data/templates/cli/utility/notifier/twitter +13 -0
- data/templates/cli/utility/splitter +7 -0
- data/templates/cli/utility/storage/cloud_files +22 -0
- data/templates/cli/utility/storage/dropbox +20 -0
- data/templates/cli/utility/storage/ftp +12 -0
- data/templates/cli/utility/storage/local +7 -0
- data/templates/cli/utility/storage/ninefold +9 -0
- data/templates/cli/utility/storage/rsync +11 -0
- data/templates/cli/utility/storage/s3 +19 -0
- data/templates/cli/utility/storage/scp +11 -0
- data/templates/cli/utility/storage/sftp +11 -0
- data/templates/cli/utility/syncer/cloud_files +48 -0
- data/templates/cli/utility/syncer/rsync_local +12 -0
- data/templates/cli/utility/syncer/rsync_pull +17 -0
- data/templates/cli/utility/syncer/rsync_push +17 -0
- data/templates/cli/utility/syncer/s3 +45 -0
- 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 +311 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe 'Backup::Pipeline' do
|
|
6
|
+
let(:pipeline) { Backup::Pipeline.new }
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'should create a new pipeline' do
|
|
10
|
+
pipeline.instance_variable_get(:@commands).should == []
|
|
11
|
+
pipeline.errors.should == []
|
|
12
|
+
pipeline.stderr.should == ''
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#<<' do
|
|
17
|
+
it 'should add a command string to @commands' do
|
|
18
|
+
pipeline << 'a command string'
|
|
19
|
+
pipeline.instance_variable_get(:@commands).should == ['a command string']
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#run' do
|
|
24
|
+
let(:stdout) { mock }
|
|
25
|
+
let(:stderr) { mock }
|
|
26
|
+
|
|
27
|
+
before do
|
|
28
|
+
pipeline.expects(:pipeline).returns('foo')
|
|
29
|
+
pipeline.stubs(:stderr_messages).returns('stderr_messages_output')
|
|
30
|
+
# stub CLI::Helpers#command_name so it simply returns what it's passed
|
|
31
|
+
pipeline.class.send(:define_method, :command_name, lambda {|arg| arg } )
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'when pipeline command is successfully executed' do
|
|
35
|
+
before do
|
|
36
|
+
Open4.expects(:popen4).with('foo').yields(nil, nil, stdout, stderr)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'when all commands within the pipeline are successful' do
|
|
40
|
+
before do
|
|
41
|
+
stdout.expects(:read).returns("0|0:1|0:\n")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'when commands output no stderr messages' do
|
|
45
|
+
before do
|
|
46
|
+
stderr.expects(:read).returns('')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should process the returned stdout/stderr and report no errors' do
|
|
50
|
+
Backup::Logger.expects(:warn).never
|
|
51
|
+
|
|
52
|
+
pipeline.run
|
|
53
|
+
pipeline.stderr.should == ''
|
|
54
|
+
pipeline.errors.should == []
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context 'when successful commands output messages on stderr' do
|
|
59
|
+
before do
|
|
60
|
+
stderr.expects(:read).returns("stderr output\n")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'should log a warning with the stderr messages' do
|
|
64
|
+
Backup::Logger.expects(:warn).with('stderr_messages_output')
|
|
65
|
+
|
|
66
|
+
pipeline.run
|
|
67
|
+
pipeline.stderr.should == 'stderr output'
|
|
68
|
+
pipeline.errors.should == []
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end # context 'when all commands within the pipeline are successful'
|
|
72
|
+
|
|
73
|
+
context 'when commands within the pipeline are not successful' do
|
|
74
|
+
before do
|
|
75
|
+
pipeline.instance_variable_set(:@commands, ['first', 'second', 'third'])
|
|
76
|
+
stderr.expects(:read).returns("stderr output\n")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context 'when the commands return in sequence' do
|
|
80
|
+
before do
|
|
81
|
+
stdout.expects(:read).returns("0|0:1|1:2|0:\n")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'should set @errors and @stderr without logging warnings' do
|
|
85
|
+
Backup::Logger.expects(:warn).never
|
|
86
|
+
|
|
87
|
+
pipeline.run
|
|
88
|
+
pipeline.stderr.should == 'stderr output'
|
|
89
|
+
pipeline.errors.count.should be(1)
|
|
90
|
+
pipeline.errors.first.should be_a_kind_of SystemCallError
|
|
91
|
+
pipeline.errors.first.errno.should be(1)
|
|
92
|
+
pipeline.errors.first.message.should match(
|
|
93
|
+
"'second' returned exit code: 1"
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
end # context 'when the commands return in sequence'
|
|
97
|
+
|
|
98
|
+
context 'when the commands return out of sequence' do
|
|
99
|
+
before do
|
|
100
|
+
stdout.expects(:read).returns("1|1:2|0:0|0:\n")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should properly associate the exitstatus for each command' do
|
|
104
|
+
Backup::Logger.expects(:warn).never
|
|
105
|
+
|
|
106
|
+
pipeline.run
|
|
107
|
+
pipeline.stderr.should == 'stderr output'
|
|
108
|
+
pipeline.errors.count.should be(1)
|
|
109
|
+
pipeline.errors.first.should be_a_kind_of SystemCallError
|
|
110
|
+
pipeline.errors.first.errno.should be(1)
|
|
111
|
+
pipeline.errors.first.message.should match(
|
|
112
|
+
"'second' returned exit code: 1"
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
end # context 'when the commands return out of sequence'
|
|
116
|
+
|
|
117
|
+
context 'when multiple commands fail (out of sequence)' do
|
|
118
|
+
before do
|
|
119
|
+
stdout.expects(:read).returns("1|1:2|0:0|3:\n")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'should properly associate the exitstatus for each command' do
|
|
123
|
+
Backup::Logger.expects(:warn).never
|
|
124
|
+
|
|
125
|
+
pipeline.run
|
|
126
|
+
pipeline.stderr.should == 'stderr output'
|
|
127
|
+
pipeline.errors.count.should be(2)
|
|
128
|
+
pipeline.errors.each {|err| err.should be_a_kind_of SystemCallError }
|
|
129
|
+
pipeline.errors[0].errno.should be(3)
|
|
130
|
+
pipeline.errors[0].message.should match(
|
|
131
|
+
"'first' returned exit code: 3"
|
|
132
|
+
)
|
|
133
|
+
pipeline.errors[1].errno.should be(1)
|
|
134
|
+
pipeline.errors[1].message.should match(
|
|
135
|
+
"'second' returned exit code: 1"
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
end # context 'when the commands return (out of sequence)'
|
|
139
|
+
|
|
140
|
+
end # context 'when commands within the pipeline are not successful'
|
|
141
|
+
end # context 'when pipeline command is successfully executed'
|
|
142
|
+
|
|
143
|
+
context 'when pipeline command fails to execute' do
|
|
144
|
+
before do
|
|
145
|
+
Open4.expects(:popen4).with('foo').raises('exec failed')
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'should raise an error' do
|
|
149
|
+
expect do
|
|
150
|
+
pipeline.run
|
|
151
|
+
end.to raise_error(
|
|
152
|
+
Backup::Errors::Pipeline::ExecutionError,
|
|
153
|
+
"Pipeline::ExecutionError: RuntimeError: exec failed"
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
end # context 'when pipeline command fails to execute'
|
|
157
|
+
|
|
158
|
+
end # describe '#run'
|
|
159
|
+
|
|
160
|
+
describe '#success?' do
|
|
161
|
+
it 'returns true when @errors is empty' do
|
|
162
|
+
pipeline.success?.should be_true
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it 'returns false when @errors is not empty' do
|
|
166
|
+
pipeline.instance_variable_set(:@errors, ['foo'])
|
|
167
|
+
pipeline.success?.should be_false
|
|
168
|
+
end
|
|
169
|
+
end # describe '#success?'
|
|
170
|
+
|
|
171
|
+
describe '#error_messages' do
|
|
172
|
+
before do
|
|
173
|
+
pipeline.instance_variable_set(
|
|
174
|
+
:@errors, [
|
|
175
|
+
StandardError.new('standard error'),
|
|
176
|
+
RuntimeError.new('runtime error')
|
|
177
|
+
]
|
|
178
|
+
)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
context 'when #stderr_messages has messages' do
|
|
182
|
+
before do
|
|
183
|
+
pipeline.expects(:stderr_messages).returns('stderr messages')
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it 'should output #stderr_messages and formatted system error messages' do
|
|
187
|
+
pipeline.error_messages.should == 'stderr messages' +
|
|
188
|
+
"The following system errors were returned:\n" +
|
|
189
|
+
"Error: StandardError: standard error\n" +
|
|
190
|
+
"Error: RuntimeError: runtime error"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
context 'when #stderr_messages has no messages' do
|
|
195
|
+
before do
|
|
196
|
+
pipeline.expects(:stderr_messages).returns(false)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it 'should only output the formatted system error messages' do
|
|
200
|
+
pipeline.error_messages.should ==
|
|
201
|
+
"The following system errors were returned:\n" +
|
|
202
|
+
"Error: StandardError: standard error\n" +
|
|
203
|
+
"Error: RuntimeError: runtime error"
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end # describe '#error_messages'
|
|
207
|
+
|
|
208
|
+
describe '#pipeline' do
|
|
209
|
+
context 'when there are multiple system commands to execute' do
|
|
210
|
+
before do
|
|
211
|
+
pipeline.instance_variable_set(:@commands, %w{ one two three })
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'should build a pipeline with redirected/collected exit codes' do
|
|
215
|
+
pipeline.send(:pipeline).should ==
|
|
216
|
+
'( ( one 2>&4; echo "0|$?:" >&3 ) | ' +
|
|
217
|
+
'( two 2>&4; echo "1|$?:" >&3 ) | ' +
|
|
218
|
+
'( three 2>&4; echo "2|$?:" >&3 ) ) 3>&1- 4>&2'
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
context 'when there is only one system command to execute' do
|
|
223
|
+
before do
|
|
224
|
+
pipeline.instance_variable_set(:@commands, ['foo'])
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'should build the command line in the same manner, but without pipes' do
|
|
228
|
+
pipeline.send(:pipeline).should ==
|
|
229
|
+
'( ( foo 2>&4; echo "0|$?:" >&3 ) ) 3>&1- 4>&2'
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end # describe '#pipeline'
|
|
233
|
+
|
|
234
|
+
describe '#stderr_message' do
|
|
235
|
+
context 'when @stderr has messages' do
|
|
236
|
+
before do
|
|
237
|
+
pipeline.instance_variable_set(:@stderr, "stderr message\n output")
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it 'should return a formatted message with the @stderr messages' do
|
|
241
|
+
pipeline.send(:stderr_messages).should ==
|
|
242
|
+
" Pipeline STDERR Messages:\n" +
|
|
243
|
+
" (Note: may be interleaved if multiple commands returned error messages)\n" +
|
|
244
|
+
"\n" +
|
|
245
|
+
" stderr message\n" +
|
|
246
|
+
" output\n"
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
context 'when @stderr is empty' do
|
|
251
|
+
it 'should return false' do
|
|
252
|
+
pipeline.send(:stderr_messages).should be_false
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end # describe '#stderr_message'
|
|
256
|
+
|
|
257
|
+
end #describe 'Backup::Pipeline'
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Use Bundler
|
|
5
|
+
require 'rubygems' if RUBY_VERSION < '1.9'
|
|
6
|
+
require 'bundler/setup'
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Load Backup
|
|
10
|
+
require 'backup'
|
|
11
|
+
|
|
12
|
+
require 'timecop'
|
|
13
|
+
|
|
14
|
+
module Backup::ExampleHelpers
|
|
15
|
+
# ripped from MiniTest :)
|
|
16
|
+
# RSpec doesn't have a method for this? Am I missing something?
|
|
17
|
+
def capture_io
|
|
18
|
+
require 'stringio'
|
|
19
|
+
|
|
20
|
+
orig_stdout, orig_stderr = $stdout, $stderr
|
|
21
|
+
captured_stdout, captured_stderr = StringIO.new, StringIO.new
|
|
22
|
+
$stdout, $stderr = captured_stdout, captured_stderr
|
|
23
|
+
|
|
24
|
+
yield
|
|
25
|
+
|
|
26
|
+
return captured_stdout.string, captured_stderr.string
|
|
27
|
+
ensure
|
|
28
|
+
$stdout = orig_stdout
|
|
29
|
+
$stderr = orig_stderr
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
require 'rspec/autorun'
|
|
34
|
+
RSpec.configure do |config|
|
|
35
|
+
##
|
|
36
|
+
# Use Mocha to mock with RSpec
|
|
37
|
+
config.mock_with :mocha
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Example Helpers
|
|
41
|
+
config.include Backup::ExampleHelpers
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# Actions to perform before each example
|
|
45
|
+
config.before(:each) do
|
|
46
|
+
FileUtils.collect_method(:noop).each do |method|
|
|
47
|
+
FileUtils.stubs(method).raises("Unexpected call to FileUtils.#{method}")
|
|
48
|
+
end
|
|
49
|
+
Open4.stubs(:popen4).raises('Unexpected call to Open4::popen4()')
|
|
50
|
+
|
|
51
|
+
[:message, :error, :warn, :normal, :silent].each do |message_type|
|
|
52
|
+
Backup::Logger.stubs(message_type)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
unless @_put_ruby_version
|
|
58
|
+
puts @_put_ruby_version = "\n\nRuby version: #{RUBY_DESCRIPTION}\n\n"
|
|
59
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe Backup::Splitter do
|
|
6
|
+
let(:model) { Backup::Model.new(:test_trigger, 'test label') }
|
|
7
|
+
let(:splitter) { Backup::Splitter.new(model, 250) }
|
|
8
|
+
let(:package) { mock }
|
|
9
|
+
|
|
10
|
+
describe '#initialize' do
|
|
11
|
+
it 'should set instance variables' do
|
|
12
|
+
splitter.instance_variable_get(:@model).should be(model)
|
|
13
|
+
splitter.instance_variable_get(:@chunk_size).should be(250)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#split_with' do
|
|
18
|
+
it 'should yield the split command, performing before/after methods' do
|
|
19
|
+
s = sequence ''
|
|
20
|
+
given_block = mock
|
|
21
|
+
block = lambda {|arg| given_block.got(arg) }
|
|
22
|
+
splitter.instance_variable_set(:@split_command, 'split command')
|
|
23
|
+
|
|
24
|
+
splitter.expects(:before_packaging).in_sequence(s)
|
|
25
|
+
given_block.expects(:got).in_sequence(s).with('split command')
|
|
26
|
+
splitter.expects(:after_packaging).in_sequence(s)
|
|
27
|
+
|
|
28
|
+
splitter.split_with(&block)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Note: using a 'M' suffix for the byte size is not OSX compatible
|
|
33
|
+
describe '#before_packaging' do
|
|
34
|
+
before do
|
|
35
|
+
model.instance_variable_set(:@package, package)
|
|
36
|
+
splitter.expects(:utility).with(:split).returns('split')
|
|
37
|
+
package.expects(:basename).returns('base_filename')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'should set @package and @split_command' do
|
|
41
|
+
Backup::Logger.expects(:message).with(
|
|
42
|
+
'Splitter configured with a chunk size of 250MB.'
|
|
43
|
+
)
|
|
44
|
+
splitter.send(:before_packaging)
|
|
45
|
+
|
|
46
|
+
splitter.instance_variable_get(:@package).should be(package)
|
|
47
|
+
|
|
48
|
+
split_suffix = File.join(Backup::Config.tmp_path, 'base_filename-')
|
|
49
|
+
splitter.instance_variable_get(:@split_command).should ==
|
|
50
|
+
"split -b 250m - '#{ split_suffix }'"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '#after_packaging' do
|
|
55
|
+
before do
|
|
56
|
+
splitter.instance_variable_set(:@package, package)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context 'when splitting occurred during packaging' do
|
|
60
|
+
before do
|
|
61
|
+
splitter.expects(:chunk_suffixes).returns(['aa', 'ab'])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'should set the chunk_suffixes for the package' do
|
|
65
|
+
package.expects(:chunk_suffixes=).with(['aa', 'ab'])
|
|
66
|
+
splitter.send(:after_packaging)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'when splitting did not occur during packaging' do
|
|
71
|
+
before do
|
|
72
|
+
splitter.expects(:chunk_suffixes).returns(['aa'])
|
|
73
|
+
package.expects(:basename).twice.returns('base_filename')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should remove the suffix from the only package file' do
|
|
77
|
+
package.expects(:chunk_suffixes=).never
|
|
78
|
+
FileUtils.expects(:mv).with(
|
|
79
|
+
File.join(Backup::Config.tmp_path, 'base_filename-aa'),
|
|
80
|
+
File.join(Backup::Config.tmp_path, 'base_filename')
|
|
81
|
+
)
|
|
82
|
+
splitter.send(:after_packaging)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end # describe '#after_packaging'
|
|
86
|
+
|
|
87
|
+
describe '#chunk_suffixes' do
|
|
88
|
+
before do
|
|
89
|
+
splitter.expects(:chunks).returns(
|
|
90
|
+
['/path/to/file.tar-aa', '/path/to/file.tar-ab']
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'should return an array of chunk suffixes' do
|
|
95
|
+
splitter.send(:chunk_suffixes).should == ['aa', 'ab']
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe '#chunks' do
|
|
100
|
+
before do
|
|
101
|
+
splitter.instance_variable_set(:@package, package)
|
|
102
|
+
package.expects(:basename).returns('base_filename')
|
|
103
|
+
FileUtils.unstub(:touch)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'should return a sorted array of chunked file paths' do
|
|
107
|
+
Dir.mktmpdir do |dir|
|
|
108
|
+
Backup::Config.expects(:tmp_path).returns(dir)
|
|
109
|
+
FileUtils.touch(File.join(dir, 'base_filename-aa'))
|
|
110
|
+
FileUtils.touch(File.join(dir, 'base_filename-ab'))
|
|
111
|
+
|
|
112
|
+
splitter.send(:chunks).should == [
|
|
113
|
+
File.join(dir, 'base_filename-aa'),
|
|
114
|
+
File.join(dir, 'base_filename-ab')
|
|
115
|
+
]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe Backup::Storage::Base do
|
|
6
|
+
let(:model) { Backup::Model.new(:test_trigger, 'test label') }
|
|
7
|
+
let(:package) { mock("package") }
|
|
8
|
+
let(:checksum_creator) { mock("checksum_creator") }
|
|
9
|
+
let(:base) { Backup::Storage::Base.new(model) }
|
|
10
|
+
|
|
11
|
+
describe '#initialize' do
|
|
12
|
+
it 'should set instance variables' do
|
|
13
|
+
base.instance_variable_get(:@model).should be(model)
|
|
14
|
+
base.instance_variable_defined?(:@storage_id).should be_true
|
|
15
|
+
base.instance_variable_get(:@storage_id).should be_nil
|
|
16
|
+
base.keep.should be_nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context 'when given a storage_id' do
|
|
20
|
+
it 'should set @storage_id' do
|
|
21
|
+
base = Backup::Storage::Base.new(model, 'my storage id')
|
|
22
|
+
base.instance_variable_get(:@storage_id).should == 'my storage id'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'when configuration defaults are set' do
|
|
27
|
+
after { Backup::Configuration::Storage::Base.clear_defaults! }
|
|
28
|
+
it 'should use the defaults' do
|
|
29
|
+
Backup::Configuration::Storage::Base.defaults do |base|
|
|
30
|
+
base.keep = 5
|
|
31
|
+
end
|
|
32
|
+
base = Backup::Storage::Base.new(model)
|
|
33
|
+
base.keep.should be(5)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end # describe '#initialize'
|
|
37
|
+
|
|
38
|
+
describe '#perform!' do
|
|
39
|
+
before do
|
|
40
|
+
model.instance_variable_set(:@package, package)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should call #transfer!, then #cycle!' do
|
|
44
|
+
s = sequence ''
|
|
45
|
+
base.expects(:transfer!).in_sequence(s)
|
|
46
|
+
base.expects(:cycle!).in_sequence(s)
|
|
47
|
+
base.perform!
|
|
48
|
+
base.instance_variable_get(:@package).should be(package)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should process checksum file" do
|
|
52
|
+
model.instance_variable_set(:@checksum_creator, checksum_creator)
|
|
53
|
+
package.stubs(:filenames).returns []
|
|
54
|
+
package.stubs(:checksum_name).returns ""
|
|
55
|
+
s = sequence ''
|
|
56
|
+
checksum_creator.expects(:process_checksum_file_before_transfer).in_sequence(s)
|
|
57
|
+
base.expects(:transfer!).in_sequence(s)
|
|
58
|
+
|
|
59
|
+
base.perform!
|
|
60
|
+
|
|
61
|
+
base.instance_variable_get(:@checksum_creator).should be(checksum_creator)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#storage_name' do
|
|
66
|
+
context 'when given a storage_id' do
|
|
67
|
+
before { base.storage_id = 'storage id' }
|
|
68
|
+
it 'should return a log-friendly name with the storage_id' do
|
|
69
|
+
base.send(:storage_name).should == 'Storage::Base (storage id)'
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'when not given a storage_id' do
|
|
74
|
+
it 'should return a log-friendly name without a storage_id' do
|
|
75
|
+
base.send(:storage_name).should == 'Storage::Base'
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe '#local_path' do
|
|
81
|
+
it 'should return the configured tmp_path' do
|
|
82
|
+
base.send(:local_path).should == Backup::Config.tmp_path
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe '#remote_path_for' do
|
|
87
|
+
before do
|
|
88
|
+
package.expects(:trigger).returns('test_trigger')
|
|
89
|
+
package.expects(:time).returns('backup_time')
|
|
90
|
+
base.expects(:path).returns('base/remote/path')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'should return the remote_path for the given package' do
|
|
94
|
+
base.send(:remote_path_for, package).should ==
|
|
95
|
+
File.join('base/remote/path', 'test_trigger', 'backup_time')
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe '#files_to_transfer_for' do
|
|
100
|
+
let(:given_block) { mock }
|
|
101
|
+
before do
|
|
102
|
+
package.stubs(:filenames).returns(
|
|
103
|
+
['2011.12.31.11.00.02.backup.tar.enc-aa',
|
|
104
|
+
'2011.12.31.11.00.02.backup.tar.enc-ab']
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'should yield the full filename and the filename without the timestamp' do
|
|
109
|
+
given_block.expects(:got).with(
|
|
110
|
+
'2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'
|
|
111
|
+
)
|
|
112
|
+
given_block.expects(:got).with(
|
|
113
|
+
'2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab'
|
|
114
|
+
)
|
|
115
|
+
base.send(:files_to_transfer_for, package) do |local_file, remote_file|
|
|
116
|
+
given_block.got(local_file, remote_file)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'should have an alias method called #transferred_files_for' do
|
|
121
|
+
base.method(:transferred_files_for).should ==
|
|
122
|
+
base.method(:files_to_transfer_for)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe '#cycle!' do
|
|
127
|
+
before do
|
|
128
|
+
base.stubs(:storage_name).returns('Storage Name')
|
|
129
|
+
base.instance_variable_set(:@package, package)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
context 'when keep is set and > 0' do
|
|
133
|
+
before { base.keep = 1 }
|
|
134
|
+
it 'should cycle' do
|
|
135
|
+
s = sequence ''
|
|
136
|
+
Backup::Logger.expects(:message).in_sequence(s).
|
|
137
|
+
with('Storage Name: Cycling Started...')
|
|
138
|
+
Backup::Storage::Cycler.expects(:cycle!).in_sequence(s).
|
|
139
|
+
with(base, package)
|
|
140
|
+
Backup::Logger.expects(:message).in_sequence(s).
|
|
141
|
+
with('Storage Name: Cycling Complete!')
|
|
142
|
+
|
|
143
|
+
base.send(:cycle!)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context 'when keep is not set or == 0' do
|
|
148
|
+
it 'should return nil when not set' do
|
|
149
|
+
base.keep = nil
|
|
150
|
+
base.send(:cycle!).should be_nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'should return nil when == 0' do
|
|
154
|
+
base.keep = 0
|
|
155
|
+
base.send(:cycle!).should be_nil
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|