imap-backup 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +2 -1
  5. data/.travis.yml +1 -1
  6. data/README.md +12 -0
  7. data/bin/imap-backup +11 -6
  8. data/docker-compose.yml +15 -0
  9. data/imap-backup.gemspec +3 -2
  10. data/lib/email/mboxrd/message.rb +30 -4
  11. data/lib/email/provider.rb +2 -2
  12. data/lib/imap/backup.rb +0 -1
  13. data/lib/imap/backup/account/connection.rb +29 -15
  14. data/lib/imap/backup/account/folder.rb +3 -3
  15. data/lib/imap/backup/configuration/account.rb +15 -12
  16. data/lib/imap/backup/configuration/asker.rb +3 -1
  17. data/lib/imap/backup/configuration/folder_chooser.rb +5 -2
  18. data/lib/imap/backup/configuration/list.rb +12 -9
  19. data/lib/imap/backup/configuration/setup.rb +5 -3
  20. data/lib/imap/backup/configuration/store.rb +4 -4
  21. data/lib/imap/backup/downloader.rb +6 -2
  22. data/lib/imap/backup/serializer/base.rb +2 -2
  23. data/lib/imap/backup/serializer/mbox.rb +16 -7
  24. data/lib/imap/backup/utils.rb +8 -3
  25. data/lib/imap/backup/version.rb +1 -1
  26. data/spec/features/backup_spec.rb +27 -0
  27. data/spec/features/helper.rb +2 -0
  28. data/spec/features/support/backup_directory.rb +27 -0
  29. data/spec/features/support/email_server.rb +40 -0
  30. data/spec/features/support/shared/connection_context.rb +12 -0
  31. data/spec/features/support/shared/message_fixtures.rb +6 -0
  32. data/spec/fixtures/connection.yml +7 -0
  33. data/spec/support/fixtures.rb +6 -0
  34. data/spec/unit/account/connection_spec.rb +19 -7
  35. data/spec/unit/account/folder_spec.rb +15 -5
  36. data/spec/unit/configuration/account_spec.rb +18 -8
  37. data/spec/unit/configuration/asker_spec.rb +6 -3
  38. data/spec/unit/configuration/connection_tester_spec.rb +1 -1
  39. data/spec/unit/configuration/folder_chooser_spec.rb +21 -11
  40. data/spec/unit/configuration/list_spec.rb +13 -6
  41. data/spec/unit/configuration/setup_spec.rb +5 -3
  42. data/spec/unit/configuration/store_spec.rb +13 -8
  43. data/spec/unit/downloader_spec.rb +3 -1
  44. data/spec/unit/email/mboxrd/message_spec.rb +32 -13
  45. data/spec/unit/email/provider_spec.rb +7 -3
  46. data/spec/unit/serializer/base_spec.rb +3 -2
  47. data/spec/unit/serializer/mbox_spec.rb +9 -6
  48. data/spec/unit/utils_spec.rb +15 -13
  49. metadata +35 -5
  50. data/lib/imap/backup/serializer/directory.rb +0 -43
  51. data/spec/unit/serializer/directory_spec.rb +0 -69
@@ -35,7 +35,9 @@ describe Imap::Backup::Configuration::Account do
35
35
  context "#run" do
36
36
  let(:highline) { double("Highline") }
37
37
  let(:menu) { MockHighlineMenu.new }
38
- let(:store) { double("Imap::Backup::Configuration::Store", accounts: accounts) }
38
+ let(:store) do
39
+ double("Imap::Backup::Configuration::Store", accounts: accounts)
40
+ end
39
41
  let(:accounts) { [account, account1] }
40
42
  let(:account) do
41
43
  {
@@ -132,7 +134,8 @@ describe Imap::Backup::Configuration::Account do
132
134
 
133
135
  context "email" do
134
136
  before do
135
- allow(Imap::Backup::Configuration::Asker).to receive(:email).and_return(new_email)
137
+ allow(Imap::Backup::Configuration::Asker).
138
+ to receive(:email) { new_email }
136
139
  subject.run
137
140
  menu.choices["modify email"].call
138
141
  end
@@ -176,7 +179,8 @@ describe Imap::Backup::Configuration::Account do
176
179
  let(:new_email) { other_email }
177
180
 
178
181
  it "indicates the error" do
179
- expect(subject).to have_received(:puts).with("There is already an account set up with that email address")
182
+ expect(subject).to have_received(:puts).
183
+ with("There is already an account set up with that email address")
180
184
  end
181
185
 
182
186
  it "doesn't set the email" do
@@ -191,7 +195,8 @@ describe Imap::Backup::Configuration::Account do
191
195
  let(:new_password) { "new_password" }
192
196
 
193
197
  before do
194
- allow(Imap::Backup::Configuration::Asker).to receive(:password).and_return(new_password)
198
+ allow(Imap::Backup::Configuration::Asker).
199
+ to receive(:password) { new_password }
195
200
  subject.run
196
201
  menu.choices["modify password"].call
197
202
  end
@@ -239,7 +244,9 @@ describe Imap::Backup::Configuration::Account do
239
244
 
240
245
  before do
241
246
  @validator = nil
242
- allow(Imap::Backup::Configuration::Asker).to receive(:backup_path) do |path, validator|
247
+ allow(
248
+ Imap::Backup::Configuration::Asker
249
+ ).to receive(:backup_path) do |path, validator|
243
250
  @validator = validator
244
251
  new_backup_path
245
252
  end
@@ -262,7 +269,8 @@ describe Imap::Backup::Configuration::Account do
262
269
  let(:chooser) { double(run: nil) }
263
270
 
264
271
  before do
265
- allow(Imap::Backup::Configuration::FolderChooser).to receive(:new).and_return(chooser)
272
+ allow(Imap::Backup::Configuration::FolderChooser).
273
+ to receive(:new) { chooser }
266
274
  subject.run
267
275
  menu.choices["choose backup folders"].call
268
276
  end
@@ -274,14 +282,16 @@ describe Imap::Backup::Configuration::Account do
274
282
 
275
283
  context "connection test" do
276
284
  before do
277
- allow(Imap::Backup::Configuration::ConnectionTester).to receive(:test).and_return("All fine")
285
+ allow(Imap::Backup::Configuration::ConnectionTester).
286
+ to receive(:test).and_return("All fine")
278
287
  allow(highline).to receive(:ask)
279
288
  subject.run
280
289
  menu.choices["test connection"].call
281
290
  end
282
291
 
283
292
  it "tests the connection" do
284
- expect(Imap::Backup::Configuration::ConnectionTester).to have_received(:test).with(account)
293
+ expect(Imap::Backup::Configuration::ConnectionTester).
294
+ to have_received(:test).with(account)
285
295
  end
286
296
  end
287
297
 
@@ -81,8 +81,10 @@ module Imap::Backup
81
81
 
82
82
  before do
83
83
  @i = 0
84
- allow(highline).to receive(:ask).with("password: ").and_return(password1)
85
- allow(highline).to receive(:ask).with("repeat password: ").and_return(password2)
84
+ allow(highline).to receive(:ask).
85
+ with("password: ").and_return(password1)
86
+ allow(highline).to receive(:ask).
87
+ with("repeat password: ").and_return(password2)
86
88
  allow(highline).to receive(:agree) do
87
89
  answer = answers[@i]
88
90
  @i += 1
@@ -107,7 +109,8 @@ module Imap::Backup
107
109
  let(:password2) { "secret" }
108
110
 
109
111
  it "asks to continue" do
110
- expect(highline).to have_received(:agree).at_least(1).times.with(/Continue\?/)
112
+ expect(highline).to have_received(:agree).
113
+ at_least(1).times.with(/Continue\?/)
111
114
  end
112
115
  end
113
116
  end
@@ -5,7 +5,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
5
5
  let(:connection) { double("Imap::Backup::Account::Connection", imap: nil) }
6
6
 
7
7
  before do
8
- allow(Imap::Backup::Account::Connection).to receive(:new).and_return(connection)
8
+ allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
9
9
  end
10
10
 
11
11
  context "call" do
@@ -4,14 +4,17 @@ describe Imap::Backup::Configuration::FolderChooser do
4
4
  include HighLineTestHelpers
5
5
 
6
6
  context "#run" do
7
- let(:connection) { double("Imap::Backup::Account::Connection", folders: remote_folders) }
7
+ let(:connection) do
8
+ double("Imap::Backup::Account::Connection", folders: remote_folders)
9
+ end
8
10
  let(:account) { {folders: []} }
9
11
  let(:remote_folders) { [] }
10
12
 
11
13
  subject { described_class.new(account) }
12
14
 
13
15
  before do
14
- allow(Imap::Backup::Account::Connection).to receive(:new).with(account).and_return(connection)
16
+ allow(Imap::Backup::Account::Connection).
17
+ to receive(:new).with(account) { connection }
15
18
  @input, @output = prepare_highline
16
19
  allow(subject).to receive(:system)
17
20
  allow(Imap::Backup.logger).to receive(:warn)
@@ -32,7 +35,8 @@ describe Imap::Backup::Configuration::FolderChooser do
32
35
  context "folder listing" do
33
36
  let(:account) { {folders: [{name: "my_folder"}]} }
34
37
  let(:remote_folders) do
35
- folder1 = double("folder", name: "my_folder") # this one is already backed up
38
+ # this one is already backed up:
39
+ folder1 = double("folder", name: "my_folder")
36
40
  folder2 = double("folder", name: "another_folder")
37
41
  [folder1, folder2]
38
42
  end
@@ -57,7 +61,7 @@ describe Imap::Backup::Configuration::FolderChooser do
57
61
  end
58
62
 
59
63
  specify "are added to the account" do
60
- expect(account[:folders]).to include({name: "another_folder"})
64
+ expect(account[:folders]).to include(name: "another_folder")
61
65
  end
62
66
 
63
67
  include_examples "it flags the account as modified"
@@ -71,7 +75,7 @@ describe Imap::Backup::Configuration::FolderChooser do
71
75
  end
72
76
 
73
77
  specify "are removed from the account" do
74
- expect(account[:folders]).to_not include({name: "my_folder"})
78
+ expect(account[:folders]).to_not include(name: "my_folder")
75
79
  end
76
80
 
77
81
  include_examples "it flags the account as modified"
@@ -82,28 +86,34 @@ describe Imap::Backup::Configuration::FolderChooser do
82
86
  let(:remote_folders) { nil }
83
87
 
84
88
  before do
85
- allow(Imap::Backup::Configuration::Setup.highline).to receive(:ask).and_return("q")
89
+ allow(Imap::Backup::Configuration::Setup.highline).
90
+ to receive(:ask).and_return("q")
86
91
  subject.run
87
92
  end
88
93
 
89
94
  it "asks to press a key" do
90
- expect(Imap::Backup::Configuration::Setup.highline).to have_received(:ask).with("Press a key ")
95
+ expect(Imap::Backup::Configuration::Setup.highline).
96
+ to have_received(:ask).with("Press a key ")
91
97
  end
92
98
  end
93
99
 
94
100
  context "with connection errors" do
95
101
  before do
96
- allow(Imap::Backup::Account::Connection).to receive(:new).with(account).and_raise("error")
97
- allow(Imap::Backup::Configuration::Setup.highline).to receive(:ask).and_return("q")
102
+ allow(Imap::Backup::Account::Connection).
103
+ to receive(:new).with(account).and_raise("error")
104
+ allow(Imap::Backup::Configuration::Setup.highline).
105
+ to receive(:ask).and_return("q")
98
106
  subject.run
99
107
  end
100
108
 
101
109
  it "prints an error message" do
102
- expect(Imap::Backup.logger).to have_received(:warn).with("Connection failed")
110
+ expect(Imap::Backup.logger).
111
+ to have_received(:warn).with("Connection failed")
103
112
  end
104
113
 
105
114
  it "asks to continue" do
106
- expect(Imap::Backup::Configuration::Setup.highline).to have_received(:ask).with("Press a key ")
115
+ expect(Imap::Backup::Configuration::Setup.highline).
116
+ to have_received(:ask).with("Press a key ")
107
117
  end
108
118
  end
109
119
  end
@@ -11,14 +11,21 @@ describe Imap::Backup::Configuration::List do
11
11
  double("Imap::Backup::Configuration::Store", accounts: accounts)
12
12
  end
13
13
  let(:exists) { true }
14
- let(:connection1) { double("Imap::Backup::Account::Connection", disconnect: nil) }
15
- let(:connection2) { double("Imap::Backup::Account::Connection", disconnect: nil) }
14
+ let(:connection1) do
15
+ double("Imap::Backup::Account::Connection", disconnect: nil)
16
+ end
17
+ let(:connection2) do
18
+ double("Imap::Backup::Account::Connection", disconnect: nil)
19
+ end
16
20
 
17
21
  before do
18
- allow(Imap::Backup::Configuration::Store).to receive(:new).and_return(store)
19
- allow(Imap::Backup::Configuration::Store).to receive(:exist?).and_return(exists)
20
- allow(Imap::Backup::Account::Connection).to receive(:new).with(accounts[0]).and_return(connection1)
21
- allow(Imap::Backup::Account::Connection).to receive(:new).with(accounts[1]).and_return(connection2)
22
+ allow(Imap::Backup::Configuration::Store).to receive(:new) { store }
23
+ allow(Imap::Backup::Configuration::Store).
24
+ to receive(:exist?) { exists }
25
+ allow(Imap::Backup::Account::Connection).
26
+ to receive(:new).with(accounts[0]) { connection1 }
27
+ allow(Imap::Backup::Account::Connection).
28
+ to receive(:new).with(accounts[1]) { connection2 }
22
29
  end
23
30
 
24
31
  subject { described_class.new }
@@ -29,7 +29,7 @@ describe Imap::Backup::Configuration::Setup do
29
29
  let(:modified) { false }
30
30
 
31
31
  before :each do
32
- allow(Imap::Backup::Configuration::Store).to receive(:new).and_return(store)
32
+ allow(Imap::Backup::Configuration::Store).to receive(:new) { store }
33
33
  allow(Imap::Backup).to receive(:setup_logging)
34
34
  @input, @output = prepare_highline
35
35
  allow(@input).to receive(:eof?).and_return(false)
@@ -100,8 +100,10 @@ describe Imap::Backup::Configuration::Setup do
100
100
 
101
101
  before do
102
102
  allow(@input).to receive(:gets).and_return("add\n", "exit\n")
103
- allow(Imap::Backup::Configuration::Asker).to receive(:email).with(no_args).and_return("new@example.com")
104
- allow(Imap::Backup::Configuration::Account).to receive(:new).with(store, blank_account, anything).and_return(account)
103
+ allow(Imap::Backup::Configuration::Asker).to receive(:email).
104
+ with(no_args).and_return("new@example.com")
105
+ allow(Imap::Backup::Configuration::Account).to receive(:new).
106
+ with(store, blank_account, anything).and_return(account)
105
107
 
106
108
  subject.run
107
109
  end
@@ -12,11 +12,15 @@ describe Imap::Backup::Configuration::Store do
12
12
  let(:configuration) { data.to_json }
13
13
 
14
14
  before do
15
- stub_const("Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY", directory)
16
- allow(File).to receive(:directory?).with(directory).and_return(directory_exists)
17
- allow(File).to receive(:exist?).with(file_path).and_return(file_exists)
18
- allow(Imap::Backup::Utils).to receive(:stat).with(directory).and_return(0700)
19
- allow(Imap::Backup::Utils).to receive(:stat).with(file_path).and_return(0600)
15
+ stub_const(
16
+ "Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY", directory
17
+ )
18
+ allow(File).to receive(:directory?).with(directory) { directory_exists }
19
+ allow(File).to receive(:exist?).with(file_path) { file_exists }
20
+ allow(Imap::Backup::Utils).
21
+ to receive(:stat).with(directory).and_return(0o700)
22
+ allow(Imap::Backup::Utils).
23
+ to receive(:stat).with(file_path).and_return(0o600)
20
24
  allow(Imap::Backup::Utils).to receive(:check_permissions).and_return(nil)
21
25
  allow(File).to receive(:read).with(file_path).and_return(configuration)
22
26
  end
@@ -151,7 +155,7 @@ describe Imap::Backup::Configuration::Store do
151
155
 
152
156
  context "when accounts are modified" do
153
157
  let(:accounts) { [{name: "foo", modified: true}] }
154
-
158
+
155
159
  before { subject.save }
156
160
 
157
161
  it "skips the 'modified' flag" do
@@ -184,7 +188,7 @@ describe Imap::Backup::Configuration::Store do
184
188
  before { subject.save }
185
189
 
186
190
  it "sets them to 0600" do
187
- expect(FileUtils).to have_received(:chmod).with(0600, file_path)
191
+ expect(FileUtils).to have_received(:chmod).with(0o600, file_path)
188
192
  end
189
193
  end
190
194
 
@@ -202,7 +206,8 @@ describe Imap::Backup::Configuration::Store do
202
206
  let(:file_exists) { true }
203
207
 
204
208
  before do
205
- allow(Imap::Backup::Utils).to receive(:check_permissions).with(file_path, 0600).and_raise("Error")
209
+ allow(Imap::Backup::Utils).to receive(:check_permissions).
210
+ with(file_path, 0o600).and_raise("Error")
206
211
  end
207
212
 
208
213
  it "fails" do
@@ -3,7 +3,9 @@ require "spec_helper"
3
3
  describe Imap::Backup::Downloader do
4
4
  describe "#run" do
5
5
  let(:message) { {"RFC822" => "blah"} }
6
- let(:folder) { double("Imap::Backup::Account::Folder", fetch: message, name: "folder") }
6
+ let(:folder) do
7
+ double("Imap::Backup::Account::Folder", fetch: message, name: "folder")
8
+ end
7
9
  let(:folder_uids) { ["111", "222", "333"] }
8
10
  let(:serializer) { double("Imap::Backup::Serializer", save: nil) }
9
11
  let(:serializer_uids) { ["222"] }
@@ -27,11 +27,28 @@ describe Email::Mboxrd::Message do
27
27
  let(:message_body) do
28
28
  double("Body", clone: cloned_message_body, force_encoding: nil)
29
29
  end
30
- let(:cloned_message_body) { "Foo\nBar\nFrom at the beginning of the line\n>>From quoted" }
30
+ let(:cloned_message_body) do
31
+ "Foo\nBar\nFrom at the beginning of the line\n>>From quoted"
32
+ end
31
33
 
32
34
  subject { described_class.new(message_body) }
33
35
 
34
- context "#to_s" do
36
+ describe ".from_serialized" do
37
+ let(:serialized_message) { "From foo@a.com\n#{imap_message}" }
38
+ let(:imap_message) { "Delivered-To: me@example.com\nFrom Me\n" }
39
+
40
+ before { @result = described_class.from_serialized(serialized_message) }
41
+
42
+ it "returns the message" do
43
+ expect(@result).to be_a(described_class)
44
+ end
45
+
46
+ it "removes one level of > before From" do
47
+ expect(@result.supplied_body).to eq(imap_message)
48
+ end
49
+ end
50
+
51
+ context "#to_serialized" do
35
52
  let(:mail) { double("Mail", from: [from], date: date) }
36
53
 
37
54
  before do
@@ -39,33 +56,34 @@ describe Email::Mboxrd::Message do
39
56
  end
40
57
 
41
58
  it "does not modify the message" do
42
- subject.to_s
59
+ subject.to_serialized
43
60
 
44
61
  expect(message_body).to_not have_received(:force_encoding).with("binary")
45
62
  end
46
63
 
47
64
  it "adds a 'From ' line at the start" do
48
- expect(subject.to_s).to start_with("From " + from + " " + date.asctime + "\n")
65
+ expected = "From #{from} #{date.asctime}\n"
66
+ expect(subject.to_serialized).to start_with(expected)
49
67
  end
50
68
 
51
69
  it "replaces existing 'From ' with '>From '" do
52
- expect(subject.to_s).to include("\n>From at the beginning")
70
+ expect(subject.to_serialized).to include("\n>From at the beginning")
53
71
  end
54
72
 
55
73
  it "appends > before '>+From '" do
56
- expect(subject.to_s).to include("\n>>>From quoted")
74
+ expect(subject.to_serialized).to include("\n>>>From quoted")
57
75
  end
58
76
 
59
77
  context "when date is missing" do
60
78
  let(:date) { nil }
61
79
 
62
80
  it "does no fail" do
63
- expect { subject.to_s }.to_not raise_error
81
+ expect { subject.to_serialized }.to_not raise_error
64
82
  end
65
83
  end
66
84
  end
67
85
 
68
- context '#from' do
86
+ context "#from" do
69
87
  before do
70
88
  # call original for these tests because we want to test the behaviour of
71
89
  # class-under-test given different behaviour of the Mail parser
@@ -75,7 +93,7 @@ describe Email::Mboxrd::Message do
75
93
  context "when original message 'from' is nil" do
76
94
  let(:message_body) { msg_no_from }
77
95
  it "'from' is empty string" do
78
- expect(subject.to_s).to start_with("From \n")
96
+ expect(subject.to_serialized).to start_with("From \n")
79
97
  end
80
98
  end
81
99
 
@@ -83,15 +101,16 @@ describe Email::Mboxrd::Message do
83
101
  let(:message_body) { msg_bad_from }
84
102
 
85
103
  it "'from' is empty string" do
86
- expect(subject.to_s).to start_with("From \n")
104
+ expect(subject.to_serialized).to start_with("From \n")
87
105
  end
88
106
  end
89
107
 
90
- context "when original message 'from' is nil and 'envelope from' is nil and 'return path' is available" do
108
+ context "when original message 'from' is nil and " \
109
+ "'envelope from' is nil and 'return path' is available" do
91
110
  let(:message_body) { msg_no_from_but_return_path }
92
111
 
93
112
  it "'return path' is used as 'from'" do
94
- expect(subject.to_s).to start_with("From " + from + " \n")
113
+ expect(subject.to_serialized).to start_with("From " + from + "\n")
95
114
  end
96
115
  end
97
116
 
@@ -99,7 +118,7 @@ describe Email::Mboxrd::Message do
99
118
  let(:message_body) { msg_no_from_but_sender }
100
119
 
101
120
  it "Sender is used as 'from'" do
102
- expect(subject.to_s).to start_with("From " + from + " \n")
121
+ expect(subject.to_serialized).to start_with("From " + from + "\n")
103
122
  end
104
123
  end
105
124
  end
@@ -3,7 +3,10 @@ require "spec_helper"
3
3
  describe Email::Provider do
4
4
  describe ".for_address" do
5
5
  context "known providers" do
6
- [["gmail.com", :gmail], ["fastmail.fm", :fastmail]].each do |domain, provider|
6
+ [
7
+ ["gmail.com", :gmail],
8
+ ["fastmail.fm", :fastmail]
9
+ ].each do |domain, provider|
7
10
  it "recognizes #{provider}" do
8
11
  address = "foo@#{domain}"
9
12
  expect(described_class.for_address(address).provider).to eq(provider)
@@ -13,7 +16,8 @@ describe Email::Provider do
13
16
 
14
17
  context "with unknown providers" do
15
18
  it "returns a default provider" do
16
- expect(described_class.for_address("foo@unknown.com").provider).to eq(:default)
19
+ result = described_class.for_address("foo@unknown.com").provider
20
+ expect(result).to eq(:default)
17
21
  end
18
22
  end
19
23
  end
@@ -22,7 +26,7 @@ describe Email::Provider do
22
26
 
23
27
  describe "#options" do
24
28
  it "returns options" do
25
- expect(subject.options).to eq(port: 993, ssl: true)
29
+ expect(subject.options).to be_a(Hash)
26
30
  end
27
31
  end
28
32
 
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Imap::Backup::Serializer::Base do
4
4
  context "#initialize" do
5
- let(:stat) { double("File::Stat", mode: 0345) }
5
+ let(:stat) { double("File::Stat", mode: 0o345) }
6
6
 
7
7
  before do
8
8
  allow(File).to receive(:exist?).with("/base/path").and_return(true)
@@ -10,9 +10,10 @@ describe Imap::Backup::Serializer::Base do
10
10
  end
11
11
 
12
12
  it "should fail if file permissions are to lax" do
13
+ message = "Permissions on '/base/path' should be 0700, not 0345"
13
14
  expect do
14
15
  described_class.new("/base/path", "my_folder")
15
- end.to raise_error(RuntimeError, "Permissions on '/base/path' should be 0700, not 0345")
16
+ end.to raise_error(RuntimeError, message)
16
17
  end
17
18
  end
18
19
  end