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,245 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ ##
6
+ # available S3 regions:
7
+ # eu-west-1, us-east-1, ap-southeast-1, us-west-1
8
+ describe Backup::Storage::S3 do
9
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
10
+ let(:storage) do
11
+ Backup::Storage::S3.new(model) do |s3|
12
+ s3.access_key_id = 'my_access_key_id'
13
+ s3.secret_access_key = 'my_secret_access_key'
14
+ s3.bucket = 'my-bucket'
15
+ s3.region = 'us-east-1'
16
+ s3.keep = 5
17
+ end
18
+ end
19
+
20
+ it 'should be a subclass of Storage::Base' do
21
+ Backup::Storage::S3.
22
+ superclass.should == Backup::Storage::Base
23
+ end
24
+
25
+ describe '#initialize' do
26
+ after { Backup::Storage::S3.clear_defaults! }
27
+
28
+ it 'should load pre-configured defaults through Base' do
29
+ Backup::Storage::S3.any_instance.expects(:load_defaults!)
30
+ storage
31
+ end
32
+
33
+ it 'should pass the model reference to Base' do
34
+ storage.instance_variable_get(:@model).should == model
35
+ end
36
+
37
+ it 'should pass the storage_id to Base' do
38
+ storage = Backup::Storage::S3.new(model, 'my_storage_id')
39
+ storage.storage_id.should == 'my_storage_id'
40
+ end
41
+
42
+ context 'when no pre-configured defaults have been set' do
43
+ it 'should use the values given' do
44
+ storage.access_key_id.should == 'my_access_key_id'
45
+ storage.secret_access_key.should == 'my_secret_access_key'
46
+ storage.bucket.should == 'my-bucket'
47
+ storage.path.should == 'backups'
48
+ storage.region.should == 'us-east-1'
49
+
50
+ storage.storage_id.should be_nil
51
+ storage.keep.should == 5
52
+ end
53
+
54
+ it 'should use default values if none are given' do
55
+ storage = Backup::Storage::S3.new(model)
56
+
57
+ storage.access_key_id.should be_nil
58
+ storage.secret_access_key.should be_nil
59
+ storage.bucket.should be_nil
60
+ storage.path.should == 'backups'
61
+ storage.region.should be_nil
62
+
63
+ storage.storage_id.should be_nil
64
+ storage.keep.should be_nil
65
+ end
66
+ end # context 'when no pre-configured defaults have been set'
67
+
68
+ context 'when pre-configured defaults have been set' do
69
+ before do
70
+ Backup::Storage::S3.defaults do |s|
71
+ s.access_key_id = 'some_access_key_id'
72
+ s.secret_access_key = 'some_secret_access_key'
73
+ s.bucket = 'some-bucket'
74
+ s.path = 'some_path'
75
+ s.region = 'some_region'
76
+ s.keep = 15
77
+ end
78
+ end
79
+
80
+ it 'should use pre-configured defaults' do
81
+ storage = Backup::Storage::S3.new(model)
82
+
83
+ storage.access_key_id.should == 'some_access_key_id'
84
+ storage.secret_access_key.should == 'some_secret_access_key'
85
+ storage.bucket.should == 'some-bucket'
86
+ storage.path.should == 'some_path'
87
+ storage.region.should == 'some_region'
88
+
89
+ storage.storage_id.should be_nil
90
+ storage.keep.should == 15
91
+ end
92
+
93
+ it 'should override pre-configured defaults' do
94
+ storage = Backup::Storage::S3.new(model) do |s|
95
+ s.access_key_id = 'new_access_key_id'
96
+ s.secret_access_key = 'new_secret_access_key'
97
+ s.bucket = 'new-bucket'
98
+ s.path = 'new_path'
99
+ s.region = 'new_region'
100
+ s.keep = 10
101
+ end
102
+
103
+ storage.access_key_id.should == 'new_access_key_id'
104
+ storage.secret_access_key.should == 'new_secret_access_key'
105
+ storage.bucket.should == 'new-bucket'
106
+ storage.path.should == 'new_path'
107
+ storage.region.should == 'new_region'
108
+
109
+ storage.storage_id.should be_nil
110
+ storage.keep.should == 10
111
+ end
112
+ end # context 'when pre-configured defaults have been set'
113
+ end # describe '#initialize'
114
+
115
+ describe '#provider' do
116
+ it 'should set the Fog provider' do
117
+ storage.send(:provider).should == 'AWS'
118
+ end
119
+ end
120
+
121
+ describe '#connection' do
122
+ let(:connection) { mock }
123
+
124
+ it 'should create a new connection' do
125
+ Fog::Storage.expects(:new).once.with(
126
+ :provider => 'AWS',
127
+ :aws_access_key_id => 'my_access_key_id',
128
+ :aws_secret_access_key => 'my_secret_access_key',
129
+ :region => 'us-east-1'
130
+ ).returns(connection)
131
+ storage.send(:connection).should == connection
132
+ end
133
+
134
+ it 'should return an existing connection' do
135
+ Fog::Storage.expects(:new).once.returns(connection)
136
+ storage.send(:connection).should == connection
137
+ storage.send(:connection).should == connection
138
+ end
139
+ end # describe '#connection'
140
+
141
+ describe '#remote_path_for' do
142
+ let(:package) { mock }
143
+
144
+ before do
145
+ # for superclass method
146
+ package.expects(:trigger).returns('trigger')
147
+ package.expects(:time).returns('time')
148
+ end
149
+
150
+ it 'should remove any preceeding slash from the remote path' do
151
+ storage.path = '/backups'
152
+ storage.send(:remote_path_for, package).should == 'backups/trigger/time'
153
+ end
154
+ end
155
+
156
+ describe '#transfer!' do
157
+ let(:connection) { mock }
158
+ let(:package) { mock }
159
+ let(:file) { mock }
160
+ let(:s) { sequence '' }
161
+
162
+ before do
163
+ storage.instance_variable_set(:@package, package)
164
+ storage.stubs(:storage_name).returns('Storage::S3')
165
+ storage.stubs(:local_path).returns('/local/path')
166
+ storage.stubs(:connection).returns(connection)
167
+ end
168
+
169
+ it 'should transfer the package files' do
170
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
171
+ returns('remote/path')
172
+ connection.expects(:sync_clock).in_sequence(s)
173
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
174
+ multiple_yields(
175
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
176
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
177
+ )
178
+ # first yield
179
+ Backup::Logger.expects(:message).in_sequence(s).with(
180
+ "Storage::S3 started transferring " +
181
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' to bucket 'my-bucket'."
182
+ )
183
+ File.expects(:open).in_sequence(s).with(
184
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'), 'r'
185
+ ).yields(file)
186
+ connection.expects(:put_object).in_sequence(s).with(
187
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-aa'), file
188
+ )
189
+ # second yield
190
+ Backup::Logger.expects(:message).in_sequence(s).with(
191
+ "Storage::S3 started transferring " +
192
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' to bucket 'my-bucket'."
193
+ )
194
+ File.expects(:open).in_sequence(s).with(
195
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'), 'r'
196
+ ).yields(file)
197
+ connection.expects(:put_object).in_sequence(s).with(
198
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-ab'), file
199
+ )
200
+
201
+ storage.send(:transfer!)
202
+ end
203
+ end # describe '#transfer!'
204
+
205
+ describe '#remove!' do
206
+ let(:package) { mock }
207
+ let(:connection) { mock }
208
+ let(:s) { sequence '' }
209
+
210
+ before do
211
+ storage.stubs(:storage_name).returns('Storage::S3')
212
+ storage.stubs(:connection).returns(connection)
213
+ end
214
+
215
+ it 'should remove the package files' do
216
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
217
+ returns('remote/path')
218
+ connection.expects(:sync_clock).in_sequence(s)
219
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
220
+ multiple_yields(
221
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
222
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
223
+ )
224
+ # first yield
225
+ Backup::Logger.expects(:message).in_sequence(s).with(
226
+ "Storage::S3 started removing " +
227
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' from bucket 'my-bucket'."
228
+ )
229
+ connection.expects(:delete_object).in_sequence(s).with(
230
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-aa')
231
+ )
232
+ # second yield
233
+ Backup::Logger.expects(:message).in_sequence(s).with(
234
+ "Storage::S3 started removing " +
235
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' from bucket 'my-bucket'."
236
+ )
237
+ connection.expects(:delete_object).in_sequence(s).with(
238
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-ab')
239
+ )
240
+
241
+ storage.send(:remove!, package)
242
+ end
243
+ end # describe '#remove!'
244
+
245
+ end
@@ -0,0 +1,233 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Storage::SCP do
6
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
7
+ let(:storage) do
8
+ Backup::Storage::SCP.new(model) do |scp|
9
+ scp.username = 'my_username'
10
+ scp.password = 'my_password'
11
+ scp.ip = '123.45.678.90'
12
+ scp.keep = 5
13
+ end
14
+ end
15
+
16
+ it 'should be a subclass of Storage::Base' do
17
+ Backup::Storage::SCP.
18
+ superclass.should == Backup::Storage::Base
19
+ end
20
+
21
+ describe '#initialize' do
22
+ after { Backup::Storage::SCP.clear_defaults! }
23
+
24
+ it 'should load pre-configured defaults through Base' do
25
+ Backup::Storage::SCP.any_instance.expects(:load_defaults!)
26
+ storage
27
+ end
28
+
29
+ it 'should pass the model reference to Base' do
30
+ storage.instance_variable_get(:@model).should == model
31
+ end
32
+
33
+ it 'should pass the storage_id to Base' do
34
+ storage = Backup::Storage::SCP.new(model, 'my_storage_id')
35
+ storage.storage_id.should == 'my_storage_id'
36
+ end
37
+
38
+ it 'should remove any preceeding tilde and slash from the path' do
39
+ storage = Backup::Storage::SCP.new(model) do |scp|
40
+ scp.path = '~/my_backups/path'
41
+ end
42
+ storage.path.should == 'my_backups/path'
43
+ end
44
+
45
+ context 'when no pre-configured defaults have been set' do
46
+ it 'should use the values given' do
47
+ storage.username.should == 'my_username'
48
+ storage.password.should == 'my_password'
49
+ storage.ip.should == '123.45.678.90'
50
+ storage.port.should == 22
51
+ storage.path.should == 'backups'
52
+
53
+ storage.storage_id.should be_nil
54
+ storage.keep.should == 5
55
+ end
56
+
57
+ it 'should use default values if none are given' do
58
+ storage = Backup::Storage::SCP.new(model)
59
+
60
+ storage.username.should be_nil
61
+ storage.password.should be_nil
62
+ storage.ip.should be_nil
63
+ storage.port.should == 22
64
+ storage.path.should == 'backups'
65
+
66
+ storage.storage_id.should be_nil
67
+ storage.keep.should be_nil
68
+ end
69
+ end # context 'when no pre-configured defaults have been set'
70
+
71
+ context 'when pre-configured defaults have been set' do
72
+ before do
73
+ Backup::Storage::SCP.defaults do |s|
74
+ s.username = 'some_username'
75
+ s.password = 'some_password'
76
+ s.ip = 'some_ip'
77
+ s.port = 'some_port'
78
+ s.path = 'some_path'
79
+ s.keep = 'some_keep'
80
+ end
81
+ end
82
+
83
+ it 'should use pre-configured defaults' do
84
+ storage = Backup::Storage::SCP.new(model)
85
+
86
+ storage.username.should == 'some_username'
87
+ storage.password.should == 'some_password'
88
+ storage.ip.should == 'some_ip'
89
+ storage.port.should == 'some_port'
90
+ storage.path.should == 'some_path'
91
+
92
+ storage.storage_id.should be_nil
93
+ storage.keep.should == 'some_keep'
94
+ end
95
+
96
+ it 'should override pre-configured defaults' do
97
+ storage = Backup::Storage::SCP.new(model) do |s|
98
+ s.username = 'new_username'
99
+ s.password = 'new_password'
100
+ s.ip = 'new_ip'
101
+ s.port = 'new_port'
102
+ s.path = 'new_path'
103
+ s.keep = 'new_keep'
104
+ end
105
+
106
+ storage.username.should == 'new_username'
107
+ storage.password.should == 'new_password'
108
+ storage.ip.should == 'new_ip'
109
+ storage.port.should == 'new_port'
110
+ storage.path.should == 'new_path'
111
+
112
+ storage.storage_id.should be_nil
113
+ storage.keep.should == 'new_keep'
114
+ end
115
+ end # context 'when pre-configured defaults have been set'
116
+ end # describe '#initialize'
117
+
118
+ describe '#connection' do
119
+ let(:connection) { mock }
120
+ it 'should yield a Net::SSH connection' do
121
+ Net::SSH.expects(:start).with(
122
+ '123.45.678.90', 'my_username', :password => 'my_password', :port => 22
123
+ ).yields(connection)
124
+
125
+ storage.send(:connection) do |ssh|
126
+ ssh.should be(connection)
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#transfer!' do
132
+ let(:connection) { mock }
133
+ let(:package) { mock }
134
+ let(:ssh_scp) { mock }
135
+ let(:s) { sequence '' }
136
+
137
+ before do
138
+ storage.instance_variable_set(:@package, package)
139
+ storage.stubs(:storage_name).returns('Storage::SCP')
140
+ storage.stubs(:local_path).returns('/local/path')
141
+ storage.stubs(:connection).yields(connection)
142
+ connection.stubs(:scp).returns(ssh_scp)
143
+ end
144
+
145
+ it 'should transfer the package files' do
146
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
147
+ returns('remote/path')
148
+ connection.expects(:exec!).in_sequence(s).with("mkdir -p 'remote/path'")
149
+
150
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
151
+ multiple_yields(
152
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
153
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
154
+ )
155
+ # first yield
156
+ Backup::Logger.expects(:message).in_sequence(s).with(
157
+ "Storage::SCP started transferring " +
158
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' to '123.45.678.90'."
159
+ )
160
+ ssh_scp.expects(:upload!).in_sequence(s).with(
161
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'),
162
+ File.join('remote/path', 'backup.tar.enc-aa')
163
+ )
164
+ # second yield
165
+ Backup::Logger.expects(:message).in_sequence(s).with(
166
+ "Storage::SCP started transferring " +
167
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' to '123.45.678.90'."
168
+ )
169
+ ssh_scp.expects(:upload!).in_sequence(s).with(
170
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'),
171
+ File.join('remote/path', 'backup.tar.enc-ab')
172
+ )
173
+
174
+ storage.send(:transfer!)
175
+ end
176
+ end # describe '#transfer!'
177
+
178
+ describe '#remove!' do
179
+ let(:package) { mock }
180
+ let(:connection) { mock }
181
+ let(:s) { sequence '' }
182
+
183
+ before do
184
+ storage.stubs(:storage_name).returns('Storage::SCP')
185
+ storage.stubs(:connection).yields(connection)
186
+ end
187
+
188
+ it 'should remove the package files' do
189
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
190
+ returns('remote/path')
191
+
192
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
193
+ multiple_yields(
194
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
195
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
196
+ )
197
+ # after both yields
198
+ Backup::Logger.expects(:message).in_sequence(s).with(
199
+ "Storage::SCP started removing " +
200
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' from '123.45.678.90'.\n" +
201
+ "Storage::SCP started removing " +
202
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' from '123.45.678.90'."
203
+ )
204
+ connection.expects(:exec!).with("rm -r 'remote/path'").in_sequence(s)
205
+
206
+ storage.send(:remove!, package)
207
+ end
208
+
209
+ context 'when the ssh connection reports errors' do
210
+ it 'should raise an error reporting the errors' do
211
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
212
+ returns('remote/path')
213
+
214
+ storage.expects(:transferred_files_for).in_sequence(s).with(package)
215
+
216
+ Backup::Logger.expects(:message).in_sequence(s)
217
+
218
+ connection.expects(:exec!).with("rm -r 'remote/path'").in_sequence(s).
219
+ yields(:ch, :stderr, 'path not found')
220
+
221
+ expect do
222
+ storage.send(:remove!, package)
223
+ end.to raise_error {|err|
224
+ err.should be_an_instance_of Backup::Errors::Storage::SCP::SSHError
225
+ err.message.should == "Storage::SCP::SSHError: " +
226
+ "Net::SSH reported the following errors:\n" +
227
+ " path not found"
228
+ }
229
+ end
230
+ end
231
+ end # describe '#remove!'
232
+
233
+ end