backup 3.0.19 → 3.0.20

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 (188) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +9 -8
  3. data/Gemfile.lock +19 -1
  4. data/Guardfile +13 -9
  5. data/README.md +93 -31
  6. data/backup.gemspec +3 -3
  7. data/bin/backup +6 -283
  8. data/lib/backup.rb +101 -72
  9. data/lib/backup/archive.rb +21 -9
  10. data/lib/backup/binder.rb +22 -0
  11. data/lib/backup/cleaner.rb +36 -0
  12. data/lib/backup/cli/helpers.rb +103 -0
  13. data/lib/backup/cli/utility.rb +308 -0
  14. data/lib/backup/compressor/base.rb +2 -2
  15. data/lib/backup/compressor/pbzip2.rb +76 -0
  16. data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
  17. data/lib/backup/configuration/database/riak.rb +25 -0
  18. data/lib/backup/configuration/encryptor/open_ssl.rb +6 -0
  19. data/lib/backup/configuration/helpers.rb +5 -18
  20. data/lib/backup/configuration/notifier/base.rb +13 -0
  21. data/lib/backup/configuration/notifier/hipchat.rb +41 -0
  22. data/lib/backup/configuration/notifier/mail.rb +38 -0
  23. data/lib/backup/configuration/notifier/prowl.rb +23 -0
  24. data/lib/backup/configuration/storage/cloudfiles.rb +4 -0
  25. data/lib/backup/configuration/storage/dropbox.rb +8 -4
  26. data/lib/backup/database/base.rb +10 -2
  27. data/lib/backup/database/mongodb.rb +16 -19
  28. data/lib/backup/database/mysql.rb +2 -2
  29. data/lib/backup/database/postgresql.rb +2 -2
  30. data/lib/backup/database/redis.rb +15 -7
  31. data/lib/backup/database/riak.rb +45 -0
  32. data/lib/backup/dependency.rb +21 -7
  33. data/lib/backup/encryptor/base.rb +1 -1
  34. data/lib/backup/encryptor/open_ssl.rb +20 -5
  35. data/lib/backup/errors.rb +124 -0
  36. data/lib/backup/finder.rb +11 -3
  37. data/lib/backup/logger.rb +121 -82
  38. data/lib/backup/model.rb +103 -44
  39. data/lib/backup/notifier/base.rb +50 -0
  40. data/lib/backup/notifier/campfire.rb +32 -52
  41. data/lib/backup/notifier/hipchat.rb +99 -0
  42. data/lib/backup/notifier/mail.rb +100 -61
  43. data/lib/backup/notifier/presently.rb +31 -40
  44. data/lib/backup/notifier/prowl.rb +73 -0
  45. data/lib/backup/notifier/twitter.rb +29 -39
  46. data/lib/backup/packager.rb +25 -0
  47. data/lib/backup/splitter.rb +62 -0
  48. data/lib/backup/storage/base.rb +178 -18
  49. data/lib/backup/storage/cloudfiles.rb +34 -28
  50. data/lib/backup/storage/dropbox.rb +64 -67
  51. data/lib/backup/storage/ftp.rb +48 -40
  52. data/lib/backup/storage/local.rb +33 -28
  53. data/lib/backup/storage/ninefold.rb +40 -26
  54. data/lib/backup/storage/object.rb +8 -6
  55. data/lib/backup/storage/rsync.rb +61 -51
  56. data/lib/backup/storage/s3.rb +29 -27
  57. data/lib/backup/storage/scp.rb +56 -36
  58. data/lib/backup/storage/sftp.rb +49 -33
  59. data/lib/backup/syncer/base.rb +1 -1
  60. data/lib/backup/syncer/rsync.rb +1 -1
  61. data/lib/backup/template.rb +46 -0
  62. data/lib/backup/version.rb +1 -1
  63. data/spec/archive_spec.rb +34 -9
  64. data/spec/backup_spec.rb +1 -1
  65. data/spec/cli/helpers_spec.rb +35 -0
  66. data/spec/cli/utility_spec.rb +38 -0
  67. data/spec/compressor/bzip2_spec.rb +1 -1
  68. data/spec/compressor/gzip_spec.rb +1 -1
  69. data/spec/compressor/lzma_spec.rb +1 -1
  70. data/spec/compressor/pbzip2_spec.rb +63 -0
  71. data/spec/configuration/base_spec.rb +1 -1
  72. data/spec/configuration/compressor/bzip2_spec.rb +1 -1
  73. data/spec/configuration/compressor/gzip_spec.rb +1 -1
  74. data/spec/configuration/compressor/lzma_spec.rb +1 -1
  75. data/spec/configuration/database/base_spec.rb +1 -1
  76. data/spec/configuration/database/mongodb_spec.rb +1 -1
  77. data/spec/configuration/database/mysql_spec.rb +1 -1
  78. data/spec/configuration/database/postgresql_spec.rb +1 -1
  79. data/spec/configuration/database/redis_spec.rb +1 -1
  80. data/spec/configuration/database/riak_spec.rb +31 -0
  81. data/spec/configuration/encryptor/gpg_spec.rb +1 -1
  82. data/spec/configuration/encryptor/open_ssl_spec.rb +4 -1
  83. data/spec/configuration/notifier/campfire_spec.rb +1 -1
  84. data/spec/configuration/notifier/hipchat_spec.rb +43 -0
  85. data/spec/configuration/notifier/mail_spec.rb +34 -22
  86. data/spec/configuration/notifier/presently_spec.rb +1 -1
  87. data/spec/configuration/notifier/prowl_spec.rb +28 -0
  88. data/spec/configuration/notifier/twitter_spec.rb +1 -1
  89. data/spec/configuration/storage/cloudfiles_spec.rb +19 -16
  90. data/spec/configuration/storage/dropbox_spec.rb +1 -1
  91. data/spec/configuration/storage/ftp_spec.rb +1 -1
  92. data/spec/configuration/storage/local_spec.rb +1 -1
  93. data/spec/configuration/storage/ninefold_spec.rb +1 -1
  94. data/spec/configuration/storage/rsync_spec.rb +1 -1
  95. data/spec/configuration/storage/s3_spec.rb +1 -1
  96. data/spec/configuration/storage/scp_spec.rb +1 -1
  97. data/spec/configuration/storage/sftp_spec.rb +1 -1
  98. data/spec/configuration/syncer/rsync_spec.rb +1 -1
  99. data/spec/configuration/syncer/s3_spec.rb +1 -1
  100. data/spec/database/base_spec.rb +10 -1
  101. data/spec/database/mongodb_spec.rb +34 -7
  102. data/spec/database/mysql_spec.rb +8 -7
  103. data/spec/database/postgresql_spec.rb +8 -7
  104. data/spec/database/redis_spec.rb +39 -9
  105. data/spec/database/riak_spec.rb +50 -0
  106. data/spec/encryptor/gpg_spec.rb +1 -1
  107. data/spec/encryptor/open_ssl_spec.rb +77 -20
  108. data/spec/errors_spec.rb +306 -0
  109. data/spec/finder_spec.rb +91 -0
  110. data/spec/logger_spec.rb +254 -33
  111. data/spec/model_spec.rb +120 -15
  112. data/spec/notifier/campfire_spec.rb +127 -52
  113. data/spec/notifier/hipchat_spec.rb +193 -0
  114. data/spec/notifier/mail_spec.rb +290 -74
  115. data/spec/notifier/presently_spec.rb +290 -73
  116. data/spec/notifier/prowl_spec.rb +149 -0
  117. data/spec/notifier/twitter_spec.rb +106 -41
  118. data/spec/spec_helper.rb +8 -2
  119. data/spec/splitter_spec.rb +71 -0
  120. data/spec/storage/base_spec.rb +280 -19
  121. data/spec/storage/cloudfiles_spec.rb +38 -22
  122. data/spec/storage/dropbox_spec.rb +17 -13
  123. data/spec/storage/ftp_spec.rb +145 -55
  124. data/spec/storage/local_spec.rb +6 -6
  125. data/spec/storage/ninefold_spec.rb +70 -29
  126. data/spec/storage/object_spec.rb +44 -44
  127. data/spec/storage/rsync_spec.rb +186 -63
  128. data/spec/storage/s3_spec.rb +23 -24
  129. data/spec/storage/scp_spec.rb +116 -41
  130. data/spec/storage/sftp_spec.rb +124 -46
  131. data/spec/syncer/rsync_spec.rb +3 -3
  132. data/spec/syncer/s3_spec.rb +1 -1
  133. data/spec/version_spec.rb +1 -1
  134. data/templates/cli/utility/archive +13 -0
  135. data/{lib/templates → templates/cli/utility}/compressor/bzip2 +1 -1
  136. data/{lib/templates → templates/cli/utility}/compressor/gzip +1 -1
  137. data/{lib/templates → templates/cli/utility}/compressor/lzma +0 -0
  138. data/templates/cli/utility/compressor/pbzip2 +7 -0
  139. data/templates/cli/utility/config +31 -0
  140. data/{lib/templates → templates/cli/utility}/database/mongodb +1 -1
  141. data/{lib/templates → templates/cli/utility}/database/mysql +1 -1
  142. data/{lib/templates → templates/cli/utility}/database/postgresql +1 -1
  143. data/{lib/templates → templates/cli/utility}/database/redis +1 -1
  144. data/templates/cli/utility/database/riak +8 -0
  145. data/{lib/templates → templates/cli/utility}/encryptor/gpg +1 -1
  146. data/templates/cli/utility/encryptor/openssl +9 -0
  147. data/templates/cli/utility/model.erb +23 -0
  148. data/{lib/templates → templates/cli/utility}/notifier/campfire +2 -1
  149. data/templates/cli/utility/notifier/hipchat +15 -0
  150. data/{lib/templates → templates/cli/utility}/notifier/mail +6 -1
  151. data/{lib/templates → templates/cli/utility}/notifier/presently +1 -0
  152. data/templates/cli/utility/notifier/prowl +11 -0
  153. data/{lib/templates → templates/cli/utility}/notifier/twitter +2 -1
  154. data/templates/cli/utility/splitter +7 -0
  155. data/templates/cli/utility/storage/cloudfiles +12 -0
  156. data/{lib/templates → templates/cli/utility}/storage/dropbox +1 -1
  157. data/{lib/templates → templates/cli/utility}/storage/ftp +0 -0
  158. data/templates/cli/utility/storage/local +7 -0
  159. data/{lib/templates → templates/cli/utility}/storage/ninefold +1 -1
  160. data/templates/cli/utility/storage/rsync +11 -0
  161. data/{lib/templates → templates/cli/utility}/storage/s3 +0 -2
  162. data/templates/cli/utility/storage/scp +11 -0
  163. data/templates/cli/utility/storage/sftp +11 -0
  164. data/{lib/templates → templates/cli/utility}/syncer/rsync +1 -1
  165. data/{lib/templates → templates/cli/utility}/syncer/s3 +1 -1
  166. data/templates/general/links +11 -0
  167. data/templates/general/version.erb +2 -0
  168. data/templates/notifier/mail/failure.erb +9 -0
  169. data/templates/notifier/mail/success.erb +7 -0
  170. data/templates/notifier/mail/warning.erb +9 -0
  171. data/templates/storage/dropbox/authorization_url.erb +6 -0
  172. data/templates/storage/dropbox/authorized.erb +4 -0
  173. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  174. metadata +81 -45
  175. data/lib/backup/cli.rb +0 -110
  176. data/lib/backup/exception/command_failed.rb +0 -8
  177. data/lib/backup/exception/command_not_found.rb +0 -8
  178. data/lib/backup/notifier/binder.rb +0 -32
  179. data/lib/backup/notifier/templates/notify_failure.erb +0 -33
  180. data/lib/backup/notifier/templates/notify_success.erb +0 -16
  181. data/lib/templates/archive +0 -7
  182. data/lib/templates/encryptor/openssl +0 -8
  183. data/lib/templates/readme +0 -15
  184. data/lib/templates/storage/cloudfiles +0 -11
  185. data/lib/templates/storage/local +0 -7
  186. data/lib/templates/storage/rsync +0 -11
  187. data/lib/templates/storage/scp +0 -11
  188. data/lib/templates/storage/sftp +0 -11
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.dirname(__FILE__) + '/../spec_helper'
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::CloudFiles do
6
6
 
@@ -45,16 +45,42 @@ describe Backup::Storage::CloudFiles do
45
45
  cf.path.should == 'my/backups'
46
46
  end
47
47
 
48
+ describe '#perform' do
49
+ it 'should invoke transfer! and cycle!' do
50
+ cf.expects(:transfer!)
51
+ cf.expects(:cycle!)
52
+ cf.perform!
53
+ end
54
+ end
55
+
48
56
  describe '#connection' do
49
- it 'should establish a connection to Rackspace Cloud Files. using the provided credentials' do
50
- Fog::Storage.expects(:new).with({
51
- :provider => 'Rackspace',
52
- :rackspace_username => 'my_username',
53
- :rackspace_api_key => 'my_api_key',
54
- :rackspace_auth_url => 'lon.auth.api.rackspacecloud.com'
55
- })
57
+ it 'should establish and re-use a connection to Rackspace Cloud Files' do
58
+ Fog::Storage.expects(:new).once.with({
59
+ :provider => 'Rackspace',
60
+ :rackspace_username => 'my_username',
61
+ :rackspace_api_key => 'my_api_key',
62
+ :rackspace_auth_url => 'lon.auth.api.rackspacecloud.com',
63
+ :rackspace_servicenet => false
64
+ }).returns(true)
56
65
 
57
66
  cf.send(:connection)
67
+ cf.send(:connection)
68
+ end
69
+
70
+ context 'with LAN (servicenet) enabled' do
71
+ it 'should establish and re-use a connection to Rackspace Cloud Files' do
72
+ Fog::Storage.expects(:new).once.with({
73
+ :provider => 'Rackspace',
74
+ :rackspace_username => 'my_username',
75
+ :rackspace_api_key => 'my_api_key',
76
+ :rackspace_auth_url => 'lon.auth.api.rackspacecloud.com',
77
+ :rackspace_servicenet => true
78
+ }).returns(true)
79
+
80
+ cf.servicenet = true
81
+ cf.send(:connection)
82
+ cf.send(:connection)
83
+ end
58
84
  end
59
85
  end
60
86
 
@@ -67,15 +93,14 @@ describe Backup::Storage::CloudFiles do
67
93
  describe '#transfer!' do
68
94
  let(:connection) { mock('Fog::Storage') }
69
95
  before do
70
- Fog::Storage.stubs(:new).returns(connection)
96
+ Fog::Storage.expects(:new).once.returns(connection)
71
97
  end
72
98
 
73
99
  it 'should transfer the provided file to the container' do
74
100
  Backup::Model.new('blah', 'blah') {}
75
101
  file = mock("Backup::Storage::CloudFiles::File")
76
102
  File.expects(:open).with("#{File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER}")}.tar").returns(file)
77
- cf.expects(:remote_file).returns("#{ Backup::TIME }.#{ Backup::TRIGGER }.tar").twice
78
- connection.expects(:put_object).with('my_container', "backups/myapp/#{ Backup::TIME }.#{ Backup::TRIGGER }.tar", file)
103
+ connection.expects(:put_object).with('my_container', "backups/myapp/#{ Backup::TIME }/#{ Backup::TRIGGER }.tar", file)
79
104
  cf.send(:transfer!)
80
105
  end
81
106
  end
@@ -83,22 +108,13 @@ describe Backup::Storage::CloudFiles do
83
108
  describe '#remove!' do
84
109
  let(:connection) { mock('Fog::Storage') }
85
110
  before do
86
- Fog::Storage.stubs(:new).returns(connection)
111
+ Fog::Storage.expects(:new).once.returns(connection)
87
112
  end
88
113
 
89
114
  it 'should remove the file from the container' do
90
- cf.expects(:remote_file).returns("#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
91
- connection.expects(:delete_object).with('my_container', "backups/myapp/#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
115
+ connection.expects(:delete_object).with('my_container', "backups/myapp/#{ Backup::TIME }/#{ Backup::TRIGGER }.tar")
92
116
  cf.send(:remove!)
93
117
  end
94
118
  end
95
119
 
96
- describe '#perform' do
97
- it 'should invoke transfer! and cycle!' do
98
- cf.expects(:transfer!)
99
- cf.expects(:cycle!)
100
- cf.perform!
101
- end
102
- end
103
-
104
120
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.dirname(__FILE__) + '/../spec_helper'
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::Dropbox do
6
6
 
@@ -54,28 +54,28 @@ describe Backup::Storage::Dropbox do
54
54
  end
55
55
 
56
56
  describe '#connection' do
57
- context "when the session cache has not yet been written" do
58
- before do
59
- db.stubs(:gets)
60
- end
57
+ before do
58
+ db.stubs(:gets)
59
+ end
61
60
 
61
+ context "when the session cache has not yet been written" do
62
62
  it do
63
63
  session = mock("Dropbox::Session")
64
64
  Dropbox::Session.expects(:new).with('my_api_key', 'my_secret').returns(session)
65
65
  session.expects(:mode=).with(:dropbox)
66
66
  session.expects(:authorize)
67
- session.expects(:authorize_url)
68
67
  db.expects(:cache_exists?).returns(false)
69
68
  db.expects(:write_cache!).with(session)
69
+
70
+ template = Backup::Template.new(db.send(:binding))
71
+ Backup::Template.expects(:new).returns(template)
72
+
73
+ template.expects(:render).times(3)
70
74
  db.send(:connection)
71
75
  end
72
76
  end
73
77
 
74
78
  context "when the session cache has already been written" do
75
- before do
76
- db.stubs(:gets)
77
- end
78
-
79
79
  it "should load the session from cache, instead of creating a new one" do
80
80
  db.expects(:cache_exists?).returns(true)
81
81
  File.expects(:read).with("#{ENV['HOME']}/Backup/.cache/my_api_keymy_secret").returns("foo")
@@ -107,14 +107,18 @@ describe Backup::Storage::Dropbox do
107
107
  end
108
108
 
109
109
  it do
110
- Backup::Logger.expects(:message).with("Backup::Storage::Dropbox started transferring \"#{ Backup::TIME }.#{ Backup::TRIGGER }.tar\".")
110
+ Backup::Logger.expects(:message).with(
111
+ "Storage::Dropbox started transferring " +
112
+ "'#{ Backup::TIME }.#{ Backup::TRIGGER }.tar'."
113
+ )
111
114
  db.send(:transfer!)
112
115
  end
113
116
 
114
117
  it do
115
118
  connection.expects(:upload).with(
116
119
  File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar"),
117
- File.join('backups', Backup::TRIGGER),
120
+ File.join('backups', Backup::TRIGGER, Backup::TIME),
121
+ :as => "#{ Backup::TRIGGER }.tar",
118
122
  :timeout => db.timeout
119
123
  )
120
124
 
@@ -125,7 +129,7 @@ describe Backup::Storage::Dropbox do
125
129
  describe '#remove!' do
126
130
  it do
127
131
  connection.expects(:delete).with(
128
- File.join('backups', Backup::TRIGGER, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
132
+ File.join('backups', Backup::TRIGGER, Backup::TIME)
129
133
  )
130
134
 
131
135
  db.send(:remove!)
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.dirname(__FILE__) + '/../spec_helper'
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::FTP do
6
6
 
@@ -55,89 +55,179 @@ describe Backup::Storage::FTP do
55
55
  ftp.passive_mode.should == false
56
56
  end
57
57
 
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
65
+
58
66
  describe '#connection' do
59
- let(:connection) { mock('Fog::Storage') }
67
+ let(:connection) { mock }
60
68
 
61
- it 'should establish a connection to the remote server using the provided ip address and credentials' do
62
- Net::FTP.expects(:new).with('123.45.678.90', 'my_username', 'my_password')
63
- ftp.send(:connection)
64
- end
69
+ it 'should establish a connection to the remote server' do
70
+ Net::FTP.expects(:open).with(
71
+ '123.45.678.90', 'my_username', 'my_password'
72
+ ).yields(connection)
65
73
 
66
- it 'should re-define the Net::FTP port' do
67
- Net::FTP.stubs(:new)
68
- ftp.port = 40
69
- ftp.send(:connection)
70
- Net::FTP::FTP_PORT.should == 40
74
+ ftp.send(:connection) do |conn|
75
+ conn.should be connection
76
+ end
71
77
  end
72
78
 
73
79
  it 'configures net/ftp to use passive mode if passive_mode set to true' do
74
80
  ftp.passive_mode = true
75
- Net::FTP.stubs(:new).returns(connection)
81
+ Net::FTP.expects(:open).with(
82
+ '123.45.678.90', 'my_username', 'my_password'
83
+ ).yields(connection)
76
84
  connection.expects(:passive=).with(true)
77
- ftp.send(:connection)
85
+
86
+ ftp.send(:connection) do |conn|
87
+ conn.should be connection
88
+ end
78
89
  end
79
- end
90
+
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
108
+
109
+ end
110
+
111
+ end # describe '#connection'
80
112
 
81
113
  describe '#transfer!' do
82
- let(:connection) { mock('Fog::Storage') }
114
+ let(:connection) { mock }
83
115
 
84
116
  before do
85
- Net::FTP.stubs(:new).returns(connection)
86
- ftp.stubs(:create_remote_directories!)
117
+ ftp.stubs(:storage_name).returns('Storage::FTP')
87
118
  end
88
119
 
89
- it 'should transfer the provided file to the path' do
90
- Backup::Model.new('blah', 'blah') {}
91
- file = mock("Backup::Storage::FTP::File")
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"
92
124
 
93
- ftp.expects(:create_remote_directories!)
94
- connection.expects(:put).with(
95
- File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar"),
96
- File.join('backups/myapp', "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
97
- )
125
+ ftp.expects(:connection).yields(connection)
126
+ ftp.expects(:create_remote_directories).with(connection)
98
127
 
99
- ftp.send(:transfer!)
100
- end
101
- end
128
+ Backup::Logger.expects(:message).with(
129
+ "Storage::FTP started transferring '#{local_file}' to '#{ftp.ip}'."
130
+ )
102
131
 
103
- describe '#remove!' do
104
- let(:connection) { mock('Net::FTP') }
132
+ connection.expects(:put).with(
133
+ File.join(Backup::TMP_PATH, local_file),
134
+ File.join('backups/myapp', Backup::TIME, remote_file)
135
+ )
105
136
 
106
- before do
107
- Net::FTP.stubs(:new).returns(connection)
137
+ ftp.send(:transfer!)
138
+ end
108
139
  end
109
140
 
110
- it 'should remove the file from the remote server path' do
111
- connection.expects(:delete).with("backups/myapp/#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
112
- ftp.send(:remove!)
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
113
170
  end
114
- end
171
+ end # describe '#transfer'
115
172
 
116
- describe '#create_remote_directories!' do
117
- let(:connection) { mock('Net::FTP') }
173
+ 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')
118
179
 
119
- before do
120
- Net::FTP.stubs(:new).returns(connection)
121
- end
180
+ ftp.expects(:connection).in_sequence(s).yields(connection)
181
+
182
+ ftp.expects(:transferred_files).in_sequence(s).multiple_yields(
183
+ ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2']
184
+ )
185
+
186
+ Backup::Logger.expects(:message).in_sequence(s).with(
187
+ "Storage::FTP started removing 'local_file1' from '#{ftp.ip}'."
188
+ )
189
+ connection.expects(:delete).in_sequence(s).with(
190
+ File.join(remote_path, 'remote_file1')
191
+ )
122
192
 
123
- it 'should properly create remote directories one by one' do
124
- ftp.path = '~/backups/some_other_folder/another_folder'
193
+ Backup::Logger.expects(:message).in_sequence(s).with(
194
+ "Storage::FTP started removing 'local_file2' from '#{ftp.ip}'."
195
+ )
196
+ connection.expects(:delete).in_sequence(s).with(
197
+ File.join(remote_path, 'remote_file2')
198
+ )
125
199
 
126
- connection.expects(:mkdir).with('~')
127
- connection.expects(:mkdir).with('~/backups')
128
- connection.expects(:mkdir).with('~/backups/some_other_folder')
129
- connection.expects(:mkdir).with('~/backups/some_other_folder/another_folder')
130
- connection.expects(:mkdir).with('~/backups/some_other_folder/another_folder/myapp')
200
+ connection.expects(:rmdir).in_sequence(s).with(remote_path)
131
201
 
132
- ftp.send(:create_remote_directories!)
202
+ ftp.send(:remove!)
133
203
  end
134
- end
204
+ end # describe '#remove!'
135
205
 
136
- describe '#perform' do
137
- it 'should invoke transfer! and cycle!' do
138
- ftp.expects(:transfer!)
139
- ftp.expects(:cycle!)
140
- ftp.perform!
206
+ describe '#create_remote_directories!' do
207
+ let(:connection) { mock }
208
+
209
+ 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")
220
+ connection.expects(:mkdir).in_sequence(s).
221
+ with("~/backups/some_other_folder/another_folder")
222
+ connection.expects(:mkdir).in_sequence(s).
223
+ with("~/backups/some_other_folder/another_folder/myapp")
224
+ connection.expects(:mkdir).in_sequence(s).
225
+ with("~/backups/some_other_folder/another_folder/myapp/#{ Backup::TIME }")
226
+
227
+ expect do
228
+ ftp.send(:create_remote_directories, connection)
229
+ end.not_to raise_error
230
+ end
141
231
  end
142
232
  end
143
233
 
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.dirname(__FILE__) + '/../spec_helper'
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Storage::Local do
6
6
 
@@ -16,7 +16,7 @@ describe Backup::Storage::Local do
16
16
  end
17
17
 
18
18
  it 'should have defined the configuration properly' do
19
- local.path.should == "#{ENV['HOME']}/backups/"
19
+ local.path.should == "#{ENV['HOME']}/backups"
20
20
  local.keep.should == 20
21
21
  end
22
22
 
@@ -50,7 +50,7 @@ describe Backup::Storage::Local do
50
50
 
51
51
  FileUtils.expects(:cp).with(
52
52
  File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar"),
53
- File.join("#{ENV['HOME']}/backups/myapp", "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
53
+ File.join("#{ENV['HOME']}/backups/myapp", Backup::TIME, "#{ Backup::TRIGGER }.tar")
54
54
  )
55
55
 
56
56
  local.send(:transfer!)
@@ -59,15 +59,15 @@ describe Backup::Storage::Local do
59
59
 
60
60
  describe '#remove!' do
61
61
  it 'should remove the file from the remote server path' do
62
- FileUtils.expects(:rm).with("#{ENV['HOME']}/backups/myapp/#{ Backup::TIME }.#{ Backup::TRIGGER }.tar")
62
+ FileUtils.expects(:rm_r).with("#{ENV['HOME']}/backups/myapp/#{ Backup::TIME }")
63
63
  local.send(:remove!)
64
64
  end
65
65
  end
66
66
 
67
- describe '#create_remote_directories!' do
67
+ describe '#create_local_directories!' do
68
68
  it 'should properly create remote directories one by one' do
69
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")
70
+ FileUtils.expects(:mkdir_p).with("#{ENV['HOME']}/backups/some_other_folder/another_folder/myapp/#{ Backup::TIME }")
71
71
  local.send(:create_local_directories!)
72
72
  end
73
73
  end