backup-agoddard 3.0.27

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 (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,254 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Storage::CloudFiles do
6
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
7
+ let(:storage) do
8
+ Backup::Storage::CloudFiles.new(model) do |cf|
9
+ cf.username = 'my_username'
10
+ cf.api_key = 'my_api_key'
11
+ cf.auth_url = 'lon.auth.api.rackspacecloud.com'
12
+ cf.container = 'my_container'
13
+ cf.keep = 5
14
+ end
15
+ end
16
+
17
+ it 'should be a subclass of Storage::Base' do
18
+ Backup::Storage::CloudFiles.
19
+ superclass.should == Backup::Storage::Base
20
+ end
21
+
22
+ describe '#initialize' do
23
+ after { Backup::Storage::CloudFiles.clear_defaults! }
24
+
25
+ it 'should load pre-configured defaults through Base' do
26
+ Backup::Storage::CloudFiles.any_instance.expects(:load_defaults!)
27
+ storage
28
+ end
29
+
30
+ it 'should pass the model reference to Base' do
31
+ storage.instance_variable_get(:@model).should == model
32
+ end
33
+
34
+ it 'should pass the storage_id to Base' do
35
+ storage = Backup::Storage::CloudFiles.new(model, 'my_storage_id')
36
+ storage.storage_id.should == 'my_storage_id'
37
+ end
38
+
39
+ context 'when no pre-configured defaults have been set' do
40
+ it 'should use the values given' do
41
+ storage.username.should == 'my_username'
42
+ storage.api_key.should == 'my_api_key'
43
+ storage.auth_url.should == 'lon.auth.api.rackspacecloud.com'
44
+ storage.container.should == 'my_container'
45
+ storage.servicenet.should == false
46
+ storage.path.should == 'backups'
47
+
48
+ storage.storage_id.should be_nil
49
+ storage.keep.should == 5
50
+ end
51
+
52
+ it 'should use default values if none are given' do
53
+ storage = Backup::Storage::CloudFiles.new(model)
54
+
55
+ storage.username.should be_nil
56
+ storage.api_key.should be_nil
57
+ storage.auth_url.should be_nil
58
+ storage.container.should be_nil
59
+ storage.servicenet.should == false
60
+ storage.path.should == 'backups'
61
+
62
+ storage.storage_id.should be_nil
63
+ storage.keep.should be_nil
64
+ end
65
+ end # context 'when no pre-configured defaults have been set'
66
+
67
+ context 'when pre-configured defaults have been set' do
68
+ before do
69
+ Backup::Storage::CloudFiles.defaults do |s|
70
+ s.username = 'some_username'
71
+ s.api_key = 'some_api_key'
72
+ s.auth_url = 'some_auth_url'
73
+ s.container = 'some_container'
74
+ s.servicenet = true
75
+ s.path = 'some_path'
76
+ s.keep = 15
77
+ end
78
+ end
79
+
80
+ it 'should use pre-configured defaults' do
81
+ storage = Backup::Storage::CloudFiles.new(model)
82
+
83
+ storage.username.should == 'some_username'
84
+ storage.api_key.should == 'some_api_key'
85
+ storage.auth_url.should == 'some_auth_url'
86
+ storage.container.should == 'some_container'
87
+ storage.servicenet.should == true
88
+ storage.path.should == 'some_path'
89
+
90
+ storage.storage_id.should be_nil
91
+ storage.keep.should == 15
92
+ end
93
+
94
+ it 'should override pre-configured defaults' do
95
+ storage = Backup::Storage::CloudFiles.new(model) do |s|
96
+ s.username = 'new_username'
97
+ s.api_key = 'new_api_key'
98
+ s.auth_url = 'new_auth_url'
99
+ s.container = 'new_container'
100
+ s.servicenet = false
101
+ s.path = 'new_path'
102
+ s.keep = 10
103
+ end
104
+
105
+ storage.username.should == 'new_username'
106
+ storage.api_key.should == 'new_api_key'
107
+ storage.auth_url.should == 'new_auth_url'
108
+ storage.container.should == 'new_container'
109
+ storage.servicenet.should == false
110
+ storage.path.should == 'new_path'
111
+
112
+ storage.storage_id.should be_nil
113
+ storage.keep.should == 10
114
+ end
115
+ end # context 'when pre-configured defaults have been set'
116
+ end # describe '#initialize'
117
+
118
+ describe '#provider' do
119
+ it 'should set the Fog provider' do
120
+ storage.send(:provider).should == 'Rackspace'
121
+ end
122
+ end
123
+
124
+ describe '#connection' do
125
+ let(:connection) { mock }
126
+
127
+ context 'when @servicenet is set to false' do
128
+ it 'should create a new standard connection' do
129
+ Fog::Storage.expects(:new).once.with(
130
+ :provider => 'Rackspace',
131
+ :rackspace_username => 'my_username',
132
+ :rackspace_api_key => 'my_api_key',
133
+ :rackspace_auth_url => 'lon.auth.api.rackspacecloud.com',
134
+ :rackspace_servicenet => false
135
+ ).returns(connection)
136
+ storage.send(:connection).should == connection
137
+ end
138
+ end
139
+
140
+ context 'when @servicenet is set to true' do
141
+ before do
142
+ storage.servicenet = true
143
+ end
144
+
145
+ it 'should create a new servicenet connection' do
146
+ Fog::Storage.expects(:new).once.with(
147
+ :provider => 'Rackspace',
148
+ :rackspace_username => 'my_username',
149
+ :rackspace_api_key => 'my_api_key',
150
+ :rackspace_auth_url => 'lon.auth.api.rackspacecloud.com',
151
+ :rackspace_servicenet => true
152
+ ).returns(connection)
153
+ storage.send(:connection).should == connection
154
+ end
155
+ end
156
+
157
+ it 'should return an existing connection' do
158
+ Fog::Storage.expects(:new).once.returns(connection)
159
+ storage.send(:connection).should == connection
160
+ storage.send(:connection).should == connection
161
+ end
162
+
163
+ end # describe '#connection'
164
+
165
+ describe '#transfer!' do
166
+ let(:connection) { mock }
167
+ let(:package) { mock }
168
+ let(:file) { mock }
169
+ let(:s) { sequence '' }
170
+
171
+ before do
172
+ storage.instance_variable_set(:@package, package)
173
+ storage.stubs(:storage_name).returns('Storage::CloudFiles')
174
+ storage.stubs(:local_path).returns('/local/path')
175
+ storage.stubs(:connection).returns(connection)
176
+ end
177
+
178
+ it 'should transfer the package files' do
179
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
180
+ returns('remote/path')
181
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
182
+ multiple_yields(
183
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
184
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
185
+ )
186
+ # first yield
187
+ Backup::Logger.expects(:message).in_sequence(s).with(
188
+ "Storage::CloudFiles started transferring " +
189
+ "'2011.12.31.11.00.02.backup.tar.enc-aa'."
190
+ )
191
+ File.expects(:open).in_sequence(s).with(
192
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'), 'r'
193
+ ).yields(file)
194
+ connection.expects(:put_object).in_sequence(s).with(
195
+ 'my_container', File.join('remote/path', 'backup.tar.enc-aa'), file
196
+ )
197
+ # second yield
198
+ Backup::Logger.expects(:message).in_sequence(s).with(
199
+ "Storage::CloudFiles started transferring " +
200
+ "'2011.12.31.11.00.02.backup.tar.enc-ab'."
201
+ )
202
+ File.expects(:open).in_sequence(s).with(
203
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'), 'r'
204
+ ).yields(file)
205
+ connection.expects(:put_object).in_sequence(s).with(
206
+ 'my_container', File.join('remote/path', 'backup.tar.enc-ab'), file
207
+ )
208
+
209
+ storage.send(:transfer!)
210
+ end
211
+ end # describe '#transfer!'
212
+
213
+ describe '#remove!' do
214
+ let(:package) { mock }
215
+ let(:connection) { mock }
216
+ let(:s) { sequence '' }
217
+
218
+ before do
219
+ storage.stubs(:storage_name).returns('Storage::CloudFiles')
220
+ storage.stubs(:connection).returns(connection)
221
+ end
222
+
223
+ it 'should remove the package files' do
224
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
225
+ returns('remote/path')
226
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
227
+ multiple_yields(
228
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
229
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
230
+ )
231
+ # first yield
232
+ Backup::Logger.expects(:message).in_sequence(s).with(
233
+ "Storage::CloudFiles started removing " +
234
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' " +
235
+ "from container 'my_container'."
236
+ )
237
+ connection.expects(:delete_object).in_sequence(s).with(
238
+ 'my_container', File.join('remote/path', 'backup.tar.enc-aa')
239
+ )
240
+ # second yield
241
+ Backup::Logger.expects(:message).in_sequence(s).with(
242
+ "Storage::CloudFiles started removing " +
243
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' " +
244
+ "from container 'my_container'."
245
+ )
246
+ connection.expects(:delete_object).in_sequence(s).with(
247
+ 'my_container', File.join('remote/path', 'backup.tar.enc-ab')
248
+ )
249
+
250
+ storage.send(:remove!, package)
251
+ end
252
+ end # describe '#remove!'
253
+
254
+ end
@@ -0,0 +1,247 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe 'Backup::Storage::Cycler' do
6
+ let(:cycler) { Backup::Storage::Cycler }
7
+ let(:storage) { mock }
8
+ let(:package) { mock }
9
+ let(:storage_file) { mock }
10
+ let(:pkg_a) { mock }
11
+ let(:pkg_b) { mock }
12
+ let(:pkg_c) { mock }
13
+ let(:s) { sequence '' }
14
+
15
+ describe '#cycle!' do
16
+ it 'should setup variables and initiate cycling' do
17
+ cycler.expects(:storage_file).in_sequence(s).returns(storage_file)
18
+ cycler.expects(:update_storage_file!).in_sequence(s)
19
+ cycler.expects(:remove_packages!).in_sequence(s)
20
+ cycler.cycle!(storage, package)
21
+ cycler.instance_variable_get(:@storage).should be(storage)
22
+ cycler.instance_variable_get(:@package).should be(package)
23
+ cycler.instance_variable_get(:@storage_file).should be(storage_file)
24
+ end
25
+ end
26
+
27
+ describe 'update_storage_file!' do
28
+ before do
29
+ cycler.instance_variable_set(:@storage, storage)
30
+ cycler.instance_variable_set(:@package, package)
31
+ cycler.instance_variable_set(:@storage_file, storage_file)
32
+ end
33
+
34
+ it 'should remove entries and set @packages_to_remove' do
35
+ storage.stubs(:keep).returns(2)
36
+ cycler.expects(:yaml_load).in_sequence(s).returns([pkg_a, pkg_b, pkg_c])
37
+ cycler.expects(:yaml_save).in_sequence(s).with([package, pkg_a])
38
+ cycler.send(:update_storage_file!)
39
+ cycler.instance_variable_get(:@packages_to_remove).should == [pkg_b, pkg_c]
40
+ end
41
+
42
+ it 'should typecast the value of keep' do
43
+ storage.stubs(:keep).returns('2')
44
+ cycler.expects(:yaml_load).in_sequence(s).returns([pkg_a, pkg_b, pkg_c])
45
+ cycler.expects(:yaml_save).in_sequence(s).with([package, pkg_a])
46
+ cycler.send(:update_storage_file!)
47
+ cycler.instance_variable_get(:@packages_to_remove).should == [pkg_b, pkg_c]
48
+ end
49
+ end
50
+
51
+ describe '#remove_packages!' do
52
+ before do
53
+ cycler.instance_variable_set(:@storage, storage)
54
+ cycler.instance_variable_set(:@packages_to_remove, [pkg_a, pkg_b, pkg_c])
55
+ end
56
+
57
+ it 'should call the @storage to remove the old packages' do
58
+ storage.expects(:remove!).in_sequence(s).with(pkg_a)
59
+ storage.expects(:remove!).in_sequence(s).with(pkg_b)
60
+ storage.expects(:remove!).in_sequence(s).with(pkg_c)
61
+ cycler.send(:remove_packages!)
62
+ end
63
+
64
+ context 'when errors occur removing packages' do
65
+ before do
66
+ pkg_b.stubs(:trigger).returns('pkg_trigger')
67
+ pkg_b.stubs(:time).returns('pkg_time')
68
+ pkg_b.stubs(:filenames).returns(['file1', 'file2'])
69
+ end
70
+
71
+ it 'should warn and continue' do
72
+ storage.expects(:remove!).in_sequence(s).with(pkg_a)
73
+ storage.expects(:remove!).in_sequence(s).with(pkg_b).raises('error message')
74
+ Backup::Logger.expects(:warn).with do |err|
75
+ err.should be_an_instance_of Backup::Errors::Storage::CyclerError
76
+ err.message.should == 'Storage::CyclerError: ' +
77
+ "There was a problem removing the following package:\n" +
78
+ " Trigger: pkg_trigger :: Dated: pkg_time\n" +
79
+ " Package included the following 2 file(s):\n" +
80
+ " file1\n" +
81
+ " file2\n" +
82
+ " Reason: RuntimeError\n" +
83
+ " error message"
84
+ end
85
+ storage.expects(:remove!).in_sequence(s).with(pkg_c)
86
+
87
+ expect do
88
+ cycler.send(:remove_packages!)
89
+ end.not_to raise_error
90
+ end
91
+ end
92
+
93
+ end # describe '#remove_packages!'
94
+
95
+ describe '#storage_file' do
96
+ before do
97
+ cycler.instance_variable_set(:@storage, storage)
98
+ storage.stubs(:class).returns('Backup::Storage::S3')
99
+ cycler.instance_variable_set(:@package, package)
100
+ package.stubs(:trigger).returns('pkg_trigger')
101
+ end
102
+
103
+ context 'when the @storage.storage_id is not set' do
104
+ before { storage.stubs(:storage_id).returns(nil) }
105
+ it 'should return the path to the YAML storage file with no suffix' do
106
+ cycler.send(:storage_file).should ==
107
+ File.join(Backup::Config.data_path, 'pkg_trigger', 'S3.yml')
108
+ end
109
+ end
110
+
111
+ context 'when the @storage.storage_id is set' do
112
+ before { storage.stubs(:storage_id).returns('Storage #1') }
113
+ it 'should sanitize the storage_id to use as a filename suffix' do
114
+ cycler.send(:storage_file).should ==
115
+ File.join(Backup::Config.data_path, 'pkg_trigger', 'S3-Storage__1.yml')
116
+ end
117
+ end
118
+
119
+ end # describe '#storage_file'
120
+
121
+ describe '#yaml_load' do
122
+ let(:obj_a) { mock }
123
+ let(:obj_b) { mock }
124
+ let(:obj_c) { mock }
125
+ let(:unsorted_objects) { [obj_a, obj_c, obj_b] }
126
+ let(:sorted_objects) { [obj_c, obj_b, obj_a] }
127
+
128
+ before do
129
+ cycler.instance_variable_set(:@storage_file, storage_file)
130
+ obj_a.instance_variable_set(:@time, '2012.01.01.07.00.00')
131
+ obj_b.instance_variable_set(:@time, '2012.01.01.08.00.00')
132
+ obj_c.instance_variable_set(:@time, '2012.01.01.09.00.00')
133
+ end
134
+
135
+ context 'when the storage file exists' do
136
+ before { File.expects(:exist?).with(storage_file).returns(true) }
137
+ context 'when the file is not empty' do
138
+ before { File.expects(:zero?).with(storage_file).returns(false) }
139
+ it 'should return YAML deserialized objects in an array, sorted by time DESC' do
140
+ YAML.expects(:load_file).with(storage_file).returns(unsorted_objects)
141
+ cycler.expects(:check_upgrade).with(sorted_objects).returns(sorted_objects)
142
+ cycler.send(:yaml_load).should be(sorted_objects)
143
+ end
144
+ end
145
+ context 'when the file is empty' do
146
+ before { File.expects(:zero?).with(storage_file).returns(true) }
147
+ it 'should return an empty array' do
148
+ cycler.send(:yaml_load).should == []
149
+ end
150
+ end
151
+ end
152
+
153
+ context 'when the storage file does not exist' do
154
+ before { File.expects(:exist?).with(storage_file).returns(false) }
155
+ it 'should return an empty array' do
156
+ cycler.send(:yaml_load).should == []
157
+ end
158
+ end
159
+ end # describe '#yaml_load'
160
+
161
+ describe '#yaml_save' do
162
+ let(:file) { mock }
163
+ let(:pkgs) { [ [1, 2, 3], [4, 5, 6] ] }
164
+ let(:pkgs_to_yaml) { pkgs.to_yaml }
165
+
166
+ it 'should save the given packages to the storage file in YAML format' do
167
+ cycler.instance_variable_set(:@storage_file, storage_file)
168
+ File.expects(:open).with(storage_file, 'w').yields(file)
169
+ file.expects(:write).with(pkgs_to_yaml)
170
+ cycler.send(:yaml_save, pkgs)
171
+ end
172
+ end # describe '#yaml_save'
173
+
174
+ describe '#check_upgrade' do
175
+ let(:yaml_v3_0_19) do
176
+ <<-EOF.gsub(/^ +/,' ').gsub(/^ (-\W\W)/, "\\1")
177
+ ---
178
+ - !ruby/object:Backup::Storage::Local
179
+ time: 2011.11.01.12.01.00
180
+ remote_file: 2011.11.01.12.01.00.backup.tar.gz
181
+ - !ruby/object:Backup::Storage::Local
182
+ time: 2011.11.01.12.02.00
183
+ remote_file: 2011.11.01.12.02.00.backup.tar.gz
184
+ - !ruby/object:Backup::Storage::Local
185
+ time: 2011.11.01.12.03.00
186
+ remote_file: 2011.11.01.12.03.00.backup.tar.gz
187
+ EOF
188
+ end
189
+ let(:yaml_v3_0_20) do
190
+ <<-EOF.gsub(/^ +/,' ').gsub(/^ (-\W\W)/, "\\1")
191
+ ---
192
+ - !ruby/object:Backup::Storage::Local
193
+ time: 2011.12.01.12.01.00
194
+ chunk_suffixes: []
195
+ filename: 2011.12.01.12.01.00.backup.tar.gz
196
+ version: 3.0.20
197
+ - !ruby/object:Backup::Storage::Local
198
+ time: 2011.12.01.12.02.00
199
+ chunk_suffixes: []
200
+ filename: 2011.12.01.12.02.00.backup.tar.gz
201
+ version: 3.0.20
202
+ - !ruby/object:Backup::Storage::Local
203
+ time: 2011.12.01.12.03.00
204
+ chunk_suffixes:
205
+ - aa
206
+ - ab
207
+ filename: 2011.12.01.12.03.00.backup.tar.gz
208
+ version: 3.0.20
209
+ EOF
210
+ end
211
+
212
+ before do
213
+ model = Backup::Model.new('foo', 'foo')
214
+ cycler.instance_variable_set(:@storage, storage)
215
+ storage.instance_variable_set(:@model, model)
216
+ end
217
+
218
+ it 'should upgrade v3.0.20 objects' do
219
+ objects = YAML.load(yaml_v3_0_20)
220
+ packages = cycler.send(:check_upgrade, objects)
221
+
222
+ packages.all? {|pkg| pkg.is_a? Backup::Package }.should be_true
223
+ packages.all? {|pkg| pkg.extension == 'tar.gz' }.should be_true
224
+
225
+ packages[0].time.should == '2011.12.01.12.01.00'
226
+ packages[0].chunk_suffixes.should == []
227
+ packages[1].time.should == '2011.12.01.12.02.00'
228
+ packages[1].chunk_suffixes.should == []
229
+ packages[2].time.should == '2011.12.01.12.03.00'
230
+ packages[2].chunk_suffixes.should == ['aa', 'ab']
231
+ end
232
+
233
+ it 'should upgrade v3.0.19 objects' do
234
+ objects = YAML.load(yaml_v3_0_19)
235
+ packages = cycler.send(:check_upgrade, objects)
236
+
237
+ packages.all? {|pkg| pkg.is_a? Backup::Package }.should be_true
238
+ packages.all? {|pkg| pkg.extension == 'tar.gz' }.should be_true
239
+ packages.all? {|pkg| pkg.chunk_suffixes == [] }.should be_true
240
+
241
+ packages[0].time.should == '2011.11.01.12.01.00'
242
+ packages[1].time.should == '2011.11.01.12.02.00'
243
+ packages[2].time.should == '2011.11.01.12.03.00'
244
+ end
245
+ end # describe '#check_upgrade'
246
+
247
+ end