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
@@ -3,229 +3,242 @@
3
3
  require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::FTP do
6
-
7
- let(:ftp) do
8
- Backup::Storage::FTP.new do |ftp|
6
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
7
+ let(:storage) do
8
+ Backup::Storage::FTP.new(model) do |ftp|
9
9
  ftp.username = 'my_username'
10
10
  ftp.password = 'my_password'
11
11
  ftp.ip = '123.45.678.90'
12
- ftp.port = 21
13
- ftp.path = '~/backups/'
14
- ftp.keep = 20
15
- ftp.passive_mode = false
12
+ ftp.keep = 5
16
13
  end
17
14
  end
18
15
 
19
- before do
20
- Backup::Configuration::Storage::FTP.clear_defaults!
21
- end
22
-
23
- it 'should have defined the configuration properly' do
24
- ftp.username.should == 'my_username'
25
- ftp.password.should == 'my_password'
26
- ftp.ip.should == '123.45.678.90'
27
- ftp.port.should == 21
28
- ftp.path.should == 'backups/'
29
- ftp.keep.should == 20
30
- ftp.passive_mode.should == false
31
- 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 == 21
22
+ storage.path.should == 'backups'
23
+ storage.passive_mode.should == false
24
+
25
+ storage.storage_id.should be_nil
26
+ storage.keep.should == 5
27
+ end
32
28
 
33
- it 'should use the defaults if a particular attribute has not been defined' do
34
- Backup::Configuration::Storage::FTP.defaults do |ftp|
35
- ftp.username = 'my_default_username'
36
- ftp.password = 'my_default_password'
37
- ftp.path = '~/backups'
29
+ it 'should set a storage_id if given' do
30
+ ftp = Backup::Storage::FTP.new(model, 'my storage_id')
31
+ ftp.storage_id.should == 'my storage_id'
38
32
  end
39
33
 
40
- ftp = Backup::Storage::FTP.new do |ftp|
41
- ftp.password = 'my_password'
42
- ftp.ip = '123.45.678.90'
34
+ it 'should remove any preceeding tilde and slash from the path' do
35
+ storage = Backup::Storage::FTP.new(model) do |ftp|
36
+ ftp.path = '~/my_backups/path'
37
+ end
38
+ storage.path.should == 'my_backups/path'
43
39
  end
44
40
 
45
- ftp.username.should == 'my_default_username'
46
- ftp.password.should == 'my_password'
47
- ftp.ip.should == '123.45.678.90'
48
- ftp.port.should == 21
49
- end
41
+ context 'when setting configuration defaults' do
42
+ after { Backup::Configuration::Storage::FTP.clear_defaults! }
43
+
44
+ it 'should use the configured defaults' do
45
+ Backup::Configuration::Storage::FTP.defaults do |ftp|
46
+ ftp.username = 'some_username'
47
+ ftp.password = 'some_password'
48
+ ftp.ip = 'some_ip'
49
+ ftp.port = 'some_port'
50
+ ftp.path = 'some_path'
51
+ ftp.passive_mode = 'some_passive_mode'
52
+ ftp.keep = 'some_keep'
53
+ end
54
+ storage = Backup::Storage::FTP.new(model)
55
+ storage.username.should == 'some_username'
56
+ storage.password.should == 'some_password'
57
+ storage.ip.should == 'some_ip'
58
+ storage.port.should == 'some_port'
59
+ storage.path.should == 'some_path'
60
+ storage.passive_mode.should == 'some_passive_mode'
61
+
62
+ storage.storage_id.should be_nil
63
+ storage.keep.should == 'some_keep'
64
+ end
50
65
 
51
- it 'should have its own defaults' do
52
- ftp = Backup::Storage::FTP.new
53
- ftp.port.should == 21
54
- ftp.path.should == 'backups'
55
- ftp.passive_mode.should == false
56
- end
66
+ it 'should override the configured defaults' do
67
+ Backup::Configuration::Storage::FTP.defaults do |ftp|
68
+ ftp.username = 'old_username'
69
+ ftp.password = 'old_password'
70
+ ftp.ip = 'old_ip'
71
+ ftp.port = 'old_port'
72
+ ftp.path = 'old_path'
73
+ ftp.passive_mode = 'old_passive_mode'
74
+ ftp.keep = 'old_keep'
75
+ end
76
+ storage = Backup::Storage::FTP.new(model) do |ftp|
77
+ ftp.username = 'new_username'
78
+ ftp.password = 'new_password'
79
+ ftp.ip = 'new_ip'
80
+ ftp.port = 'new_port'
81
+ ftp.path = 'new_path'
82
+ ftp.passive_mode = 'new_passive_mode'
83
+ ftp.keep = 'new_keep'
84
+ end
85
+
86
+ storage.username.should == 'new_username'
87
+ storage.password.should == 'new_password'
88
+ storage.ip.should == 'new_ip'
89
+ storage.port.should == 'new_port'
90
+ storage.path.should == 'new_path'
91
+ storage.passive_mode.should == 'new_passive_mode'
92
+
93
+ storage.storage_id.should be_nil
94
+ storage.keep.should == 'new_keep'
95
+ end
96
+ end # context 'when setting configuration defaults'
57
97
 
58
- describe '#perform' do
59
- it 'should invoke transfer! and cycle!' do
60
- ftp.expects(:transfer!)
61
- ftp.expects(:cycle!)
62
- ftp.perform!
63
- end
64
- end
98
+ end # describe '#initialize'
65
99
 
66
100
  describe '#connection' do
67
101
  let(:connection) { mock }
68
102
 
69
- it 'should establish a connection to the remote server' do
103
+ it 'should yield a connection to the remote server' do
70
104
  Net::FTP.expects(:open).with(
71
105
  '123.45.678.90', 'my_username', 'my_password'
72
106
  ).yields(connection)
73
107
 
74
- ftp.send(:connection) do |conn|
75
- conn.should be connection
108
+ storage.send(:connection) do |ftp|
109
+ ftp.should be(connection)
76
110
  end
77
111
  end
78
112
 
79
- it 'configures net/ftp to use passive mode if passive_mode set to true' do
80
- ftp.passive_mode = true
113
+ it 'should set passive mode if @passive_mode is true' do
114
+ storage.passive_mode = true
81
115
  Net::FTP.expects(:open).with(
82
116
  '123.45.678.90', 'my_username', 'my_password'
83
117
  ).yields(connection)
84
118
  connection.expects(:passive=).with(true)
85
119
 
86
- ftp.send(:connection) do |conn|
87
- conn.should be connection
120
+ storage.send(:connection) do |ftp|
121
+ ftp.should be(connection)
88
122
  end
89
123
  end
90
124
 
91
- context 'when re-defining the Net::FTP port' do
92
-
93
- def reset_ftp_port
94
- if defined? Net::FTP::FTP_PORT
95
- Net::FTP.send(:remove_const, :FTP_PORT)
96
- end; Net::FTP.send(:const_set, :FTP_PORT, 21)
97
- end
98
-
99
- before { reset_ftp_port }
100
- after { reset_ftp_port }
101
-
102
- it 'should re-define Net::FTP::FTP_PORT' do
103
- Net::FTP.stubs(:open)
104
- ftp.port = 40
105
- ftp.send(:connection)
106
- Net::FTP::FTP_PORT.should == 40
107
- end
125
+ it 'should set the Net::FTP_PORT constant' do
126
+ storage.port = 40
127
+ Net::FTP.expects(:const_defined?).with(:FTP_PORT).returns(true)
128
+ Net::FTP.expects(:send).with(:remove_const, :FTP_PORT)
129
+ Net::FTP.expects(:send).with(:const_set, :FTP_PORT, 40)
108
130
 
131
+ Net::FTP.expects(:open)
132
+ storage.send(:connection)
109
133
  end
110
134
 
111
135
  end # describe '#connection'
112
136
 
113
137
  describe '#transfer!' do
114
138
  let(:connection) { mock }
139
+ let(:package) { mock }
140
+ let(:s) { sequence '' }
115
141
 
116
142
  before do
117
- ftp.stubs(:storage_name).returns('Storage::FTP')
143
+ storage.instance_variable_set(:@package, package)
144
+ storage.stubs(:storage_name).returns('Storage::FTP')
145
+ storage.stubs(:local_path).returns('/local/path')
146
+ storage.stubs(:connection).yields(connection)
118
147
  end
119
148
 
120
- context 'when file chunking is not used' do
121
- it 'should create remote paths and transfer using a single connection' do
122
- local_file = "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar"
123
- remote_file = "#{ Backup::TRIGGER }.tar"
124
-
125
- ftp.expects(:connection).yields(connection)
126
- ftp.expects(:create_remote_directories).with(connection)
127
-
128
- Backup::Logger.expects(:message).with(
129
- "Storage::FTP started transferring '#{local_file}' to '#{ftp.ip}'."
130
- )
131
-
132
- connection.expects(:put).with(
133
- File.join(Backup::TMP_PATH, local_file),
134
- File.join('backups/myapp', Backup::TIME, remote_file)
135
- )
149
+ it 'should transfer the package files' do
150
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
151
+ returns('remote/path')
152
+ storage.expects(:create_remote_path).in_sequence(s).with(
153
+ 'remote/path', connection
154
+ )
136
155
 
137
- ftp.send(:transfer!)
138
- end
139
- end
156
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
157
+ multiple_yields(
158
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
159
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
160
+ )
161
+ # first yield
162
+ Backup::Logger.expects(:message).in_sequence(s).with(
163
+ "Storage::FTP started transferring " +
164
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' to '123.45.678.90'."
165
+ )
166
+ connection.expects(:put).in_sequence(s).with(
167
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'),
168
+ File.join('remote/path', 'backup.tar.enc-aa')
169
+ )
170
+ # second yield
171
+ Backup::Logger.expects(:message).in_sequence(s).with(
172
+ "Storage::FTP started transferring " +
173
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' to '123.45.678.90'."
174
+ )
175
+ connection.expects(:put).in_sequence(s).with(
176
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'),
177
+ File.join('remote/path', 'backup.tar.enc-ab')
178
+ )
140
179
 
141
- context 'when file chunking is used' do
142
- it 'should transfer all the provided files using a single connection' do
143
- s = sequence ''
144
-
145
- ftp.expects(:connection).in_sequence(s).yields(connection)
146
- ftp.expects(:create_remote_directories).in_sequence(s).with(connection)
147
-
148
- ftp.expects(:files_to_transfer).in_sequence(s).multiple_yields(
149
- ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2']
150
- )
151
-
152
- Backup::Logger.expects(:message).in_sequence(s).with(
153
- "Storage::FTP started transferring 'local_file1' to '#{ftp.ip}'."
154
- )
155
- connection.expects(:put).in_sequence(s).with(
156
- File.join(Backup::TMP_PATH, 'local_file1'),
157
- File.join('backups/myapp', Backup::TIME, 'remote_file1')
158
- )
159
-
160
- Backup::Logger.expects(:message).in_sequence(s).with(
161
- "Storage::FTP started transferring 'local_file2' to '#{ftp.ip}'."
162
- )
163
- connection.expects(:put).in_sequence(s).with(
164
- File.join(Backup::TMP_PATH, 'local_file2'),
165
- File.join('backups/myapp', Backup::TIME, 'remote_file2')
166
- )
167
-
168
- ftp.send(:transfer!)
169
- end
180
+ storage.send(:transfer!)
170
181
  end
171
- end # describe '#transfer'
182
+ end # describe '#transfer!'
172
183
 
173
184
  describe '#remove!' do
174
- it 'should remove all remote files with a single FTP connection' do
175
- s = sequence ''
176
- connection = mock
177
- remote_path = "backups/myapp/#{ Backup::TIME }"
178
- ftp.stubs(:storage_name).returns('Storage::FTP')
185
+ let(:package) { mock }
186
+ let(:connection) { mock }
187
+ let(:s) { sequence '' }
179
188
 
180
- ftp.expects(:connection).in_sequence(s).yields(connection)
189
+ before do
190
+ storage.stubs(:storage_name).returns('Storage::FTP')
191
+ storage.stubs(:connection).yields(connection)
192
+ end
181
193
 
182
- ftp.expects(:transferred_files).in_sequence(s).multiple_yields(
183
- ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2']
184
- )
194
+ it 'should remove the package files' do
195
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
196
+ returns('remote/path')
185
197
 
198
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
199
+ multiple_yields(
200
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
201
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
202
+ )
203
+ # first yield
186
204
  Backup::Logger.expects(:message).in_sequence(s).with(
187
- "Storage::FTP started removing 'local_file1' from '#{ftp.ip}'."
205
+ "Storage::FTP started removing " +
206
+ "'2011.12.31.11.00.02.backup.tar.enc-aa' from '123.45.678.90'."
188
207
  )
189
208
  connection.expects(:delete).in_sequence(s).with(
190
- File.join(remote_path, 'remote_file1')
209
+ File.join('remote/path', 'backup.tar.enc-aa')
191
210
  )
192
-
211
+ # second yield
193
212
  Backup::Logger.expects(:message).in_sequence(s).with(
194
- "Storage::FTP started removing 'local_file2' from '#{ftp.ip}'."
213
+ "Storage::FTP started removing " +
214
+ "'2011.12.31.11.00.02.backup.tar.enc-ab' from '123.45.678.90'."
195
215
  )
196
216
  connection.expects(:delete).in_sequence(s).with(
197
- File.join(remote_path, 'remote_file2')
217
+ File.join('remote/path', 'backup.tar.enc-ab')
198
218
  )
199
219
 
200
- connection.expects(:rmdir).in_sequence(s).with(remote_path)
220
+ connection.expects(:rmdir).with('remote/path').in_sequence(s)
201
221
 
202
- ftp.send(:remove!)
222
+ storage.send(:remove!, package)
203
223
  end
204
224
  end # describe '#remove!'
205
225
 
206
- describe '#create_remote_directories!' do
207
- let(:connection) { mock }
226
+ describe '#create_remote_path' do
227
+ let(:connection) { mock }
228
+ let(:remote_path) { 'backups/folder/another_folder' }
229
+ let(:s) { sequence '' }
208
230
 
209
231
  context 'while properly creating remote directories one by one' do
210
- it 'should rescue any FTPPermErrors' do
211
- s = sequence ''
212
- ftp.path = '~/backups/some_other_folder/another_folder'
213
-
214
- connection.expects(:mkdir).in_sequence(s).
215
- with("~").raises(Net::FTPPermError)
216
- connection.expects(:mkdir).in_sequence(s).
217
- with("~/backups").raises(Net::FTPPermError)
218
- connection.expects(:mkdir).in_sequence(s).
219
- with("~/backups/some_other_folder")
232
+ it 'should rescue any FTPPermErrors and continue' do
220
233
  connection.expects(:mkdir).in_sequence(s).
221
- with("~/backups/some_other_folder/another_folder")
234
+ with("backups").raises(Net::FTPPermError)
222
235
  connection.expects(:mkdir).in_sequence(s).
223
- with("~/backups/some_other_folder/another_folder/myapp")
236
+ with("backups/folder")
224
237
  connection.expects(:mkdir).in_sequence(s).
225
- with("~/backups/some_other_folder/another_folder/myapp/#{ Backup::TIME }")
238
+ with("backups/folder/another_folder")
226
239
 
227
240
  expect do
228
- ftp.send(:create_remote_directories, connection)
241
+ storage.send(:create_remote_path, remote_path, connection)
229
242
  end.not_to raise_error
230
243
  end
231
244
  end
@@ -3,81 +3,233 @@
3
3
  require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::Local do
6
-
7
- let(:local) do
8
- Backup::Storage::Local.new do |local|
9
- local.path = '~/backups/'
10
- local.keep = 20
6
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
7
+ let(:storage_path) do
8
+ File.join(File.expand_path(ENV['HOME'] || ''), 'backups')
9
+ end
10
+ let(:storage) do
11
+ Backup::Storage::Local.new(model) do |local|
12
+ local.keep = 5
11
13
  end
12
14
  end
13
15
 
14
- before do
15
- Backup::Configuration::Storage::Local.clear_defaults!
16
- end
16
+ describe '#initialize' do
17
+ it 'should set the correct values' do
18
+ storage.path.should == storage_path
17
19
 
18
- it 'should have defined the configuration properly' do
19
- local.path.should == "#{ENV['HOME']}/backups"
20
- local.keep.should == 20
21
- end
20
+ storage.storage_id.should be_nil
21
+ storage.keep.should == 5
22
+ end
22
23
 
23
- it 'should use the defaults if a particular attribute has not been defined' do
24
- Backup::Configuration::Storage::Local.defaults do |local|
25
- local.path = '~/backups'
24
+ it 'should set a storage_id if given' do
25
+ local = Backup::Storage::Local.new(model, 'my storage_id')
26
+ local.storage_id.should == 'my storage_id'
26
27
  end
27
28
 
28
- local = Backup::Storage::Local.new do |local|
29
- local.path = '~/my-backups'
29
+ it 'should expand any path given' do
30
+ storage = Backup::Storage::Local.new(model) do |local|
31
+ local.path = 'my_backups/path'
32
+ end
33
+ storage.path.should == File.expand_path('my_backups/path')
30
34
  end
31
35
 
32
- local.path.should == "#{ENV['HOME']}/my-backups"
33
- end
36
+ context 'when setting configuration defaults' do
37
+ after { Backup::Configuration::Storage::Local.clear_defaults! }
34
38
 
35
- it 'should have its own defaults' do
36
- local = Backup::Storage::Local.new
37
- local.path.should == "#{ENV['HOME']}/backups"
38
- end
39
+ it 'should use the configured defaults' do
40
+ Backup::Configuration::Storage::Local.defaults do |local|
41
+ local.path = 'some_path'
42
+ local.keep = 'some_keep'
43
+ end
44
+ storage = Backup::Storage::Local.new(model)
45
+ storage.path.should == File.expand_path('some_path')
39
46
 
40
- describe '#transfer!' do
41
- before do
42
- local.stubs(:create_local_directories!)
43
- end
47
+ storage.storage_id.should be_nil
48
+ storage.keep.should == 'some_keep'
49
+ end
44
50
 
45
- it 'should transfer the provided file to the path' do
46
- Backup::Model.new('blah', 'blah') {}
47
- file = mock("Backup::Storage::Local::File")
51
+ it 'should override the configured defaults' do
52
+ Backup::Configuration::Storage::Local.defaults do |local|
53
+ local.path = 'old_path'
54
+ local.keep = 'old_keep'
55
+ end
56
+ storage = Backup::Storage::Local.new(model) do |local|
57
+ local.path = 'new_path'
58
+ local.keep = 'new_keep'
59
+ end
48
60
 
49
- local.expects(:create_local_directories!)
61
+ storage.path.should == File.expand_path('new_path')
50
62
 
51
- FileUtils.expects(:cp).with(
52
- File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar"),
53
- File.join("#{ENV['HOME']}/backups/myapp", Backup::TIME, "#{ Backup::TRIGGER }.tar")
54
- )
63
+ storage.storage_id.should be_nil
64
+ storage.keep.should == 'new_keep'
65
+ end
66
+ end # context 'when setting configuration defaults'
67
+
68
+ end # describe '#initialize'
69
+
70
+ describe '#transfer!' do
71
+ let(:package) { mock }
72
+ let(:s) { sequence '' }
55
73
 
56
- local.send(:transfer!)
74
+ before do
75
+ storage.instance_variable_set(:@package, package)
76
+ storage.stubs(:storage_name).returns('Storage::Local')
77
+ storage.stubs(:local_path).returns('/local/path')
57
78
  end
58
- end
79
+
80
+ context 'when transfer_method is :mv' do
81
+ before { storage.stubs(:transfer_method).returns(:mv) }
82
+ it 'should move the package files to their destination' do
83
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
84
+ returns('remote/path')
85
+ FileUtils.expects(:mkdir_p).in_sequence(s).with('remote/path')
86
+
87
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
88
+ multiple_yields(
89
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
90
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
91
+ )
92
+ # first yield
93
+ Backup::Logger.expects(:message).in_sequence(s).with(
94
+ "Storage::Local started transferring " +
95
+ "'2011.12.31.11.00.02.backup.tar.enc-aa'."
96
+ )
97
+ FileUtils.expects(:mv).in_sequence(s).with(
98
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'),
99
+ File.join('remote/path', 'backup.tar.enc-aa')
100
+ )
101
+ # second yield
102
+ Backup::Logger.expects(:message).in_sequence(s).with(
103
+ "Storage::Local started transferring " +
104
+ "'2011.12.31.11.00.02.backup.tar.enc-ab'."
105
+ )
106
+ FileUtils.expects(:mv).in_sequence(s).with(
107
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'),
108
+ File.join('remote/path', 'backup.tar.enc-ab')
109
+ )
110
+
111
+ storage.send(:transfer!)
112
+ end
113
+ end # context 'when transfer_method is :mv'
114
+
115
+ context 'when transfer_method is :cp' do
116
+ before { storage.stubs(:transfer_method).returns(:cp) }
117
+ it 'should copy the package files to their destination' do
118
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
119
+ returns('remote/path')
120
+ FileUtils.expects(:mkdir_p).in_sequence(s).with('remote/path')
121
+
122
+ storage.expects(:files_to_transfer_for).in_sequence(s).with(package).
123
+ multiple_yields(
124
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
125
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
126
+ )
127
+ # first yield
128
+ Backup::Logger.expects(:message).in_sequence(s).with(
129
+ "Storage::Local started transferring " +
130
+ "'2011.12.31.11.00.02.backup.tar.enc-aa'."
131
+ )
132
+ FileUtils.expects(:cp).in_sequence(s).with(
133
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'),
134
+ File.join('remote/path', 'backup.tar.enc-aa')
135
+ )
136
+ # second yield
137
+ Backup::Logger.expects(:message).in_sequence(s).with(
138
+ "Storage::Local started transferring " +
139
+ "'2011.12.31.11.00.02.backup.tar.enc-ab'."
140
+ )
141
+ FileUtils.expects(:cp).in_sequence(s).with(
142
+ File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'),
143
+ File.join('remote/path', 'backup.tar.enc-ab')
144
+ )
145
+
146
+ storage.send(:transfer!)
147
+ end
148
+ end # context 'when transfer_method is :cp'
149
+
150
+ end # describe '#transfer!'
59
151
 
60
152
  describe '#remove!' do
61
- it 'should remove the file from the remote server path' do
62
- FileUtils.expects(:rm_r).with("#{ENV['HOME']}/backups/myapp/#{ Backup::TIME }")
63
- local.send(:remove!)
64
- end
65
- end
153
+ let(:package) { mock }
154
+ let(:s) { sequence '' }
66
155
 
67
- describe '#create_local_directories!' do
68
- it 'should properly create remote directories one by one' do
69
- local.path = "#{ENV['HOME']}/backups/some_other_folder/another_folder"
70
- FileUtils.expects(:mkdir_p).with("#{ENV['HOME']}/backups/some_other_folder/another_folder/myapp/#{ Backup::TIME }")
71
- local.send(:create_local_directories!)
156
+ before do
157
+ storage.stubs(:storage_name).returns('Storage::Local')
72
158
  end
73
- end
74
159
 
75
- describe '#perform' do
76
- it 'should invoke transfer! and cycle!' do
77
- local.expects(:transfer!)
78
- local.expects(:cycle!)
79
- local.perform!
160
+ it 'should remove the package files' do
161
+ storage.expects(:remote_path_for).in_sequence(s).with(package).
162
+ returns('remote/path')
163
+
164
+ storage.expects(:transferred_files_for).in_sequence(s).with(package).
165
+ multiple_yields(
166
+ ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'],
167
+ ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab']
168
+ )
169
+ # after both yields
170
+ Backup::Logger.expects(:message).in_sequence(s).with(
171
+ "Storage::Local started removing " +
172
+ "'2011.12.31.11.00.02.backup.tar.enc-aa'.\n" +
173
+ "Storage::Local started removing " +
174
+ "'2011.12.31.11.00.02.backup.tar.enc-ab'."
175
+ )
176
+ FileUtils.expects(:rm_r).in_sequence(s).with('remote/path')
177
+
178
+ storage.send(:remove!, package)
80
179
  end
81
- end
180
+ end # describe '#remove!'
181
+
182
+ describe '#transfer_method' do
183
+ context 'when the storage is the last for the model' do
184
+ before do
185
+ model.storages << storage
186
+ end
187
+
188
+ it 'should return :mv' do
189
+ storage.send(:transfer_method).should == :mv
190
+ storage.instance_variable_get(:@transfer_method).should == :mv
191
+ end
192
+
193
+ it 'should only check once' do
194
+ storage.instance_variable_set(:@transfer_method, :mv)
195
+ model.expects(:storages).never
196
+ storage.send(:transfer_method).should == :mv
197
+ end
198
+ end # context 'when the storage is the last for the model'
199
+
200
+ context 'when the storage is not the last for the model' do
201
+ let(:package) { mock }
202
+
203
+ before do
204
+ model.storages << storage
205
+ model.storages << Backup::Storage::Local.new(model)
206
+
207
+ storage.instance_variable_set(:@package, package)
208
+ end
209
+
210
+ it 'should log a warning and return :cp' do
211
+ storage.expects(:remote_path_for).with(package).returns('remote_path')
212
+ Backup::Logger.expects(:warn).with do |err|
213
+ err.should be_an_instance_of Backup::Errors::Storage::Local::TransferError
214
+ err.message.should ==
215
+ "Storage::Local::TransferError: Local File Copy Warning!\n" +
216
+ " The final backup file(s) for 'test label' (test_trigger)\n" +
217
+ " will be *copied* to 'remote_path'\n" +
218
+ " To avoid this, when using more than one Storage, the 'Local' Storage\n" +
219
+ " should be added *last* so the files may be *moved* to their destination."
220
+ end
221
+
222
+ storage.send(:transfer_method).should == :cp
223
+ storage.instance_variable_get(:@transfer_method).should == :cp
224
+ end
225
+
226
+ it 'should only check once' do
227
+ storage.instance_variable_set(:@transfer_method, :cp)
228
+ model.expects(:storages).never
229
+ storage.send(:transfer_method).should == :cp
230
+ end
231
+ end # context 'when the storage is not the last for the model'
232
+
233
+ end # describe '#transfer_method'
82
234
 
83
235
  end