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
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Database::Riak do
6
+
7
+ before do
8
+ Backup::Database::Riak.any_instance.stubs(:load_defaults!)
9
+ end
10
+
11
+ let(:db) do
12
+ Backup::Database::Riak.new do |db|
13
+ db.name = 'mydatabase'
14
+ db.node = 'riak@localhost'
15
+ db.cookie = 'riak'
16
+ end
17
+ end
18
+
19
+ describe '#new' do
20
+ it 'should read the adapter details correctly' do
21
+ db.name.should == 'mydatabase'
22
+ db.node.should == 'riak@localhost'
23
+ db.cookie.should == 'riak'
24
+ end
25
+ end
26
+
27
+ describe '#riakadmin_string' do
28
+ it 'should return the full riakadmin string' do
29
+ db.riakadmin.should == "riak-admin backup riak@localhost riak"
30
+ end
31
+ end
32
+
33
+ describe '#perform!' do
34
+ before do
35
+ db.stubs(:mkdir)
36
+ db.stubs(:run)
37
+ end
38
+
39
+ it 'should ensure the directory is available' do
40
+ db.expects(:mkdir).with(File.join(Backup::TMP_PATH, "myapp", "Riak"))
41
+ db.perform!
42
+ end
43
+
44
+ it do
45
+ Backup::Logger.expects(:message).
46
+ with("Backup::Database::Riak started dumping and archiving 'mydatabase'.")
47
+ db.perform!
48
+ end
49
+ end
50
+ 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::Encryptor::GPG do
6
6
 
@@ -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::Encryptor::OpenSSL do
6
6
 
@@ -20,34 +20,80 @@ describe Backup::Encryptor::OpenSSL do
20
20
  end
21
21
 
22
22
  it do
23
- encryptor.send(:options).should == "aes-256-cbc"
23
+ encryptor.send(:pass).should == ["-k ''"]
24
+ end
25
+
26
+ it do
27
+ encryptor.send(:options).should == "aes-256-cbc -k ''"
24
28
  end
25
29
  end
26
30
 
27
31
  context "when a block is provided" do
28
- let(:encryptor) do
29
- Backup::Encryptor::OpenSSL.new do |e|
30
- e.password = "my_secret_password"
31
- e.salt = true
32
- e.base64 = true
32
+
33
+ context "with a password" do
34
+ let(:encryptor) do
35
+ Backup::Encryptor::OpenSSL.new do |e|
36
+ e.password = "my_secret_password"
37
+ e.salt = true
38
+ e.base64 = true
39
+ end
33
40
  end
34
- end
35
41
 
36
- it do
37
- encryptor.password.should == "my_secret_password"
38
- end
42
+ it do
43
+ encryptor.password.should == "my_secret_password"
44
+ end
39
45
 
40
- it do
41
- encryptor.send(:salt).should == ['-salt']
42
- end
46
+ it do
47
+ encryptor.send(:salt).should == ['-salt']
48
+ end
43
49
 
44
- it do
45
- encryptor.send(:base64).should == ['-base64']
50
+ it do
51
+ encryptor.send(:base64).should == ['-base64']
52
+ end
53
+
54
+ it do
55
+ encryptor.send(:pass).should == ["-k 'my_secret_password'"]
56
+ end
57
+
58
+ it do
59
+ encryptor.send(:options).should == "aes-256-cbc -base64 -salt -k 'my_secret_password'"
60
+ end
46
61
  end
47
62
 
48
- it do
49
- encryptor.send(:options).should == "aes-256-cbc -base64 -salt"
63
+ context "with a password file" do
64
+ let(:encryptor) do
65
+ Backup::Encryptor::OpenSSL.new do |e|
66
+ e.password_file = "/path/to/password/file"
67
+ e.salt = true
68
+ e.base64 = true
69
+ end
70
+ end
71
+
72
+ it do
73
+ encryptor.password.should == nil
74
+ end
75
+
76
+ it do
77
+ encryptor.password_file.should == "/path/to/password/file"
78
+ end
79
+
80
+ it do
81
+ encryptor.send(:salt).should == ['-salt']
82
+ end
83
+
84
+ it do
85
+ encryptor.send(:base64).should == ['-base64']
86
+ end
87
+
88
+ it do
89
+ encryptor.send(:pass).should == ['-pass file:/path/to/password/file']
90
+ end
91
+
92
+ it do
93
+ encryptor.send(:options).should == "aes-256-cbc -base64 -salt -pass file:/path/to/password/file"
94
+ end
50
95
  end
96
+
51
97
  end
52
98
 
53
99
  describe '#perform!' do
@@ -60,7 +106,7 @@ describe Backup::Encryptor::OpenSSL do
60
106
  it do
61
107
  encryptor = Backup::Encryptor::OpenSSL.new
62
108
  encryptor.expects(:utility).returns(:openssl)
63
- encryptor.expects(:run).with("openssl aes-256-cbc -in '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar") }' -out '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar.enc") }' -k ''")
109
+ encryptor.expects(:run).with("openssl aes-256-cbc -k '' -in '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar") }' -out '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar.enc") }'")
64
110
  encryptor.perform!
65
111
  end
66
112
 
@@ -71,7 +117,18 @@ describe Backup::Encryptor::OpenSSL do
71
117
  e.base64 = true
72
118
  end
73
119
  encryptor.stubs(:utility).returns(:openssl)
74
- encryptor.expects(:run).with("openssl aes-256-cbc -base64 -salt -in '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar") }' -out '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar.enc") }' -k 'my_secret_password'")
120
+ encryptor.expects(:run).with("openssl aes-256-cbc -base64 -salt -k 'my_secret_password' -in '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar") }' -out '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar.enc") }'")
121
+ encryptor.perform!
122
+ end
123
+
124
+ it do
125
+ encryptor = Backup::Encryptor::OpenSSL.new do |e|
126
+ e.password_file = "/path/to/password/file"
127
+ e.salt = true
128
+ e.base64 = true
129
+ end
130
+ encryptor.stubs(:utility).returns(:openssl)
131
+ encryptor.expects(:run).with("openssl aes-256-cbc -base64 -salt -pass file:/path/to/password/file -in '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar") }' -out '#{ File.join(Backup::TMP_PATH, "#{Backup::TIME}.#{Backup::TRIGGER}.tar.enc") }'")
75
132
  encryptor.perform!
76
133
  end
77
134
 
@@ -0,0 +1,306 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../spec_helper.rb', __FILE__)
4
+
5
+ # Note: none of these tests require the use of the ErrorsHelper
6
+ describe 'Errors::Error' do
7
+ let(:klass) { Backup::Errors::Error }
8
+
9
+ it 'allow errors to cascade through the system' do
10
+ class ErrorA < klass; end
11
+ class ErrorB < klass; end
12
+ class ErrorC < klass; end
13
+ class ErrorD < klass; end
14
+
15
+ expect do
16
+ begin
17
+ begin
18
+ begin
19
+ raise ErrorA, 'an error occurred in Zone A'
20
+ rescue => err
21
+ raise ErrorB.wrap(err, <<-EOS)
22
+ an error occurred in Zone B
23
+
24
+ the following error should give a reason
25
+ EOS
26
+ end
27
+ rescue => err
28
+ raise ErrorC.wrap(err)
29
+ end
30
+ rescue => err
31
+ raise ErrorD.wrap(err, 'an error occurred in Zone D')
32
+ end
33
+ end.to raise_error(ErrorD,
34
+ "ErrorD: an error occurred in Zone D\n" +
35
+ " Reason: ErrorC\n" +
36
+ " ErrorB: an error occurred in Zone B\n" +
37
+ " \n" +
38
+ " the following error should give a reason\n" +
39
+ " Reason: ErrorA\n" +
40
+ " an error occurred in Zone A"
41
+ )
42
+ end
43
+
44
+ describe '#initialize' do
45
+
46
+ it 'creates a StandardError' do
47
+ klass.new.should be_a_kind_of StandardError
48
+ end
49
+
50
+ context 'when given a message' do
51
+
52
+ it 'formats a simple message' do
53
+ err = klass.new('error message')
54
+ err.message.should == 'Error: error message'
55
+ end
56
+
57
+ it 'formats a multi-line message' do
58
+ err = klass.new(" error message\n" +
59
+ " This is a multi-line error message.\n" +
60
+ "It should be properly indented. ")
61
+
62
+ err.message.should == "Error: error message\n" +
63
+ " This is a multi-line error message.\n" +
64
+ " It should be properly indented."
65
+ end
66
+
67
+ context 'when given an original error' do
68
+
69
+ it 'includes the original error' do
70
+ orig_err = StandardError.new('original message')
71
+ err = klass.new('error message', orig_err)
72
+ err.message.should == "Error: error message\n" +
73
+ " Reason: StandardError\n" +
74
+ " original message"
75
+ end
76
+
77
+ it 'formats all messages' do
78
+ orig_err = StandardError.new(" original message\n" +
79
+ " This is a multi-line error message.\n" +
80
+ "It should be properly indented.")
81
+ err = klass.new(" error message\n" +
82
+ " This is a multi-line error message.\n" +
83
+ "It should be properly indented. ", orig_err)
84
+
85
+ err.message.should == "Error: error message\n" +
86
+ " This is a multi-line error message.\n" +
87
+ " It should be properly indented.\n" +
88
+ " Reason: StandardError\n" +
89
+ " original message\n" +
90
+ " This is a multi-line error message.\n" +
91
+ " It should be properly indented."
92
+ end
93
+
94
+ it 'uses the original error backtrace' do
95
+ begin
96
+ raise StandardError.new
97
+ rescue => err
98
+ klass.new(nil, err).backtrace.
99
+ should == err.backtrace
100
+ end
101
+ end
102
+
103
+ it 'reports if original error had no message' do
104
+ orig_err = StandardError.new
105
+ err = klass.new('error message', orig_err)
106
+ err.message.should == "Error: error message\n" +
107
+ " Reason: StandardError (no message given)"
108
+ end
109
+
110
+ end # context 'when given an original error'
111
+
112
+ context 'when given an original Errors::Error' do
113
+ let(:subklass) do
114
+ class SubKlass < klass; end
115
+ SubKlass
116
+ end
117
+
118
+ it 'includes the original error' do
119
+ orig_err = subklass.new('original message')
120
+ err = klass.new('error message', orig_err)
121
+ err.message.should == "Error: error message\n" +
122
+ " Reason: SubKlass\n" +
123
+ " original message"
124
+ end
125
+
126
+ it 'formats all messages' do
127
+ orig_err = subklass.new(" original message\n" +
128
+ " This is a multi-line error message.\n" +
129
+ "It should be properly indented.")
130
+ err = klass.new(" error message\n" +
131
+ " This is a multi-line error message.\n" +
132
+ "It should be properly indented. ", orig_err)
133
+
134
+ err.message.should == "Error: error message\n" +
135
+ " This is a multi-line error message.\n" +
136
+ " It should be properly indented.\n" +
137
+ " Reason: SubKlass\n" +
138
+ " original message\n" +
139
+ " This is a multi-line error message.\n" +
140
+ " It should be properly indented."
141
+ end
142
+
143
+ it 'uses the original error backtrace' do
144
+ begin
145
+ raise subklass.new
146
+ rescue => err
147
+ klass.new(nil, err).backtrace.
148
+ should == err.backtrace
149
+ end
150
+ end
151
+
152
+ it 'reports if original error had no message' do
153
+ orig_err = subklass.new
154
+ err = klass.new('error message', orig_err)
155
+ err.message.should == "Error: error message\n" +
156
+ " Reason: SubKlass (no message given)"
157
+ end
158
+
159
+ end # context 'when given an original Errors::Error'
160
+
161
+ end # context 'when given a message'
162
+
163
+ context 'when given no message' do
164
+
165
+ it 'strips the module namespace from the default message' do
166
+ err = klass.new
167
+ err.message.should == 'Error'
168
+ end
169
+
170
+ context 'when given an original error' do
171
+
172
+ it 'uses the original error message' do
173
+ orig_err = StandardError.new
174
+ err = klass.new(nil, orig_err)
175
+ err.message.should == 'Error: StandardError'
176
+
177
+ orig_err = StandardError.new('original message')
178
+ err = klass.new(nil, orig_err)
179
+ err.message.should == 'Error: StandardError: original message'
180
+
181
+ orig_err = StandardError.new(" original message\n" +
182
+ " This is a multi-line error message.\n" +
183
+ "It should be properly indented.")
184
+ err = klass.new(nil, orig_err)
185
+ err.message.should == "Error: StandardError: original message\n" +
186
+ " This is a multi-line error message.\n" +
187
+ " It should be properly indented."
188
+ end
189
+
190
+ end # context 'when given an original error'
191
+
192
+ context 'when given an original Errors::Error' do
193
+ let(:subklass) do
194
+ class SubKlass < klass; end
195
+ SubKlass
196
+ end
197
+
198
+ it 'uses the original error message' do
199
+ orig_err = subklass.new
200
+ err = klass.new(nil, orig_err)
201
+ err.message.should == 'Error: SubKlass'
202
+
203
+ orig_err = subklass.new('original message')
204
+ err = klass.new(nil, orig_err)
205
+ err.message.should == 'Error: SubKlass: original message'
206
+
207
+ orig_err = subklass.new(" original message\n" +
208
+ " This is a multi-line error message.\n" +
209
+ "It should be properly indented.")
210
+ err = klass.new(nil, orig_err)
211
+ err.message.should == "Error: SubKlass: original message\n" +
212
+ " This is a multi-line error message.\n" +
213
+ " It should be properly indented."
214
+ end
215
+
216
+ end # context 'when given an original Errors::Error'
217
+
218
+ end # context 'when given no message'
219
+
220
+ end # describe '#initialize'
221
+
222
+ describe '#wrap' do
223
+ describe 'swaps the parameters to provide a cleaner way to' do
224
+
225
+ it 'raise a wrapped error with a message' do
226
+ orig_err = StandardError.new <<-EOS
227
+ original message
228
+ This is a multi-line error message.
229
+ It should be properly indented.
230
+ EOS
231
+
232
+ expect do
233
+ raise klass.wrap(orig_err), <<-EOS
234
+ error message
235
+ This is a multi-line error message.
236
+ It should be properly indented.
237
+ EOS
238
+ end.to raise_error(klass,
239
+ "Error: error message\n" +
240
+ " This is a multi-line error message.\n" +
241
+ " It should be properly indented.\n" +
242
+ " Reason: StandardError\n" +
243
+ " original message\n" +
244
+ " This is a multi-line error message.\n" +
245
+ " It should be properly indented."
246
+ )
247
+ end
248
+
249
+ it 'return a wrapped error with a message' do
250
+ orig_err = StandardError.new <<-EOS
251
+ original message
252
+ This is a multi-line error message.
253
+ It should be properly indented.
254
+ EOS
255
+
256
+ err = klass.wrap(orig_err, <<-EOS)
257
+ error message
258
+ This will wrap the original error
259
+ and it's message will be given below
260
+ EOS
261
+
262
+ err.message.should ==
263
+ "Error: error message\n" +
264
+ " This will wrap the original error\n" +
265
+ " and it's message will be given below\n" +
266
+ " Reason: StandardError\n" +
267
+ " original message\n" +
268
+ " This is a multi-line error message.\n" +
269
+ " It should be properly indented."
270
+ end
271
+
272
+ end # describe 'swaps the parameters to provide a cleaner way to'
273
+ end # describe '#wrap'
274
+
275
+ end # describe 'Errors::Error'
276
+
277
+ describe 'ErrorHelper' do
278
+ let(:base) { Backup::Errors }
279
+
280
+ it 'dynamically creates namespaces and subclasses of Errors::Error' do
281
+ Backup::Errors::FooBarError.new.
282
+ should be_a_kind_of base::Error
283
+ Backup::Errors::Foo::Bar::Error.new.
284
+ should be_a_kind_of base::Error
285
+ end
286
+
287
+ context 'new error classes created within new namespaces' do
288
+ it 'retain the added portion of namespace in their messages' do
289
+ orig_err = StandardError.new('original message')
290
+ err = base::FooMod::FooError.new('error message', orig_err)
291
+ err.message.should ==
292
+ "FooMod::FooError: error message\n" +
293
+ " Reason: StandardError\n" +
294
+ " original message"
295
+
296
+ err2 = base::Foo::Bar::Mod::FooBarError.wrap(err, 'foobar message')
297
+ err2.message.should ==
298
+ "Foo::Bar::Mod::FooBarError: foobar message\n" +
299
+ " Reason: FooMod::FooError\n" +
300
+ " error message\n" +
301
+ " Reason: StandardError\n" +
302
+ " original message"
303
+ end
304
+ end
305
+
306
+ end # describe ErrorHelper