backup-agoddard 3.0.27

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of backup-agoddard might be problematic. Click here for more details.

Files changed (190) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +10 -0
  3. data/Gemfile +28 -0
  4. data/Guardfile +23 -0
  5. data/LICENSE.md +24 -0
  6. data/README.md +478 -0
  7. data/backup.gemspec +32 -0
  8. data/bin/backup +11 -0
  9. data/lib/backup.rb +133 -0
  10. data/lib/backup/archive.rb +117 -0
  11. data/lib/backup/binder.rb +22 -0
  12. data/lib/backup/cleaner.rb +121 -0
  13. data/lib/backup/cli/helpers.rb +93 -0
  14. data/lib/backup/cli/utility.rb +255 -0
  15. data/lib/backup/compressor/base.rb +35 -0
  16. data/lib/backup/compressor/bzip2.rb +50 -0
  17. data/lib/backup/compressor/custom.rb +53 -0
  18. data/lib/backup/compressor/gzip.rb +50 -0
  19. data/lib/backup/compressor/lzma.rb +52 -0
  20. data/lib/backup/compressor/pbzip2.rb +59 -0
  21. data/lib/backup/config.rb +174 -0
  22. data/lib/backup/configuration.rb +33 -0
  23. data/lib/backup/configuration/helpers.rb +130 -0
  24. data/lib/backup/configuration/store.rb +24 -0
  25. data/lib/backup/database/base.rb +53 -0
  26. data/lib/backup/database/mongodb.rb +230 -0
  27. data/lib/backup/database/mysql.rb +160 -0
  28. data/lib/backup/database/postgresql.rb +144 -0
  29. data/lib/backup/database/redis.rb +136 -0
  30. data/lib/backup/database/riak.rb +67 -0
  31. data/lib/backup/dependency.rb +108 -0
  32. data/lib/backup/encryptor/base.rb +29 -0
  33. data/lib/backup/encryptor/gpg.rb +760 -0
  34. data/lib/backup/encryptor/open_ssl.rb +72 -0
  35. data/lib/backup/errors.rb +124 -0
  36. data/lib/backup/hooks.rb +68 -0
  37. data/lib/backup/logger.rb +152 -0
  38. data/lib/backup/model.rb +409 -0
  39. data/lib/backup/notifier/base.rb +81 -0
  40. data/lib/backup/notifier/campfire.rb +155 -0
  41. data/lib/backup/notifier/hipchat.rb +93 -0
  42. data/lib/backup/notifier/mail.rb +206 -0
  43. data/lib/backup/notifier/prowl.rb +65 -0
  44. data/lib/backup/notifier/pushover.rb +88 -0
  45. data/lib/backup/notifier/twitter.rb +70 -0
  46. data/lib/backup/package.rb +47 -0
  47. data/lib/backup/packager.rb +100 -0
  48. data/lib/backup/pipeline.rb +110 -0
  49. data/lib/backup/splitter.rb +75 -0
  50. data/lib/backup/storage/base.rb +99 -0
  51. data/lib/backup/storage/cloudfiles.rb +87 -0
  52. data/lib/backup/storage/cycler.rb +117 -0
  53. data/lib/backup/storage/dropbox.rb +178 -0
  54. data/lib/backup/storage/ftp.rb +119 -0
  55. data/lib/backup/storage/local.rb +82 -0
  56. data/lib/backup/storage/ninefold.rb +116 -0
  57. data/lib/backup/storage/rsync.rb +149 -0
  58. data/lib/backup/storage/s3.rb +94 -0
  59. data/lib/backup/storage/scp.rb +99 -0
  60. data/lib/backup/storage/sftp.rb +108 -0
  61. data/lib/backup/syncer/base.rb +46 -0
  62. data/lib/backup/syncer/cloud/base.rb +247 -0
  63. data/lib/backup/syncer/cloud/cloud_files.rb +78 -0
  64. data/lib/backup/syncer/cloud/s3.rb +68 -0
  65. data/lib/backup/syncer/rsync/base.rb +49 -0
  66. data/lib/backup/syncer/rsync/local.rb +55 -0
  67. data/lib/backup/syncer/rsync/pull.rb +36 -0
  68. data/lib/backup/syncer/rsync/push.rb +116 -0
  69. data/lib/backup/template.rb +46 -0
  70. data/lib/backup/version.rb +43 -0
  71. data/spec-live/.gitignore +6 -0
  72. data/spec-live/README +7 -0
  73. data/spec-live/backups/config.rb +83 -0
  74. data/spec-live/backups/config.yml.template +46 -0
  75. data/spec-live/backups/models.rb +184 -0
  76. data/spec-live/compressor/custom_spec.rb +30 -0
  77. data/spec-live/compressor/gzip_spec.rb +30 -0
  78. data/spec-live/encryptor/gpg_keys.rb +239 -0
  79. data/spec-live/encryptor/gpg_spec.rb +287 -0
  80. data/spec-live/notifier/mail_spec.rb +121 -0
  81. data/spec-live/spec_helper.rb +151 -0
  82. data/spec-live/storage/dropbox_spec.rb +151 -0
  83. data/spec-live/storage/local_spec.rb +83 -0
  84. data/spec-live/storage/scp_spec.rb +193 -0
  85. data/spec-live/syncer/cloud/s3_spec.rb +124 -0
  86. data/spec/archive_spec.rb +335 -0
  87. data/spec/cleaner_spec.rb +312 -0
  88. data/spec/cli/helpers_spec.rb +301 -0
  89. data/spec/cli/utility_spec.rb +411 -0
  90. data/spec/compressor/base_spec.rb +52 -0
  91. data/spec/compressor/bzip2_spec.rb +217 -0
  92. data/spec/compressor/custom_spec.rb +106 -0
  93. data/spec/compressor/gzip_spec.rb +217 -0
  94. data/spec/compressor/lzma_spec.rb +123 -0
  95. data/spec/compressor/pbzip2_spec.rb +165 -0
  96. data/spec/config_spec.rb +321 -0
  97. data/spec/configuration/helpers_spec.rb +247 -0
  98. data/spec/configuration/store_spec.rb +39 -0
  99. data/spec/configuration_spec.rb +62 -0
  100. data/spec/database/base_spec.rb +63 -0
  101. data/spec/database/mongodb_spec.rb +510 -0
  102. data/spec/database/mysql_spec.rb +411 -0
  103. data/spec/database/postgresql_spec.rb +353 -0
  104. data/spec/database/redis_spec.rb +334 -0
  105. data/spec/database/riak_spec.rb +176 -0
  106. data/spec/dependency_spec.rb +51 -0
  107. data/spec/encryptor/base_spec.rb +40 -0
  108. data/spec/encryptor/gpg_spec.rb +909 -0
  109. data/spec/encryptor/open_ssl_spec.rb +148 -0
  110. data/spec/errors_spec.rb +306 -0
  111. data/spec/hooks_spec.rb +35 -0
  112. data/spec/logger_spec.rb +367 -0
  113. data/spec/model_spec.rb +694 -0
  114. data/spec/notifier/base_spec.rb +104 -0
  115. data/spec/notifier/campfire_spec.rb +217 -0
  116. data/spec/notifier/hipchat_spec.rb +211 -0
  117. data/spec/notifier/mail_spec.rb +316 -0
  118. data/spec/notifier/prowl_spec.rb +138 -0
  119. data/spec/notifier/pushover_spec.rb +123 -0
  120. data/spec/notifier/twitter_spec.rb +153 -0
  121. data/spec/package_spec.rb +61 -0
  122. data/spec/packager_spec.rb +213 -0
  123. data/spec/pipeline_spec.rb +259 -0
  124. data/spec/spec_helper.rb +60 -0
  125. data/spec/splitter_spec.rb +120 -0
  126. data/spec/storage/base_spec.rb +166 -0
  127. data/spec/storage/cloudfiles_spec.rb +254 -0
  128. data/spec/storage/cycler_spec.rb +247 -0
  129. data/spec/storage/dropbox_spec.rb +480 -0
  130. data/spec/storage/ftp_spec.rb +271 -0
  131. data/spec/storage/local_spec.rb +259 -0
  132. data/spec/storage/ninefold_spec.rb +343 -0
  133. data/spec/storage/rsync_spec.rb +362 -0
  134. data/spec/storage/s3_spec.rb +245 -0
  135. data/spec/storage/scp_spec.rb +233 -0
  136. data/spec/storage/sftp_spec.rb +244 -0
  137. data/spec/syncer/base_spec.rb +109 -0
  138. data/spec/syncer/cloud/base_spec.rb +515 -0
  139. data/spec/syncer/cloud/cloud_files_spec.rb +181 -0
  140. data/spec/syncer/cloud/s3_spec.rb +174 -0
  141. data/spec/syncer/rsync/base_spec.rb +98 -0
  142. data/spec/syncer/rsync/local_spec.rb +149 -0
  143. data/spec/syncer/rsync/pull_spec.rb +98 -0
  144. data/spec/syncer/rsync/push_spec.rb +333 -0
  145. data/spec/version_spec.rb +21 -0
  146. data/templates/cli/utility/archive +25 -0
  147. data/templates/cli/utility/compressor/bzip2 +4 -0
  148. data/templates/cli/utility/compressor/custom +11 -0
  149. data/templates/cli/utility/compressor/gzip +4 -0
  150. data/templates/cli/utility/compressor/lzma +10 -0
  151. data/templates/cli/utility/compressor/pbzip2 +10 -0
  152. data/templates/cli/utility/config +32 -0
  153. data/templates/cli/utility/database/mongodb +18 -0
  154. data/templates/cli/utility/database/mysql +21 -0
  155. data/templates/cli/utility/database/postgresql +17 -0
  156. data/templates/cli/utility/database/redis +16 -0
  157. data/templates/cli/utility/database/riak +11 -0
  158. data/templates/cli/utility/encryptor/gpg +27 -0
  159. data/templates/cli/utility/encryptor/openssl +9 -0
  160. data/templates/cli/utility/model.erb +23 -0
  161. data/templates/cli/utility/notifier/campfire +12 -0
  162. data/templates/cli/utility/notifier/hipchat +15 -0
  163. data/templates/cli/utility/notifier/mail +22 -0
  164. data/templates/cli/utility/notifier/prowl +11 -0
  165. data/templates/cli/utility/notifier/pushover +11 -0
  166. data/templates/cli/utility/notifier/twitter +13 -0
  167. data/templates/cli/utility/splitter +7 -0
  168. data/templates/cli/utility/storage/cloud_files +22 -0
  169. data/templates/cli/utility/storage/dropbox +20 -0
  170. data/templates/cli/utility/storage/ftp +12 -0
  171. data/templates/cli/utility/storage/local +7 -0
  172. data/templates/cli/utility/storage/ninefold +9 -0
  173. data/templates/cli/utility/storage/rsync +11 -0
  174. data/templates/cli/utility/storage/s3 +19 -0
  175. data/templates/cli/utility/storage/scp +11 -0
  176. data/templates/cli/utility/storage/sftp +11 -0
  177. data/templates/cli/utility/syncer/cloud_files +46 -0
  178. data/templates/cli/utility/syncer/rsync_local +12 -0
  179. data/templates/cli/utility/syncer/rsync_pull +17 -0
  180. data/templates/cli/utility/syncer/rsync_push +17 -0
  181. data/templates/cli/utility/syncer/s3 +43 -0
  182. data/templates/general/links +11 -0
  183. data/templates/general/version.erb +2 -0
  184. data/templates/notifier/mail/failure.erb +9 -0
  185. data/templates/notifier/mail/success.erb +7 -0
  186. data/templates/notifier/mail/warning.erb +9 -0
  187. data/templates/storage/dropbox/authorization_url.erb +6 -0
  188. data/templates/storage/dropbox/authorized.erb +4 -0
  189. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  190. metadata +277 -0
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Dependency do
6
+ before do
7
+ Backup::Dependency.stubs(:all).returns(
8
+ 'net-sftp' => {
9
+ :require => 'net/sftp',
10
+ :version => '~> 2.0.5',
11
+ :for => 'SFTP Protocol (SFTP Storage)'
12
+ })
13
+ end
14
+
15
+ describe ".load" do
16
+ it "should load and require given dependency" do
17
+ Backup::Dependency.expects(:gem).with("net-sftp", "~> 2.0.5")
18
+ Backup::Dependency.expects(:require).with("net/sftp")
19
+ Backup::Dependency.load("net-sftp")
20
+ end
21
+
22
+ context "on a missing dependency" do
23
+ before do
24
+ Backup::Dependency.stubs(:gem).raises(LoadError)
25
+ end
26
+
27
+ it "should display error message" do
28
+ Backup::Logger.expects(:error).with do |exception|
29
+ exception.message.should == "Dependency::LoadError: Dependency missing
30
+ Dependency required for:
31
+ SFTP Protocol (SFTP Storage)
32
+ To install the gem, issue the following command:
33
+ > gem install net-sftp -v '~> 2.0.5'
34
+ Please try again after installing the missing dependency."
35
+ end
36
+
37
+ expect do
38
+ Backup::Dependency.load("net-sftp")
39
+ end.to raise_error(SystemExit)
40
+ end
41
+
42
+ it "should exit with status code 1" do
43
+ Backup::Logger.expects(:error)
44
+
45
+ expect do
46
+ Backup::Dependency.load("net-sftp")
47
+ end.to raise_error { |exit| exit.status.should be(1) }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Encryptor::Base do
6
+ let(:base) { Backup::Encryptor::Base.new }
7
+
8
+ it 'should include CLI::Helpers' do
9
+ Backup::Encryptor::Base.
10
+ include?(Backup::CLI::Helpers).should be_true
11
+ end
12
+
13
+ it 'should include Configuration::Helpers' do
14
+ Backup::Encryptor::Base.
15
+ include?(Backup::Configuration::Helpers).should be_true
16
+ end
17
+
18
+ describe '#initialize' do
19
+ it 'should load defaults' do
20
+ Backup::Encryptor::Base.any_instance.expects(:load_defaults!)
21
+ base
22
+ end
23
+ end
24
+
25
+ describe '#encryptor_name' do
26
+ it 'should return class name with Backup namespace removed' do
27
+ base.send(:encryptor_name).should == 'Encryptor::Base'
28
+ end
29
+ end
30
+
31
+ describe '#log!' do
32
+ it 'should log a message' do
33
+ base.expects(:encryptor_name).returns('Encryptor Name')
34
+ Backup::Logger.expects(:message).with(
35
+ 'Using Encryptor Name to encrypt the archive.'
36
+ )
37
+ base.send(:log!)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,909 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Encryptor::GPG do
6
+ let(:encryptor) do
7
+ Backup::Encryptor::GPG.new do |e|
8
+ e.mode = :symmetric
9
+ e.passphrase = 'test secret'
10
+ end
11
+ end
12
+
13
+ it 'should be a subclass of Encryptor::Base' do
14
+ Backup::Encryptor::GPG.
15
+ superclass.should == Backup::Encryptor::Base
16
+ end
17
+
18
+ it 'supports three modes of operation' do
19
+ Backup::Encryptor::GPG::MODES.should == [:asymmetric, :symmetric, :both]
20
+ end
21
+
22
+ describe '#mode=' do
23
+ it 'should accept valid modes' do
24
+ mode = Backup::Encryptor::GPG::MODES.shuffle.first
25
+ encryptor.mode = mode
26
+ encryptor.mode.should == mode
27
+ end
28
+
29
+ it 'should convert string input to a symbol' do
30
+ mode = Backup::Encryptor::GPG::MODES.shuffle.first
31
+ encryptor.mode = mode.to_s
32
+ encryptor.mode.should == mode
33
+ end
34
+
35
+ it 'should raise an error for invalid modes' do
36
+ expect do
37
+ encryptor.mode = 'foo'
38
+ end.to raise_error(Backup::Errors::Encryptor::GPG::InvalidModeError)
39
+ end
40
+ end # describe '#mode='
41
+
42
+ describe '#initialize' do
43
+ after { Backup::Encryptor::GPG.clear_defaults! }
44
+
45
+ it 'should load pre-configured defaults' do
46
+ Backup::Encryptor::GPG.any_instance.expects(:load_defaults!)
47
+ encryptor
48
+ end
49
+
50
+ context 'when no pre-configured defaults have been set' do
51
+ it 'should use the values given' do
52
+ encryptor.mode.should == :symmetric
53
+ encryptor.passphrase.should == 'test secret'
54
+ end
55
+
56
+ it 'should use default values if none are given' do
57
+ encryptor = Backup::Encryptor::GPG.new
58
+ encryptor.mode.should == :asymmetric
59
+ encryptor.keys.should be_nil
60
+ encryptor.recipients.should be_nil
61
+ encryptor.passphrase.should be_nil
62
+ encryptor.passphrase_file.should be_nil
63
+ encryptor.gpg_config.should be_nil
64
+ encryptor.gpg_homedir.should be_nil
65
+ end
66
+ end # context 'when no pre-configured defaults have been set'
67
+
68
+ context 'when pre-configured defaults have been set' do
69
+ before do
70
+ Backup::Encryptor::GPG.defaults do |e|
71
+ e.mode = :both
72
+ e.keys = { 'test_key' => 'test public key' }
73
+ e.recipients = 'test_key'
74
+ e.passphrase_file = 'my/pass/file'
75
+ end
76
+ end
77
+
78
+ it 'should use pre-configured defaults' do
79
+ encryptor = Backup::Encryptor::GPG.new
80
+ encryptor.mode.should == :both
81
+ encryptor.keys.should == { 'test_key' => 'test public key' }
82
+ encryptor.recipients.should == 'test_key'
83
+ encryptor.passphrase_file.should == 'my/pass/file'
84
+ end
85
+
86
+ it 'should override pre-configured defaults' do
87
+ encryptor.mode.should == :symmetric
88
+ encryptor.keys.should == { 'test_key' => 'test public key' }
89
+ encryptor.recipients.should == 'test_key'
90
+ encryptor.passphrase.should == 'test secret'
91
+ encryptor.passphrase_file.should == 'my/pass/file'
92
+ end
93
+ end # context 'when pre-configured defaults have been set'
94
+ end # describe '#initialize'
95
+
96
+ describe '#encrypt_with' do
97
+ before do
98
+ encryptor.expects(:log!)
99
+ encryptor.expects(:prepare)
100
+ encryptor.expects(:cleanup) # ensure call
101
+ end
102
+
103
+ context 'when encryption can be performed' do
104
+ it 'should yield the encryption command and extension' do
105
+ encryptor.expects(:mode_options).twice.returns('mode_options')
106
+ encryptor.expects(:base_options).returns('base_options')
107
+ encryptor.expects(:utility).with(:gpg).returns('gpg')
108
+
109
+ encryptor.encrypt_with do |command, ext|
110
+ command.should == 'gpg base_options mode_options'
111
+ ext.should == '.gpg'
112
+ end
113
+ end
114
+ end
115
+
116
+ context 'when encryption can not be performed' do
117
+ it 'should raise an error when no mode_options are returned' do
118
+ encryptor.expects(:mode_options).returns([])
119
+
120
+ expect do
121
+ encryptor.encrypt_with
122
+ end.to raise_error(Backup::Errors::Encryptor::GPG::EncryptionError)
123
+ end
124
+ end
125
+ end # describe '#encrypt_with'
126
+
127
+ describe '#prepare and #cleanup' do
128
+ it 'should setup required variables' do
129
+ encryptor.instance_variable_set(:@tempdirs, nil)
130
+ FileUtils.expects(:rm_rf).never
131
+ encryptor.send(:prepare)
132
+ encryptor.instance_variable_get(:@tempdirs).should == []
133
+ end
134
+
135
+ it 'should remove any tempdirs and clear all variables' do
136
+ encryptor.instance_variable_set(:@tempdirs, ['a', 'b'])
137
+ FileUtils.expects(:rm_rf).with(['a', 'b'], {:secure => true})
138
+
139
+ encryptor.instance_variable_set(:@base_options, true)
140
+ encryptor.instance_variable_set(:@mode_options, true)
141
+ encryptor.instance_variable_set(:@user_recipients, true)
142
+ encryptor.instance_variable_set(:@user_keys, true)
143
+ encryptor.instance_variable_set(:@system_identifiers, true)
144
+
145
+ encryptor.send(:cleanup)
146
+
147
+ encryptor.instance_variable_get(:@tempdirs).should == []
148
+ encryptor.instance_variable_get(:@base_options).should be_nil
149
+ encryptor.instance_variable_get(:@mode_options).should be_nil
150
+ encryptor.instance_variable_get(:@user_recipients).should be_nil
151
+ encryptor.instance_variable_get(:@user_keys).should be_nil
152
+ encryptor.instance_variable_get(:@system_identifiers).should be_nil
153
+ end
154
+ end # describe '#prepare and #cleanup'
155
+
156
+ describe '#base_options' do
157
+ context 'while caching the return value in @base_options' do
158
+ before { encryptor.instance_variable_set(:@base_options, nil) }
159
+
160
+ context 'when #gpg_homedir is given' do
161
+ it 'should return the proper options' do
162
+ encryptor.expects(:setup_gpg_homedir).once.returns('/a/dir')
163
+ encryptor.expects(:setup_gpg_config).once.returns(false)
164
+
165
+ ret = "--no-tty --homedir '/a/dir'"
166
+ encryptor.send(:base_options).should == ret
167
+ encryptor.send(:base_options).should == ret
168
+ encryptor.instance_variable_get(:@base_options).should == ret
169
+ end
170
+ end
171
+
172
+ context 'when #gpg_config is given' do
173
+ it 'should return the proper options' do
174
+ encryptor.expects(:setup_gpg_homedir).once.returns(false)
175
+ encryptor.expects(:setup_gpg_config).once.returns('/a/file')
176
+
177
+ ret = "--no-tty --options '/a/file'"
178
+ encryptor.send(:base_options).should == ret
179
+ encryptor.send(:base_options).should == ret
180
+ encryptor.instance_variable_get(:@base_options).should == ret
181
+ end
182
+ end
183
+
184
+ context 'when #gpg_homedir and #gpg_config is given' do
185
+ it 'should return the proper options' do
186
+ encryptor.expects(:setup_gpg_homedir).once.returns('/a/dir')
187
+ encryptor.expects(:setup_gpg_config).once.returns('/a/file')
188
+
189
+ ret = "--no-tty --homedir '/a/dir' --options '/a/file'"
190
+ encryptor.send(:base_options).should == ret
191
+ encryptor.send(:base_options).should == ret
192
+ encryptor.instance_variable_get(:@base_options).should == ret
193
+ end
194
+ end
195
+
196
+ context 'when neither #gpg_homedir and #gpg_config is given' do
197
+ it 'should return the proper options' do
198
+ encryptor.expects(:setup_gpg_homedir).once.returns(false)
199
+ encryptor.expects(:setup_gpg_config).once.returns(false)
200
+
201
+ ret = '--no-tty'
202
+ encryptor.send(:base_options).should == ret
203
+ encryptor.send(:base_options).should == ret
204
+ encryptor.instance_variable_get(:@base_options).should == ret
205
+ end
206
+ end
207
+ end
208
+ end # describe '#base_options'
209
+
210
+ describe '#setup_gpg_homedir' do
211
+ context 'when #gpg_homedir is not set' do
212
+ it 'should return false' do
213
+ encryptor.gpg_homedir = nil
214
+ encryptor.send(:setup_gpg_homedir).should be_false
215
+ end
216
+ end
217
+
218
+ context 'when #gpg_homedir is set' do
219
+ let(:path) { 'some/path' }
220
+ let(:expanded_path) { File.expand_path(path) }
221
+
222
+ before do
223
+ encryptor.gpg_homedir = path
224
+ Backup::Config.stubs(:user).returns('a_user')
225
+ end
226
+
227
+ context 'and no errors occur' do
228
+ before do
229
+ FileUtils.expects(:mkdir_p).with(expanded_path)
230
+ FileUtils.expects(:chown).with('a_user', nil, expanded_path)
231
+ FileUtils.expects(:chmod).with(0700, expanded_path)
232
+ end
233
+
234
+ context 'and the gpg_homedir files exist' do
235
+ before do
236
+ %w{ pubring.gpg secring.gpg trustdb.gpg }.each do |file|
237
+ File.expects(:exist?).with(
238
+ File.join(expanded_path, file)
239
+ ).returns(true)
240
+ end
241
+ end
242
+
243
+ it 'should ensure permissions and return the path' do
244
+ encryptor.expects(:utility).never
245
+ encryptor.send(:setup_gpg_homedir).should == expanded_path
246
+ end
247
+ end
248
+
249
+ context 'and the gpg_homedir files do not exist' do
250
+ before do
251
+ File.stubs(:exist?).returns(false)
252
+ end
253
+
254
+ it 'should call gpg to initialize the files' do
255
+ encryptor.expects(:utility).with(:gpg).returns('gpg')
256
+ encryptor.expects(:run).with(
257
+ "gpg --homedir '#{ expanded_path }' -K 2>&1 >/dev/null"
258
+ )
259
+ encryptor.send(:setup_gpg_homedir).should == expanded_path
260
+ end
261
+ end
262
+ end
263
+
264
+ context 'and errors occur' do
265
+ it 'should wrap and raise the error' do
266
+ File.expects(:expand_path).raises('error message')
267
+
268
+ expect do
269
+ encryptor.send(:setup_gpg_homedir)
270
+ end.to raise_error {|err|
271
+ err.should
272
+ be_an_instance_of Backup::Errors::Encryptor::GPG::HomedirError
273
+ err.message.should
274
+ match(/Reason: RuntimeError\n error message/)
275
+ }
276
+ end
277
+ end
278
+ end
279
+ end # describe '#setup_gpg_homedir'
280
+
281
+ describe '#setup_gpg_config' do
282
+ context 'when #gpg_config is not set' do
283
+ it 'should return false' do
284
+ encryptor.gpg_config = nil
285
+ encryptor.send(:setup_gpg_config).should be_false
286
+ end
287
+ end
288
+
289
+ context 'when #gpg_config is set' do
290
+ before do
291
+ encryptor.gpg_config = <<-EOF
292
+ # a comment
293
+ text which will be
294
+
295
+ \tthe content of a gpg.conf file
296
+ EOF
297
+ Backup::Config.stubs(:tmp_path).returns('/Backup/tmp')
298
+ encryptor.instance_variable_set(:@tempdirs, [])
299
+ end
300
+
301
+ context 'when no errors occur' do
302
+ let(:tempdir) { mock }
303
+ let(:tempfile) { mock }
304
+ let(:tempfile_path) { mock }
305
+ let(:path) { mock }
306
+
307
+ before do
308
+ encryptor.expects(:cleanup).never
309
+ tempfile.stubs(:path).returns(tempfile_path)
310
+ end
311
+
312
+ it 'should create and return the file path' do
313
+ # create temporary directory and convert to a Pathname object
314
+ Dir.expects(:mktmpdir).with(
315
+ 'backup-gpg_config', '/Backup/tmp'
316
+ ).returns(tempdir)
317
+
318
+ # create temporary file within the temporary directory
319
+ Tempfile.expects(:open).with(
320
+ 'backup-gpg_config', tempdir
321
+ ).returns(tempfile)
322
+
323
+ # write the gpg_config, stripping leading tabs/spaces
324
+ tempfile.expects(:write).with(
325
+ "# a comment\n" +
326
+ "text which will be\n" +
327
+ "\n" +
328
+ "the content of a gpg.conf file\n"
329
+ )
330
+ # close the file
331
+ tempfile.expects(:close)
332
+
333
+ # check the config file
334
+ encryptor.expects(:check_gpg_config).with(tempfile_path)
335
+
336
+ # method returns the tempfile's path
337
+ encryptor.send(:setup_gpg_config).should == tempfile_path
338
+
339
+ # tempdir added to @tempdirs
340
+ encryptor.instance_variable_get(:@tempdirs)[0].should == tempdir
341
+ end
342
+ end
343
+
344
+ context 'when errors occur' do
345
+ before do
346
+ encryptor.expects(:cleanup) # run before the error is raised
347
+ end
348
+
349
+ it 'should wrap and raise the error' do
350
+ Dir.expects(:mktmpdir).raises('an error')
351
+
352
+ expect do
353
+ encryptor.send(:setup_gpg_config)
354
+ end.to raise_error {|err|
355
+ err.should be_an_instance_of(
356
+ Backup::Errors::Encryptor::GPG::GPGConfigError
357
+ )
358
+ err.message.should match(
359
+ /Error creating temporary file for #gpg_config/
360
+ )
361
+ err.message.should match(
362
+ /Reason: RuntimeError\n an error/
363
+ )
364
+ }
365
+ end
366
+ end
367
+ end
368
+ end # describe '#setup_gpg_config'
369
+
370
+ describe '#check_gpg_config' do
371
+ let(:cmd_ret) { mock }
372
+ let(:file_path) { '/path/to/tempfile' }
373
+
374
+ before do
375
+ encryptor.expects(:utility).with(:gpg).returns('gpg')
376
+ encryptor.expects(:run).with(
377
+ "gpg --options '#{ file_path }' --gpgconf-test 2>&1"
378
+ ).returns(cmd_ret)
379
+ end
380
+
381
+ context 'when no errors are reported' do
382
+ before { cmd_ret.expects(:chomp).returns('') }
383
+
384
+ it 'should do nothing' do
385
+ encryptor.send(:check_gpg_config, file_path).should be_nil
386
+ end
387
+ end
388
+
389
+ context 'when errors are reported' do
390
+ let(:error_message) { "gpg: /path/to/tempfile:1: invalid option" }
391
+ before { cmd_ret.expects(:chomp).returns(error_message) }
392
+
393
+ it 'should raise the error message reported' do
394
+ expect do
395
+ encryptor.send(:check_gpg_config, file_path)
396
+ end.to raise_error(RuntimeError, error_message)
397
+ end
398
+ end
399
+ end # describe '#check_gpg_config'
400
+
401
+ describe '#mode_options' do
402
+ let(:s_opts) { "-c --passphrase_file '/some/file'" }
403
+ let(:a_opts) { "-e --trust-model always -r 'identifier'" }
404
+
405
+ context 'while caching the return value in @mode_options' do
406
+ before { encryptor.instance_variable_set(:@mode_options, nil) }
407
+
408
+ context 'when #mode is :symmetric' do
409
+ it 'should return symmetric encryption options' do
410
+ encryptor.expects(:symmetric_options).once.returns(s_opts)
411
+ encryptor.expects(:asymmetric_options).never
412
+
413
+ encryptor.mode = :symmetric
414
+ encryptor.send(:mode_options).should == s_opts
415
+ encryptor.send(:mode_options).should == s_opts
416
+ encryptor.instance_variable_get(:@mode_options).should == s_opts
417
+ end
418
+ end
419
+
420
+ context 'when #mode is :asymmetric' do
421
+ it 'should return asymmetric encryption options' do
422
+ encryptor.expects(:symmetric_options).never
423
+ encryptor.expects(:asymmetric_options).once.returns(a_opts)
424
+
425
+ encryptor.mode = :asymmetric
426
+ encryptor.send(:mode_options).should == a_opts
427
+ encryptor.send(:mode_options).should == a_opts
428
+ encryptor.instance_variable_get(:@mode_options).should == a_opts
429
+ end
430
+ end
431
+
432
+ context 'when #mode is :both' do
433
+ it 'should return both symmetric and asymmetric encryption options' do
434
+ encryptor.expects(:symmetric_options).once.returns(s_opts)
435
+ encryptor.expects(:asymmetric_options).once.returns(a_opts)
436
+
437
+ encryptor.mode = :both
438
+ opts = "#{ s_opts } #{ a_opts }"
439
+
440
+ encryptor.send(:mode_options).should == opts
441
+ encryptor.send(:mode_options).should == opts
442
+ encryptor.instance_variable_get(:@mode_options).should == opts
443
+ end
444
+ end
445
+ end
446
+ end # describe '#mode_options'
447
+
448
+ describe '#symmetric_options' do
449
+ let(:path) { '/path/to/passphrase/file' }
450
+ let(:s_opts) { "-c --passphrase-file '#{ path }'" }
451
+
452
+ context 'when setup_passphrase_file returns a path' do
453
+ it 'should return the options' do
454
+ encryptor.expects(:setup_passphrase_file).returns(path)
455
+ File.expects(:exist?).with(path).returns(true)
456
+
457
+ encryptor.send(:symmetric_options).should == s_opts
458
+ end
459
+ end
460
+
461
+ context 'when setup_passphrase_file returns false' do
462
+ before do
463
+ encryptor.expects(:setup_passphrase_file).returns(false)
464
+ end
465
+
466
+ context 'and no :passphrase_file is set' do
467
+ it 'should return nil and log a warning' do
468
+ encryptor.expects(:passphrase_file).returns(nil)
469
+ Backup::Logger.expects(:warn)
470
+
471
+ encryptor.send(:symmetric_options).should be_nil
472
+ end
473
+ end
474
+
475
+ context 'and a :passphrase_file is set' do
476
+ before do
477
+ encryptor.expects(:passphrase_file).twice.returns(path)
478
+ File.expects(:expand_path).with(path).returns(path)
479
+ end
480
+
481
+ context 'when :passphrase_file exists' do
482
+ it 'should return the options' do
483
+ File.expects(:exist?).with(path).returns(true)
484
+ encryptor.send(:symmetric_options).should == s_opts
485
+ end
486
+ end
487
+
488
+ context 'when :passphrase_file is no valid' do
489
+ it 'should return nil and log a warning' do
490
+ File.expects(:exist?).with(path).returns(false)
491
+ Backup::Logger.expects(:warn)
492
+ encryptor.send(:symmetric_options).should be_nil
493
+ end
494
+ end
495
+ end
496
+ end
497
+ end # describe '#symmetric_options'
498
+
499
+ describe '#setup_passphrase_file' do
500
+ context 'when :passphrase is not set' do
501
+ it 'should return false' do
502
+ encryptor.expects(:passphrase).returns(nil)
503
+ encryptor.send(:setup_passphrase_file).should be_false
504
+ end
505
+ end
506
+
507
+ context 'when :passphrase is set' do
508
+ let(:tempdir) { mock }
509
+ let(:tempfile) { mock }
510
+ let(:tempfile_path) { mock }
511
+
512
+ before do
513
+ encryptor.instance_variable_set(:@tempdirs, [])
514
+ Backup::Config.stubs(:tmp_path).returns('/Backup/tmp')
515
+ encryptor.stubs(:passphrase).returns('a secret')
516
+ tempfile.stubs(:path).returns(tempfile_path)
517
+ end
518
+
519
+ context 'and no errors occur' do
520
+ it 'should return the path for the temp file' do
521
+ # creates temporary directory in Config.tmp_path
522
+ Dir.expects(:mktmpdir).
523
+ with('backup-gpg_passphrase', '/Backup/tmp').
524
+ returns(tempdir)
525
+
526
+ # create the temporary file in that temporary directory
527
+ Tempfile.expects(:open).
528
+ with('backup-gpg_passphrase', tempdir).
529
+ returns(tempfile)
530
+ tempfile.expects(:write).with('a secret')
531
+ tempfile.expects(:close)
532
+
533
+ encryptor.send(:setup_passphrase_file).should == tempfile_path
534
+
535
+ # adds the temporary directory to @tempdirs
536
+ encryptor.instance_variable_get(:@tempdirs)[0].should == tempdir
537
+ end
538
+ end
539
+
540
+ context 'and an error occurs' do
541
+ it 'should return false and log a warning' do
542
+ Dir.expects(:mktmpdir).raises('an error')
543
+ Backup::Logger.expects(:warn).with do |err|
544
+ err.should be_an_instance_of(
545
+ Backup::Errors::Encryptor::GPG::PassphraseError
546
+ )
547
+ err.message.should match(
548
+ /Reason: RuntimeError\n an error/
549
+ )
550
+ end
551
+ encryptor.send(:setup_passphrase_file).should be_false
552
+ end
553
+ end
554
+
555
+ end
556
+ end # describe '#setup_passphrase_file'
557
+
558
+ describe '#asymmetric_options' do
559
+ context 'when recipients are found' do
560
+ it 'should return the options' do
561
+ encryptor.stubs(:user_recipients).returns(['keyid1', 'keyid2'])
562
+ encryptor.send(:asymmetric_options).should ==
563
+ "-e --trust-model always -r 'keyid1' -r 'keyid2'"
564
+ end
565
+ end
566
+
567
+ context 'when no recipients are found' do
568
+ it 'should return nil log a warning' do
569
+ encryptor.expects(:user_recipients).returns([])
570
+ Backup::Logger.expects(:warn)
571
+ encryptor.send(:asymmetric_options).should be_nil
572
+ end
573
+ end
574
+ end # describe '#asymmetric_options'
575
+
576
+ describe '#user_recipients' do
577
+ context 'when an Array of :recipients are given' do
578
+ it 'should return the recipient list and cache the result' do
579
+ encryptor.expects(:recipients).returns(
580
+ ['key_id1', 'key_id2', 'key_id3', 'key_id4']
581
+ )
582
+ encryptor.expects(:clean_identifier).with('key_id1').returns('key_id1')
583
+ encryptor.expects(:clean_identifier).with('key_id2').returns('key_id2')
584
+ encryptor.expects(:clean_identifier).with('key_id3').returns('key_id3')
585
+ encryptor.expects(:clean_identifier).with('key_id4').returns('key_id4')
586
+
587
+ # key_id1 and key_id3 will be found in the system
588
+ encryptor.stubs(:system_identifiers).returns(['key_id1', 'key_id3'])
589
+
590
+ # key_id2 will be imported (key_id returned)
591
+ encryptor.stubs(:user_keys).returns({ 'key_id2' => 'a public key' })
592
+ encryptor.expects(:import_key).
593
+ with('key_id2', 'a public key').
594
+ returns('key_id2')
595
+
596
+ # key_id4 will not be found in user_keys, so a warning will be logged.
597
+ # This will return nil into the array, which will be compacted out.
598
+ Backup::Logger.expects(:warn).with do |msg|
599
+ msg.should match(/'key_id4'/)
600
+ end
601
+
602
+ encryptor.instance_variable_set(:@user_recipients, nil)
603
+ recipient_list = ['key_id1', 'key_id2', 'key_id3']
604
+ encryptor.send(:user_recipients).should == recipient_list
605
+ # results are cached (expectations would fail if called twice)
606
+ encryptor.send(:user_recipients).should == recipient_list
607
+ encryptor.instance_variable_get(:@user_recipients).should == recipient_list
608
+ end
609
+ end
610
+
611
+ context 'when :recipients is a single recipient, given as a String' do
612
+ it 'should return the cleaned identifier in an Array' do
613
+ encryptor.expects(:recipients).returns('key_id')
614
+ # the key will be found in system_identifiers
615
+ encryptor.stubs(:system_identifiers).returns(['key_id'])
616
+ encryptor.expects(:clean_identifier).with('key_id').returns('key_id')
617
+
618
+ encryptor.send(:user_recipients).should == ['key_id']
619
+ end
620
+ end
621
+
622
+ context 'when :recipients is not set' do
623
+ it 'should return an empty Array' do
624
+ encryptor.expects(:recipients).returns(nil)
625
+ encryptor.send(:user_recipients).should == []
626
+ end
627
+ end
628
+ end # describe '#user_recipients'
629
+
630
+ describe '#user_keys' do
631
+ context 'when :keys has been set' do
632
+ before do
633
+ encryptor.expects(:keys).returns(
634
+ { 'key1' => :foo, 'key2' => :foo, 'key3' => :foo }
635
+ )
636
+ encryptor.instance_variable_set(:@user_keys, nil)
637
+ end
638
+
639
+ it 'should return a new Hash of #keys with cleaned identifiers' do
640
+ encryptor.expects(:clean_identifier).with('key1').returns('clean_key1')
641
+ encryptor.expects(:clean_identifier).with('key2').returns('clean_key2')
642
+ encryptor.expects(:clean_identifier).with('key3').returns('clean_key3')
643
+
644
+ Backup::Logger.expects(:warn).never
645
+
646
+ cleaned_hash = {
647
+ 'clean_key1' => :foo, 'clean_key2' => :foo, 'clean_key3' => :foo
648
+ }
649
+ encryptor.send(:user_keys).should == cleaned_hash
650
+ # results are cached (expectations would fail if called twice)
651
+ encryptor.send(:user_keys).should == cleaned_hash
652
+ encryptor.instance_variable_get(:@user_keys).should == cleaned_hash
653
+ end
654
+
655
+ it 'should log a warning if cleaning results in a duplicate identifier' do
656
+ encryptor.expects(:clean_identifier).with('key1').returns('clean_key1')
657
+ encryptor.expects(:clean_identifier).with('key2').returns('clean_key2')
658
+ # return a duplicate key
659
+ encryptor.expects(:clean_identifier).with('key3').returns('clean_key2')
660
+
661
+ Backup::Logger.expects(:warn)
662
+
663
+ cleaned_hash = {
664
+ 'clean_key1' => :foo, 'clean_key2' => :foo
665
+ }
666
+ encryptor.send(:user_keys).should == cleaned_hash
667
+ # results are cached (expectations would fail if called twice)
668
+ encryptor.send(:user_keys).should == cleaned_hash
669
+ encryptor.instance_variable_get(:@user_keys).should == cleaned_hash
670
+ end
671
+ end
672
+
673
+ context 'when :keys has not be set' do
674
+ before do
675
+ encryptor.expects(:keys).returns(nil)
676
+ encryptor.instance_variable_set(:@user_keys, nil)
677
+ end
678
+
679
+ it 'should return an empty hash' do
680
+ encryptor.send(:user_keys).should == {}
681
+ end
682
+ end
683
+ end # describe '#user_keys'
684
+
685
+ describe '#clean_identifier' do
686
+ it 'should remove all spaces and upcase non-email identifiers' do
687
+ encryptor.send(:clean_identifier, ' 9d66 6290 c5f7 ee0f ').
688
+ should == '9D666290C5F7EE0F'
689
+ end
690
+
691
+ # Even though spaces in an email are technically possible,
692
+ # GPG won't allow anything but /[A-Za-z0-9_\-.]/
693
+ it 'should remove all spaces and wrap email addresses in <>' do
694
+ emails = [
695
+ "\t Foo.Bar@example.com ",
696
+ " < Foo-Bar@example.com\t > ",
697
+ "< <Foo_Bar @\texample.com> >"
698
+ ]
699
+ cleaned = [
700
+ '<Foo.Bar@example.com>',
701
+ '<Foo-Bar@example.com>',
702
+ '<Foo_Bar@example.com>'
703
+ ]
704
+
705
+ emails.map {|email|
706
+ encryptor.send(:clean_identifier, email)
707
+ }.should == cleaned
708
+ end
709
+ end # describe '#clean_identifier'
710
+
711
+ describe '#import_key' do
712
+ let(:gpg_return_ok) {
713
+ <<-EOS.gsub(/^ +/, '')
714
+ gpg: keyring `/tmp/.gnupg/secring.gpg' created
715
+ gpg: keyring `/tmp/.gnupg/pubring.gpg' created
716
+ gpg: /tmp/.gnupg/trustdb.gpg: trustdb created
717
+ gpg: key 0x9D666290C5F7EE0F: public key "Backup Test <backup01@foo.com>" imported
718
+ gpg: Total number processed: 1
719
+ gpg: imported: 1 (RSA: 1)
720
+ EOS
721
+ }
722
+ let(:gpg_return_failed) {
723
+ <<-EOS.gsub(/^ +/, '')
724
+ gpg: no valid OpenPGP data found.
725
+ gpg: Total number processed: 0
726
+ EOS
727
+ }
728
+ let(:gpg_key) {
729
+ <<-EOS
730
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
731
+ Version: GnuPG v1.4.12 (GNU/Linux)
732
+
733
+ mI0EUAmiNwEEAKpNP4GVKcjJrTtAh0XKk0NQsId6h/1pzEok2bExkNvD6eSjYRFL
734
+ gXY+pNqaEE6cHrg+uQatVQITX8EoVJhQ9Z1mYJB+g62zqOQPe10Spb381O9y4dN/
735
+ /ge/yL+/+R2CUrKeNF9nSA24+V4mTSqgo7sTnevDzGj4Srzs76MmkpU=
736
+ =TU/B
737
+ -----END PGP PUBLIC KEY BLOCK-----
738
+ EOS
739
+ }
740
+ let(:tempfile) { mock }
741
+
742
+ before do
743
+ Backup::Config.stubs(:tmp_path).returns('/tmp/path')
744
+ encryptor.stubs(:base_options).returns("--some 'base options'")
745
+ encryptor.stubs(:utility).returns('gpg')
746
+ tempfile.stubs(:path).returns('/tmp/file/path')
747
+ end
748
+
749
+ context 'when the import is successful' do
750
+ it 'should return the long key ID' do
751
+ Tempfile.expects(:open).with(
752
+ 'backup-gpg_import', '/tmp/path'
753
+ ).returns(tempfile)
754
+ tempfile.expects(:write).with(<<-EOS)
755
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
756
+ Version: GnuPG v1.4.12 (GNU/Linux)
757
+
758
+ mI0EUAmiNwEEAKpNP4GVKcjJrTtAh0XKk0NQsId6h/1pzEok2bExkNvD6eSjYRFL
759
+ gXY+pNqaEE6cHrg+uQatVQITX8EoVJhQ9Z1mYJB+g62zqOQPe10Spb381O9y4dN/
760
+ /ge/yL+/+R2CUrKeNF9nSA24+V4mTSqgo7sTnevDzGj4Srzs76MmkpU=
761
+ =TU/B
762
+ -----END PGP PUBLIC KEY BLOCK-----
763
+ EOS
764
+
765
+ tempfile.expects(:close)
766
+
767
+ encryptor.expects(:run).with(
768
+ "gpg --some 'base options' --keyid-format 0xlong " +
769
+ "--import '/tmp/file/path' 2>&1"
770
+ ).returns(gpg_return_ok)
771
+
772
+ tempfile.expects(:delete)
773
+
774
+ Backup::Logger.expects(:warn).never
775
+
776
+ encryptor.send(:import_key, 'some_identifier', gpg_key).
777
+ should == '9D666290C5F7EE0F'
778
+ end
779
+ end
780
+
781
+ context 'when the import is unsuccessful' do
782
+ it 'should return nil and log a warning' do
783
+ Tempfile.expects(:open).raises('an error')
784
+ Backup::Logger.expects(:warn).with {|err|
785
+ err.should be_an_instance_of(
786
+ Backup::Errors::Encryptor::GPG::KeyImportError
787
+ )
788
+ err.message.should match(
789
+ /Public key import failed for 'some_identifier'/
790
+ )
791
+ err.message.should match(
792
+ /Reason: RuntimeError\n an error/
793
+ )
794
+ }
795
+
796
+ encryptor.send(:import_key, 'some_identifier', 'foo').should be_nil
797
+ end
798
+ end
799
+ end # describe '#import_key'
800
+
801
+ describe '#system_identifiers' do
802
+ let(:gpg_output) {
803
+ <<-EOS.gsub(/^ +/, '')
804
+ tru::1:1343402941:0:3:1:5
805
+ pub:-:1024:1:5EFD157FFF9CFEA6:1342808803:::-:::scESC:
806
+ fpr:::::::::72E56E48E362BB402B3344045EFD157FFF9CFEA6:
807
+ uid:-::::1342808803::3BED8A0A5100FE9028BEB53610247518594B60A8::Backup Test (No Email):
808
+ sub:-:1024:1:E6CF1DC860A82E07:1342808803::::::e:
809
+ pub:-:1024:1:570CE9221E3DA3E8:1342808841:::-:::scESC:
810
+ fpr:::::::::616BBC8409C1AED791F8E6F8570CE9221E3DA3E8:
811
+ uid:-::::1342808875::ECFF419EFE4BD3C7CBCCD58FACAD283A9E98FECD::Backup Test <backup04@foo.com>:
812
+ uid:-::::1342808841::DDFD072C193BB45587EBA9D19A7DA1BB0E5E8A22::Backup Test <backup03@foo.com>:
813
+ sub:-:1024:1:B65C0ADEB804268D:1342808841::::::e:
814
+ pub:-:1024:1:54F81C93A7641A16:1342809011:::-:::scESC:
815
+ fpr:::::::::71335B9B960CF3A3071535F454F81C93A7641A16:
816
+ uid:-::::1342809011::2E5801E9C064C2A165B61EE35D50A5F9B64BF345::Backup Test (other email is <backup06@foo.com>) <backup05@foo.com>:
817
+ sub:-:1024:1:5B57BC34628252C7:1342809011::::::e:
818
+ pub:-:1024:1:0A5B6CC9581A88CF:1342809049:::-:::scESC:
819
+ fpr:::::::::E8C459082544924B8AEA06280A5B6CC9581A88CF:
820
+ uid:-::::1342809470::4A404F9ED6780E7E0E02A7F7607828E648789058::Backup Test <backup08@foo.com>:
821
+ uid:-::::::9785ADEBBBCE94CE0FF25774F610F2B11C839E9B::Backup Test <backup07@foo.com>:
822
+ uid:r::::::4AD074B1857819EFA105DFB6C464600AA451BF18::Backup Test <backup09@foo.com>:
823
+ sub:e:1024:1:60A420E39B979B06:1342809049:1342895611:::::e:
824
+ sub:-:1024:1:A05786E7AD5B8352:1342809166::::::e:
825
+ pub:i:1024:1:4A83569F4E5E8D8A:1342810132:::-:::esca:
826
+ fpr:::::::::FFEAD1DB201FB214873E73994A83569F4E5E8D8A:
827
+ uid:-::::::3D41A10AF2437C8C5BF6050FA80FE20CE30769BF::Backup Test <backup10@foo.com>:
828
+ sub:i:1024:1:662F18DB92C8DFD8:1342810132::::::e:
829
+ pub:r:1024:1:15ECEF9ECA136FFF:1342810387:::-:::sc:
830
+ fpr:::::::::3D1CBF3FEFCE5ABB728922F615ECEF9ECA136FFF:
831
+ uid:r::::1342810387::296434E1662AE0B2FF8E93EC3BF3AFE24514D0E0::Backup Test <backup11@foo.com>:
832
+ sub:r:1024:1:097A79EB1F7D4619:1342810387::::::e:
833
+ sub:r:1024:1:39093E8E9057625E:1342810404::::::e:
834
+ pub:e:1024:1:31920687A8A7941B:1342810629:1342897029::-:::sc:
835
+ fpr:::::::::03B399CBC2F4B61019D14BCD31920687A8A7941B:
836
+ uid:e::::1342810629::ED8151565B25281CB92DD1E534701E660126CB0C::Backup Test <backup12@foo.com>:
837
+ sub:e:1024:1:AEF89BEE95042A0F:1342810629:1342897029:::::e:
838
+ pub:-:1024:1:E3DBAEC3FEEA03E2:1342810728:::-:::scSC:
839
+ fpr:::::::::444B0870D985CF70BBB7F4DCE3DBAEC3FEEA03E2:
840
+ uid:-::::1342810796::4D1B8CC29335BF79232CA71210F75CF80318B06A::Backup Test <backup13@foo.com>:
841
+ uid:-::::1342810728::F1422363E8DC1EC3076906505CE66855BB44CAB7::Backup Test <backup14@foo.com>:
842
+ sub:e:1024:1:C95DED316504D17C:1342810728:1342897218:::::e:
843
+ pub:u:1024:1:027B83DB8A82B9CB:1343402840:::u:::scESC:
844
+ fpr:::::::::A20D90150CE4E5F851AD3A9D027B83DB8A82B9CB:
845
+ uid:u::::1343402840::307F1E025E8BEB7DABCADC353291184AD493A28E::Backup Test <backup01@foo.com>:
846
+ sub:u:1024:1:EF31D36414FD8B2B:1343402840::::::e:
847
+ pub:u:1024:1:4CEA6442A4A57A76:1343402867:::u:::scESC:
848
+ fpr:::::::::5742EAFB4CF38014B474671E4CEA6442A4A57A76:
849
+ uid:u::::1343402932::C220D9FF5C9652AA31D3CE0487D88EFF291FA1ED::Backup Test:
850
+ uid:u::::1343402922::E89778553F703C26517AD8321C17C81F3213A782::Backup Test <backup02@foo.com>:
851
+ sub:u:1024:1:140DDC2E97DA3567:1343402867::::::e:
852
+ EOS
853
+ }
854
+
855
+ let(:valid_identifiers) {
856
+ %w{ FF9CFEA6 5EFD157FFF9CFEA6 72E56E48E362BB402B3344045EFD157FFF9CFEA6
857
+ 1E3DA3E8 570CE9221E3DA3E8 616BBC8409C1AED791F8E6F8570CE9221E3DA3E8
858
+ <backup04@foo.com> <backup03@foo.com>
859
+ A7641A16 54F81C93A7641A16 71335B9B960CF3A3071535F454F81C93A7641A16
860
+ <backup05@foo.com>
861
+ 581A88CF 0A5B6CC9581A88CF E8C459082544924B8AEA06280A5B6CC9581A88CF
862
+ <backup08@foo.com> <backup07@foo.com>
863
+ FEEA03E2 E3DBAEC3FEEA03E2 444B0870D985CF70BBB7F4DCE3DBAEC3FEEA03E2
864
+ <backup13@foo.com> <backup14@foo.com>
865
+ 8A82B9CB 027B83DB8A82B9CB A20D90150CE4E5F851AD3A9D027B83DB8A82B9CB
866
+ <backup01@foo.com>
867
+ A4A57A76 4CEA6442A4A57A76 5742EAFB4CF38014B474671E4CEA6442A4A57A76
868
+ <backup02@foo.com> }
869
+ }
870
+ it 'should return an array of all valid identifiers' do
871
+ encryptor.instance_variable_set(:@system_identifiers, nil)
872
+
873
+ encryptor.expects(:utility).with(:gpg).returns('gpg')
874
+ encryptor.expects(:base_options).returns("--base 'options'")
875
+ encryptor.expects(:run).with(
876
+ "gpg --base 'options' --with-colons --fixed-list-mode --fingerprint"
877
+ ).returns(gpg_output)
878
+
879
+ encryptor.send(:system_identifiers).should == valid_identifiers
880
+ # results cached
881
+ encryptor.send(:system_identifiers).should == valid_identifiers
882
+ encryptor.instance_variable_get(:@system_identifiers).
883
+ should == valid_identifiers
884
+ end
885
+ end # describe '#system_identifiers'
886
+
887
+ describe 'deprecations' do
888
+ describe '#key' do
889
+ it 'should import #key, use identifier for #recipients and log a warning' do
890
+ encryptor.expects(:import_key).
891
+ with('deprecated :key', 'a public key').
892
+ returns('an_identifier')
893
+
894
+ Backup::Logger.expects(:warn).with {|err|
895
+ err.should be_an_instance_of(Backup::Errors::ConfigurationError)
896
+ err.message.should match(
897
+ "GPG#key has been deprecated as of backup v.3.0.26"
898
+ )
899
+ err.message.should match(
900
+ "replaced with #keys and #recipients"
901
+ )
902
+ }
903
+
904
+ encryptor.key = 'a public key'
905
+ encryptor.recipients.should == 'an_identifier'
906
+ end
907
+ end # describe '#key'
908
+ end # describe 'deprecations'
909
+ end