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,649 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../spec_helper.rb', __FILE__)
4
+
5
+ describe 'Backup::Model' do
6
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
7
+ let(:s) { sequence '' }
8
+
9
+ before do
10
+ Backup::Model.all.clear
11
+ end
12
+
13
+ describe '.all' do
14
+ it 'should be an empty array by default' do
15
+ Backup::Model.all.should == []
16
+ end
17
+ end
18
+
19
+ describe 'finder methods' do
20
+ before do
21
+ [:a, :b, :c, :b, :d].each_with_index do |sym, i|
22
+ Backup::Model.new("trigger_#{sym}", "label#{i}")
23
+ end
24
+ end
25
+
26
+ describe '.find' do
27
+ it 'should return the first matching model' do
28
+ Backup::Model.find('trigger_b').label.should == 'label1'
29
+ end
30
+
31
+ it 'should accept symbols' do
32
+ Backup::Model.find(:trigger_b).label.should == 'label1'
33
+ end
34
+
35
+ it 'should raise an error if trigger is not found' do
36
+ expect do
37
+ Backup::Model.find(:f)
38
+ end.to raise_error(
39
+ Backup::Errors::Model::MissingTriggerError,
40
+ "Model::MissingTriggerError: Could not find trigger 'f'."
41
+ )
42
+ end
43
+ end
44
+
45
+ describe '.find_matching' do
46
+ it 'should find all triggers matching a wildcard' do
47
+ Backup::Model.find_matching('tri*_b').count.should be(2)
48
+ Backup::Model.find_matching('trigg*').count.should be(5)
49
+ end
50
+
51
+ it 'should return an empty array if no matches are found' do
52
+ Backup::Model.find_matching('foo*').should == []
53
+ end
54
+ end
55
+
56
+ end # describe 'finder methods'
57
+
58
+ describe '#initialize' do
59
+
60
+ it 'should convert trigger to a string' do
61
+ Backup::Model.new(:foo, :bar).trigger.should == 'foo'
62
+ end
63
+
64
+ it 'should convert label to a string' do
65
+ Backup::Model.new(:foo, :bar).label.should == 'bar'
66
+ end
67
+
68
+ it 'should set all procedure variables to an empty array' do
69
+ model.send(:procedure_instance_variables).each do |var|
70
+ model.instance_variable_get(var).should == []
71
+ end
72
+ end
73
+
74
+ it 'should accept and instance_eval a block' do
75
+ block = lambda {|model| throw(:instance, model) }
76
+ caught = catch(:instance) do
77
+ Backup::Model.new('gotcha', '', &block)
78
+ end
79
+ caught.trigger.should == 'gotcha'
80
+ end
81
+
82
+ it 'should add itself to Model.all' do
83
+ Backup::Model.all.should == [model]
84
+ end
85
+
86
+ end # describe '#initialize'
87
+
88
+ describe 'DSL Methods' do
89
+
90
+ module Fake
91
+ module NoArg
92
+ class Base
93
+ attr_accessor :block_arg
94
+ def initialize(&block)
95
+ instance_eval(&block) if block_given?
96
+ end
97
+ end
98
+ end
99
+ module OneArg
100
+ class Base
101
+ attr_accessor :arg1, :block_arg
102
+ def initialize(arg1, &block)
103
+ @arg1 = arg1
104
+ instance_eval(&block) if block_given?
105
+ end
106
+ end
107
+ end
108
+ module TwoArgs
109
+ class Base
110
+ attr_accessor :arg1, :arg2, :block_arg
111
+ def initialize(arg1, arg2, &block)
112
+ @arg1 = arg1
113
+ @arg2 = arg2
114
+ instance_eval(&block) if block_given?
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ # Set +const+ to +replacement+ for the calling block
121
+ def using_fake(const, replacement)
122
+ orig = Backup.const_get(const)
123
+ Backup.send(:remove_const, const)
124
+ Backup.const_set(const, replacement)
125
+ yield
126
+ Backup.send(:remove_const, const)
127
+ Backup.const_set(const, orig)
128
+ end
129
+
130
+ describe '#archive' do
131
+ it 'should add archives' do
132
+ using_fake('Archive', Fake::TwoArgs::Base) do
133
+ model.archive('foo') {|a| a.block_arg = :foo }
134
+ model.archive('bar') {|a| a.block_arg = :bar }
135
+ model.archives.count.should == 2
136
+ a1, a2 = model.archives
137
+ a1.arg1.should be(model)
138
+ a1.arg2.should == 'foo'
139
+ a1.block_arg.should == :foo
140
+ a2.arg1.should be(model)
141
+ a2.arg2.should == 'bar'
142
+ a2.block_arg.should == :bar
143
+ end
144
+ end
145
+ end
146
+
147
+ describe '#database' do
148
+ it 'should add databases' do
149
+ using_fake('Database', Fake::OneArg) do
150
+ model.database('Base') {|a| a.block_arg = :foo }
151
+ model.database('Base') {|a| a.block_arg = :bar }
152
+ model.databases.count.should be(2)
153
+ d1, d2 = model.databases
154
+ d1.arg1.should be(model)
155
+ d1.block_arg.should == :foo
156
+ d2.arg1.should be(model)
157
+ d2.block_arg.should == :bar
158
+ end
159
+ end
160
+
161
+ it 'should accept a nested class name' do
162
+ using_fake('Database', Fake) do
163
+ model.database('OneArg::Base')
164
+ model.databases.first.should be_an_instance_of Fake::OneArg::Base
165
+ end
166
+ end
167
+ end
168
+
169
+ describe '#store_with' do
170
+ it 'should add storages' do
171
+ using_fake('Storage', Fake::TwoArgs) do
172
+ model.store_with('Base', 'foo') {|a| a.block_arg = :foo }
173
+ model.store_with('Base', 'bar') {|a| a.block_arg = :bar }
174
+ model.storages.count.should be(2)
175
+ s1, s2 = model.storages
176
+ s1.arg1.should be(model)
177
+ s1.arg2.should == 'foo'
178
+ s1.block_arg.should == :foo
179
+ s2.arg1.should be(model)
180
+ s2.arg2.should == 'bar'
181
+ s2.block_arg.should == :bar
182
+ end
183
+ end
184
+
185
+ it 'should accept a nested class name' do
186
+ using_fake('Storage', Fake) do
187
+ model.store_with('TwoArgs::Base')
188
+ model.storages.first.should be_an_instance_of Fake::TwoArgs::Base
189
+ end
190
+ end
191
+ end
192
+
193
+ describe '#sync_with' do
194
+ it 'should add syncers' do
195
+ using_fake('Syncer', Fake::NoArg) do
196
+ model.sync_with('Base') {|a| a.block_arg = :foo }
197
+ model.sync_with('Base') {|a| a.block_arg = :bar }
198
+ model.syncers.count.should be(2)
199
+ s1, s2 = model.syncers
200
+ s1.block_arg.should == :foo
201
+ s2.block_arg.should == :bar
202
+ end
203
+ end
204
+
205
+ it 'should accept a nested class name' do
206
+ using_fake('Syncer', Fake) do
207
+ model.sync_with('NoArg::Base')
208
+ model.syncers.first.should be_an_instance_of Fake::NoArg::Base
209
+ end
210
+ end
211
+
212
+ it 'should warn user of change from RSync to RSync::Local' do
213
+ Backup::Logger.expects(:warn)
214
+ model.sync_with('Backup::Config::RSync')
215
+ model.syncers.first.should be_an_instance_of Backup::Syncer::RSync::Local
216
+ end
217
+ end
218
+
219
+ describe '#notify_by' do
220
+ it 'should add notifiers' do
221
+ using_fake('Notifier', Fake::OneArg) do
222
+ model.notify_by('Base') {|a| a.block_arg = :foo }
223
+ model.notify_by('Base') {|a| a.block_arg = :bar }
224
+ model.notifiers.count.should be(2)
225
+ n1, n2 = model.notifiers
226
+ n1.arg1.should be(model)
227
+ n1.block_arg.should == :foo
228
+ n2.arg1.should be(model)
229
+ n2.block_arg.should == :bar
230
+ end
231
+ end
232
+
233
+ it 'should accept a nested class name' do
234
+ using_fake('Notifier', Fake) do
235
+ model.notify_by('OneArg::Base')
236
+ model.notifiers.first.should be_an_instance_of Fake::OneArg::Base
237
+ end
238
+ end
239
+ end
240
+
241
+ describe '#encrypt_with' do
242
+ it 'should add an encryptor' do
243
+ using_fake('Encryptor', Fake::NoArg) do
244
+ model.encrypt_with('Base') {|a| a.block_arg = :foo }
245
+ model.encryptor.should be_an_instance_of Fake::NoArg::Base
246
+ model.encryptor.block_arg.should == :foo
247
+ end
248
+ end
249
+
250
+ it 'should accept a nested class name' do
251
+ using_fake('Encryptor', Fake) do
252
+ model.encrypt_with('NoArg::Base')
253
+ model.encryptor.should be_an_instance_of Fake::NoArg::Base
254
+ end
255
+ end
256
+ end
257
+
258
+ describe '#compress_with' do
259
+ it 'should add a compressor' do
260
+ using_fake('Compressor', Fake::NoArg) do
261
+ model.compress_with('Base') {|a| a.block_arg = :foo }
262
+ model.compressor.should be_an_instance_of Fake::NoArg::Base
263
+ model.compressor.block_arg.should == :foo
264
+ end
265
+ end
266
+
267
+ it 'should accept a nested class name' do
268
+ using_fake('Compressor', Fake) do
269
+ model.compress_with('NoArg::Base')
270
+ model.compressor.should be_an_instance_of Fake::NoArg::Base
271
+ end
272
+ end
273
+ end
274
+
275
+ describe '#split_into_chunks_of' do
276
+ it 'should add a splitter' do
277
+ using_fake('Splitter', Fake::TwoArgs::Base) do
278
+ model.split_into_chunks_of(123)
279
+ model.splitter.should be_an_instance_of Fake::TwoArgs::Base
280
+ model.splitter.arg1.should be(model)
281
+ model.splitter.arg2.should == 123
282
+ end
283
+ end
284
+
285
+ it 'should raise an error if chunk_size is not an Integer' do
286
+ expect do
287
+ model.split_into_chunks_of('345')
288
+ end.to raise_error {|err|
289
+ err.should be_an_instance_of Backup::Errors::Model::ConfigurationError
290
+ err.message.should match(/must be an Integer/)
291
+ }
292
+ end
293
+ end
294
+
295
+ end # describe 'DSL Methods'
296
+
297
+ describe '#prepare!' do
298
+ it 'should prepare for the backup' do
299
+ FileUtils.expects(:mkdir_p).with(
300
+ File.join(Backup::Config.data_path, 'test_trigger')
301
+ )
302
+ Backup::Cleaner.expects(:prepare).with(model)
303
+
304
+ model.prepare!
305
+ end
306
+ end
307
+
308
+ describe '#perform!' do
309
+ let(:procedure_a) { lambda {} }
310
+ let(:procedure_b) { mock }
311
+ let(:procedure_c) { mock }
312
+ let(:procedure_d) { lambda {} }
313
+ let(:procedure_e) { lambda {} }
314
+ let(:procedure_f) { mock }
315
+ let(:procedures) do
316
+ [ procedure_a, [procedure_b, procedure_c],
317
+ procedure_d, procedure_e, [procedure_f] ]
318
+ end
319
+ let(:syncer_a) { mock }
320
+ let(:syncer_b) { mock }
321
+ let(:syncers) { [syncer_a, syncer_b] }
322
+ let(:notifier_a) { mock }
323
+ let(:notifier_b) { mock }
324
+ let(:notifiers) { [notifier_a, notifier_b] }
325
+
326
+ it 'should set the @time and @started_at variables' do
327
+ Timecop.freeze(Time.now)
328
+ started_at = Time.now
329
+ time = started_at.strftime("%Y.%m.%d.%H.%M.%S")
330
+
331
+ model.perform!
332
+ model.time.should == time
333
+ model.instance_variable_get(:@started_at).should == started_at
334
+ end
335
+
336
+ context 'when no errors occur' do
337
+ before do
338
+ model.expects(:procedures).returns(procedures)
339
+ model.expects(:syncers).returns(syncers)
340
+ model.expects(:notifiers).returns(notifiers)
341
+ end
342
+
343
+ context 'when databases are configured' do
344
+ before do
345
+ model.instance_variable_set(:@databases, [true])
346
+ end
347
+
348
+ it 'should perform all procedures' do
349
+ model.expects(:log!).in_sequence(s).with(:started)
350
+
351
+ procedure_a.expects(:call).in_sequence(s)
352
+ procedure_b.expects(:perform!).in_sequence(s)
353
+ procedure_c.expects(:perform!).in_sequence(s)
354
+ procedure_d.expects(:call).in_sequence(s)
355
+ procedure_e.expects(:call).in_sequence(s)
356
+ procedure_f.expects(:perform!).in_sequence(s)
357
+
358
+ syncer_a.expects(:perform!).in_sequence(s)
359
+ syncer_b.expects(:perform!).in_sequence(s)
360
+
361
+ notifier_a.expects(:perform!).in_sequence(s)
362
+ notifier_b.expects(:perform!).in_sequence(s)
363
+
364
+ model.expects(:log!).in_sequence(s).with(:finished)
365
+
366
+ model.perform!
367
+ end
368
+ end
369
+
370
+ context 'when archives are configured' do
371
+ before do
372
+ model.instance_variable_set(:@archives, [true])
373
+ end
374
+
375
+ it 'should perform all procedures' do
376
+ model.expects(:log!).in_sequence(s).with(:started)
377
+
378
+ procedure_a.expects(:call).in_sequence(s)
379
+ procedure_b.expects(:perform!).in_sequence(s)
380
+ procedure_c.expects(:perform!).in_sequence(s)
381
+ procedure_d.expects(:call).in_sequence(s)
382
+ procedure_e.expects(:call).in_sequence(s)
383
+ procedure_f.expects(:perform!).in_sequence(s)
384
+
385
+ syncer_a.expects(:perform!).in_sequence(s)
386
+ syncer_b.expects(:perform!).in_sequence(s)
387
+
388
+ notifier_a.expects(:perform!).in_sequence(s)
389
+ notifier_b.expects(:perform!).in_sequence(s)
390
+
391
+ model.expects(:log!).in_sequence(s).with(:finished)
392
+
393
+ model.perform!
394
+ end
395
+ end
396
+
397
+ end # context 'when no errors occur'
398
+
399
+ # for the purposes of testing the error handling, we're just going to
400
+ # stub the first thing this method calls and raise an error
401
+ context 'when errors occur' do
402
+ let(:error_a) { mock }
403
+ let(:error_b) { mock }
404
+ let(:notifier) { mock }
405
+
406
+ before do
407
+ error_a.stubs(:backtrace).returns(['many', 'backtrace', 'lines'])
408
+ end
409
+
410
+ it 'logs, notifies and continues if a StandardError is rescued' do
411
+ Time.stubs(:now).raises(StandardError, 'non-fatal error')
412
+
413
+ Backup::Errors::ModelError.expects(:wrap).in_sequence(s).with do |err, msg|
414
+ err.message.should == 'non-fatal error'
415
+ msg.should match(/Backup for test label \(test_trigger\) Failed!/)
416
+ end.returns(error_a)
417
+ Backup::Logger.expects(:error).in_sequence(s).with(error_a)
418
+ Backup::Logger.expects(:error).in_sequence(s).with(
419
+ "\nBacktrace:\n\s\smany\n\s\sbacktrace\n\s\slines\n\n"
420
+ )
421
+
422
+ Backup::Cleaner.expects(:warnings).in_sequence(s).with(model)
423
+
424
+ Backup::Errors::ModelError.expects(:new).in_sequence(s).with do |msg|
425
+ msg.should match(/Backup will now attempt to continue/)
426
+ end.returns(error_b)
427
+ Backup::Logger.expects(:message).in_sequence(s).with(error_b)
428
+
429
+ # notifiers called, but any Exception is ignored
430
+ notifier.expects(:perform!).with(true).raises(Exception)
431
+ model.expects(:notifiers).returns([notifier])
432
+
433
+ # returns to allow next trigger to run
434
+ expect { model.perform! }.not_to raise_error
435
+ end
436
+
437
+ it 'logs, notifies and exits if an Exception is rescued' do
438
+ Time.stubs(:now).raises(Exception, 'fatal error')
439
+
440
+ Backup::Errors::ModelError.expects(:wrap).in_sequence(s).with do |err, msg|
441
+ err.message.should == 'fatal error'
442
+ msg.should match(/Backup for test label \(test_trigger\) Failed!/)
443
+ end.returns(error_a)
444
+ Backup::Logger.expects(:error).in_sequence(s).with(error_a)
445
+ Backup::Logger.expects(:error).in_sequence(s).with(
446
+ "\nBacktrace:\n\s\smany\n\s\sbacktrace\n\s\slines\n\n"
447
+ )
448
+
449
+ Backup::Cleaner.expects(:warnings).in_sequence(s).with(model)
450
+
451
+ Backup::Errors::ModelError.expects(:new).in_sequence(s).with do |msg|
452
+ msg.should match(/Backup will now exit/)
453
+ end.returns(error_b)
454
+ Backup::Logger.expects(:error).in_sequence(s).with(error_b)
455
+
456
+ expect do
457
+ # notifiers called, but any Exception is ignored
458
+ notifier = mock
459
+ notifier.expects(:perform!).with(true).raises(Exception)
460
+ model.expects(:notifiers).returns([notifier])
461
+ end.not_to raise_error
462
+
463
+ expect do
464
+ model.perform!
465
+ end.to raise_error(SystemExit) {|exit| exit.status.should be(1) }
466
+ end
467
+
468
+ end # context 'when errors occur'
469
+
470
+ end # describe '#perform!'
471
+
472
+ describe '#package!' do
473
+ it 'should package the backup' do
474
+ Backup::Packager.expects(:package!).in_sequence(s).with(model)
475
+ Backup::Cleaner.expects(:remove_packaging).in_sequence(s).with(model)
476
+
477
+ model.send(:package!)
478
+ model.package.should be_an_instance_of Backup::Package
479
+ end
480
+ end
481
+
482
+ describe '#clean' do
483
+ it 'should remove the final packaged files' do
484
+ package = mock
485
+ model.instance_variable_set(:@package, package)
486
+ Backup::Cleaner.expects(:remove_package).with(package)
487
+
488
+ model.send(:clean!)
489
+ end
490
+ end
491
+
492
+ describe '#procedures' do
493
+ it 'should return an array of specific, ordered procedures' do
494
+ model.stubs(:databases).returns(:databases)
495
+ model.stubs(:archives).returns(:archives)
496
+ model.stubs(:package!).returns(:package)
497
+ model.stubs(:storages).returns(:storages)
498
+ model.stubs(:clean!).returns(:clean)
499
+
500
+ one, two, three, four, five = model.send(:procedures)
501
+ one.should == :databases
502
+ two.should == :archives
503
+ three.call.should == :package
504
+ four.should == :storages
505
+ five.call.should == :clean
506
+ end
507
+ end
508
+
509
+ describe '#procedure_instance_variables' do
510
+ # these are all set to an empty Array in #initialize
511
+ it 'should return an array of Array holding instance variables' do
512
+ model.send(:procedure_instance_variables).should ==
513
+ [:@databases, :@archives, :@storages, :@notifiers, :@syncers]
514
+ end
515
+ end
516
+
517
+ describe '#get_class_from_scope' do
518
+
519
+ module Fake
520
+ module TestScope
521
+ class TestKlass; end
522
+ end
523
+ end
524
+ module TestScope
525
+ module TestKlass; end
526
+ end
527
+
528
+ context 'when name is given as a string' do
529
+ it 'should return the constant for the given scope and name' do
530
+ model.send(
531
+ :get_class_from_scope,
532
+ Fake,
533
+ 'TestScope'
534
+ ).should == Fake::TestScope
535
+ end
536
+
537
+ it 'should accept a nested class name' do
538
+ model.send(
539
+ :get_class_from_scope,
540
+ Fake,
541
+ 'TestScope::TestKlass'
542
+ ).should == Fake::TestScope::TestKlass
543
+ end
544
+ end
545
+
546
+ context 'when name is given as a module' do
547
+ it 'should return the constant for the given scope and name' do
548
+ model.send(
549
+ :get_class_from_scope,
550
+ Fake,
551
+ TestScope
552
+ ).should == Fake::TestScope
553
+ end
554
+
555
+ it 'should accept a nested class name' do
556
+ model.send(
557
+ :get_class_from_scope,
558
+ Fake,
559
+ TestScope::TestKlass
560
+ ).should == Fake::TestScope::TestKlass
561
+ end
562
+ end
563
+
564
+ context 'when name is given as a module defined under Backup::Config' do
565
+ # this is necessary since the specs in spec/config_spec.rb
566
+ # remove all the constants from Backup::Config as part of those tests.
567
+ before(:all) do
568
+ module Backup::Config
569
+ module TestScope
570
+ module TestKlass; end
571
+ end
572
+ end
573
+ end
574
+
575
+ it 'should return the constant for the given scope and name' do
576
+ model.send(
577
+ :get_class_from_scope,
578
+ Fake,
579
+ Backup::Config::TestScope
580
+ ).should == Fake::TestScope
581
+ end
582
+
583
+ it 'should accept a nested class name' do
584
+ model.send(
585
+ :get_class_from_scope,
586
+ Fake,
587
+ Backup::Config::TestScope::TestKlass
588
+ ).should == Fake::TestScope::TestKlass
589
+ end
590
+ end
591
+
592
+ end # describe '#get_class_from_scope'
593
+
594
+ describe '#log!' do
595
+ context 'when action is :started' do
596
+ it 'should log that the backup has started with the version' do
597
+ Backup::Logger.expects(:message).with(
598
+ "Performing Backup for 'test label (test_trigger)'!\n" +
599
+ "[ backup #{ Backup::Version.current } : #{ RUBY_DESCRIPTION } ]"
600
+ )
601
+ model.send(:log!, :started)
602
+ end
603
+ end
604
+
605
+ context 'when action is :finished' do
606
+ before { model.expects(:elapsed_time).returns('01:02:03') }
607
+ context 'when warnings were issued' do
608
+ before { Backup::Logger.expects(:has_warnings?).returns(true) }
609
+ it 'should log a warning that the backup has finished with warnings' do
610
+ Backup::Logger.expects(:warn).with(
611
+ "Backup for 'test label (test_trigger)' " +
612
+ "Completed Successfully (with Warnings) in 01:02:03"
613
+ )
614
+ model.send(:log!, :finished)
615
+ end
616
+ end
617
+
618
+ context 'when no warnings were issued' do
619
+ it 'should log that the backup has finished with the elapsed time' do
620
+ Backup::Logger.expects(:message).with(
621
+ "Backup for 'test label (test_trigger)' " +
622
+ "Completed Successfully in 01:02:03"
623
+ )
624
+ model.send(:log!, :finished)
625
+ end
626
+ end
627
+ end
628
+ end # describe '#log!'
629
+
630
+ describe '#elapsed_time' do
631
+ it 'should return a string representing the elapsed time' do
632
+ Timecop.freeze(Time.now)
633
+ { 0 => '00:00:00', 1 => '00:00:01', 59 => '00:00:59',
634
+ 60 => '00:01:00', 61 => '00:01:01', 119 => '00:01:59',
635
+ 3540 => '00:59:00', 3541 => '00:59:01', 3599 => '00:59:59',
636
+ 3600 => '01:00:00', 3601 => '01:00:01', 3659 => '01:00:59',
637
+ 3660 => '01:01:00', 3661 => '01:01:01', 3719 => '01:01:59',
638
+ 7140 => '01:59:00', 7141 => '01:59:01', 7199 => '01:59:59',
639
+ 212400 => '59:00:00', 212401 => '59:00:01', 212459 => '59:00:59',
640
+ 212460 => '59:01:00', 212461 => '59:01:01', 212519 => '59:01:59',
641
+ 215940 => '59:59:00', 215941 => '59:59:01', 215999 => '59:59:59'
642
+ }.each do |duration, expected|
643
+ model.instance_variable_set(:@started_at, Time.now - duration)
644
+ model.send(:elapsed_time).should == expected
645
+ end
646
+ end
647
+ end
648
+
649
+ end