imap-backup 4.0.5 → 4.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/bin/imap-backup +5 -2
  3. data/lib/imap/backup/account/connection.rb +70 -58
  4. data/lib/imap/backup/account/folder.rb +23 -3
  5. data/lib/imap/backup/account.rb +6 -7
  6. data/lib/imap/backup/cli/accounts.rb +43 -0
  7. data/lib/imap/backup/cli/folders.rb +3 -1
  8. data/lib/imap/backup/cli/helpers.rb +8 -9
  9. data/lib/imap/backup/cli/local.rb +4 -2
  10. data/lib/imap/backup/cli/setup.rb +1 -1
  11. data/lib/imap/backup/cli/status.rb +1 -1
  12. data/lib/imap/backup/cli/utils.rb +3 -2
  13. data/lib/imap/backup/{configuration/store.rb → configuration.rb} +49 -14
  14. data/lib/imap/backup/downloader.rb +26 -12
  15. data/lib/imap/backup/logger.rb +42 -0
  16. data/lib/imap/backup/sanitizer.rb +42 -0
  17. data/lib/imap/backup/serializer/mbox_store.rb +2 -2
  18. data/lib/imap/backup/{configuration → setup}/account.rb +59 -41
  19. data/lib/imap/backup/{configuration → setup}/asker.rb +5 -5
  20. data/lib/imap/backup/setup/connection_tester.rb +26 -0
  21. data/lib/imap/backup/{configuration → setup}/folder_chooser.rb +25 -17
  22. data/lib/imap/backup/setup/helpers.rb +15 -0
  23. data/lib/imap/backup/{configuration/setup.rb → setup.rb} +33 -25
  24. data/lib/imap/backup/uploader.rb +2 -2
  25. data/lib/imap/backup/version.rb +2 -2
  26. data/lib/imap/backup.rb +7 -33
  27. data/lib/retry_on_error.rb +1 -1
  28. data/spec/features/backup_spec.rb +1 -0
  29. data/spec/features/status_spec.rb +43 -0
  30. data/spec/features/support/email_server.rb +5 -2
  31. data/spec/features/support/shared/connection_context.rb +7 -5
  32. data/spec/support/higline_test_helpers.rb +1 -1
  33. data/spec/support/silence_logging.rb +1 -1
  34. data/spec/unit/email/provider/base_spec.rb +1 -1
  35. data/spec/unit/email/provider_spec.rb +2 -2
  36. data/spec/unit/imap/backup/account/connection_spec.rb +22 -26
  37. data/spec/unit/imap/backup/cli/accounts_spec.rb +47 -0
  38. data/spec/unit/imap/backup/cli/local_spec.rb +15 -4
  39. data/spec/unit/imap/backup/cli/utils_spec.rb +54 -42
  40. data/spec/unit/imap/backup/{configuration/store_spec.rb → configuration_spec.rb} +23 -24
  41. data/spec/unit/imap/backup/downloader_spec.rb +1 -1
  42. data/spec/unit/imap/backup/logger_spec.rb +48 -0
  43. data/spec/unit/imap/backup/{configuration → setup}/account_spec.rb +78 -70
  44. data/spec/unit/imap/backup/{configuration → setup}/asker_spec.rb +2 -2
  45. data/spec/unit/imap/backup/{configuration → setup}/connection_tester_spec.rb +10 -10
  46. data/spec/unit/imap/backup/{configuration → setup}/folder_chooser_spec.rb +25 -26
  47. data/spec/unit/imap/backup/{configuration/setup_spec.rb → setup_spec.rb} +81 -52
  48. metadata +51 -48
  49. data/lib/imap/backup/configuration/connection_tester.rb +0 -14
  50. data/lib/imap/backup/configuration/list.rb +0 -53
  51. data/spec/support/shared_examples/account_flagging.rb +0 -23
  52. data/spec/unit/imap/backup/configuration/list_spec.rb +0 -89
  53. data/spec/unit/imap/backup_spec.rb +0 -28
@@ -1,17 +1,43 @@
1
- describe Imap::Backup::Configuration::Account do
1
+ describe Imap::Backup::Setup::Account do
2
2
  ACCOUNT = "account".freeze
3
3
  GMAIL_IMAP_SERVER = "imap.gmail.com".freeze
4
4
  HIGHLINE = "highline".freeze
5
- STORE = "store".freeze
6
-
7
- subject { described_class.new(store, account, highline) }
5
+ CONFIG = "config".freeze
6
+
7
+ subject { described_class.new(config, account, highline) }
8
+
9
+ let(:account) do
10
+ instance_double(
11
+ Imap::Backup::Account,
12
+ username: existing_email,
13
+ password: existing_password,
14
+ server: current_server,
15
+ connection_options: nil,
16
+ local_path: "/backup/path",
17
+ folders: [{name: "my_folder"}],
18
+ modified?: false
19
+ )
20
+ end
21
+ let(:account1) do
22
+ instance_double(
23
+ Imap::Backup::Account,
24
+ username: other_email,
25
+ local_path: other_existing_path
26
+ )
27
+ end
28
+ let(:accounts) { [account, account1] }
29
+ let(:existing_email) { "user@example.com" }
30
+ let(:new_email) { "foo@example.com" }
31
+ let(:current_server) { "imap.example.com" }
32
+ let(:existing_password) { "password" }
33
+ let(:other_email) { "other@example.com" }
34
+ let(:other_existing_path) { "/other/existing/path" }
8
35
 
9
- let(:account) { ACCOUNT }
10
36
  let(:highline) { HIGHLINE }
11
- let(:store) { STORE }
37
+ let(:config) { CONFIG }
12
38
 
13
39
  describe "#initialize" do
14
- [:store, :account, :highline].each do |param|
40
+ [:config, :account, :highline].each do |param|
15
41
  it "expects #{param}" do
16
42
  expect(subject.send(param)).to eq(send(param))
17
43
  end
@@ -40,31 +66,9 @@ describe Imap::Backup::Configuration::Account do
40
66
 
41
67
  let(:highline) { instance_double(HighLine) }
42
68
  let(:menu) { highline_menu_class.new }
43
- let(:store) do
44
- instance_double(Imap::Backup::Configuration::Store, accounts: accounts)
45
- end
46
- let(:accounts) { [account, account1] }
47
- let(:account) do
48
- {
49
- username: existing_email,
50
- server: current_server,
51
- local_path: "/backup/path",
52
- folders: [{name: "my_folder"}],
53
- password: existing_password
54
- }
69
+ let(:config) do
70
+ instance_double(Imap::Backup::Configuration, accounts: accounts)
55
71
  end
56
- let(:account1) do
57
- {
58
- username: other_email,
59
- local_path: other_existing_path
60
- }
61
- end
62
- let(:existing_email) { "user@example.com" }
63
- let(:new_email) { "foo@example.com" }
64
- let(:current_server) { "imap.example.com" }
65
- let(:existing_password) { "password" }
66
- let(:other_email) { "other@example.com" }
67
- let(:other_existing_path) { "/other/existing/path" }
68
72
 
69
73
  before do
70
74
  allow(Kernel).to receive(:system)
@@ -100,7 +104,7 @@ describe Imap::Backup::Configuration::Account do
100
104
  "choose backup folders",
101
105
  "test connection",
102
106
  "delete",
103
- "return to main menu",
107
+ "(q) return to main menu",
104
108
  "quit" # TODO: quit is hidden
105
109
  ].each do |item|
106
110
  before { subject.run }
@@ -113,11 +117,11 @@ describe Imap::Backup::Configuration::Account do
113
117
 
114
118
  describe "account details" do
115
119
  [
116
- ["email", /email:\s+user@example.com/],
117
- ["server", /server:\s+imap.example.com/],
118
- ["password", /password:\s+x+/],
119
- ["path", %r(path:\s+/backup/path)],
120
- ["folders", /folders:\s+my_folder/]
120
+ ["email", /email\s+user@example.com/],
121
+ ["password", /password\s+x+/],
122
+ ["path", %r(path\s+/backup/path)],
123
+ ["folders", /folders\s+my_folder/],
124
+ ["server", /server\s+imap.example.com/]
121
125
  ].each do |attribute, value|
122
126
  before { subject.run }
123
127
 
@@ -132,14 +136,16 @@ describe Imap::Backup::Configuration::Account do
132
136
  before { subject.run }
133
137
 
134
138
  it "indicates that a password is not set" do
135
- expect(menu.header).to include("password: (unset)")
139
+ expect(menu.header).to include("password (unset)")
136
140
  end
137
141
  end
138
142
  end
139
143
 
140
144
  describe "choosing 'modify email'" do
141
145
  before do
142
- allow(Imap::Backup::Configuration::Asker).
146
+ allow(account).to receive(:"username=")
147
+ allow(account).to receive(:"server=")
148
+ allow(Imap::Backup::Setup::Asker).
143
149
  to receive(:email) { new_email }
144
150
  subject.run
145
151
  menu.choices["modify email"].call
@@ -158,7 +164,7 @@ describe Imap::Backup::Configuration::Account do
158
164
  let(:current_server) { nil }
159
165
 
160
166
  it "sets a default server" do
161
- expect(account[:server]).to eq(expected)
167
+ expect(account).to have_received(:"server=").with(expected)
162
168
  end
163
169
  end
164
170
 
@@ -166,7 +172,7 @@ describe Imap::Backup::Configuration::Account do
166
172
  let(:current_server) { "" }
167
173
 
168
174
  it "sets a default server" do
169
- expect(account[:server]).to eq(expected)
175
+ expect(account).to have_received(:"server=").with(expected)
170
176
  end
171
177
  end
172
178
  end
@@ -183,17 +189,15 @@ describe Imap::Backup::Configuration::Account do
183
189
  end
184
190
 
185
191
  it "does not set a default server" do
186
- expect(account[:server]).to be_nil
192
+ expect(account).to_not have_received(:"server=")
187
193
  end
188
194
  end
189
195
  end
190
196
 
191
197
  context "when the email is new" do
192
198
  it "modifies the email address" do
193
- expect(account[:username]).to eq(new_email)
199
+ expect(account).to have_received(:"username=").with(new_email)
194
200
  end
195
-
196
- include_examples "it flags the account as modified"
197
201
  end
198
202
 
199
203
  context "when the email already exists" do
@@ -205,10 +209,8 @@ describe Imap::Backup::Configuration::Account do
205
209
  end
206
210
 
207
211
  it "doesn't set the email" do
208
- expect(account[:username]).to eq(existing_email)
212
+ expect(account.username).to eq(existing_email)
209
213
  end
210
-
211
- include_examples "it doesn't flag the account as modified"
212
214
  end
213
215
  end
214
216
 
@@ -216,7 +218,8 @@ describe Imap::Backup::Configuration::Account do
216
218
  let(:new_password) { "new_password" }
217
219
 
218
220
  before do
219
- allow(Imap::Backup::Configuration::Asker).
221
+ allow(account).to receive(:"password=")
222
+ allow(Imap::Backup::Setup::Asker).
220
223
  to receive(:password) { new_password }
221
224
  subject.run
222
225
  menu.choices["modify password"].call
@@ -224,20 +227,16 @@ describe Imap::Backup::Configuration::Account do
224
227
 
225
228
  context "when the user enters a password" do
226
229
  it "updates the password" do
227
- expect(account[:password]).to eq(new_password)
230
+ expect(account).to have_received(:"password=").with(new_password)
228
231
  end
229
-
230
- include_examples "it flags the account as modified"
231
232
  end
232
233
 
233
234
  context "when the user cancels" do
234
235
  let(:new_password) { nil }
235
236
 
236
237
  it "does nothing" do
237
- expect(account[:password]).to eq(existing_password)
238
+ expect(account.password).to eq(existing_password)
238
239
  end
239
-
240
- include_examples "it doesn't flag the account as modified"
241
240
  end
242
241
  end
243
242
 
@@ -245,6 +244,7 @@ describe Imap::Backup::Configuration::Account do
245
244
  let(:server) { "server" }
246
245
 
247
246
  before do
247
+ allow(account).to receive(:"server=")
248
248
  allow(highline).to receive(:ask).with("server: ") { server }
249
249
 
250
250
  subject.run
@@ -253,19 +253,18 @@ describe Imap::Backup::Configuration::Account do
253
253
  end
254
254
 
255
255
  it "updates the server" do
256
- expect(account[:server]).to eq(server)
256
+ expect(account).to have_received(:"server=").with(server)
257
257
  end
258
-
259
- include_examples "it flags the account as modified"
260
258
  end
261
259
 
262
260
  describe "choosing 'modify backup path'" do
263
261
  let(:new_backup_path) { "/new/path" }
264
262
 
265
263
  before do
264
+ allow(account).to receive(:"local_path=")
266
265
  @validator = nil
267
266
  allow(
268
- Imap::Backup::Configuration::Asker
267
+ Imap::Backup::Setup::Asker
269
268
  ).to receive(:backup_path) do |_path, validator|
270
269
  @validator = validator
271
270
  new_backup_path
@@ -275,7 +274,7 @@ describe Imap::Backup::Configuration::Account do
275
274
  end
276
275
 
277
276
  it "updates the path" do
278
- expect(account[:local_path]).to eq(new_backup_path)
277
+ expect(account).to have_received(:"local_path=").with(new_backup_path)
279
278
  end
280
279
 
281
280
  context "when the path is not used by other backups" do
@@ -293,17 +292,15 @@ describe Imap::Backup::Configuration::Account do
293
292
  # rubocop:enable RSpec/InstanceVariable
294
293
  end
295
294
  end
296
-
297
- include_examples "it flags the account as modified"
298
295
  end
299
296
 
300
297
  describe "choosing 'choose backup folders'" do
301
298
  let(:chooser) do
302
- instance_double(Imap::Backup::Configuration::FolderChooser, run: nil)
299
+ instance_double(Imap::Backup::Setup::FolderChooser, run: nil)
303
300
  end
304
301
 
305
302
  before do
306
- allow(Imap::Backup::Configuration::FolderChooser).
303
+ allow(Imap::Backup::Setup::FolderChooser).
307
304
  to receive(:new) { chooser }
308
305
  subject.run
309
306
  menu.choices["choose backup folders"].call
@@ -315,17 +312,23 @@ describe Imap::Backup::Configuration::Account do
315
312
  end
316
313
 
317
314
  describe "choosing 'test connection'" do
315
+ let(:connection_tester) do
316
+ instance_double(
317
+ Imap::Backup::Setup::ConnectionTester,
318
+ test: "All fine"
319
+ )
320
+ end
321
+
318
322
  before do
319
- allow(Imap::Backup::Configuration::ConnectionTester).
320
- to receive(:test) { "All fine" }
323
+ allow(Imap::Backup::Setup::ConnectionTester).
324
+ to receive(:new) { connection_tester }
321
325
  allow(highline).to receive(:ask)
322
326
  subject.run
323
327
  menu.choices["test connection"].call
324
328
  end
325
329
 
326
330
  it "tests the connection" do
327
- expect(Imap::Backup::Configuration::ConnectionTester).
328
- to have_received(:test).with(account)
331
+ expect(connection_tester).to have_received(:test)
329
332
  end
330
333
  end
331
334
 
@@ -333,6 +336,7 @@ describe Imap::Backup::Configuration::Account do
333
336
  let(:confirmed) { true }
334
337
 
335
338
  before do
339
+ allow(account).to receive(:mark_for_deletion!)
336
340
  allow(highline).to receive(:agree) { confirmed }
337
341
  subject.run
338
342
  catch :done do
@@ -345,13 +349,17 @@ describe Imap::Backup::Configuration::Account do
345
349
  end
346
350
 
347
351
  context "when the user confirms deletion" do
348
- include_examples "it flags the account to be deleted"
352
+ it "flags the account to be deleted" do
353
+ expect(account).to have_received(:mark_for_deletion!)
354
+ end
349
355
  end
350
356
 
351
357
  context "without confirmation" do
352
358
  let(:confirmed) { false }
353
359
 
354
- include_examples "it doesn't flag the account to be deleted"
360
+ it "doesn't flag the account to be deleted" do
361
+ expect(account).to_not have_received(:mark_for_deletion!)
362
+ end
355
363
  end
356
364
  end
357
365
  end
@@ -1,5 +1,5 @@
1
1
  module Imap::Backup
2
- describe Configuration::Asker do
2
+ describe Setup::Asker do
3
3
  subject { described_class.new(highline) }
4
4
 
5
5
  let(:highline) { double }
@@ -16,7 +16,7 @@ module Imap::Backup
16
16
  let(:answer) { "foo" }
17
17
 
18
18
  before do
19
- allow(Configuration::Setup).to receive(:highline) { highline }
19
+ allow(Setup).to receive(:highline) { highline }
20
20
  allow(highline).to receive(:ask) do |&b|
21
21
  b.call query
22
22
  answer
@@ -1,5 +1,7 @@
1
- describe Imap::Backup::Configuration::ConnectionTester do
2
- describe ".test" do
1
+ describe Imap::Backup::Setup::ConnectionTester do
2
+ describe "#test" do
3
+ subject { described_class.new("foo") }
4
+
3
5
  let(:connection) do
4
6
  instance_double(Imap::Backup::Account::Connection, client: nil)
5
7
  end
@@ -8,17 +10,15 @@ describe Imap::Backup::Configuration::ConnectionTester do
8
10
  allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
9
11
  end
10
12
 
11
- describe "call" do
12
- it "tries to connect" do
13
- expect(connection).to receive(:client)
13
+ it "tries to connect" do
14
+ expect(connection).to receive(:client)
14
15
 
15
- subject.test("foo")
16
- end
16
+ subject.test
17
17
  end
18
18
 
19
19
  describe "success" do
20
20
  it "returns success" do
21
- expect(subject.test("foo")).to match(/successful/)
21
+ expect(subject.test).to match(/successful/)
22
22
  end
23
23
  end
24
24
 
@@ -35,7 +35,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
35
35
  end
36
36
 
37
37
  it "returns error" do
38
- expect(subject.test("foo")).to match(/no response/i)
38
+ expect(subject.test).to match(/no response/i)
39
39
  end
40
40
  end
41
41
 
@@ -43,7 +43,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
43
43
  let(:error) { "Error" }
44
44
 
45
45
  it "returns error" do
46
- expect(subject.test("foo")).to match(/unexpected error/i)
46
+ expect(subject.test).to match(/unexpected error/i)
47
47
  end
48
48
  end
49
49
  end
@@ -1,4 +1,4 @@
1
- describe Imap::Backup::Configuration::FolderChooser do
1
+ describe Imap::Backup::Setup::FolderChooser do
2
2
  include HighLineTestHelpers
3
3
 
4
4
  describe "#run" do
@@ -6,10 +6,17 @@ describe Imap::Backup::Configuration::FolderChooser do
6
6
 
7
7
  let(:connection) do
8
8
  instance_double(
9
- Imap::Backup::Account::Connection, folders: connection_folders
9
+ Imap::Backup::Account::Connection, folder_names: connection_folders
10
10
  )
11
11
  end
12
- let(:account) { {folders: []} }
12
+ let(:account) do
13
+ instance_double(
14
+ Imap::Backup::Account,
15
+ folders: account_folders,
16
+ "folders=": nil
17
+ )
18
+ end
19
+ let(:account_folders) { [] }
13
20
  let(:connection_folders) { [] }
14
21
  let!(:highline_streams) { prepare_highline }
15
22
  let(:input) { highline_streams[0] }
@@ -18,7 +25,7 @@ describe Imap::Backup::Configuration::FolderChooser do
18
25
  before do
19
26
  allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
20
27
  allow(Kernel).to receive(:system)
21
- allow(Imap::Backup.logger).to receive(:warn)
28
+ allow(Imap::Backup::Logger.logger).to receive(:warn)
22
29
  end
23
30
 
24
31
  describe "display" do
@@ -36,7 +43,7 @@ describe Imap::Backup::Configuration::FolderChooser do
36
43
  end
37
44
 
38
45
  describe "folder listing" do
39
- let(:account) { {folders: [{name: "my_folder"}]} }
46
+ let(:account_folders) { [{name: "my_folder"}]}
40
47
  let(:connection_folders) do
41
48
  # N.B. my_folder is already backed up
42
49
  %w(my_folder another_folder)
@@ -62,10 +69,9 @@ describe Imap::Backup::Configuration::FolderChooser do
62
69
  end
63
70
 
64
71
  specify "are added to the account" do
65
- expect(account[:folders]).to include(name: "another_folder")
72
+ expect(account).to have_received(:"folders=").
73
+ with([{name: "my_folder"}, {name: "another_folder"}])
66
74
  end
67
-
68
- include_examples "it flags the account as modified"
69
75
  end
70
76
 
71
77
  context "when removing folders" do
@@ -76,22 +82,16 @@ describe Imap::Backup::Configuration::FolderChooser do
76
82
  end
77
83
 
78
84
  specify "are removed from the account" do
79
- expect(account[:folders]).to_not include(name: "my_folder")
85
+ expect(account).to have_received(:"folders=").with([])
80
86
  end
81
-
82
- include_examples "it flags the account as modified"
83
87
  end
84
88
  end
85
89
 
86
90
  context "with missing remote folders" do
87
- let(:account) do
88
- {folders: [{name: "on_server"}, {name: "not_on_server"}]}
89
- end
90
- let(:connection_folders) do
91
- [
92
- instance_double(Imap::Backup::Account::Folder, name: "on_server")
93
- ]
91
+ let(:account_folders) do
92
+ [{name: "on_server"}, {name: "not_on_server"}]
94
93
  end
94
+ let(:connection_folders) { ["on_server"] }
95
95
 
96
96
  before do
97
97
  allow(Kernel).to receive(:puts)
@@ -99,22 +99,21 @@ describe Imap::Backup::Configuration::FolderChooser do
99
99
  end
100
100
 
101
101
  specify "are removed from the account" do
102
- expect(account[:folders]).to_not include(name: "not_on_server")
102
+ expect(account).to have_received(:"folders=").
103
+ with([{name: "on_server"}])
103
104
  end
104
-
105
- include_examples "it flags the account as modified"
106
105
  end
107
106
 
108
107
  context "when folders are not available" do
109
108
  let(:connection_folders) { nil }
110
109
 
111
110
  before do
112
- allow(Imap::Backup::Configuration::Setup.highline).
111
+ allow(Imap::Backup::Setup.highline).
113
112
  to receive(:ask) { "q" }
114
113
  end
115
114
 
116
115
  it "asks to press a key" do
117
- expect(Imap::Backup::Configuration::Setup.highline).
116
+ expect(Imap::Backup::Setup.highline).
118
117
  to receive(:ask).with("Press a key ")
119
118
 
120
119
  subject.run
@@ -125,19 +124,19 @@ describe Imap::Backup::Configuration::FolderChooser do
125
124
  before do
126
125
  allow(Imap::Backup::Account::Connection).
127
126
  to receive(:new).with(account).and_raise("error")
128
- allow(Imap::Backup::Configuration::Setup.highline).
127
+ allow(Imap::Backup::Setup.highline).
129
128
  to receive(:ask) { "q" }
130
129
  end
131
130
 
132
131
  it "prints an error message" do
133
- expect(Imap::Backup.logger).
132
+ expect(Imap::Backup::Logger.logger).
134
133
  to receive(:warn).with("Connection failed")
135
134
 
136
135
  subject.run
137
136
  end
138
137
 
139
138
  it "asks to continue" do
140
- expect(Imap::Backup::Configuration::Setup.highline).
139
+ expect(Imap::Backup::Setup.highline).
141
140
  to receive(:ask).with("Press a key ")
142
141
 
143
142
  subject.run