backup 3.0.20 → 3.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. data/Gemfile +1 -5
  2. data/Gemfile.lock +46 -50
  3. data/README.md +54 -27
  4. data/lib/backup.rb +16 -39
  5. data/lib/backup/archive.rb +42 -18
  6. data/lib/backup/cleaner.rb +110 -25
  7. data/lib/backup/cli/helpers.rb +17 -32
  8. data/lib/backup/cli/utility.rb +46 -107
  9. data/lib/backup/compressor/base.rb +14 -2
  10. data/lib/backup/compressor/bzip2.rb +10 -24
  11. data/lib/backup/compressor/gzip.rb +10 -24
  12. data/lib/backup/compressor/lzma.rb +10 -23
  13. data/lib/backup/compressor/pbzip2.rb +12 -32
  14. data/lib/backup/config.rb +171 -0
  15. data/lib/backup/configuration/compressor/base.rb +1 -2
  16. data/lib/backup/configuration/compressor/pbzip2.rb +4 -4
  17. data/lib/backup/configuration/database/base.rb +2 -1
  18. data/lib/backup/configuration/database/mongodb.rb +8 -0
  19. data/lib/backup/configuration/database/mysql.rb +4 -0
  20. data/lib/backup/configuration/database/postgresql.rb +4 -0
  21. data/lib/backup/configuration/database/redis.rb +4 -0
  22. data/lib/backup/configuration/database/riak.rb +5 -1
  23. data/lib/backup/configuration/encryptor/base.rb +1 -2
  24. data/lib/backup/configuration/encryptor/open_ssl.rb +1 -1
  25. data/lib/backup/configuration/helpers.rb +7 -2
  26. data/lib/backup/configuration/notifier/base.rb +4 -28
  27. data/lib/backup/configuration/storage/base.rb +1 -1
  28. data/lib/backup/configuration/storage/dropbox.rb +14 -4
  29. data/lib/backup/configuration/syncer/base.rb +10 -0
  30. data/lib/backup/configuration/syncer/rsync/base.rb +28 -0
  31. data/lib/backup/configuration/syncer/rsync/local.rb +11 -0
  32. data/lib/backup/configuration/syncer/rsync/pull.rb +11 -0
  33. data/lib/backup/configuration/syncer/rsync/push.rb +31 -0
  34. data/lib/backup/configuration/syncer/s3.rb +0 -4
  35. data/lib/backup/database/base.rb +25 -7
  36. data/lib/backup/database/mongodb.rb +112 -75
  37. data/lib/backup/database/mysql.rb +54 -29
  38. data/lib/backup/database/postgresql.rb +60 -42
  39. data/lib/backup/database/redis.rb +61 -39
  40. data/lib/backup/database/riak.rb +35 -11
  41. data/lib/backup/dependency.rb +4 -5
  42. data/lib/backup/encryptor/base.rb +13 -1
  43. data/lib/backup/encryptor/gpg.rb +39 -39
  44. data/lib/backup/encryptor/open_ssl.rb +28 -38
  45. data/lib/backup/logger.rb +20 -11
  46. data/lib/backup/model.rb +206 -163
  47. data/lib/backup/notifier/base.rb +27 -25
  48. data/lib/backup/notifier/campfire.rb +7 -13
  49. data/lib/backup/notifier/hipchat.rb +28 -28
  50. data/lib/backup/notifier/mail.rb +24 -26
  51. data/lib/backup/notifier/presently.rb +10 -18
  52. data/lib/backup/notifier/prowl.rb +9 -17
  53. data/lib/backup/notifier/twitter.rb +11 -18
  54. data/lib/backup/package.rb +47 -0
  55. data/lib/backup/packager.rb +81 -16
  56. data/lib/backup/splitter.rb +48 -35
  57. data/lib/backup/storage/base.rb +44 -172
  58. data/lib/backup/storage/cloudfiles.rb +31 -46
  59. data/lib/backup/storage/cycler.rb +117 -0
  60. data/lib/backup/storage/dropbox.rb +92 -76
  61. data/lib/backup/storage/ftp.rb +30 -40
  62. data/lib/backup/storage/local.rb +44 -45
  63. data/lib/backup/storage/ninefold.rb +55 -49
  64. data/lib/backup/storage/rsync.rb +49 -56
  65. data/lib/backup/storage/s3.rb +33 -44
  66. data/lib/backup/storage/scp.rb +21 -48
  67. data/lib/backup/storage/sftp.rb +26 -40
  68. data/lib/backup/syncer/base.rb +7 -0
  69. data/lib/backup/syncer/rsync/base.rb +78 -0
  70. data/lib/backup/syncer/rsync/local.rb +53 -0
  71. data/lib/backup/syncer/rsync/pull.rb +38 -0
  72. data/lib/backup/syncer/rsync/push.rb +113 -0
  73. data/lib/backup/syncer/s3.rb +42 -32
  74. data/lib/backup/version.rb +1 -1
  75. data/spec/archive_spec.rb +235 -69
  76. data/spec/cleaner_spec.rb +304 -0
  77. data/spec/cli/helpers_spec.rb +142 -1
  78. data/spec/cli/utility_spec.rb +338 -13
  79. data/spec/compressor/base_spec.rb +31 -0
  80. data/spec/compressor/bzip2_spec.rb +60 -35
  81. data/spec/compressor/gzip_spec.rb +60 -35
  82. data/spec/compressor/lzma_spec.rb +60 -35
  83. data/spec/compressor/pbzip2_spec.rb +98 -37
  84. data/spec/config_spec.rb +321 -0
  85. data/spec/configuration/base_spec.rb +4 -4
  86. data/spec/configuration/compressor/bzip2_spec.rb +1 -0
  87. data/spec/configuration/compressor/gzip_spec.rb +1 -0
  88. data/spec/configuration/compressor/lzma_spec.rb +1 -0
  89. data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
  90. data/spec/configuration/database/base_spec.rb +2 -1
  91. data/spec/configuration/database/mongodb_spec.rb +26 -16
  92. data/spec/configuration/database/mysql_spec.rb +4 -0
  93. data/spec/configuration/database/postgresql_spec.rb +4 -0
  94. data/spec/configuration/database/redis_spec.rb +4 -0
  95. data/spec/configuration/database/riak_spec.rb +4 -0
  96. data/spec/configuration/encryptor/gpg_spec.rb +1 -0
  97. data/spec/configuration/encryptor/open_ssl_spec.rb +1 -0
  98. data/spec/configuration/notifier/base_spec.rb +32 -0
  99. data/spec/configuration/notifier/campfire_spec.rb +1 -0
  100. data/spec/configuration/notifier/hipchat_spec.rb +1 -0
  101. data/spec/configuration/notifier/mail_spec.rb +1 -0
  102. data/spec/configuration/notifier/presently_spec.rb +1 -0
  103. data/spec/configuration/notifier/prowl_spec.rb +1 -0
  104. data/spec/configuration/notifier/twitter_spec.rb +1 -0
  105. data/spec/configuration/storage/cloudfiles_spec.rb +1 -0
  106. data/spec/configuration/storage/dropbox_spec.rb +4 -3
  107. data/spec/configuration/storage/ftp_spec.rb +1 -0
  108. data/spec/configuration/storage/local_spec.rb +1 -0
  109. data/spec/configuration/storage/ninefold_spec.rb +1 -0
  110. data/spec/configuration/storage/rsync_spec.rb +3 -1
  111. data/spec/configuration/storage/s3_spec.rb +1 -0
  112. data/spec/configuration/storage/scp_spec.rb +1 -0
  113. data/spec/configuration/storage/sftp_spec.rb +1 -0
  114. data/spec/configuration/syncer/rsync/base_spec.rb +33 -0
  115. data/spec/configuration/syncer/rsync/local_spec.rb +10 -0
  116. data/spec/configuration/syncer/rsync/pull_spec.rb +10 -0
  117. data/spec/configuration/syncer/{rsync_spec.rb → rsync/push_spec.rb} +12 -15
  118. data/spec/configuration/syncer/s3_spec.rb +2 -3
  119. data/spec/database/base_spec.rb +35 -20
  120. data/spec/database/mongodb_spec.rb +298 -119
  121. data/spec/database/mysql_spec.rb +147 -72
  122. data/spec/database/postgresql_spec.rb +155 -100
  123. data/spec/database/redis_spec.rb +200 -97
  124. data/spec/database/riak_spec.rb +82 -24
  125. data/spec/dependency_spec.rb +49 -0
  126. data/spec/encryptor/base_spec.rb +30 -0
  127. data/spec/encryptor/gpg_spec.rb +105 -28
  128. data/spec/encryptor/open_ssl_spec.rb +85 -114
  129. data/spec/logger_spec.rb +74 -8
  130. data/spec/model_spec.rb +528 -220
  131. data/spec/notifier/base_spec.rb +89 -0
  132. data/spec/notifier/campfire_spec.rb +147 -119
  133. data/spec/notifier/hipchat_spec.rb +140 -145
  134. data/spec/notifier/mail_spec.rb +190 -248
  135. data/spec/notifier/presently_spec.rb +147 -282
  136. data/spec/notifier/prowl_spec.rb +79 -111
  137. data/spec/notifier/twitter_spec.rb +87 -106
  138. data/spec/package_spec.rb +61 -0
  139. data/spec/packager_spec.rb +154 -0
  140. data/spec/spec_helper.rb +36 -13
  141. data/spec/splitter_spec.rb +90 -41
  142. data/spec/storage/base_spec.rb +95 -239
  143. data/spec/storage/cloudfiles_spec.rb +185 -75
  144. data/spec/storage/cycler_spec.rb +239 -0
  145. data/spec/storage/dropbox_spec.rb +318 -87
  146. data/spec/storage/ftp_spec.rb +165 -152
  147. data/spec/storage/local_spec.rb +206 -54
  148. data/spec/storage/ninefold_spec.rb +264 -128
  149. data/spec/storage/rsync_spec.rb +244 -163
  150. data/spec/storage/s3_spec.rb +175 -64
  151. data/spec/storage/scp_spec.rb +156 -150
  152. data/spec/storage/sftp_spec.rb +153 -135
  153. data/spec/syncer/base_spec.rb +22 -0
  154. data/spec/syncer/rsync/base_spec.rb +118 -0
  155. data/spec/syncer/rsync/local_spec.rb +121 -0
  156. data/spec/syncer/rsync/pull_spec.rb +90 -0
  157. data/spec/syncer/rsync/push_spec.rb +327 -0
  158. data/spec/syncer/s3_spec.rb +180 -91
  159. data/templates/cli/utility/config +1 -1
  160. data/templates/cli/utility/database/mongodb +4 -0
  161. data/templates/cli/utility/database/mysql +3 -0
  162. data/templates/cli/utility/database/postgresql +3 -0
  163. data/templates/cli/utility/database/redis +3 -0
  164. data/templates/cli/utility/database/riak +3 -0
  165. data/templates/cli/utility/storage/dropbox +4 -1
  166. data/templates/cli/utility/syncer/rsync_local +12 -0
  167. data/templates/cli/utility/syncer/{rsync → rsync_pull} +2 -2
  168. data/templates/cli/utility/syncer/rsync_push +17 -0
  169. data/templates/storage/dropbox/authorization_url.erb +1 -1
  170. metadata +42 -17
  171. data/lib/backup/configuration/syncer/rsync.rb +0 -45
  172. data/lib/backup/finder.rb +0 -87
  173. data/lib/backup/storage/object.rb +0 -47
  174. data/lib/backup/syncer/rsync.rb +0 -152
  175. data/spec/backup_spec.rb +0 -11
  176. data/spec/finder_spec.rb +0 -91
  177. data/spec/storage/object_spec.rb +0 -74
  178. data/spec/syncer/rsync_spec.rb +0 -195
@@ -6,105 +6,216 @@ require File.expand_path('../../spec_helper.rb', __FILE__)
6
6
  # available S3 regions:
7
7
  # eu-west-1, us-east-1, ap-southeast-1, us-west-1
8
8
  describe Backup::Storage::S3 do
9
-
10
- let(:s3) do
11
- Backup::Storage::S3.new do |s3|
9
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
10
+ let(:storage) do
11
+ Backup::Storage::S3.new(model) do |s3|
12
12
  s3.access_key_id = 'my_access_key_id'
13
13
  s3.secret_access_key = 'my_secret_access_key'
14
- s3.region = 'us-east-1'
15
14
  s3.bucket = 'my-bucket'
16
- s3.path = 'backups'
17
- s3.keep = 20
15
+ s3.region = 'us-east-1'
16
+ s3.keep = 5
18
17
  end
19
18
  end
20
19
 
21
- before do
22
- Backup::Configuration::Storage::S3.clear_defaults!
23
- end
20
+ describe '#initialize' do
21
+ it 'should set the correct values' do
22
+ storage.access_key_id.should == 'my_access_key_id'
23
+ storage.secret_access_key.should == 'my_secret_access_key'
24
+ storage.bucket.should == 'my-bucket'
25
+ storage.path.should == 'backups'
26
+ storage.region.should == 'us-east-1'
24
27
 
25
- it 'should have defined the configuration properly' do
26
- s3.access_key_id.should == 'my_access_key_id'
27
- s3.secret_access_key.should == 'my_secret_access_key'
28
- s3.region.should == 'us-east-1'
29
- s3.bucket.should == 'my-bucket'
30
- s3.keep.should == 20
31
- end
32
-
33
- it 'should use the defaults if a particular attribute has not been defined' do
34
- Backup::Configuration::Storage::S3.defaults do |s3|
35
- s3.access_key_id = 'my_access_key_id'
36
- s3.region = 'us-east-1'
37
- s3.keep = 500
28
+ storage.storage_id.should be_nil
29
+ storage.keep.should == 5
38
30
  end
39
31
 
40
- s3 = Backup::Storage::S3.new do |s3|
41
- s3.region = 'us-west-1'
42
- s3.path = 'my/backups'
32
+ it 'should set a storage_id if given' do
33
+ s3 = Backup::Storage::S3.new(model, 'my storage_id')
34
+ s3.storage_id.should == 'my storage_id'
43
35
  end
44
36
 
45
- s3.access_key_id.should == 'my_access_key_id' # not defined, uses default
46
- s3.secret_access_key.should == nil # not defined, no default
47
- s3.region.should == 'us-west-1' # defined, overwrites default
48
- s3.bucket.should == nil # not defined, no default
49
- s3.path.should == 'my/backups' # overwritten from Backup::Storage::S3
50
- s3.keep.should == 500 # comes from the default configuration
51
- end
37
+ context 'when setting configuration defaults' do
38
+ after { Backup::Configuration::Storage::S3.clear_defaults! }
39
+
40
+ it 'should use the configured defaults' do
41
+ Backup::Configuration::Storage::S3.defaults do |s3|
42
+ s3.access_key_id = 'some_access_key_id'
43
+ s3.secret_access_key = 'some_secret_access_key'
44
+ s3.bucket = 'some-bucket'
45
+ s3.path = 'some_path'
46
+ s3.region = 'some_region'
47
+ s3.keep = 15
48
+ end
49
+ storage = Backup::Storage::S3.new(model)
50
+ storage.access_key_id.should == 'some_access_key_id'
51
+ storage.secret_access_key.should == 'some_secret_access_key'
52
+ storage.bucket.should == 'some-bucket'
53
+ storage.path.should == 'some_path'
54
+ storage.region.should == 'some_region'
55
+
56
+ storage.storage_id.should be_nil
57
+ storage.keep.should == 15
58
+ end
59
+
60
+ it 'should override the configured defaults' do
61
+ Backup::Configuration::Storage::S3.defaults do |s3|
62
+ s3.access_key_id = 'old_access_key_id'
63
+ s3.secret_access_key = 'old_secret_access_key'
64
+ s3.bucket = 'old-bucket'
65
+ s3.path = 'old_path'
66
+ s3.region = 'old_region'
67
+ s3.keep = 15
68
+ end
69
+ storage = Backup::Storage::S3.new(model) do |s3|
70
+ s3.access_key_id = 'new_access_key_id'
71
+ s3.secret_access_key = 'new_secret_access_key'
72
+ s3.bucket = 'new-bucket'
73
+ s3.path = 'new_path'
74
+ s3.region = 'new_region'
75
+ s3.keep = 10
76
+ end
77
+
78
+ storage.access_key_id.should == 'new_access_key_id'
79
+ storage.secret_access_key.should == 'new_secret_access_key'
80
+ storage.bucket.should == 'new-bucket'
81
+ storage.path.should == 'new_path'
82
+ storage.region.should == 'new_region'
83
+
84
+ storage.storage_id.should be_nil
85
+ storage.keep.should == 10
86
+ end
87
+ end # context 'when setting configuration defaults'
88
+
89
+ end # describe '#initialize'
52
90
 
53
91
  describe '#provider' do
54
- it 'should be AWS' do
55
- s3.provider == 'AWS'
56
- end
57
- end
58
-
59
- describe '#perform' do
60
- it 'should invoke transfer! and cycle!' do
61
- s3.expects(:transfer!)
62
- s3.expects(:cycle!)
63
- s3.perform!
92
+ it 'should set the Fog provider' do
93
+ storage.send(:provider).should == 'AWS'
64
94
  end
65
95
  end
66
96
 
67
97
  describe '#connection' do
68
- it 'should establish and re-use a connection to Amazon S3' do
69
- Fog::Storage.expects(:new).once.with({
98
+ let(:connection) { mock }
99
+
100
+ it 'should create a new connection' do
101
+ Fog::Storage.expects(:new).once.with(
70
102
  :provider => 'AWS',
71
103
  :aws_access_key_id => 'my_access_key_id',
72
104
  :aws_secret_access_key => 'my_secret_access_key',
73
105
  :region => 'us-east-1'
74
- }).returns(true)
106
+ ).returns(connection)
107
+ storage.send(:connection).should == connection
108
+ end
75
109
 
76
- s3.send(:connection)
77
- s3.send(:connection)
110
+ it 'should return an existing connection' do
111
+ Fog::Storage.expects(:new).once.returns(connection)
112
+ storage.send(:connection).should == connection
113
+ storage.send(:connection).should == connection
114
+ end
115
+ end # describe '#connection'
116
+
117
+ describe '#remote_path_for' do
118
+ let(:package) { mock }
119
+
120
+ before do
121
+ # for superclass method
122
+ package.expects(:trigger).returns('trigger')
123
+ package.expects(:time).returns('time')
124
+ end
125
+
126
+ it 'should remove any preceeding slash from the remote path' do
127
+ storage.path = '/backups'
128
+ storage.send(:remote_path_for, package).should == 'backups/trigger/time'
78
129
  end
79
130
  end
80
131
 
81
132
  describe '#transfer!' do
82
- let(:connection) { mock('Fog::Storage') }
133
+ let(:connection) { mock }
134
+ let(:package) { mock }
135
+ let(:file) { mock }
136
+ let(:s) { sequence '' }
137
+
83
138
  before do
84
- Fog::Storage.expects(:new).once.returns(connection)
139
+ storage.instance_variable_set(:@package, package)
140
+ storage.stubs(:storage_name).returns('Storage::S3')
141
+ storage.stubs(:local_path).returns('/local/path')
142
+ storage.stubs(:connection).returns(connection)
85
143
  end
86
144
 
87
- it 'should transfer the provided file to the bucket' do
88
- Backup::Model.new('blah', 'blah') {}
89
- file = mock("Backup::Storage::S3::File")
90
- File.expects(:open).with("#{File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER}")}.tar").returns(file)
91
- connection.expects(:sync_clock)
92
- connection.expects(:put_object).with('my-bucket', "backups/myapp/#{ Backup::TIME }/#{ Backup::TRIGGER }.tar", file)
93
- s3.send(:transfer!)
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(:sync_clock).in_sequence(s)
149
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
150
+ multiple_yields(
151
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
152
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
153
+ )
154
+ # first yield
155
+ Backup::Logger.expects(:message).in_sequence(s).with(
156
+ "Storage::S3 started transferring " +
157
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' to bucket 'my-bucket'."
158
+ )
159
+ File.expects(:open).in_sequence(s).with(
160
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'), 'r'
161
+ ).yields(file)
162
+ connection.expects(:put_object).in_sequence(s).with(
163
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-aa'), file
164
+ )
165
+ # second yield
166
+ Backup::Logger.expects(:message).in_sequence(s).with(
167
+ "Storage::S3 started transferring " +
168
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' to bucket 'my-bucket'."
169
+ )
170
+ File.expects(:open).in_sequence(s).with(
171
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'), 'r'
172
+ ).yields(file)
173
+ connection.expects(:put_object).in_sequence(s).with(
174
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-ab'), file
175
+ )
176
+
177
+ storage.send(:transfer!)
94
178
  end
95
- end
179
+ end # describe '#transfer!'
96
180
 
97
181
  describe '#remove!' do
98
- let(:connection) { mock('Fog::Storage') }
182
+ let(:package) { mock }
183
+ let(:connection) { mock }
184
+ let(:s) { sequence '' }
185
+
99
186
  before do
100
- Fog::Storage.expects(:new).once.returns(connection)
187
+ storage.stubs(:storage_name).returns('Storage::S3')
188
+ storage.stubs(:connection).returns(connection)
101
189
  end
102
190
 
103
- it 'should remove the file from the bucket' do
104
- connection.expects(:sync_clock)
105
- connection.expects(:delete_object).with('my-bucket', "backups/myapp/#{ Backup::TIME }/#{ Backup::TRIGGER }.tar")
106
- s3.send(:remove!)
191
+ it 'should remove the package files' do
192
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
193
+ returns('remote/path')
194
+ connection.expects(:sync_clock).in_sequence(s)
195
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
196
+ multiple_yields(
197
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
198
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
199
+ )
200
+ # first yield
201
+ Backup::Logger.expects(:message).in_sequence(s).with(
202
+ "Storage::S3 started removing " +
203
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' from bucket 'my-bucket'."
204
+ )
205
+ connection.expects(:delete_object).in_sequence(s).with(
206
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-aa')
207
+ )
208
+ # second yield
209
+ Backup::Logger.expects(:message).in_sequence(s).with(
210
+ "Storage::S3 started removing " +
211
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' from bucket 'my-bucket'."
212
+ )
213
+ connection.expects(:delete_object).in_sequence(s).with(
214
+ 'my-bucket', File.join('remote/path', 'backup.tar.enc-ab')
215
+ )
216
+
217
+ storage.send(:remove!, package)
107
218
  end
108
- end
219
+ end # describe '#remove!'
109
220
 
110
221
  end
@@ -3,201 +3,207 @@
3
3
  require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::SCP do
6
-
7
- let(:scp) do
8
- Backup::Storage::SCP.new do |scp|
9
- scp.username = 'my_username'
10
- scp.password = 'my_password'
11
- scp.ip = '123.45.678.90'
12
- scp.port = 22
13
- scp.path = '~/backups/'
14
- scp.keep = 20
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
15
13
  end
16
14
  end
17
15
 
18
- before do
19
- Backup::Configuration::Storage::SCP.clear_defaults!
20
- end
16
+ describe '#initialize' do
17
+ it 'should set the correct values' do
18
+ storage.username.should == 'my_username'
19
+ storage.password.should == 'my_password'
20
+ storage.ip.should == '123.45.678.90'
21
+ storage.port.should == 22
22
+ storage.path.should == 'backups'
21
23
 
22
- it 'should have defined the configuration properly' do
23
- scp.username.should == 'my_username'
24
- scp.password.should == 'my_password'
25
- scp.ip.should == '123.45.678.90'
26
- scp.port.should == 22
27
- scp.path.should == 'backups/'
28
- scp.keep.should == 20
29
- end
24
+ storage.storage_id.should be_nil
25
+ storage.keep.should == 5
26
+ end
30
27
 
31
- it 'should use the defaults if a particular attribute has not been defined' do
32
- Backup::Configuration::Storage::SCP.defaults do |scp|
33
- scp.username = 'my_default_username'
34
- scp.password = 'my_default_password'
35
- scp.path = '~/backups'
28
+ it 'should set a storage_id if given' do
29
+ scp = Backup::Storage::SCP.new(model, 'my storage_id')
30
+ scp.storage_id.should == 'my storage_id'
36
31
  end
37
32
 
38
- scp = Backup::Storage::SCP.new do |scp|
39
- scp.password = 'my_password'
40
- scp.ip = '123.45.678.90'
33
+ it 'should remove any preceeding tilde and slash from the path' do
34
+ storage = Backup::Storage::SCP.new(model) do |scp|
35
+ scp.path = '~/my_backups/path'
36
+ end
37
+ storage.path.should == 'my_backups/path'
41
38
  end
42
39
 
43
- scp.username.should == 'my_default_username'
44
- scp.password.should == 'my_password'
45
- scp.ip.should == '123.45.678.90'
46
- scp.port.should == 22
47
- end
40
+ context 'when setting configuration defaults' do
41
+ after { Backup::Configuration::Storage::SCP.clear_defaults! }
42
+
43
+ it 'should use the configured defaults' do
44
+ Backup::Configuration::Storage::SCP.defaults do |scp|
45
+ scp.username = 'some_username'
46
+ scp.password = 'some_password'
47
+ scp.ip = 'some_ip'
48
+ scp.port = 'some_port'
49
+ scp.path = 'some_path'
50
+ scp.keep = 'some_keep'
51
+ end
52
+ storage = Backup::Storage::SCP.new(model)
53
+ storage.username.should == 'some_username'
54
+ storage.password.should == 'some_password'
55
+ storage.ip.should == 'some_ip'
56
+ storage.port.should == 'some_port'
57
+ storage.path.should == 'some_path'
58
+
59
+ storage.storage_id.should be_nil
60
+ storage.keep.should == 'some_keep'
61
+ end
48
62
 
49
- it 'should have its own defaults' do
50
- scp = Backup::Storage::SCP.new
51
- scp.port.should == 22
52
- scp.path.should == 'backups'
53
- end
63
+ it 'should override the configured defaults' do
64
+ Backup::Configuration::Storage::SCP.defaults do |scp|
65
+ scp.username = 'old_username'
66
+ scp.password = 'old_password'
67
+ scp.ip = 'old_ip'
68
+ scp.port = 'old_port'
69
+ scp.path = 'old_path'
70
+ scp.keep = 'old_keep'
71
+ end
72
+ storage = Backup::Storage::SCP.new(model) do |scp|
73
+ scp.username = 'new_username'
74
+ scp.password = 'new_password'
75
+ scp.ip = 'new_ip'
76
+ scp.port = 'new_port'
77
+ scp.path = 'new_path'
78
+ scp.keep = 'new_keep'
79
+ end
80
+
81
+ storage.username.should == 'new_username'
82
+ storage.password.should == 'new_password'
83
+ storage.ip.should == 'new_ip'
84
+ storage.port.should == 'new_port'
85
+ storage.path.should == 'new_path'
86
+
87
+ storage.storage_id.should be_nil
88
+ storage.keep.should == 'new_keep'
89
+ end
90
+ end # context 'when setting configuration defaults'
54
91
 
55
- describe '#perform' do
56
- it 'should invoke transfer! and cycle!' do
57
- scp.expects(:transfer!)
58
- scp.expects(:cycle!)
59
- scp.perform!
60
- end
61
- end
92
+ end # describe '#initialize'
62
93
 
63
94
  describe '#connection' do
64
- it 'should establish a connection to the remote server' do
65
- connection = mock
95
+ let(:connection) { mock }
96
+ it 'should yield a Net::SSH connection' do
66
97
  Net::SSH.expects(:start).with(
67
- '123.45.678.90',
68
- 'my_username',
69
- :password => 'my_password',
70
- :port => 22
98
+ '123.45.678.90', 'my_username', :password => 'my_password', :port => 22
71
99
  ).yields(connection)
72
100
 
73
- scp.send(:connection) do |ssh|
74
- ssh.should be connection
101
+ storage.send(:connection) do |ssh|
102
+ ssh.should be(connection)
75
103
  end
76
104
  end
77
105
  end
78
106
 
79
107
  describe '#transfer!' do
108
+ let(:connection) { mock }
109
+ let(:package) { mock }
110
+ let(:ssh_scp) { mock }
111
+ let(:s) { sequence '' }
80
112
 
81
113
  before do
82
- scp.stubs(:storage_name).returns('Storage::SCP')
114
+ storage.instance_variable_set(:@package, package)
115
+ storage.stubs(:storage_name).returns('Storage::SCP')
116
+ storage.stubs(:local_path).returns('/local/path')
117
+ storage.stubs(:connection).yields(connection)
118
+ connection.stubs(:scp).returns(ssh_scp)
83
119
  end
84
120
 
85
- context 'when file chunking is not used' do
86
- it 'should create remote paths and transfer using a single connection' do
87
- ssh, ssh_scp = mock, mock
88
- local_file = "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar"
89
- remote_file = "#{ Backup::TRIGGER }.tar"
90
-
91
- scp.expects(:connection).yields(ssh)
92
- scp.expects(:create_remote_directories).with(ssh)
93
-
94
- Backup::Logger.expects(:message).with(
95
- "Storage::SCP started transferring '#{local_file}' to '#{scp.ip}'."
96
- )
121
+ it 'should transfer the package files' do
122
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
123
+ returns('remote/path')
124
+ connection.expects(:exec!).in_sequence(s).with("mkdir -p 'remote/path'")
97
125
 
98
- ssh.expects(:scp).returns(ssh_scp)
99
- ssh_scp.expects(:upload!).with(
100
- File.join(Backup::TMP_PATH, local_file),
101
- File.join('backups/myapp', Backup::TIME, remote_file)
102
- )
103
-
104
- scp.send(:transfer!)
105
- end
106
- end
126
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
127
+ multiple_yields(
128
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
129
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
130
+ )
131
+ # first yield
132
+ Backup::Logger.expects(:message).in_sequence(s).with(
133
+ "Storage::SCP started transferring " +
134
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' to '123.45.678.90'."
135
+ )
136
+ ssh_scp.expects(:upload!).in_sequence(s).with(
137
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'),
138
+ File.join('remote/path', 'backup.tar.enc-aa')
139
+ )
140
+ # second yield
141
+ Backup::Logger.expects(:message).in_sequence(s).with(
142
+ "Storage::SCP started transferring " +
143
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' to '123.45.678.90'."
144
+ )
145
+ ssh_scp.expects(:upload!).in_sequence(s).with(
146
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'),
147
+ File.join('remote/path', 'backup.tar.enc-ab')
148
+ )
107
149
 
108
- context 'when file chunking is used' do
109
- it 'should transfer all the provided files using a single connection' do
110
- s = sequence ''
111
- ssh, ssh_scp = mock, mock
112
-
113
- scp.expects(:connection).in_sequence(s).yields(ssh)
114
- scp.expects(:create_remote_directories).in_sequence(s).with(ssh)
115
-
116
- scp.expects(:files_to_transfer).in_sequence(s).multiple_yields(
117
- ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2']
118
- )
119
-
120
- Backup::Logger.expects(:message).in_sequence(s).with(
121
- "Storage::SCP started transferring 'local_file1' to '#{scp.ip}'."
122
- )
123
- ssh.expects(:scp).in_sequence(s).returns(ssh_scp)
124
- ssh_scp.expects(:upload!).in_sequence(s).with(
125
- File.join(Backup::TMP_PATH, 'local_file1'),
126
- File.join('backups/myapp', Backup::TIME, 'remote_file1')
127
- )
128
-
129
- Backup::Logger.expects(:message).in_sequence(s).with(
130
- "Storage::SCP started transferring 'local_file2' to '#{scp.ip}'."
131
- )
132
- ssh.expects(:scp).in_sequence(s).returns(ssh_scp)
133
- ssh_scp.expects(:upload!).in_sequence(s).with(
134
- File.join(Backup::TMP_PATH, 'local_file2'),
135
- File.join('backups/myapp', Backup::TIME, 'remote_file2')
136
- )
137
-
138
- scp.send(:transfer!)
139
- end
150
+ storage.send(:transfer!)
140
151
  end
141
-
142
152
  end # describe '#transfer!'
143
153
 
144
154
  describe '#remove!' do
155
+ let(:package) { mock }
156
+ let(:connection) { mock }
157
+ let(:s) { sequence '' }
145
158
 
146
159
  before do
147
- scp.stubs(:storage_name).returns('Storage::SCP')
160
+ storage.stubs(:storage_name).returns('Storage::SCP')
161
+ storage.stubs(:connection).yields(connection)
148
162
  end
149
163
 
150
- it 'should remove all remote files with a single logger call' do
151
- ssh = mock
164
+ it 'should remove the package files' do
165
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
166
+ returns('remote/path')
152
167
 
153
- scp.expects(:transferred_files).multiple_yields(
154
- ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2']
168
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
169
+ multiple_yields(
170
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
171
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
155
172
  )
156
-
157
- Backup::Logger.expects(:message).with(
158
- "Storage::SCP started removing 'local_file1' from '#{scp.ip}'.\n" +
159
- "Storage::SCP started removing 'local_file2' from '#{scp.ip}'."
173
+ # after both yields
174
+ Backup::Logger.expects(:message).in_sequence(s).with(
175
+ "Storage::SCP started removing " +
176
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' from '123.45.678.90'.\n" +
177
+ "Storage::SCP started removing " +
178
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' from '123.45.678.90'."
160
179
  )
180
+ connection.expects(:exec!).with("rm -r 'remote/path'").in_sequence(s)
161
181
 
162
- scp.expects(:connection).yields(ssh)
163
- ssh.expects(:exec!).with("rm -r 'backups/myapp/#{ Backup::TIME }'")
164
-
165
- scp.send(:remove!)
182
+ storage.send(:remove!, package)
166
183
  end
167
184
 
168
- it 'should raise an error if Net::SSH reports errors' do
169
- ssh = mock
185
+ context 'when the ssh connection reports errors' do
186
+ it 'should raise an error reporting the errors' do
187
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
188
+ returns('remote/path')
170
189
 
171
- scp.expects(:transferred_files)
172
- Backup::Logger.expects(:message)
190
+ storage.expects(:transferred_files_for).in_sequence(s).with(package)
173
191
 
174
- scp.expects(:connection).yields(ssh)
175
- ssh.expects(:exec!).yields('', :stderr, 'error message')
192
+ Backup::Logger.expects(:message).in_sequence(s)
176
193
 
177
- expect do
178
- scp.send(:remove!)
179
- end.to raise_error(
180
- Backup::Errors::Storage::SCP::SSHError,
181
- "Storage::SCP::SSHError: Net::SSH reported the following errors:\n" +
182
- " error message"
183
- )
184
- end
185
-
186
- end # describe '#remove!'
187
-
188
- describe '#create_remote_directories' do
189
- it 'should properly create remote directories one by one' do
190
- ssh = mock
191
- scp.path = 'backups/some_other_folder/another_folder'
194
+ connection.expects(:exec!).with("rm -r 'remote/path'").in_sequence(s).
195
+ yields(:ch, :stderr, 'path not found')
192
196
 
193
- ssh.expects(:exec!).with("mkdir 'backups'")
194
- ssh.expects(:exec!).with("mkdir 'backups/some_other_folder'")
195
- ssh.expects(:exec!).with("mkdir 'backups/some_other_folder/another_folder'")
196
- ssh.expects(:exec!).with("mkdir 'backups/some_other_folder/another_folder/myapp'")
197
- ssh.expects(:exec!).with("mkdir 'backups/some_other_folder/another_folder/myapp/#{ Backup::TIME }'")
198
-
199
- scp.send(:create_remote_directories, ssh)
197
+ expect do
198
+ storage.send(:remove!, package)
199
+ end.to raise_error {|err|
200
+ err.should be_an_instance_of Backup::Errors::Storage::SCP::SSHError
201
+ err.message.should == "Storage::SCP::SSHError: " +
202
+ "Net::SSH reported the following errors:\n" +
203
+ " path not found"
204
+ }
205
+ end
200
206
  end
201
- end
207
+ end # describe '#remove!'
202
208
 
203
209
  end