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.
Files changed (244) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +10 -0
  3. data/Gemfile +28 -0
  4. data/Gemfile.lock +130 -0
  5. data/Guardfile +21 -0
  6. data/LICENSE.md +24 -0
  7. data/README.md +476 -0
  8. data/backup_checksum.gemspec +32 -0
  9. data/bin/backup +11 -0
  10. data/lib/backup.rb +217 -0
  11. data/lib/backup/archive.rb +117 -0
  12. data/lib/backup/binder.rb +22 -0
  13. data/lib/backup/checksum/base.rb +44 -0
  14. data/lib/backup/checksum/shasum.rb +16 -0
  15. data/lib/backup/cleaner.rb +121 -0
  16. data/lib/backup/cli/helpers.rb +88 -0
  17. data/lib/backup/cli/utility.rb +247 -0
  18. data/lib/backup/compressor/base.rb +29 -0
  19. data/lib/backup/compressor/bzip2.rb +50 -0
  20. data/lib/backup/compressor/gzip.rb +47 -0
  21. data/lib/backup/compressor/lzma.rb +50 -0
  22. data/lib/backup/compressor/pbzip2.rb +56 -0
  23. data/lib/backup/config.rb +173 -0
  24. data/lib/backup/configuration/base.rb +15 -0
  25. data/lib/backup/configuration/checksum/base.rb +9 -0
  26. data/lib/backup/configuration/checksum/shasum.rb +9 -0
  27. data/lib/backup/configuration/compressor/base.rb +9 -0
  28. data/lib/backup/configuration/compressor/bzip2.rb +23 -0
  29. data/lib/backup/configuration/compressor/gzip.rb +23 -0
  30. data/lib/backup/configuration/compressor/lzma.rb +23 -0
  31. data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
  32. data/lib/backup/configuration/database/base.rb +19 -0
  33. data/lib/backup/configuration/database/mongodb.rb +49 -0
  34. data/lib/backup/configuration/database/mysql.rb +42 -0
  35. data/lib/backup/configuration/database/postgresql.rb +41 -0
  36. data/lib/backup/configuration/database/redis.rb +39 -0
  37. data/lib/backup/configuration/database/riak.rb +29 -0
  38. data/lib/backup/configuration/encryptor/base.rb +9 -0
  39. data/lib/backup/configuration/encryptor/gpg.rb +17 -0
  40. data/lib/backup/configuration/encryptor/open_ssl.rb +32 -0
  41. data/lib/backup/configuration/helpers.rb +52 -0
  42. data/lib/backup/configuration/notifier/base.rb +28 -0
  43. data/lib/backup/configuration/notifier/campfire.rb +25 -0
  44. data/lib/backup/configuration/notifier/hipchat.rb +41 -0
  45. data/lib/backup/configuration/notifier/mail.rb +112 -0
  46. data/lib/backup/configuration/notifier/presently.rb +25 -0
  47. data/lib/backup/configuration/notifier/prowl.rb +23 -0
  48. data/lib/backup/configuration/notifier/twitter.rb +21 -0
  49. data/lib/backup/configuration/storage/base.rb +18 -0
  50. data/lib/backup/configuration/storage/cloudfiles.rb +25 -0
  51. data/lib/backup/configuration/storage/dropbox.rb +58 -0
  52. data/lib/backup/configuration/storage/ftp.rb +29 -0
  53. data/lib/backup/configuration/storage/local.rb +17 -0
  54. data/lib/backup/configuration/storage/ninefold.rb +20 -0
  55. data/lib/backup/configuration/storage/rsync.rb +29 -0
  56. data/lib/backup/configuration/storage/s3.rb +25 -0
  57. data/lib/backup/configuration/storage/scp.rb +25 -0
  58. data/lib/backup/configuration/storage/sftp.rb +25 -0
  59. data/lib/backup/configuration/syncer/base.rb +10 -0
  60. data/lib/backup/configuration/syncer/cloud.rb +23 -0
  61. data/lib/backup/configuration/syncer/cloud_files.rb +30 -0
  62. data/lib/backup/configuration/syncer/rsync/base.rb +28 -0
  63. data/lib/backup/configuration/syncer/rsync/local.rb +11 -0
  64. data/lib/backup/configuration/syncer/rsync/pull.rb +11 -0
  65. data/lib/backup/configuration/syncer/rsync/push.rb +31 -0
  66. data/lib/backup/configuration/syncer/s3.rb +23 -0
  67. data/lib/backup/database/base.rb +59 -0
  68. data/lib/backup/database/mongodb.rb +232 -0
  69. data/lib/backup/database/mysql.rb +163 -0
  70. data/lib/backup/database/postgresql.rb +146 -0
  71. data/lib/backup/database/redis.rb +139 -0
  72. data/lib/backup/database/riak.rb +69 -0
  73. data/lib/backup/dependency.rb +114 -0
  74. data/lib/backup/encryptor/base.rb +29 -0
  75. data/lib/backup/encryptor/gpg.rb +80 -0
  76. data/lib/backup/encryptor/open_ssl.rb +72 -0
  77. data/lib/backup/errors.rb +124 -0
  78. data/lib/backup/logger.rb +152 -0
  79. data/lib/backup/model.rb +386 -0
  80. data/lib/backup/notifier/base.rb +81 -0
  81. data/lib/backup/notifier/campfire.rb +168 -0
  82. data/lib/backup/notifier/hipchat.rb +99 -0
  83. data/lib/backup/notifier/mail.rb +206 -0
  84. data/lib/backup/notifier/presently.rb +88 -0
  85. data/lib/backup/notifier/prowl.rb +65 -0
  86. data/lib/backup/notifier/twitter.rb +70 -0
  87. data/lib/backup/package.rb +51 -0
  88. data/lib/backup/packager.rb +108 -0
  89. data/lib/backup/pipeline.rb +107 -0
  90. data/lib/backup/splitter.rb +75 -0
  91. data/lib/backup/storage/base.rb +119 -0
  92. data/lib/backup/storage/cloudfiles.rb +87 -0
  93. data/lib/backup/storage/cycler.rb +117 -0
  94. data/lib/backup/storage/dropbox.rb +181 -0
  95. data/lib/backup/storage/ftp.rb +119 -0
  96. data/lib/backup/storage/local.rb +82 -0
  97. data/lib/backup/storage/ninefold.rb +116 -0
  98. data/lib/backup/storage/rsync.rb +149 -0
  99. data/lib/backup/storage/s3.rb +94 -0
  100. data/lib/backup/storage/scp.rb +99 -0
  101. data/lib/backup/storage/sftp.rb +108 -0
  102. data/lib/backup/syncer/base.rb +42 -0
  103. data/lib/backup/syncer/cloud.rb +190 -0
  104. data/lib/backup/syncer/cloud_files.rb +56 -0
  105. data/lib/backup/syncer/rsync/base.rb +52 -0
  106. data/lib/backup/syncer/rsync/local.rb +53 -0
  107. data/lib/backup/syncer/rsync/pull.rb +38 -0
  108. data/lib/backup/syncer/rsync/push.rb +113 -0
  109. data/lib/backup/syncer/s3.rb +47 -0
  110. data/lib/backup/template.rb +46 -0
  111. data/lib/backup/version.rb +43 -0
  112. data/spec/archive_spec.rb +335 -0
  113. data/spec/cleaner_spec.rb +304 -0
  114. data/spec/cli/helpers_spec.rb +176 -0
  115. data/spec/cli/utility_spec.rb +363 -0
  116. data/spec/compressor/base_spec.rb +31 -0
  117. data/spec/compressor/bzip2_spec.rb +83 -0
  118. data/spec/compressor/gzip_spec.rb +83 -0
  119. data/spec/compressor/lzma_spec.rb +83 -0
  120. data/spec/compressor/pbzip2_spec.rb +124 -0
  121. data/spec/config_spec.rb +321 -0
  122. data/spec/configuration/base_spec.rb +35 -0
  123. data/spec/configuration/compressor/bzip2_spec.rb +29 -0
  124. data/spec/configuration/compressor/gzip_spec.rb +29 -0
  125. data/spec/configuration/compressor/lzma_spec.rb +29 -0
  126. data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
  127. data/spec/configuration/database/base_spec.rb +17 -0
  128. data/spec/configuration/database/mongodb_spec.rb +56 -0
  129. data/spec/configuration/database/mysql_spec.rb +53 -0
  130. data/spec/configuration/database/postgresql_spec.rb +53 -0
  131. data/spec/configuration/database/redis_spec.rb +50 -0
  132. data/spec/configuration/database/riak_spec.rb +35 -0
  133. data/spec/configuration/encryptor/gpg_spec.rb +26 -0
  134. data/spec/configuration/encryptor/open_ssl_spec.rb +35 -0
  135. data/spec/configuration/notifier/base_spec.rb +32 -0
  136. data/spec/configuration/notifier/campfire_spec.rb +32 -0
  137. data/spec/configuration/notifier/hipchat_spec.rb +44 -0
  138. data/spec/configuration/notifier/mail_spec.rb +71 -0
  139. data/spec/configuration/notifier/presently_spec.rb +35 -0
  140. data/spec/configuration/notifier/prowl_spec.rb +29 -0
  141. data/spec/configuration/notifier/twitter_spec.rb +35 -0
  142. data/spec/configuration/storage/cloudfiles_spec.rb +41 -0
  143. data/spec/configuration/storage/dropbox_spec.rb +38 -0
  144. data/spec/configuration/storage/ftp_spec.rb +44 -0
  145. data/spec/configuration/storage/local_spec.rb +29 -0
  146. data/spec/configuration/storage/ninefold_spec.rb +32 -0
  147. data/spec/configuration/storage/rsync_spec.rb +41 -0
  148. data/spec/configuration/storage/s3_spec.rb +38 -0
  149. data/spec/configuration/storage/scp_spec.rb +41 -0
  150. data/spec/configuration/storage/sftp_spec.rb +41 -0
  151. data/spec/configuration/syncer/cloud_files_spec.rb +44 -0
  152. data/spec/configuration/syncer/rsync/base_spec.rb +33 -0
  153. data/spec/configuration/syncer/rsync/local_spec.rb +10 -0
  154. data/spec/configuration/syncer/rsync/pull_spec.rb +10 -0
  155. data/spec/configuration/syncer/rsync/push_spec.rb +43 -0
  156. data/spec/configuration/syncer/s3_spec.rb +38 -0
  157. data/spec/database/base_spec.rb +54 -0
  158. data/spec/database/mongodb_spec.rb +428 -0
  159. data/spec/database/mysql_spec.rb +335 -0
  160. data/spec/database/postgresql_spec.rb +278 -0
  161. data/spec/database/redis_spec.rb +260 -0
  162. data/spec/database/riak_spec.rb +108 -0
  163. data/spec/dependency_spec.rb +49 -0
  164. data/spec/encryptor/base_spec.rb +30 -0
  165. data/spec/encryptor/gpg_spec.rb +134 -0
  166. data/spec/encryptor/open_ssl_spec.rb +129 -0
  167. data/spec/errors_spec.rb +306 -0
  168. data/spec/logger_spec.rb +363 -0
  169. data/spec/model_spec.rb +649 -0
  170. data/spec/notifier/base_spec.rb +89 -0
  171. data/spec/notifier/campfire_spec.rb +199 -0
  172. data/spec/notifier/hipchat_spec.rb +188 -0
  173. data/spec/notifier/mail_spec.rb +280 -0
  174. data/spec/notifier/presently_spec.rb +181 -0
  175. data/spec/notifier/prowl_spec.rb +117 -0
  176. data/spec/notifier/twitter_spec.rb +132 -0
  177. data/spec/package_spec.rb +61 -0
  178. data/spec/packager_spec.rb +225 -0
  179. data/spec/pipeline_spec.rb +257 -0
  180. data/spec/spec_helper.rb +59 -0
  181. data/spec/splitter_spec.rb +120 -0
  182. data/spec/storage/base_spec.rb +160 -0
  183. data/spec/storage/cloudfiles_spec.rb +230 -0
  184. data/spec/storage/cycler_spec.rb +239 -0
  185. data/spec/storage/dropbox_spec.rb +370 -0
  186. data/spec/storage/ftp_spec.rb +247 -0
  187. data/spec/storage/local_spec.rb +235 -0
  188. data/spec/storage/ninefold_spec.rb +319 -0
  189. data/spec/storage/rsync_spec.rb +345 -0
  190. data/spec/storage/s3_spec.rb +221 -0
  191. data/spec/storage/scp_spec.rb +209 -0
  192. data/spec/storage/sftp_spec.rb +220 -0
  193. data/spec/syncer/base_spec.rb +22 -0
  194. data/spec/syncer/cloud_files_spec.rb +192 -0
  195. data/spec/syncer/rsync/base_spec.rb +118 -0
  196. data/spec/syncer/rsync/local_spec.rb +121 -0
  197. data/spec/syncer/rsync/pull_spec.rb +90 -0
  198. data/spec/syncer/rsync/push_spec.rb +327 -0
  199. data/spec/syncer/s3_spec.rb +192 -0
  200. data/spec/version_spec.rb +21 -0
  201. data/templates/cli/utility/archive +25 -0
  202. data/templates/cli/utility/compressor/bzip2 +7 -0
  203. data/templates/cli/utility/compressor/gzip +7 -0
  204. data/templates/cli/utility/compressor/lzma +7 -0
  205. data/templates/cli/utility/compressor/pbzip2 +7 -0
  206. data/templates/cli/utility/config +31 -0
  207. data/templates/cli/utility/database/mongodb +18 -0
  208. data/templates/cli/utility/database/mysql +21 -0
  209. data/templates/cli/utility/database/postgresql +17 -0
  210. data/templates/cli/utility/database/redis +16 -0
  211. data/templates/cli/utility/database/riak +11 -0
  212. data/templates/cli/utility/encryptor/gpg +12 -0
  213. data/templates/cli/utility/encryptor/openssl +9 -0
  214. data/templates/cli/utility/model.erb +23 -0
  215. data/templates/cli/utility/notifier/campfire +12 -0
  216. data/templates/cli/utility/notifier/hipchat +15 -0
  217. data/templates/cli/utility/notifier/mail +22 -0
  218. data/templates/cli/utility/notifier/presently +13 -0
  219. data/templates/cli/utility/notifier/prowl +11 -0
  220. data/templates/cli/utility/notifier/twitter +13 -0
  221. data/templates/cli/utility/splitter +7 -0
  222. data/templates/cli/utility/storage/cloud_files +22 -0
  223. data/templates/cli/utility/storage/dropbox +20 -0
  224. data/templates/cli/utility/storage/ftp +12 -0
  225. data/templates/cli/utility/storage/local +7 -0
  226. data/templates/cli/utility/storage/ninefold +9 -0
  227. data/templates/cli/utility/storage/rsync +11 -0
  228. data/templates/cli/utility/storage/s3 +19 -0
  229. data/templates/cli/utility/storage/scp +11 -0
  230. data/templates/cli/utility/storage/sftp +11 -0
  231. data/templates/cli/utility/syncer/cloud_files +48 -0
  232. data/templates/cli/utility/syncer/rsync_local +12 -0
  233. data/templates/cli/utility/syncer/rsync_pull +17 -0
  234. data/templates/cli/utility/syncer/rsync_push +17 -0
  235. data/templates/cli/utility/syncer/s3 +45 -0
  236. data/templates/general/links +11 -0
  237. data/templates/general/version.erb +2 -0
  238. data/templates/notifier/mail/failure.erb +9 -0
  239. data/templates/notifier/mail/success.erb +7 -0
  240. data/templates/notifier/mail/warning.erb +9 -0
  241. data/templates/storage/dropbox/authorization_url.erb +6 -0
  242. data/templates/storage/dropbox/authorized.erb +4 -0
  243. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  244. metadata +311 -0
@@ -0,0 +1,306 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../spec_helper.rb', __FILE__)
4
+
5
+ # Note: none of these tests require the use of the ErrorsHelper
6
+ describe 'Errors::Error' do
7
+ let(:klass) { Backup::Errors::Error }
8
+
9
+ it 'allow errors to cascade through the system' do
10
+ class ErrorA < klass; end
11
+ class ErrorB < klass; end
12
+ class ErrorC < klass; end
13
+ class ErrorD < klass; end
14
+
15
+ expect do
16
+ begin
17
+ begin
18
+ begin
19
+ raise ErrorA, 'an error occurred in Zone A'
20
+ rescue => err
21
+ raise ErrorB.wrap(err, <<-EOS)
22
+ an error occurred in Zone B
23
+
24
+ the following error should give a reason
25
+ EOS
26
+ end
27
+ rescue => err
28
+ raise ErrorC.wrap(err)
29
+ end
30
+ rescue => err
31
+ raise ErrorD.wrap(err, 'an error occurred in Zone D')
32
+ end
33
+ end.to raise_error(ErrorD,
34
+ "ErrorD: an error occurred in Zone D\n" +
35
+ " Reason: ErrorC\n" +
36
+ " ErrorB: an error occurred in Zone B\n" +
37
+ " \n" +
38
+ " the following error should give a reason\n" +
39
+ " Reason: ErrorA\n" +
40
+ " an error occurred in Zone A"
41
+ )
42
+ end
43
+
44
+ describe '#initialize' do
45
+
46
+ it 'creates a StandardError' do
47
+ klass.new.should be_a_kind_of StandardError
48
+ end
49
+
50
+ context 'when given a message' do
51
+
52
+ it 'formats a simple message' do
53
+ err = klass.new('error message')
54
+ err.message.should == 'Error: error message'
55
+ end
56
+
57
+ it 'formats a multi-line message' do
58
+ err = klass.new(" error message\n" +
59
+ " This is a multi-line error message.\n" +
60
+ "It should be properly indented. ")
61
+
62
+ err.message.should == "Error: error message\n" +
63
+ " This is a multi-line error message.\n" +
64
+ " It should be properly indented."
65
+ end
66
+
67
+ context 'when given an original error' do
68
+
69
+ it 'includes the original error' do
70
+ orig_err = StandardError.new('original message')
71
+ err = klass.new('error message', orig_err)
72
+ err.message.should == "Error: error message\n" +
73
+ " Reason: StandardError\n" +
74
+ " original message"
75
+ end
76
+
77
+ it 'formats all messages' do
78
+ orig_err = StandardError.new(" original message\n" +
79
+ " This is a multi-line error message.\n" +
80
+ "It should be properly indented.")
81
+ err = klass.new(" error message\n" +
82
+ " This is a multi-line error message.\n" +
83
+ "It should be properly indented. ", orig_err)
84
+
85
+ err.message.should == "Error: error message\n" +
86
+ " This is a multi-line error message.\n" +
87
+ " It should be properly indented.\n" +
88
+ " Reason: StandardError\n" +
89
+ " original message\n" +
90
+ " This is a multi-line error message.\n" +
91
+ " It should be properly indented."
92
+ end
93
+
94
+ it 'uses the original error backtrace' do
95
+ begin
96
+ raise StandardError.new
97
+ rescue => err
98
+ klass.new(nil, err).backtrace.
99
+ should == err.backtrace
100
+ end
101
+ end
102
+
103
+ it 'reports if original error had no message' do
104
+ orig_err = StandardError.new
105
+ err = klass.new('error message', orig_err)
106
+ err.message.should == "Error: error message\n" +
107
+ " Reason: StandardError (no message given)"
108
+ end
109
+
110
+ end # context 'when given an original error'
111
+
112
+ context 'when given an original Errors::Error' do
113
+ let(:subklass) do
114
+ class SubKlass < klass; end
115
+ SubKlass
116
+ end
117
+
118
+ it 'includes the original error' do
119
+ orig_err = subklass.new('original message')
120
+ err = klass.new('error message', orig_err)
121
+ err.message.should == "Error: error message\n" +
122
+ " Reason: SubKlass\n" +
123
+ " original message"
124
+ end
125
+
126
+ it 'formats all messages' do
127
+ orig_err = subklass.new(" original message\n" +
128
+ " This is a multi-line error message.\n" +
129
+ "It should be properly indented.")
130
+ err = klass.new(" error message\n" +
131
+ " This is a multi-line error message.\n" +
132
+ "It should be properly indented. ", orig_err)
133
+
134
+ err.message.should == "Error: error message\n" +
135
+ " This is a multi-line error message.\n" +
136
+ " It should be properly indented.\n" +
137
+ " Reason: SubKlass\n" +
138
+ " original message\n" +
139
+ " This is a multi-line error message.\n" +
140
+ " It should be properly indented."
141
+ end
142
+
143
+ it 'uses the original error backtrace' do
144
+ begin
145
+ raise subklass.new
146
+ rescue => err
147
+ klass.new(nil, err).backtrace.
148
+ should == err.backtrace
149
+ end
150
+ end
151
+
152
+ it 'reports if original error had no message' do
153
+ orig_err = subklass.new
154
+ err = klass.new('error message', orig_err)
155
+ err.message.should == "Error: error message\n" +
156
+ " Reason: SubKlass (no message given)"
157
+ end
158
+
159
+ end # context 'when given an original Errors::Error'
160
+
161
+ end # context 'when given a message'
162
+
163
+ context 'when given no message' do
164
+
165
+ it 'strips the module namespace from the default message' do
166
+ err = klass.new
167
+ err.message.should == 'Error'
168
+ end
169
+
170
+ context 'when given an original error' do
171
+
172
+ it 'uses the original error message' do
173
+ orig_err = StandardError.new
174
+ err = klass.new(nil, orig_err)
175
+ err.message.should == 'Error: StandardError'
176
+
177
+ orig_err = StandardError.new('original message')
178
+ err = klass.new(nil, orig_err)
179
+ err.message.should == 'Error: StandardError: original message'
180
+
181
+ orig_err = StandardError.new(" original message\n" +
182
+ " This is a multi-line error message.\n" +
183
+ "It should be properly indented.")
184
+ err = klass.new(nil, orig_err)
185
+ err.message.should == "Error: StandardError: original message\n" +
186
+ " This is a multi-line error message.\n" +
187
+ " It should be properly indented."
188
+ end
189
+
190
+ end # context 'when given an original error'
191
+
192
+ context 'when given an original Errors::Error' do
193
+ let(:subklass) do
194
+ class SubKlass < klass; end
195
+ SubKlass
196
+ end
197
+
198
+ it 'uses the original error message' do
199
+ orig_err = subklass.new
200
+ err = klass.new(nil, orig_err)
201
+ err.message.should == 'Error: SubKlass'
202
+
203
+ orig_err = subklass.new('original message')
204
+ err = klass.new(nil, orig_err)
205
+ err.message.should == 'Error: SubKlass: original message'
206
+
207
+ orig_err = subklass.new(" original message\n" +
208
+ " This is a multi-line error message.\n" +
209
+ "It should be properly indented.")
210
+ err = klass.new(nil, orig_err)
211
+ err.message.should == "Error: SubKlass: original message\n" +
212
+ " This is a multi-line error message.\n" +
213
+ " It should be properly indented."
214
+ end
215
+
216
+ end # context 'when given an original Errors::Error'
217
+
218
+ end # context 'when given no message'
219
+
220
+ end # describe '#initialize'
221
+
222
+ describe '#wrap' do
223
+ describe 'swaps the parameters to provide a cleaner way to' do
224
+
225
+ it 'raise a wrapped error with a message' do
226
+ orig_err = StandardError.new <<-EOS
227
+ original message
228
+ This is a multi-line error message.
229
+ It should be properly indented.
230
+ EOS
231
+
232
+ expect do
233
+ raise klass.wrap(orig_err), <<-EOS
234
+ error message
235
+ This is a multi-line error message.
236
+ It should be properly indented.
237
+ EOS
238
+ end.to raise_error(klass,
239
+ "Error: error message\n" +
240
+ " This is a multi-line error message.\n" +
241
+ " It should be properly indented.\n" +
242
+ " Reason: StandardError\n" +
243
+ " original message\n" +
244
+ " This is a multi-line error message.\n" +
245
+ " It should be properly indented."
246
+ )
247
+ end
248
+
249
+ it 'return a wrapped error with a message' do
250
+ orig_err = StandardError.new <<-EOS
251
+ original message
252
+ This is a multi-line error message.
253
+ It should be properly indented.
254
+ EOS
255
+
256
+ err = klass.wrap(orig_err, <<-EOS)
257
+ error message
258
+ This will wrap the original error
259
+ and it's message will be given below
260
+ EOS
261
+
262
+ err.message.should ==
263
+ "Error: error message\n" +
264
+ " This will wrap the original error\n" +
265
+ " and it's message will be given below\n" +
266
+ " Reason: StandardError\n" +
267
+ " original message\n" +
268
+ " This is a multi-line error message.\n" +
269
+ " It should be properly indented."
270
+ end
271
+
272
+ end # describe 'swaps the parameters to provide a cleaner way to'
273
+ end # describe '#wrap'
274
+
275
+ end # describe 'Errors::Error'
276
+
277
+ describe 'ErrorHelper' do
278
+ let(:base) { Backup::Errors }
279
+
280
+ it 'dynamically creates namespaces and subclasses of Errors::Error' do
281
+ Backup::Errors::FooBarError.new.
282
+ should be_a_kind_of base::Error
283
+ Backup::Errors::Foo::Bar::Error.new.
284
+ should be_a_kind_of base::Error
285
+ end
286
+
287
+ context 'new error classes created within new namespaces' do
288
+ it 'retain the added portion of namespace in their messages' do
289
+ orig_err = StandardError.new('original message')
290
+ err = base::FooMod::FooError.new('error message', orig_err)
291
+ err.message.should ==
292
+ "FooMod::FooError: error message\n" +
293
+ " Reason: StandardError\n" +
294
+ " original message"
295
+
296
+ err2 = base::Foo::Bar::Mod::FooBarError.wrap(err, 'foobar message')
297
+ err2.message.should ==
298
+ "Foo::Bar::Mod::FooBarError: foobar message\n" +
299
+ " Reason: FooMod::FooError\n" +
300
+ " error message\n" +
301
+ " Reason: StandardError\n" +
302
+ " original message"
303
+ end
304
+ end
305
+
306
+ end # describe ErrorHelper
@@ -0,0 +1,363 @@
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') }.to
78
+ 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
+ it 'should truncate the file, removing older lines' do
185
+ max_bytes = 5_000
186
+ line_len = 120
187
+ Dir.mktmpdir do |dir|
188
+ Backup::Config.update(:root_path => dir)
189
+ FileUtils.mkdir_p(Backup::Config.log_path)
190
+ log_file = File.join(Backup::Config.log_path, 'backup.log')
191
+
192
+ lineno = 0
193
+ over_max = (max_bytes * 1.25).to_i
194
+ File.open(log_file, 'w') do |f|
195
+ until f.pos > over_max
196
+ f.puts "#{ lineno += 1 }: ".ljust(line_len, 'x')
197
+ end
198
+ end
199
+ File.stat(log_file).size.
200
+ should be_within(line_len + 2).of(over_max)
201
+
202
+ subject.truncate!(max_bytes)
203
+
204
+ File.stat(log_file).size.
205
+ should be_within(line_len + 2).of(max_bytes)
206
+
207
+ File.readlines(log_file).last.chomp.
208
+ should == "#{ lineno }: ".ljust(line_len, 'x')
209
+
210
+ File.exist?(log_file + '~').should be_false
211
+ end
212
+ end
213
+ end
214
+
215
+ end # describe '#truncate!'
216
+
217
+ describe '#loggify' do
218
+
219
+ it 'returns an array of strings split on newline separators' do
220
+ str_aa = "first line\nsecond line"
221
+ str_ab = "first line\nsecond line\n"
222
+ expected_a = ["[#{logger_time}][msg_type] first line",
223
+ "[#{logger_time}][msg_type] second line"]
224
+
225
+ str_b = 'string with no newline'
226
+ expected_b = ["[#{logger_time}][msg_type] string with no newline"]
227
+
228
+ subject.send(:loggify, str_aa, :msg_type).should == expected_a
229
+ subject.send(:loggify, str_ab, :msg_type).should == expected_a
230
+ subject.send(:loggify, str_b, :msg_type).should == expected_b
231
+ end
232
+
233
+ it 'formats a string with color if color is given' do
234
+ green_type = ["[#{logger_time}][#{"\e[32mmsg_type\e[0m"}] foo"]
235
+ yellow_type = ["[#{logger_time}][#{"\e[33mmsg_type\e[0m"}] foo"]
236
+ red_type = ["[#{logger_time}][#{"\e[31mmsg_type\e[0m"}] foo"]
237
+
238
+ subject.send(:loggify, 'foo', :msg_type, :green ).should == green_type
239
+ subject.send(:loggify, 'foo', :msg_type, :yellow).should == yellow_type
240
+ subject.send(:loggify, 'foo', :msg_type, :red ).should == red_type
241
+ end
242
+
243
+ it 'does not colorize if no color given' do
244
+ no_color = ["[#{logger_time}][msg_type] foo"]
245
+ subject.send(:loggify, 'foo', :msg_type).should == no_color
246
+ end
247
+
248
+ it 'accepts blank lines in the message' do
249
+ str = "first line\n\nthird line"
250
+ expected = ["[#{logger_time}][msg_type] first line",
251
+ "[#{logger_time}][msg_type] ",
252
+ "[#{logger_time}][msg_type] third line"]
253
+
254
+ subject.send(:loggify, str, :msg_type).should == expected
255
+ end
256
+
257
+ it 'accepts an object responding to #to_s for the message' do
258
+ obj = StandardError.new("first line\nsecond line")
259
+ expected = ["[#{logger_time}][msg_type] first line",
260
+ "[#{logger_time}][msg_type] second line"]
261
+
262
+ subject.send(:loggify, obj, :msg_type).should == expected
263
+ end
264
+
265
+ it 'returns an unformatted lines if type is not given' do
266
+ str_a = 'single line'
267
+ str_b = "first line\n\nthird line"
268
+ expected_a = ['single line']
269
+ expected_b = ['first line', '', 'third line']
270
+
271
+ subject.send(:loggify, str_a).should == expected_a
272
+ subject.send(:loggify, str_b).should == expected_b
273
+ end
274
+
275
+ end # describe '#loggify'
276
+
277
+ describe '#to_console' do
278
+
279
+ context 'when +stderr+ is not set (false)' do
280
+ it 'writes an array of strings to stdout' do
281
+ lines = [ 'line one', 'line two', 'line three']
282
+ lines.each {|line| subject.expects(:puts).with(line).in_sequence(s) }
283
+ subject.send(:to_console, lines)
284
+ end
285
+ end
286
+
287
+ context 'when +stderr+ is set (true)' do
288
+ it 'writes an array of strings to stdout' do
289
+ lines = [ 'line one', 'line two', 'line three']
290
+ lines.each {|line| Kernel.expects(:warn).with(line).in_sequence(s) }
291
+ subject.send(:to_console, lines, true)
292
+ end
293
+ end
294
+
295
+ it 'returns nil if quiet? is true' do
296
+ subject.quiet = true
297
+ subject.expects(:puts).never
298
+ subject.send(:to_console, 'a string')
299
+ end
300
+
301
+ end # describe '#to_console'
302
+
303
+ describe '#to_file' do
304
+
305
+ it 'writes an array of strings to the log file' do
306
+ lines = ['line one', 'line two', 'line three']
307
+ File.stubs(:open).yields(logfile_mock)
308
+ lines.each {|line| logfile_mock.expects(:puts).with(line).in_sequence(s) }
309
+ subject.send(:to_file, lines)
310
+ end
311
+
312
+ it 'appends each line written to #messages' do
313
+ lines = ['line one', 'line two', 'line three']
314
+ File.stubs(:open)
315
+ a_mock = mock
316
+ subject.expects(:messages).returns(a_mock)
317
+ a_mock.expects(:push).with('line one', 'line two', 'line three')
318
+ subject.send(:to_file, lines)
319
+ end
320
+
321
+ it 'only opens the log file once to append multiple lines' do
322
+ lines = ['line one', 'line two', 'line three']
323
+ File.expects(:open).once.with(logfile_path, 'a').yields(logfile_mock)
324
+ logfile_mock.expects(:puts).times(3)
325
+ subject.send(:to_file, lines)
326
+ end
327
+
328
+ end # describe '#to_file'
329
+
330
+ describe 'color methods' do
331
+
332
+ it 'color methods send strings to #colorize with color codes' do
333
+ colors = [ [:green, 32], [:yellow, 33], [:red, 31] ]
334
+ colors.each do |color, code|
335
+ subject.expects(:colorize).with('foo', code).in_sequence(s)
336
+ end
337
+ colors.each {|color, code| subject.send(color, 'foo') }
338
+ end
339
+
340
+ it '#colorize adds the code to the string' do
341
+ [32, 33, 31].each do |code|
342
+ subject.send(:colorize, 'foo', code).
343
+ should == "\e[#{code}mfoo\e[0m"
344
+ end
345
+ end
346
+
347
+ end # color methods
348
+
349
+ describe '#quiet' do
350
+ it 'should be nil by default' do
351
+ # of course, 'before' is setting it to nil ;)
352
+ subject.quiet.should be_nil
353
+ end
354
+
355
+ it 'can be set true/false' do
356
+ subject.quiet = true
357
+ subject.quiet.should be_true
358
+ subject.quiet = false
359
+ subject.quiet.should be_false
360
+ end
361
+ end
362
+
363
+ end