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