backup 3.0.20 → 3.0.21

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 (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