backup-agoddard 3.0.27

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of backup-agoddard might be problematic. Click here for more details.

Files changed (190) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +10 -0
  3. data/Gemfile +28 -0
  4. data/Guardfile +23 -0
  5. data/LICENSE.md +24 -0
  6. data/README.md +478 -0
  7. data/backup.gemspec +32 -0
  8. data/bin/backup +11 -0
  9. data/lib/backup.rb +133 -0
  10. data/lib/backup/archive.rb +117 -0
  11. data/lib/backup/binder.rb +22 -0
  12. data/lib/backup/cleaner.rb +121 -0
  13. data/lib/backup/cli/helpers.rb +93 -0
  14. data/lib/backup/cli/utility.rb +255 -0
  15. data/lib/backup/compressor/base.rb +35 -0
  16. data/lib/backup/compressor/bzip2.rb +50 -0
  17. data/lib/backup/compressor/custom.rb +53 -0
  18. data/lib/backup/compressor/gzip.rb +50 -0
  19. data/lib/backup/compressor/lzma.rb +52 -0
  20. data/lib/backup/compressor/pbzip2.rb +59 -0
  21. data/lib/backup/config.rb +174 -0
  22. data/lib/backup/configuration.rb +33 -0
  23. data/lib/backup/configuration/helpers.rb +130 -0
  24. data/lib/backup/configuration/store.rb +24 -0
  25. data/lib/backup/database/base.rb +53 -0
  26. data/lib/backup/database/mongodb.rb +230 -0
  27. data/lib/backup/database/mysql.rb +160 -0
  28. data/lib/backup/database/postgresql.rb +144 -0
  29. data/lib/backup/database/redis.rb +136 -0
  30. data/lib/backup/database/riak.rb +67 -0
  31. data/lib/backup/dependency.rb +108 -0
  32. data/lib/backup/encryptor/base.rb +29 -0
  33. data/lib/backup/encryptor/gpg.rb +760 -0
  34. data/lib/backup/encryptor/open_ssl.rb +72 -0
  35. data/lib/backup/errors.rb +124 -0
  36. data/lib/backup/hooks.rb +68 -0
  37. data/lib/backup/logger.rb +152 -0
  38. data/lib/backup/model.rb +409 -0
  39. data/lib/backup/notifier/base.rb +81 -0
  40. data/lib/backup/notifier/campfire.rb +155 -0
  41. data/lib/backup/notifier/hipchat.rb +93 -0
  42. data/lib/backup/notifier/mail.rb +206 -0
  43. data/lib/backup/notifier/prowl.rb +65 -0
  44. data/lib/backup/notifier/pushover.rb +88 -0
  45. data/lib/backup/notifier/twitter.rb +70 -0
  46. data/lib/backup/package.rb +47 -0
  47. data/lib/backup/packager.rb +100 -0
  48. data/lib/backup/pipeline.rb +110 -0
  49. data/lib/backup/splitter.rb +75 -0
  50. data/lib/backup/storage/base.rb +99 -0
  51. data/lib/backup/storage/cloudfiles.rb +87 -0
  52. data/lib/backup/storage/cycler.rb +117 -0
  53. data/lib/backup/storage/dropbox.rb +178 -0
  54. data/lib/backup/storage/ftp.rb +119 -0
  55. data/lib/backup/storage/local.rb +82 -0
  56. data/lib/backup/storage/ninefold.rb +116 -0
  57. data/lib/backup/storage/rsync.rb +149 -0
  58. data/lib/backup/storage/s3.rb +94 -0
  59. data/lib/backup/storage/scp.rb +99 -0
  60. data/lib/backup/storage/sftp.rb +108 -0
  61. data/lib/backup/syncer/base.rb +46 -0
  62. data/lib/backup/syncer/cloud/base.rb +247 -0
  63. data/lib/backup/syncer/cloud/cloud_files.rb +78 -0
  64. data/lib/backup/syncer/cloud/s3.rb +68 -0
  65. data/lib/backup/syncer/rsync/base.rb +49 -0
  66. data/lib/backup/syncer/rsync/local.rb +55 -0
  67. data/lib/backup/syncer/rsync/pull.rb +36 -0
  68. data/lib/backup/syncer/rsync/push.rb +116 -0
  69. data/lib/backup/template.rb +46 -0
  70. data/lib/backup/version.rb +43 -0
  71. data/spec-live/.gitignore +6 -0
  72. data/spec-live/README +7 -0
  73. data/spec-live/backups/config.rb +83 -0
  74. data/spec-live/backups/config.yml.template +46 -0
  75. data/spec-live/backups/models.rb +184 -0
  76. data/spec-live/compressor/custom_spec.rb +30 -0
  77. data/spec-live/compressor/gzip_spec.rb +30 -0
  78. data/spec-live/encryptor/gpg_keys.rb +239 -0
  79. data/spec-live/encryptor/gpg_spec.rb +287 -0
  80. data/spec-live/notifier/mail_spec.rb +121 -0
  81. data/spec-live/spec_helper.rb +151 -0
  82. data/spec-live/storage/dropbox_spec.rb +151 -0
  83. data/spec-live/storage/local_spec.rb +83 -0
  84. data/spec-live/storage/scp_spec.rb +193 -0
  85. data/spec-live/syncer/cloud/s3_spec.rb +124 -0
  86. data/spec/archive_spec.rb +335 -0
  87. data/spec/cleaner_spec.rb +312 -0
  88. data/spec/cli/helpers_spec.rb +301 -0
  89. data/spec/cli/utility_spec.rb +411 -0
  90. data/spec/compressor/base_spec.rb +52 -0
  91. data/spec/compressor/bzip2_spec.rb +217 -0
  92. data/spec/compressor/custom_spec.rb +106 -0
  93. data/spec/compressor/gzip_spec.rb +217 -0
  94. data/spec/compressor/lzma_spec.rb +123 -0
  95. data/spec/compressor/pbzip2_spec.rb +165 -0
  96. data/spec/config_spec.rb +321 -0
  97. data/spec/configuration/helpers_spec.rb +247 -0
  98. data/spec/configuration/store_spec.rb +39 -0
  99. data/spec/configuration_spec.rb +62 -0
  100. data/spec/database/base_spec.rb +63 -0
  101. data/spec/database/mongodb_spec.rb +510 -0
  102. data/spec/database/mysql_spec.rb +411 -0
  103. data/spec/database/postgresql_spec.rb +353 -0
  104. data/spec/database/redis_spec.rb +334 -0
  105. data/spec/database/riak_spec.rb +176 -0
  106. data/spec/dependency_spec.rb +51 -0
  107. data/spec/encryptor/base_spec.rb +40 -0
  108. data/spec/encryptor/gpg_spec.rb +909 -0
  109. data/spec/encryptor/open_ssl_spec.rb +148 -0
  110. data/spec/errors_spec.rb +306 -0
  111. data/spec/hooks_spec.rb +35 -0
  112. data/spec/logger_spec.rb +367 -0
  113. data/spec/model_spec.rb +694 -0
  114. data/spec/notifier/base_spec.rb +104 -0
  115. data/spec/notifier/campfire_spec.rb +217 -0
  116. data/spec/notifier/hipchat_spec.rb +211 -0
  117. data/spec/notifier/mail_spec.rb +316 -0
  118. data/spec/notifier/prowl_spec.rb +138 -0
  119. data/spec/notifier/pushover_spec.rb +123 -0
  120. data/spec/notifier/twitter_spec.rb +153 -0
  121. data/spec/package_spec.rb +61 -0
  122. data/spec/packager_spec.rb +213 -0
  123. data/spec/pipeline_spec.rb +259 -0
  124. data/spec/spec_helper.rb +60 -0
  125. data/spec/splitter_spec.rb +120 -0
  126. data/spec/storage/base_spec.rb +166 -0
  127. data/spec/storage/cloudfiles_spec.rb +254 -0
  128. data/spec/storage/cycler_spec.rb +247 -0
  129. data/spec/storage/dropbox_spec.rb +480 -0
  130. data/spec/storage/ftp_spec.rb +271 -0
  131. data/spec/storage/local_spec.rb +259 -0
  132. data/spec/storage/ninefold_spec.rb +343 -0
  133. data/spec/storage/rsync_spec.rb +362 -0
  134. data/spec/storage/s3_spec.rb +245 -0
  135. data/spec/storage/scp_spec.rb +233 -0
  136. data/spec/storage/sftp_spec.rb +244 -0
  137. data/spec/syncer/base_spec.rb +109 -0
  138. data/spec/syncer/cloud/base_spec.rb +515 -0
  139. data/spec/syncer/cloud/cloud_files_spec.rb +181 -0
  140. data/spec/syncer/cloud/s3_spec.rb +174 -0
  141. data/spec/syncer/rsync/base_spec.rb +98 -0
  142. data/spec/syncer/rsync/local_spec.rb +149 -0
  143. data/spec/syncer/rsync/pull_spec.rb +98 -0
  144. data/spec/syncer/rsync/push_spec.rb +333 -0
  145. data/spec/version_spec.rb +21 -0
  146. data/templates/cli/utility/archive +25 -0
  147. data/templates/cli/utility/compressor/bzip2 +4 -0
  148. data/templates/cli/utility/compressor/custom +11 -0
  149. data/templates/cli/utility/compressor/gzip +4 -0
  150. data/templates/cli/utility/compressor/lzma +10 -0
  151. data/templates/cli/utility/compressor/pbzip2 +10 -0
  152. data/templates/cli/utility/config +32 -0
  153. data/templates/cli/utility/database/mongodb +18 -0
  154. data/templates/cli/utility/database/mysql +21 -0
  155. data/templates/cli/utility/database/postgresql +17 -0
  156. data/templates/cli/utility/database/redis +16 -0
  157. data/templates/cli/utility/database/riak +11 -0
  158. data/templates/cli/utility/encryptor/gpg +27 -0
  159. data/templates/cli/utility/encryptor/openssl +9 -0
  160. data/templates/cli/utility/model.erb +23 -0
  161. data/templates/cli/utility/notifier/campfire +12 -0
  162. data/templates/cli/utility/notifier/hipchat +15 -0
  163. data/templates/cli/utility/notifier/mail +22 -0
  164. data/templates/cli/utility/notifier/prowl +11 -0
  165. data/templates/cli/utility/notifier/pushover +11 -0
  166. data/templates/cli/utility/notifier/twitter +13 -0
  167. data/templates/cli/utility/splitter +7 -0
  168. data/templates/cli/utility/storage/cloud_files +22 -0
  169. data/templates/cli/utility/storage/dropbox +20 -0
  170. data/templates/cli/utility/storage/ftp +12 -0
  171. data/templates/cli/utility/storage/local +7 -0
  172. data/templates/cli/utility/storage/ninefold +9 -0
  173. data/templates/cli/utility/storage/rsync +11 -0
  174. data/templates/cli/utility/storage/s3 +19 -0
  175. data/templates/cli/utility/storage/scp +11 -0
  176. data/templates/cli/utility/storage/sftp +11 -0
  177. data/templates/cli/utility/syncer/cloud_files +46 -0
  178. data/templates/cli/utility/syncer/rsync_local +12 -0
  179. data/templates/cli/utility/syncer/rsync_pull +17 -0
  180. data/templates/cli/utility/syncer/rsync_push +17 -0
  181. data/templates/cli/utility/syncer/s3 +43 -0
  182. data/templates/general/links +11 -0
  183. data/templates/general/version.erb +2 -0
  184. data/templates/notifier/mail/failure.erb +9 -0
  185. data/templates/notifier/mail/success.erb +7 -0
  186. data/templates/notifier/mail/warning.erb +9 -0
  187. data/templates/storage/dropbox/authorization_url.erb +6 -0
  188. data/templates/storage/dropbox/authorized.erb +4 -0
  189. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  190. metadata +277 -0
@@ -0,0 +1,287 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe 'Encryptor::GPG',
6
+ :if => Backup::SpecLive::CONFIG['encryptor']['gpg']['specs_enabled'] do
7
+
8
+ def archive_file_for(model)
9
+ File.join(
10
+ Backup::SpecLive::TMP_PATH,
11
+ "#{model.trigger}", model.time, "#{model.trigger}.tar.gpg"
12
+ )
13
+ end
14
+
15
+ # clear out, then load the encryptor.gpg_homedir with the keys for the
16
+ # given key_type (:public/:private) for the given identifiers.
17
+ #
18
+ def load_gpg_homedir(encryptor, key_type, identifiers)
19
+ # Clear out any files if the directory exists
20
+ dir = File.expand_path(encryptor.gpg_homedir)
21
+ FileUtils.rm(Dir[File.join(dir, '*')]) if File.exists?(dir)
22
+
23
+ # Make sure the directory exists with proper permissions.
24
+ # This will also initialize the keyring files, so this method can be
25
+ # called with no identifiers to simply reset the directory without
26
+ # importing any keys.
27
+ encryptor.send(:setup_gpg_homedir)
28
+
29
+ # Import the keys, making sure each import is successful.
30
+ # #import_key will log a warning for the identifier if the
31
+ # import fails, so we'll just abort if we get a failure here.
32
+ [identifiers].flatten.compact.each do |identifier|
33
+ ret_id = encryptor.send(:import_key,
34
+ identifier, Backup::SpecLive::GPGKeys[identifier][key_type]
35
+ )
36
+ unless ret_id == Backup::SpecLive::GPGKeys[identifier][:long_id]
37
+ abort("load_gpg_homedir failed")
38
+ end
39
+ end
40
+ end
41
+
42
+ # make sure the archive can be decrypted
43
+ def can_decrypt?(model, passphrase = nil)
44
+ enc = model.encryptor
45
+ archive = archive_file_for(model)
46
+ outfile = File.join(File.dirname(archive), 'outfile')
47
+
48
+ pass_opt = "--passphrase '#{ passphrase }'" if passphrase
49
+ enc.send(:run,
50
+ "#{ enc.send(:utility, :gpg) } #{ enc.send(:base_options) } " +
51
+ "#{ pass_opt } -o '#{ outfile }' -d '#{ archive }' 2>&1"
52
+ )
53
+
54
+ if File.exist?(outfile)
55
+ File.delete(outfile)
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ context 'using :asymmetric mode with some existing keys' do
63
+ let(:model) { h_set_trigger('encryptor_gpg_asymmetric') }
64
+
65
+ it 'should encrypt the archive' do
66
+ recipients = [:backup01, :backup02, :backup03, :backup04]
67
+ # Preload keys for backup01 and backup02.
68
+ # Keys for backup03 and backup04 are configured in :keys in the model
69
+ # and will be imported when the model is performed.
70
+ # The Model specifies all 4 as :recipients.
71
+ load_gpg_homedir(model.encryptor, :public, recipients[0..1])
72
+
73
+ model.perform!
74
+
75
+ Backup::Logger.has_warnings?.should be_false
76
+
77
+ File.exist?(archive_file_for(model)).should be_true
78
+
79
+ # make sure all 4 recipients can decrypt the archive
80
+ recipients.each do |recipient|
81
+ load_gpg_homedir(model.encryptor, :private, recipient)
82
+ can_decrypt?(model).should be_true
83
+ end
84
+ end
85
+ end # context 'using :asymmetric mode with some existing keys'
86
+
87
+ context 'using :asymmetric mode with a missing public key' do
88
+ let(:model) { h_set_trigger('encryptor_gpg_asymmetric_missing') }
89
+
90
+ # backup01 will be preloaded.
91
+ # backup02 will be imported from :keys
92
+ # backupfoo will be a missing recipient
93
+ it 'should encrypt the archive' do
94
+ load_gpg_homedir(model.encryptor, :public, :backup01)
95
+
96
+ model.perform!
97
+
98
+ Backup::Logger.has_warnings?.should be_true
99
+ Backup::Logger.messages.any? {|msg|
100
+ msg =~ /No public key was found in #keys for '<backupfoo@foo.com>'/
101
+ }.should be_true
102
+
103
+ File.exist?(archive_file_for(model)).should be_true
104
+
105
+ [:backup01, :backup02].each do |recipient|
106
+ load_gpg_homedir(model.encryptor, :private, recipient)
107
+ can_decrypt?(model).should be_true
108
+ end
109
+ end
110
+ end # context 'using :asymmetric mode with a missing public key'
111
+
112
+ context 'using :asymmetric mode with no valid public keys' do
113
+ let(:model) { h_set_trigger('encryptor_gpg_asymmetric_fail') }
114
+
115
+ it 'should abort the backup' do
116
+ model.perform!
117
+
118
+ # issues warnings about the missing keys
119
+ Backup::Logger.has_warnings?.should be_true
120
+ Backup::Logger.messages.any? {|msg|
121
+ msg =~ /No public key was found in #keys for '<backupfoo@foo.com>'/
122
+ }.should be_true
123
+ Backup::Logger.messages.any? {|msg|
124
+ msg =~ /No public key was found in #keys for '<backupfoo2@foo.com>'/
125
+ }.should be_true
126
+
127
+ # issues warning about not being able to perform asymmetric encryption
128
+ Backup::Logger.messages.any? {|msg|
129
+ msg =~ /No recipients available for asymmetric encryption/
130
+ }.should be_true
131
+
132
+ # Since there are no other options for encryption,
133
+ # the backup failes with an error.
134
+ Backup::Logger.messages.any? {|msg|
135
+ msg =~ /\[error\]\s+ModelError/
136
+ }.should be_true
137
+ Backup::Logger.messages.any? {|msg|
138
+ msg =~ /\[error\]\s+Reason: Encryptor::GPG::EncryptionError/
139
+ }.should be_true
140
+ Backup::Logger.messages.any? {|msg|
141
+ msg =~ /\[error\]\s+Encryption could not be performed for mode 'asymmetric'/
142
+ }.should be_true
143
+
144
+ # Although, any further backup models would be run, as this error
145
+ # is rescued in Backup::Model#perform
146
+ Backup::Logger.messages.any? {|msg|
147
+ msg =~ /Backup will now attempt to continue/
148
+ }.should be_true
149
+
150
+ File.exist?(archive_file_for(model)).should be_false
151
+ end
152
+ end # context 'using :asymmetric mode with no valid public keys'
153
+
154
+ context 'using :symmetric mode' do
155
+ let(:model) { h_set_trigger('encryptor_gpg_symmetric') }
156
+
157
+ it 'should encrypt the archive' do
158
+ model.perform!
159
+
160
+ Backup::Logger.has_warnings?.should be_false
161
+
162
+ File.exist?(archive_file_for(model)).should be_true
163
+
164
+ can_decrypt?(model, 'a secret').should be_true
165
+
166
+ # note that without specifying any preferences, the default
167
+ # algorithm used is CAST5
168
+ Backup::Logger.messages.any? {|msg|
169
+ msg =~ /gpg: CAST5 encrypted data/
170
+ }.should be_true
171
+ end
172
+ end # context 'using :symmetric mode'
173
+
174
+ # The #gpg_config preferences should also be able to override the algorithm
175
+ # preferences in the recipients' public keys, but the gpg output doesn't
176
+ # give us an easy way to check this. You'd have to inspect the leading bytes
177
+ # of the encrypted file per RFC4880, and I'm not going that far :)
178
+ context 'using :symmetric mode with given gpg_config' do
179
+ let(:model) { h_set_trigger('encryptor_gpg_symmetric_with_config') }
180
+
181
+ it 'should encrypt the archive using the proper algorithm preference' do
182
+ model.perform!
183
+
184
+ Backup::Logger.has_warnings?.should be_false
185
+
186
+ File.exist?(archive_file_for(model)).should be_true
187
+
188
+ can_decrypt?(model, 'a secret').should be_true
189
+
190
+ # preferences set in #gpg_config specified using AES256 before CAST5
191
+ Backup::Logger.messages.any? {|msg|
192
+ msg =~ /gpg: AES256 encrypted data/
193
+ }.should be_true
194
+ end
195
+ end # context 'using :symmetric mode with given gpg_config'
196
+
197
+ context 'using :both mode' do
198
+ let(:model) { h_set_trigger('encryptor_gpg_both') }
199
+
200
+ it 'should encrypt the archive' do
201
+ # Preload key for backup01.
202
+ # Key for backup03 will be imported when the model is performed.
203
+ load_gpg_homedir(model.encryptor, :public, :backup01)
204
+
205
+ model.perform!
206
+
207
+ Backup::Logger.has_warnings?.should be_false
208
+
209
+ File.exist?(archive_file_for(model)).should be_true
210
+
211
+ # make sure both recipients can decrypt the archive
212
+ [:backup01, :backup03].each do |recipient|
213
+ load_gpg_homedir(model.encryptor, :private, recipient)
214
+ can_decrypt?(model).should be_true
215
+ end
216
+
217
+ # with no private keys in the keyring,
218
+ # archive can be decrypted using the passphrase.
219
+ load_gpg_homedir(model.encryptor, :private, nil)
220
+ can_decrypt?(model, 'a secret').should be_true
221
+ end
222
+ end # context 'using :both mode'
223
+
224
+ context 'using :both mode with no valid asymmetric recipients' do
225
+ let(:model) { h_set_trigger('encryptor_gpg_both_no_asymmetric') }
226
+
227
+ it 'should encrypt the archive using only symmetric encryption' do
228
+ # we'll load backup02, but this isn't one of the :recipients
229
+ load_gpg_homedir(model.encryptor, :public, :backup02)
230
+
231
+ model.perform!
232
+
233
+ # issues warnings about the missing keys
234
+ Backup::Logger.has_warnings?.should be_true
235
+ Backup::Logger.messages.any? {|msg|
236
+ msg =~ /No public key was found in #keys for '16325C61'/
237
+ }.should be_true
238
+ Backup::Logger.messages.any? {|msg|
239
+ msg =~ /No public key was found in #keys for '<backup03@foo.com>'/
240
+ }.should be_true
241
+
242
+ # issues warning about not being able to perform asymmetric encryption
243
+ Backup::Logger.messages.any? {|msg|
244
+ msg =~ /No recipients available for asymmetric encryption/
245
+ }.should be_true
246
+
247
+ # backup proceeded, since symmetric encryption could still be performed
248
+ File.exist?(archive_file_for(model)).should be_true
249
+
250
+ # with no private keys in the keyring,
251
+ # archive can be decrypted using the passphrase.
252
+ load_gpg_homedir(model.encryptor, :private, nil)
253
+ can_decrypt?(model, 'a secret').should be_true
254
+ end
255
+ end # context 'using :both mode with no valid asymmetric recipients'
256
+
257
+ context 'when using the deprecated #key accessor' do
258
+ let(:model) {
259
+ # See notes in spec-live/spec_helper.rb
260
+ h_set_single_model do
261
+ Backup::Model.new(:encryptor_gpg_deprecate_key, 'test_label') do
262
+ archive :test_archive, &Backup::SpecLive::ARCHIVE_JOB
263
+ encrypt_with 'GPG' do |e|
264
+ e.key = Backup::SpecLive::GPGKeys[:backup03][:public]
265
+ end
266
+ store_with 'Local'
267
+ end
268
+ end
269
+ }
270
+
271
+ it 'should log a warning and store an encrypted archive' do
272
+ model.perform!
273
+
274
+ Backup::Logger.has_warnings?.should be_true
275
+ Backup::Logger.messages.any? {|msg|
276
+ msg =~ /GPG#key has been deprecated/
277
+ }.should be_true
278
+
279
+ File.exist?(archive_file_for(model)).should be_true
280
+
281
+ load_gpg_homedir(model.encryptor, :private, :backup03)
282
+
283
+ can_decrypt?(model).should be_true
284
+ end
285
+ end # context 'when using the deprecated #key accessor'
286
+
287
+ end
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe 'Notifier::Mail',
6
+ :if => Backup::SpecLive::CONFIG['notifier']['mail']['specs_enabled'] do
7
+ describe 'Notifier::Mail :smtp' do
8
+ let(:trigger) { 'notifier_mail' }
9
+
10
+ it 'should send a success email' do
11
+ model = h_set_trigger(trigger)
12
+ model.perform!
13
+
14
+ Backup::Logger.has_warnings?.should be_false
15
+ Backup::Logger.messages.any? {|msg| msg =~ /\[error\]/ }.should be_false
16
+ end
17
+
18
+ it 'should send a warning email' do
19
+ model = h_set_trigger(trigger)
20
+ Backup::Logger.warn 'You have been warned!'
21
+ model.perform!
22
+
23
+ Backup::Logger.has_warnings?.should be_true
24
+ Backup::Logger.messages.any? {|msg| msg =~ /\[error\]/ }.should be_false
25
+ end
26
+
27
+ it 'should send a failure email for non-fatal errors' do
28
+ model = h_set_trigger(trigger)
29
+ model.stubs(:databases).raises('A successful failure?')
30
+ model.perform!
31
+
32
+ Backup::Logger.has_warnings?.should be_false
33
+ Backup::Logger.messages.any? {|msg|
34
+ msg =~ /\[error\]\s+A successful failure/
35
+ }.should be_true
36
+ Backup::Logger.messages.any? {|msg|
37
+ msg =~ /Backup will now attempt to continue/
38
+ }.should be_true
39
+ end
40
+
41
+ it 'should send a failure email for fatal errors' do
42
+ model = h_set_trigger(trigger)
43
+ model.stubs(:databases).raises(NoMemoryError, 'with increasing frequency...')
44
+ expect do
45
+ model.perform!
46
+ end.to raise_error(SystemExit)
47
+
48
+ Backup::Logger.has_warnings?.should be_false
49
+ Backup::Logger.messages.any? {|msg|
50
+ msg =~ /with increasing frequency/
51
+ }.should be_true
52
+ Backup::Logger.messages.any? {|msg|
53
+ msg =~ /Backup will now exit/
54
+ }.should be_true
55
+ end
56
+ end # describe 'Notifier::Mail :smtp'
57
+
58
+ describe 'Notifier::Mail :file' do
59
+ let(:trigger) { 'notifier_mail_file' }
60
+ let(:test_email) { File.join(Backup::SpecLive::TMP_PATH, 'test@backup') }
61
+
62
+ it 'should send a success email' do
63
+ model = h_set_trigger(trigger)
64
+ model.perform!
65
+
66
+ Backup::Logger.has_warnings?.should be_false
67
+ Backup::Logger.messages.any? {|msg| msg =~ /\[error\]/ }.should be_false
68
+
69
+ File.exist?(test_email).should be_true
70
+ File.read(test_email).should match(/without any errors/)
71
+ end
72
+
73
+ it 'should send a warning email' do
74
+ model = h_set_trigger(trigger)
75
+ Backup::Logger.warn 'You have been warned!'
76
+ model.perform!
77
+
78
+ Backup::Logger.has_warnings?.should be_true
79
+ Backup::Logger.messages.any? {|msg| msg =~ /\[error\]/ }.should be_false
80
+
81
+ File.exist?(test_email).should be_true
82
+ File.read(test_email).should match(/You have been warned/)
83
+ end
84
+
85
+ it 'should send a failure email for non-fatal errors' do
86
+ model = h_set_trigger(trigger)
87
+ model.stubs(:databases).raises('A successful failure?')
88
+ model.perform!
89
+
90
+ Backup::Logger.has_warnings?.should be_false
91
+ Backup::Logger.messages.any? {|msg|
92
+ msg =~ /\[error\]\s+A successful failure/
93
+ }.should be_true
94
+ Backup::Logger.messages.any? {|msg|
95
+ msg =~ /Backup will now attempt to continue/
96
+ }.should be_true
97
+
98
+ File.exist?(test_email).should be_true
99
+ File.read(test_email).should match(/successful failure/)
100
+ end
101
+
102
+ it 'should send a failure email for fatal errors' do
103
+ model = h_set_trigger(trigger)
104
+ model.stubs(:databases).raises(NoMemoryError, 'with increasing frequency...')
105
+ expect do
106
+ model.perform!
107
+ end.to raise_error(SystemExit)
108
+
109
+ Backup::Logger.has_warnings?.should be_false
110
+ Backup::Logger.messages.any? {|msg|
111
+ msg =~ /with increasing frequency/
112
+ }.should be_true
113
+ Backup::Logger.messages.any? {|msg|
114
+ msg =~ /Backup will now exit/
115
+ }.should be_true
116
+
117
+ File.exist?(test_email).should be_true
118
+ File.read(test_email).should match(/with increasing frequency/)
119
+ end
120
+ end # describe 'Notifier::Mail :file'
121
+ end
@@ -0,0 +1,151 @@
1
+ # encoding: utf-8
2
+
3
+ ## # Use Bundler
4
+ require 'rubygems' if RUBY_VERSION < '1.9'
5
+ require 'bundler/setup'
6
+
7
+ ##
8
+ # Load Backup
9
+ require 'backup'
10
+
11
+ # Backup::SpecLive::GPGKeys
12
+ # Loaded here so these are available in backups/models.rb
13
+ # as well as within encryptor/gpg_spec.rb
14
+ require File.expand_path('../encryptor/gpg_keys.rb', __FILE__)
15
+
16
+ module Backup
17
+ module SpecLive
18
+ PATH = File.expand_path('..', __FILE__)
19
+ # to archive local backups, etc...
20
+ TMP_PATH = PATH + '/tmp'
21
+ SYNC_PATH = PATH + '/sync'
22
+
23
+ ARCHIVE_JOB = lambda do |archive|
24
+ archive.add File.expand_path('../../lib/backup', __FILE__)
25
+ archive.exclude File.expand_path('../../lib/backup/storage', __FILE__)
26
+ end
27
+
28
+ config = PATH + '/backups/config.yml'
29
+ if File.exist?(config)
30
+ CONFIG = YAML.load_file(config)
31
+ else
32
+ puts "The 'spec-live/backups/config.yml' file is required."
33
+ puts "Use 'spec-live/backups/config.yml.template' to create one"
34
+ exit!
35
+ end
36
+
37
+ class << self
38
+ attr_accessor :load_models
39
+ end
40
+
41
+ module ExampleHelpers
42
+
43
+ # This method loads all defaults in config.rb and all the Models
44
+ # in models.rb, then returns the Model for the given trigger.
45
+ def h_set_trigger(trigger)
46
+ Backup::SpecLive.load_models = true
47
+ Backup::Logger.clear!
48
+ Backup::Model.all.clear
49
+ Backup::Config.load_config!
50
+ model = Backup::Model.find(trigger)
51
+ model.prepare!
52
+ model
53
+ end
54
+
55
+ # This method can be used to setup a test where you need to setup
56
+ # and perform a single Model that can not be setup in models.rb.
57
+ # This is primarily for Models used to test deprecations, since
58
+ # those warnings will be output when the Model is instantiated
59
+ # and will pollute the output of all other tests.
60
+ #
61
+ # Usage:
62
+ # model = h_set_single_model do
63
+ # Backup::Model.new(:test_trigger, 'test label') do
64
+ # ...setup model...
65
+ # end
66
+ # end
67
+ #
68
+ # The block doesn't have to return the model, as it will be retrieved
69
+ # from Model.all (since it will be the only one).
70
+ #
71
+ # Remember when defining the model that the DSL constants won't be
72
+ # available, as the block is not being evaluated in the context of
73
+ # the Backup::Config module. So, just use strings instead.
74
+ # e.g. store_with 'Local' vs store_with Local
75
+ #
76
+ # Note this will still load any defaults setup in config.rb, so don't
77
+ # do anything in config.rb that would generate a deprecation warning :)
78
+ #
79
+ def h_set_single_model(&block)
80
+ Backup::SpecLive.load_models = false
81
+ Backup::Logger.clear!
82
+ Backup::Model.all.clear
83
+ Backup::Config.load_config!
84
+ block.call
85
+ model = Backup::Model.all.first
86
+ model.prepare!
87
+ model
88
+ end
89
+
90
+ def h_clean_data_paths!
91
+ paths = [:data_path, :log_path, :tmp_path ].map do |name|
92
+ Backup::Config.send(name)
93
+ end + [Backup::SpecLive::TMP_PATH]
94
+ paths.each do |path|
95
+ h_safety_check(path)
96
+ FileUtils.rm_rf(path)
97
+ FileUtils.mkdir_p(path)
98
+ end
99
+ end
100
+
101
+ def h_safety_check(path)
102
+ # Rule #1: Do No Harm.
103
+ unless (
104
+ path.start_with?(Backup::SpecLive::PATH) &&
105
+ Backup::SpecLive::PATH.end_with?('spec-live')
106
+ ) || path.include?('spec_live_test_dir')
107
+ warn "\nSafety Check Failed:\nPath: #{path}\n\n" +
108
+ caller(1).join("\n")
109
+ exit!
110
+ end
111
+ end
112
+
113
+ end # ExampleHelpers
114
+ end
115
+
116
+ Config.update(:root_path => SpecLive::PATH + '/backups')
117
+
118
+ Logger.quiet = true unless ENV['VERBOSE']
119
+ end
120
+
121
+ ##
122
+ # Use Mocha to mock with RSpec
123
+ require 'rspec'
124
+ RSpec.configure do |config|
125
+ config.mock_with :mocha
126
+ config.include Backup::SpecLive::ExampleHelpers
127
+ config.before(:each) do
128
+ h_clean_data_paths!
129
+ if ENV['VERBOSE']
130
+ /spec-live\/(.*):/ =~ self.example.metadata[:example_group][:block].inspect
131
+ puts "\n\nSPEC: #{$1}"
132
+ puts "DESC: #{self.example.metadata[:full_description]}"
133
+ puts '-' * 78
134
+ end
135
+ end
136
+ end
137
+
138
+ puts "\nRuby version: #{ RUBY_DESCRIPTION }\n"
139
+
140
+ unless ENV['VERBOSE']
141
+ puts <<-EOS
142
+
143
+ Some of these tests can be slow, so be patient.
144
+ It's recommended you run these with:
145
+ $ VERBOSE=1 rspec spec-live/
146
+ For some tests, [error] and [warning] messages are normal.
147
+ Some could pass, but still have problems.
148
+ So, pay attention to the messages :)
149
+
150
+ EOS
151
+ end