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::Notifier::Twitter do
6
6
  let(:notifier) do
@@ -12,22 +12,22 @@ describe Backup::Notifier::Twitter do
12
12
  end
13
13
  end
14
14
 
15
- it do
16
- notifier.consumer_key.should == 'consumer_key'
17
- notifier.consumer_secret.should == 'consumer_secret'
18
- notifier.oauth_token.should == 'oauth_token'
19
- notifier.oauth_token_secret.should == 'oauth_token_secret'
15
+ describe '#initialize' do
16
+ it 'sets the correct defaults' do
17
+ notifier.consumer_key.should == 'consumer_key'
18
+ notifier.consumer_secret.should == 'consumer_secret'
19
+ notifier.oauth_token.should == 'oauth_token'
20
+ notifier.oauth_token_secret.should == 'oauth_token_secret'
20
21
 
21
- notifier.on_success.should == true
22
- notifier.on_failure.should == true
23
- end
22
+ notifier.on_success.should == true
23
+ notifier.on_warning.should == true
24
+ notifier.on_failure.should == true
25
+ end
24
26
 
25
- describe 'defaults' do
26
- it do
27
+ it 'uses and overrides configuration defaults' do
27
28
  Backup::Configuration::Notifier::Twitter.defaults do |twitter|
28
29
  twitter.consumer_key = 'new_consumer_key'
29
30
  twitter.on_success = false
30
- twitter.on_failure = true
31
31
  end
32
32
  notifier = Backup::Notifier::Twitter.new do |twitter|
33
33
  twitter.consumer_key = 'my_own_consumer_key'
@@ -35,52 +35,117 @@ describe Backup::Notifier::Twitter do
35
35
 
36
36
  notifier.consumer_key.should == 'my_own_consumer_key'
37
37
  notifier.on_success.should == false
38
+ notifier.on_warning.should == true
38
39
  notifier.on_failure.should == true
39
40
  end
40
- end
41
41
 
42
- describe '#initialize' do
43
- it do
44
- Backup::Notifier::Twitter.any_instance.expects(:set_defaults!)
45
- Backup::Notifier::Twitter.new
42
+ it 'create a new Twitter::Client' do
43
+ notifier.twitter_client.should be_an_instance_of ::Twitter::Client
44
+ #notifier.twitter_client.credentials?.should be_true
45
+ options = ::Twitter.options # v1.7.1 API
46
+ options[:consumer_key].should == notifier.consumer_key
47
+ options[:consumer_secret].should == notifier.consumer_secret
48
+ options[:oauth_token].should == notifier.oauth_token
49
+ options[:oauth_token_secret].should == notifier.oauth_token_secret
46
50
  end
47
51
  end
48
52
 
49
53
  describe '#perform!' do
50
- let(:model) { Backup::Model.new('blah', 'blah') {} }
54
+ let(:model) { Backup::Model.new('trigger', 'label') {} }
55
+ let(:message) { '[Backup::%s] label (trigger)' }
56
+
51
57
  before do
52
58
  notifier.on_success = false
59
+ notifier.on_warning = false
53
60
  notifier.on_failure = false
54
61
  end
55
62
 
56
- context "when successful" do
57
- it do
58
- Backup::Logger.expects(:message).with("Backup::Notifier::Twitter started notifying about the process.")
59
- notifier.expects("notify_success!")
60
- notifier.on_success = true
61
- notifier.perform!(model)
63
+ context 'success' do
64
+
65
+ context 'when on_success is true' do
66
+ before { notifier.on_success = true }
67
+
68
+ it 'sends success message' do
69
+ notifier.expects(:log!)
70
+ notifier.twitter_client.expects(:update).with(message % 'Success')
71
+
72
+ notifier.perform!(model)
73
+ end
62
74
  end
63
75
 
64
- it do
65
- notifier.expects("notify_success!").never
66
- notifier.on_success = false
67
- notifier.perform!(model)
76
+ context 'when on_success is false' do
77
+ it 'sends no message' do
78
+ notifier.expects(:log!).never
79
+ notifier.expects(:notify!).never
80
+ notifier.twitter_client.expects(:update).never
81
+
82
+ notifier.perform!(model)
83
+ end
68
84
  end
69
- end
70
85
 
71
- context "when failed" do
72
- it do
73
- Backup::Logger.expects(:message).with("Backup::Notifier::Twitter started notifying about the process.")
74
- notifier.expects("notify_failure!")
75
- notifier.on_failure = true
76
- notifier.perform!(model, Exception.new)
86
+ end # context 'success'
87
+
88
+ context 'warning' do
89
+ before { Backup::Logger.stubs(:has_warnings?).returns(true) }
90
+
91
+ context 'when on_success is true' do
92
+ before { notifier.on_success = true }
93
+
94
+ it 'sends warning message' do
95
+ notifier.expects(:log!)
96
+ notifier.twitter_client.expects(:update).with(message % 'Warning')
97
+
98
+ notifier.perform!(model)
99
+ end
100
+ end
101
+
102
+ context 'when on_warning is true' do
103
+ before { notifier.on_warning = true }
104
+
105
+ it 'sends warning message' do
106
+ notifier.expects(:log!)
107
+ notifier.twitter_client.expects(:update).with(message % 'Warning')
108
+
109
+ notifier.perform!(model)
110
+ end
77
111
  end
78
112
 
79
- it do
80
- notifier.expects("notify_failure!").never
81
- notifier.on_failure = false
82
- notifier.perform!(model, Exception.new)
113
+ context 'when on_success and on_warning are false' do
114
+ it 'sends no message' do
115
+ notifier.expects(:log!).never
116
+ notifier.expects(:notify!).never
117
+ notifier.twitter_client.expects(:update).never
118
+
119
+ notifier.perform!(model)
120
+ end
83
121
  end
84
- end
85
- end
122
+
123
+ end # context 'warning'
124
+
125
+ context 'failure' do
126
+
127
+ context 'when on_failure is true' do
128
+ before { notifier.on_failure = true }
129
+
130
+ it 'sends failure message' do
131
+ notifier.expects(:log!)
132
+ notifier.twitter_client.expects(:update).with(message % 'Failure')
133
+
134
+ notifier.perform!(model, Exception.new)
135
+ end
136
+ end
137
+
138
+ context 'when on_failure is false' do
139
+ it 'sends no message' do
140
+ notifier.expects(:log!).never
141
+ notifier.expects(:notify!).never
142
+ notifier.twitter_client.expects(:update).never
143
+
144
+ notifier.perform!(model, Exception.new)
145
+ end
146
+ end
147
+
148
+ end # context 'failure'
149
+
150
+ end # describe '#perform!'
86
151
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  # encoding: utf-8
2
2
 
3
+ ##
4
+ # Use Bundler
5
+ require 'rubygems' if RUBY_VERSION < '1.9'
6
+ require 'bundler/setup'
7
+
3
8
  ##
4
9
  # Load Backup
5
- require File.expand_path( '../../lib/backup', __FILE__ )
10
+ require 'backup'
6
11
 
7
12
  ##
8
13
  # Use Mocha to mock with RSpec
14
+ require 'rspec'
9
15
  RSpec.configure do |config|
10
16
  config.mock_with :mocha
11
17
  config.before(:each) do
@@ -26,5 +32,5 @@ module Backup
26
32
  end
27
33
 
28
34
  unless @_put_ruby_version
29
- puts @_put_ruby_version = "\n\nRuby version: #{ENV['rvm_ruby_string']}\n\n"
35
+ puts @_put_ruby_version = "\n\nRuby version: #{RUBY_DESCRIPTION}\n\n"
30
36
  end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Splitter do
6
+ let(:model) { mock("Backup::Model") }
7
+ let(:splitter) { Backup::Splitter.new(model) }
8
+
9
+ before do
10
+ splitter.stubs(:chunks).returns([
11
+ "/some/file.tar.gz.enc-ad",
12
+ "/some/file.tar.gz.enc-ac",
13
+ "/some/file.tar.gz.enc-ab",
14
+ "/some/file.tar.gz.enc-aa",
15
+ ])
16
+ end
17
+
18
+ describe "#chunk_suffixes" do
19
+ it "should return an array of chunk suffixes (ordered in alphabetical order)" do
20
+ splitter.send(:chunk_suffixes).should == ["aa", "ab", "ac", "ad"]
21
+ end
22
+ end
23
+
24
+ describe "#bytes_representation_of" do
25
+ it "should convert megabytes to bytes" do
26
+ splitter.send(:bytes_representation_of, 50).should == 52428800
27
+ end
28
+ end
29
+
30
+ describe "#split!" do
31
+ before do
32
+ model.stubs(:file).returns("/some/file.tar.gz.enc")
33
+ end
34
+
35
+ [nil, true, false, "123", :sym].each do |value|
36
+ it "should not split: chunk_size must be an integer" do
37
+ model.stubs(:chunk_size).returns(value)
38
+
39
+ File.expects(:size).never
40
+ splitter.expects(:bytes_representation_of).never
41
+ splitter.expects(:run).never
42
+ splitter.split!
43
+ end
44
+ end
45
+
46
+ it "should not split: chunk size is 300mb, file is 300mb" do
47
+ File.expects(:size).with(model.file).returns(52428800) # 300mb
48
+ model.stubs(:chunk_size).returns(300)
49
+
50
+ splitter.expects(:run).never
51
+ splitter.split!
52
+ end
53
+
54
+ it "should not split: chunk size is 300mb, file size is 200mb" do
55
+ File.expects(:size).with(model.file).returns(209715200) # 200mb
56
+ model.stubs(:chunk_size).returns(300)
57
+
58
+ splitter.expects(:run).never
59
+ splitter.split!
60
+ end
61
+
62
+ it "should split: chunk size is 300mb, file size is 400mb" do
63
+ File.expects(:size).with(model.file).returns(419430400) # 400mb
64
+ model.stubs(:chunk_size).returns(300)
65
+
66
+ splitter.expects(:utility).with(:split).returns("split")
67
+ splitter.expects(:run).with("split -b 300m '/some/file.tar.gz.enc' '/some/file.tar.gz.enc-'")
68
+ splitter.split!
69
+ end
70
+ end
71
+ end
@@ -1,29 +1,290 @@
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::Base do
6
- let(:base) { Backup::Storage::Base.new }
7
-
8
- it do
9
- storage_object = mock
10
- Backup::Storage::Object.expects(:new).with('Base').returns(storage_object)
11
- storage_object.stubs(:load).returns([])
12
- storage_object.expects(:write)
13
- base.keep = 1
14
- base.cycle!
6
+
7
+ describe '#initialize' do
8
+
9
+ after do
10
+ Backup::Configuration::Storage::Base.clear_defaults!
11
+ end
12
+
13
+ it 'should create a new storage object with default values' do
14
+ base = Backup::Storage::Base.new
15
+ base.keep.should be_nil
16
+ base.time.should == Backup::TIME
17
+ end
18
+
19
+ it 'should set configured defaults' do
20
+ Backup::Configuration::Storage::Base.defaults do |base|
21
+ base.keep = 5
22
+ end
23
+
24
+ base = Backup::Storage::Base.new
25
+ base.keep.should == 5
26
+ base.time.should == Backup::TIME
27
+ end
28
+
29
+ it 'should override the configuration defaults with the configure block' do
30
+ Backup::Configuration::Storage::Base.defaults do |base|
31
+ base.keep = 5
32
+ end
33
+
34
+ base = Backup::Storage::Base.new do |base|
35
+ base.keep = 10
36
+ end
37
+ base.keep.should == 10
38
+ base.time.should == Backup::TIME
39
+ end
40
+
41
+ it 'should store the configuration block' do
42
+ config_block = lambda {|base| base.keep = 10 }
43
+ base = Backup::Storage::Base.new(&config_block)
44
+
45
+ base.keep.should == 10
46
+ base.configure_block.should be config_block
47
+ end
48
+
49
+ it 'should set the storage_id using an optional block parameter' do
50
+ base = Backup::Storage::Base.new('my storage_id') do |base|
51
+ base.keep = 10
52
+ end
53
+ base.keep.should == 10
54
+ base.time.should == Backup::TIME
55
+ base.storage_id.should == 'my storage_id'
56
+ end
57
+
58
+ end # describe '#inititalize'
59
+
60
+ describe '#clean!' do
61
+
62
+ context 'when clearing instance variables for cycling' do
63
+ it 'version stamps the object' do
64
+ cycle_required_variables = %w[ @filename @time @chunk_suffixes ]
65
+ expected_variables = (cycle_required_variables + ['@version']).sort
66
+
67
+ base = Backup::Storage::Base.new do |config|
68
+ config.storage_id = 'bar_id'
69
+ config.keep = 3
70
+ end
71
+ base.time = Time.utc(2011, 12, 2)
72
+ base.chunk_suffixes = ['aa', 'ab']
73
+ base.instance_variable_set(:@filename, 'foo.tar')
74
+ base.version.should be_nil
75
+
76
+ base.send(:clean!)
77
+ base.instance_variables.map(&:to_s).sort.should == expected_variables
78
+ base.time.should == Time.utc(2011, 12, 2)
79
+ base.chunk_suffixes.should == ['aa', 'ab']
80
+ base.filename.should == 'foo.tar'
81
+ base.version.should == Backup::Version.current
82
+ end
83
+ end
84
+
15
85
  end
16
86
 
17
- it do
18
- base.keep = 3
19
- storage_object = mock
20
- objects = %w[1 2 3 4].map { Backup::Storage::Base.new }
87
+ describe '#update!' do
88
+
89
+ it 'updates the storage object with the given configure_block' do
90
+ base_a = Backup::Storage::Base.new do |config|
91
+ config.storage_id = 'foo_id'
92
+ config.keep = 5
93
+ end
94
+ base_b = Backup::Storage::Base.new do |config|
95
+ config.storage_id = 'bar_id'
96
+ config.keep = 3
97
+ end
98
+ base_b.expects(:upgrade_if_needed!)
99
+
100
+ base_b.send(:update!, base_a.configure_block)
101
+ base_b.storage_id.should == 'foo_id'
102
+ base_b.keep.should == 5
103
+ end
104
+
105
+ it 'updates YAML loaded objects, which were `cleaned` for cycling' do
106
+ base = Backup::Storage::Base.new do |config|
107
+ config.storage_id = 'foo_id'
108
+ config.keep = 5
109
+ end
110
+ base.time.should == Backup::TIME
111
+
112
+ loaded = Backup::Storage::Base.new do |config|
113
+ config.storage_id = 'bar_id'
114
+ config.keep = 3
115
+ end
116
+ loaded.time = Time.utc(2011, 12, 2)
117
+ loaded.chunk_suffixes = ['aa', 'ab']
118
+ loaded.instance_variable_set(:@filename, 'foo.tar')
119
+
120
+ loaded.send(:clean!)
121
+ loaded.storage_id.should == nil
122
+ loaded.keep.should == nil
123
+ loaded.version.should == Backup::Version.current
124
+
125
+ loaded.send(:update!, base.configure_block)
126
+ loaded.storage_id.should == 'foo_id'
127
+ loaded.keep.should == 5
128
+ loaded.time.should == Time.utc(2011, 12, 2)
129
+ loaded.chunk_suffixes.should == ['aa', 'ab']
130
+ loaded.filename.should == 'foo.tar'
131
+ loaded.version.should == Backup::Version.current
132
+ end
133
+
134
+ end # describe '#update!'
135
+
136
+ describe '#upgrade_if_needed!' do
137
+
138
+ it 'upgrades <= 3.0.19' do
139
+ v_3_0_19_yaml = <<-EOF.gsub(/^\s+/,' ').gsub(/^ -/,'-')
140
+ ---
141
+ !ruby/object:Backup::Storage::SCP
142
+ username: a_user
143
+ password: a_password
144
+ ip: an_address
145
+ port: a_port
146
+ path: a_path
147
+ keep: a_few
148
+ time: 2011.11.01.01.02.03
149
+ local_file: 2011.11.01.01.02.03.a_backup.tar
150
+ remote_file: 2011.11.01.01.02.03.a_backup.tar
151
+ EOF
152
+ loaded = YAML.load(v_3_0_19_yaml)
153
+ cycle_required_variables = %w[ @filename @time @chunk_suffixes ]
154
+ expected_variables = (cycle_required_variables + ['@version']).sort
155
+
156
+ loaded.send(:upgrade_if_needed!)
157
+ loaded.instance_variables.map(&:to_s).sort.should == expected_variables
158
+ loaded.filename.should == '2011.11.01.01.02.03.a_backup.tar'
159
+ loaded.time.should == '2011.11.01.01.02.03'
160
+ loaded.chunk_suffixes.should == []
161
+ loaded.version.should == Backup::Version.current
162
+ end
163
+
164
+ end # describe '#upgrade_if_needed!'
165
+
166
+ describe '#cycle!' do
167
+ let(:base) { Backup::Storage::Base.new {} }
168
+
169
+ it 'updates loaded objects and adds current object' do
170
+ s = sequence ''
171
+ storage_object = mock
172
+ loaded_object = mock
173
+
174
+ Backup::Storage::Object.expects(:new).in_sequence(s).
175
+ with('Base', nil).returns(storage_object)
176
+ storage_object.expects(:load).in_sequence(s).
177
+ returns([loaded_object])
178
+ loaded_object.expects(:update!).in_sequence(s).
179
+ with(base.configure_block)
180
+ objects = [base, loaded_object]
181
+ objects.each {|object| object.expects(:clean!).in_sequence(s) }
182
+ storage_object.expects(:write).in_sequence(s).
183
+ with(objects)
184
+
185
+ base.keep = 2
186
+ base.send(:cycle!)
187
+ end
188
+
189
+ context 'when removing old stored objects' do
190
+
191
+ it 'should warn and continue on errors' do
192
+ num_to_load = 6
193
+ num_to_keep = 3
194
+ obj_to_fail = 2 # we're removing 3, so fail the 2nd one.
195
+
196
+ s = sequence ''
197
+ storage_object = mock
198
+ raised_error = StandardError.new
199
+ loaded_objects = []
200
+ (1..num_to_load).each do |n|
201
+ instance_eval <<-EOS
202
+ loaded_object#{n} = mock
203
+ loaded_object#{n}.stubs(:filename).returns("file#{n}")
204
+ loaded_objects << loaded_object#{n}
205
+ EOS
206
+ end
207
+
208
+ Backup::Storage::Object.expects(:new).in_sequence(s).
209
+ with('Base', nil).returns(storage_object)
210
+ storage_object.expects(:load).in_sequence(s).
211
+ returns(loaded_objects)
212
+ loaded_objects.each do |loaded_object|
213
+ loaded_object.expects(:update!).in_sequence(s).
214
+ with(base.configure_block)
215
+ end
216
+ objects = [base] + loaded_objects
217
+
218
+ objects_to_remove = objects[num_to_keep..-1]
219
+ objects_to_remove.each_with_index do |object_to_remove, i|
220
+ Backup::Logger.expects(:message).in_sequence(s).
221
+ with {|msg| msg.include?(object_to_remove.filename) }
222
+ if i == obj_to_fail
223
+ object_to_remove.expects(:remove!).in_sequence(s).
224
+ raises(raised_error)
225
+ Backup::Errors::Storage::CycleError.expects(:wrap).in_sequence(s).
226
+ with(raised_error, "#{base.storage_name} failed to remove " +
227
+ "'#{object_to_remove.filename}'").
228
+ returns(:wrapped_error)
229
+ Backup::Logger.expects(:warn).in_sequence(s).
230
+ with(:wrapped_error)
231
+ else
232
+ object_to_remove.expects(:remove!).in_sequence(s)
233
+ end
234
+ end
235
+
236
+ objects = objects - objects_to_remove
237
+ objects.each {|object| object.expects(:clean!).in_sequence(s) }
238
+ storage_object.expects(:write).in_sequence(s).
239
+ with(objects)
240
+
241
+ base.keep = num_to_keep
242
+ base.send(:cycle!)
243
+ end
244
+
245
+ end
246
+
247
+ end
248
+
249
+ describe '#chunks' do
250
+
251
+ it 'returns sorted filenames for chunk_suffixes' do
252
+ base = Backup::Storage::Base.new
253
+ base.chunk_suffixes = ["aa", "ad", "ae", "ab", "ac"]
254
+ base.stubs(:filename).returns("file.tar")
255
+ base.chunks.should == [
256
+ "#{base.filename}-aa",
257
+ "#{base.filename}-ab",
258
+ "#{base.filename}-ac",
259
+ "#{base.filename}-ad",
260
+ "#{base.filename}-ae",
261
+ ]
262
+
263
+ base.chunk_suffixes.should == ["aa", "ad", "ae", "ab", "ac"]
264
+ end
265
+
266
+ end
267
+
268
+ describe '#storage_name' do
269
+ let(:s3) { Backup::Storage::S3.new {} }
270
+
271
+ describe 'returns storage class name with the Backup:: namespace removed' do
272
+
273
+ context 'when storage_id is set' do
274
+ before { s3.storage_id = 'my storage' }
275
+
276
+ it 'appends the storage_id' do
277
+ s3.storage_name.should == 'Storage::S3 (my storage)'
278
+ end
279
+ end
280
+
281
+ context 'when storage_id is not set' do
282
+ it 'does not append the storage_id' do
283
+ s3.storage_name.should == 'Storage::S3'
284
+ end
285
+ end
21
286
 
22
- Backup::Storage::Object.expects(:new).with('Base').returns(storage_object)
23
- storage_object.stubs(:load).returns(objects)
24
- storage_object.expects(:write)
25
- Backup::Storage::Base.any_instance.expects(:remove!).times(2)
287
+ end
26
288
 
27
- base.cycle!
28
289
  end
29
290
  end