imap-backup 2.2.2 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +51 -0
- data/.rubocop.yml +2 -2
- data/.rubocop_todo.yml +10 -26
- data/README.md +6 -13
- data/bin/imap-backup +4 -1
- data/docs/01-credentials-screen.png +0 -0
- data/docs/02-new-project.png +0 -0
- data/docs/03-initial-credentials-for-project.png +0 -0
- data/docs/04-credential-type-selection.png +0 -0
- data/docs/05-cant-create-without-consent-setup.png +0 -0
- data/docs/06-user-type-selection.png +0 -0
- data/docs/07-consent-screen-form.png +0 -0
- data/docs/08-app-scopes.png +0 -0
- data/docs/09-scope-selection.png +0 -0
- data/docs/10-updated-app-scopes.png +0 -0
- data/docs/11-test-users.png +0 -0
- data/docs/12-add-users.png +0 -0
- data/docs/13-create-oauth-client.png +0 -0
- data/docs/14-application-details.png +0 -0
- data/docs/16-initial-menu.png +0 -0
- data/docs/17-inputting-the-email-address.png +0 -0
- data/docs/18-choose-password.png +0 -0
- data/docs/19-supply-client-info.png +0 -0
- data/docs/20-choose-gmail-account.png +0 -0
- data/docs/21-accept-warnings.png +0 -0
- data/docs/22-grant-access.png +0 -0
- data/docs/24-confirm-choices.png +0 -0
- data/docs/25-success-code.png +0 -0
- data/docs/26-type-code-into-imap-backup.png +0 -0
- data/docs/27-success.png +0 -0
- data/docs/setting-up-gmail.md +166 -0
- data/imap-backup.gemspec +3 -8
- data/lib/email/mboxrd/message.rb +2 -0
- data/lib/email/provider.rb +3 -1
- data/lib/gmail/authenticator.rb +160 -0
- data/lib/google/auth/stores/in_memory_token_store.rb +9 -0
- data/lib/imap/backup.rb +2 -1
- data/lib/imap/backup/account/connection.rb +67 -35
- data/lib/imap/backup/account/folder.rb +18 -6
- data/lib/imap/backup/configuration/account.rb +9 -1
- data/lib/imap/backup/configuration/folder_chooser.rb +14 -15
- data/lib/imap/backup/configuration/gmail_oauth2.rb +82 -0
- data/lib/imap/backup/configuration/setup.rb +4 -1
- data/lib/imap/backup/configuration/store.rb +12 -12
- data/lib/imap/backup/serializer/mbox_store.rb +2 -2
- data/lib/imap/backup/version.rb +4 -3
- data/lib/retry_on_error.rb +14 -0
- data/spec/features/backup_spec.rb +1 -1
- data/spec/fixtures/connection.yml +1 -1
- data/spec/support/fixtures.rb +7 -2
- data/spec/unit/gmail/authenticator_spec.rb +138 -0
- data/spec/unit/google/auth/stores/in_memory_token_store_spec.rb +15 -0
- data/spec/unit/imap/backup/account/connection_spec.rb +146 -53
- data/spec/unit/imap/backup/account/folder_spec.rb +42 -10
- data/spec/unit/imap/backup/configuration/account_spec.rb +37 -24
- data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +7 -13
- data/spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb +84 -0
- data/spec/unit/imap/backup/configuration/setup_spec.rb +51 -31
- metadata +83 -9
- data/.travis.yml +0 -25
@@ -1,50 +1,53 @@
|
|
1
|
-
|
2
|
-
def self.backup_folder
|
3
|
-
"backup_folder"
|
4
|
-
end
|
1
|
+
require "ostruct"
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
describe Imap::Backup::Account::Connection do
|
4
|
+
BACKUP_FOLDER = "backup_folder".freeze
|
5
|
+
FOLDER_CONFIG = {name: BACKUP_FOLDER}.freeze
|
6
|
+
FOLDER_NAME = "my_folder".freeze
|
7
|
+
GMAIL_IMAP_SERVER = "imap.gmail.com".freeze
|
8
|
+
LOCAL_PATH = "local_path".freeze
|
9
|
+
LOCAL_UID = "local_uid".freeze
|
10
|
+
PASSWORD = "secret".freeze
|
11
|
+
ROOT_NAME = "foo".freeze
|
12
|
+
SERVER = "imap.example.com".freeze
|
13
|
+
USERNAME = "username@example.com".freeze
|
9
14
|
|
10
15
|
subject { described_class.new(options) }
|
11
16
|
|
12
17
|
let(:imap) do
|
13
|
-
instance_double(Net::IMAP, login: nil, disconnect: nil)
|
18
|
+
instance_double(Net::IMAP, authenticate: nil, login: nil, disconnect: nil)
|
14
19
|
end
|
15
20
|
let(:imap_folders) { [] }
|
16
21
|
let(:options) do
|
17
22
|
{
|
18
|
-
username:
|
19
|
-
password:
|
20
|
-
local_path:
|
21
|
-
folders:
|
23
|
+
username: USERNAME,
|
24
|
+
password: PASSWORD,
|
25
|
+
local_path: LOCAL_PATH,
|
26
|
+
folders: config_folders,
|
27
|
+
server: server
|
22
28
|
}
|
23
29
|
end
|
24
|
-
let(:
|
25
|
-
let(:backup_folders) { [self.class.folder_config] }
|
26
|
-
let(:username) { "username@gmail.com" }
|
30
|
+
let(:config_folders) { [FOLDER_CONFIG] }
|
27
31
|
let(:root_info) do
|
28
|
-
instance_double(Net::IMAP::MailboxList, name:
|
32
|
+
instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)
|
29
33
|
end
|
30
|
-
let(:root_name) { "foo" }
|
31
34
|
let(:serializer) do
|
32
35
|
instance_double(
|
33
36
|
Imap::Backup::Serializer::Mbox,
|
34
37
|
folder: serialized_folder,
|
35
38
|
force_uid_validity: nil,
|
36
39
|
apply_uid_validity: new_uid_validity,
|
37
|
-
uids: [
|
40
|
+
uids: [LOCAL_UID]
|
38
41
|
)
|
39
42
|
end
|
40
43
|
let(:serialized_folder) { nil }
|
44
|
+
let(:server) { SERVER }
|
41
45
|
let(:new_uid_validity) { nil }
|
42
|
-
let(:local_uid) { "local_uid" }
|
43
46
|
|
44
47
|
before do
|
45
48
|
allow(Net::IMAP).to receive(:new) { imap }
|
46
49
|
allow(imap).to receive(:list).with("", "") { [root_info] }
|
47
|
-
allow(imap).to receive(:list).with(
|
50
|
+
allow(imap).to receive(:list).with(ROOT_NAME, "*") { imap_folders }
|
48
51
|
allow(Imap::Backup::Utils).to receive(:make_folder)
|
49
52
|
end
|
50
53
|
|
@@ -56,12 +59,13 @@ describe Imap::Backup::Account::Connection do
|
|
56
59
|
|
57
60
|
describe "#initialize" do
|
58
61
|
[
|
59
|
-
[:username,
|
60
|
-
[:
|
61
|
-
[:
|
62
|
+
[:username, USERNAME],
|
63
|
+
[:password, PASSWORD],
|
64
|
+
[:local_path, LOCAL_PATH],
|
65
|
+
[:server, SERVER]
|
62
66
|
].each do |attr, expected|
|
63
67
|
it "expects #{attr}" do
|
64
|
-
expect(subject.
|
68
|
+
expect(subject.public_send(attr)).to eq(expected)
|
65
69
|
end
|
66
70
|
end
|
67
71
|
|
@@ -73,22 +77,106 @@ describe Imap::Backup::Account::Connection do
|
|
73
77
|
end
|
74
78
|
|
75
79
|
describe "#imap" do
|
76
|
-
let
|
80
|
+
let(:result) { subject.imap }
|
77
81
|
|
78
82
|
it "returns the IMAP connection" do
|
79
83
|
expect(result).to eq(imap)
|
80
84
|
end
|
81
85
|
|
82
|
-
|
86
|
+
it "uses the password" do
|
87
|
+
result
|
88
|
+
|
89
|
+
expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with the GMail IMAP server" do
|
93
|
+
ACCESS_TOKEN = "access_token".freeze
|
94
|
+
|
95
|
+
let(:server) { GMAIL_IMAP_SERVER }
|
96
|
+
let(:refresh_token) { true }
|
97
|
+
let(:result) { nil }
|
98
|
+
let(:authenticator) do
|
99
|
+
instance_double(
|
100
|
+
Gmail::Authenticator,
|
101
|
+
credentials: credentials
|
102
|
+
)
|
103
|
+
end
|
104
|
+
let(:credentials) { OpenStruct.new(access_token: ACCESS_TOKEN) }
|
105
|
+
|
106
|
+
before do
|
107
|
+
allow(Gmail::Authenticator).
|
108
|
+
to receive(:refresh_token?) { refresh_token }
|
109
|
+
allow(Gmail::Authenticator).
|
110
|
+
to receive(:new).
|
111
|
+
with(email: USERNAME, token: PASSWORD) { authenticator }
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when the password is our copy of a GMail refresh token" do
|
115
|
+
it "uses the OAuth2 access_token to authenticate" do
|
116
|
+
subject.imap
|
117
|
+
|
118
|
+
expect(imap).to have_received(:authenticate).with(
|
119
|
+
"XOAUTH2", USERNAME, ACCESS_TOKEN
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when the refresh token is invalid" do
|
124
|
+
let(:credentials) { nil }
|
125
|
+
|
126
|
+
it "raises" do
|
127
|
+
expect { subject.imap }.to raise_error(String)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "when the password is not our copy of a GMail refresh token" do
|
133
|
+
let(:refresh_token) { false }
|
134
|
+
|
135
|
+
it "uses the password" do
|
136
|
+
subject.imap
|
137
|
+
|
138
|
+
expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "when the first login attempt fails" do
|
144
|
+
before do
|
145
|
+
outcomes = [-> { raise EOFError }, -> { true }]
|
146
|
+
allow(imap).to receive(:login) { outcomes.shift.call }
|
147
|
+
end
|
148
|
+
|
149
|
+
it "retries" do
|
150
|
+
subject.imap
|
151
|
+
|
152
|
+
expect(imap).to have_received(:login).twice
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when run" do
|
157
|
+
before { subject.imap }
|
158
|
+
|
159
|
+
include_examples "connects to IMAP"
|
160
|
+
end
|
83
161
|
end
|
84
162
|
|
85
163
|
describe "#folders" do
|
86
164
|
let(:imap_folders) do
|
87
|
-
[instance_double(Net::IMAP::MailboxList)]
|
165
|
+
[instance_double(Net::IMAP::MailboxList, name: BACKUP_FOLDER)]
|
88
166
|
end
|
89
167
|
|
90
168
|
it "returns the list of folders" do
|
91
|
-
expect(subject.folders).to eq(
|
169
|
+
expect(subject.folders).to eq([BACKUP_FOLDER])
|
170
|
+
end
|
171
|
+
|
172
|
+
context "with non-ASCII folder names" do
|
173
|
+
let(:imap_folders) do
|
174
|
+
[instance_double(Net::IMAP::MailboxList, name: "Gel&APY-scht")]
|
175
|
+
end
|
176
|
+
|
177
|
+
it "converts them to UTF-8" do
|
178
|
+
expect(subject.folders).to eq(["Gelöscht"])
|
179
|
+
end
|
92
180
|
end
|
93
181
|
end
|
94
182
|
|
@@ -104,11 +192,11 @@ describe Imap::Backup::Account::Connection do
|
|
104
192
|
end
|
105
193
|
|
106
194
|
it "returns the names of folders" do
|
107
|
-
expect(subject.status[0][:name]).to eq(
|
195
|
+
expect(subject.status[0][:name]).to eq(BACKUP_FOLDER)
|
108
196
|
end
|
109
197
|
|
110
198
|
it "returns local message uids" do
|
111
|
-
expect(subject.status[0][:local]).to eq([
|
199
|
+
expect(subject.status[0][:local]).to eq([LOCAL_UID])
|
112
200
|
end
|
113
201
|
|
114
202
|
it "retrieves the available uids" do
|
@@ -132,16 +220,13 @@ describe Imap::Backup::Account::Connection do
|
|
132
220
|
before do
|
133
221
|
allow(Imap::Backup::Downloader).
|
134
222
|
to receive(:new).with(folder, serializer) { downloader }
|
223
|
+
allow(Imap::Backup::Account::Folder).to receive(:new).
|
224
|
+
with(subject, BACKUP_FOLDER) { folder }
|
225
|
+
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
226
|
+
with(LOCAL_PATH, BACKUP_FOLDER) { serializer }
|
135
227
|
end
|
136
228
|
|
137
|
-
context "with supplied
|
138
|
-
before do
|
139
|
-
allow(Imap::Backup::Account::Folder).to receive(:new).
|
140
|
-
with(subject, self.class.backup_folder) { folder }
|
141
|
-
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
142
|
-
with(local_path, self.class.backup_folder) { serializer }
|
143
|
-
end
|
144
|
-
|
229
|
+
context "with supplied config_folders" do
|
145
230
|
it "runs the downloader" do
|
146
231
|
expect(downloader).to receive(:run)
|
147
232
|
|
@@ -159,20 +244,20 @@ describe Imap::Backup::Account::Connection do
|
|
159
244
|
end
|
160
245
|
end
|
161
246
|
|
162
|
-
context "without supplied
|
247
|
+
context "without supplied config_folders" do
|
163
248
|
let(:imap_folders) do
|
164
|
-
[instance_double(Net::IMAP::MailboxList, name:
|
249
|
+
[instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)]
|
165
250
|
end
|
166
251
|
|
167
252
|
before do
|
168
253
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
169
|
-
with(subject,
|
254
|
+
with(subject, ROOT_NAME) { folder }
|
170
255
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
171
|
-
with(
|
256
|
+
with(LOCAL_PATH, ROOT_NAME) { serializer }
|
172
257
|
end
|
173
258
|
|
174
|
-
context "when supplied
|
175
|
-
let(:
|
259
|
+
context "when supplied config_folders is nil" do
|
260
|
+
let(:config_folders) { nil }
|
176
261
|
|
177
262
|
it "runs the downloader for each folder" do
|
178
263
|
expect(downloader).to receive(:run).exactly(:once)
|
@@ -181,8 +266,8 @@ describe Imap::Backup::Account::Connection do
|
|
181
266
|
end
|
182
267
|
end
|
183
268
|
|
184
|
-
context "when supplied
|
185
|
-
let(:
|
269
|
+
context "when supplied config_folders is an empty list" do
|
270
|
+
let(:config_folders) { [] }
|
186
271
|
|
187
272
|
it "runs the downloader for each folder" do
|
188
273
|
expect(downloader).to receive(:run).exactly(:once)
|
@@ -192,14 +277,22 @@ describe Imap::Backup::Account::Connection do
|
|
192
277
|
end
|
193
278
|
|
194
279
|
context "when the imap server doesn't return folders" do
|
195
|
-
let(:
|
280
|
+
let(:config_folders) { nil }
|
196
281
|
let(:imap_folders) { nil }
|
197
282
|
|
198
|
-
it "
|
199
|
-
expect
|
283
|
+
it "fails" do
|
284
|
+
expect do
|
285
|
+
subject.run_backup
|
286
|
+
end.to raise_error(RuntimeError, /Unable to get folder list/)
|
200
287
|
end
|
201
288
|
end
|
202
289
|
end
|
290
|
+
|
291
|
+
context "when run" do
|
292
|
+
before { subject.run_backup }
|
293
|
+
|
294
|
+
include_examples "connects to IMAP"
|
295
|
+
end
|
203
296
|
end
|
204
297
|
|
205
298
|
describe "#restore" do
|
@@ -208,7 +301,7 @@ describe Imap::Backup::Account::Connection do
|
|
208
301
|
Imap::Backup::Account::Folder,
|
209
302
|
create: nil,
|
210
303
|
uids: uids,
|
211
|
-
name:
|
304
|
+
name: FOLDER_NAME,
|
212
305
|
uid_validity: uid_validity
|
213
306
|
)
|
214
307
|
end
|
@@ -236,9 +329,9 @@ describe Imap::Backup::Account::Connection do
|
|
236
329
|
|
237
330
|
before do
|
238
331
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
239
|
-
with(subject,
|
332
|
+
with(subject, FOLDER_NAME) { folder }
|
240
333
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
241
|
-
with(anything,
|
334
|
+
with(anything, FOLDER_NAME) { serializer }
|
242
335
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
243
336
|
with(subject, "new name") { updated_folder }
|
244
337
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
@@ -248,7 +341,7 @@ describe Imap::Backup::Account::Connection do
|
|
248
341
|
allow(Imap::Backup::Uploader).to receive(:new).
|
249
342
|
with(updated_folder, updated_serializer) { updated_uploader }
|
250
343
|
allow(Pathname).to receive(:glob).
|
251
|
-
and_yield(Pathname.new(File.join(
|
344
|
+
and_yield(Pathname.new(File.join(LOCAL_PATH, "#{FOLDER_NAME}.imap")))
|
252
345
|
end
|
253
346
|
|
254
347
|
it "sets local uid validity" do
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# rubocop:disable RSpec/PredicateMatcher
|
2
2
|
|
3
3
|
describe Imap::Backup::Account::Folder do
|
4
|
-
|
4
|
+
FOLDER_NAME = "Gelöscht".freeze
|
5
|
+
ENCODED_FOLDER_NAME = "Gel&APY-scht".freeze
|
6
|
+
|
7
|
+
subject { described_class.new(connection, FOLDER_NAME) }
|
5
8
|
|
6
9
|
let(:imap) do
|
7
10
|
instance_double(
|
@@ -16,7 +19,7 @@ describe Imap::Backup::Account::Folder do
|
|
16
19
|
instance_double(Imap::Backup::Account::Connection, imap: imap)
|
17
20
|
end
|
18
21
|
let(:missing_mailbox_data) do
|
19
|
-
OpenStruct.new(text: "Unknown Mailbox:
|
22
|
+
OpenStruct.new(text: "Unknown Mailbox: #{FOLDER_NAME}")
|
20
23
|
end
|
21
24
|
let(:missing_mailbox_response) { OpenStruct.new(data: missing_mailbox_data) }
|
22
25
|
let(:missing_mailbox_error) do
|
@@ -36,7 +39,8 @@ describe Imap::Backup::Account::Folder do
|
|
36
39
|
|
37
40
|
context "with missing mailboxes" do
|
38
41
|
before do
|
39
|
-
allow(imap).to receive(:examine).
|
42
|
+
allow(imap).to receive(:examine).
|
43
|
+
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
40
44
|
end
|
41
45
|
|
42
46
|
it "returns an empty array" do
|
@@ -50,7 +54,8 @@ describe Imap::Backup::Account::Folder do
|
|
50
54
|
end
|
51
55
|
|
52
56
|
before do
|
53
|
-
allow(imap).to receive(:examine).
|
57
|
+
allow(imap).to receive(:examine).
|
58
|
+
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
54
59
|
end
|
55
60
|
|
56
61
|
it "returns an empty array" do
|
@@ -82,7 +87,8 @@ describe Imap::Backup::Account::Folder do
|
|
82
87
|
|
83
88
|
context "when the mailbox doesn't exist" do
|
84
89
|
before do
|
85
|
-
allow(imap).to receive(:examine).
|
90
|
+
allow(imap).to receive(:examine).
|
91
|
+
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
86
92
|
end
|
87
93
|
|
88
94
|
it "is nil" do
|
@@ -97,11 +103,28 @@ describe Imap::Backup::Account::Folder do
|
|
97
103
|
expect(subject.fetch(123)).to be_nil
|
98
104
|
end
|
99
105
|
end
|
106
|
+
|
107
|
+
context "when the first fetch_uid attempts fail" do
|
108
|
+
before do
|
109
|
+
outcomes = [-> { raise EOFError }, -> { [fetch_data_item] }]
|
110
|
+
allow(imap).to receive(:uid_fetch) { outcomes.shift.call }
|
111
|
+
end
|
112
|
+
|
113
|
+
it "retries" do
|
114
|
+
subject.fetch(123)
|
115
|
+
|
116
|
+
expect(imap).to have_received(:uid_fetch).twice
|
117
|
+
end
|
118
|
+
|
119
|
+
it "succeeds" do
|
120
|
+
subject.fetch(123)
|
121
|
+
end
|
122
|
+
end
|
100
123
|
end
|
101
124
|
|
102
125
|
describe "#folder" do
|
103
126
|
it "is the name" do
|
104
|
-
expect(subject.folder).to eq(
|
127
|
+
expect(subject.folder).to eq(FOLDER_NAME)
|
105
128
|
end
|
106
129
|
end
|
107
130
|
|
@@ -114,7 +137,8 @@ describe Imap::Backup::Account::Folder do
|
|
114
137
|
|
115
138
|
context "when the folder doesn't exist" do
|
116
139
|
before do
|
117
|
-
allow(imap).to receive(:examine).
|
140
|
+
allow(imap).to receive(:examine).
|
141
|
+
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
118
142
|
end
|
119
143
|
|
120
144
|
it "is false" do
|
@@ -134,14 +158,21 @@ describe Imap::Backup::Account::Folder do
|
|
134
158
|
|
135
159
|
context "when the folder doesn't exist" do
|
136
160
|
before do
|
137
|
-
allow(imap).to receive(:examine).
|
161
|
+
allow(imap).to receive(:examine).
|
162
|
+
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
138
163
|
end
|
139
164
|
|
140
|
-
it "
|
165
|
+
it "creates the folder" do
|
141
166
|
expect(imap).to receive(:create)
|
142
167
|
|
143
168
|
subject.create
|
144
169
|
end
|
170
|
+
|
171
|
+
it "encodes the folder name" do
|
172
|
+
expect(imap).to receive(:create).with(ENCODED_FOLDER_NAME)
|
173
|
+
|
174
|
+
subject.create
|
175
|
+
end
|
145
176
|
end
|
146
177
|
end
|
147
178
|
|
@@ -154,7 +185,8 @@ describe Imap::Backup::Account::Folder do
|
|
154
185
|
|
155
186
|
context "when the folder doesn't exist" do
|
156
187
|
before do
|
157
|
-
allow(imap).to receive(:examine).
|
188
|
+
allow(imap).to receive(:examine).
|
189
|
+
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
158
190
|
end
|
159
191
|
|
160
192
|
it "raises an error" do
|
@@ -1,13 +1,16 @@
|
|
1
|
-
# rubocop:disable RSpec/NestedGroups
|
2
|
-
|
3
1
|
describe Imap::Backup::Configuration::Account do
|
4
|
-
|
5
|
-
|
2
|
+
ACCOUNT = "account".freeze
|
3
|
+
GMAIL_IMAP_SERVER = "imap.gmail.com".freeze
|
4
|
+
HIGHLINE = "highline".freeze
|
5
|
+
STORE = "store".freeze
|
6
|
+
|
7
|
+
subject { described_class.new(store, account, highline) }
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
let(:account) { ACCOUNT }
|
10
|
+
let(:highline) { HIGHLINE }
|
11
|
+
let(:store) { STORE }
|
10
12
|
|
13
|
+
describe "#initialize" do
|
11
14
|
[:store, :account, :highline].each do |param|
|
12
15
|
it "expects #{param}" do
|
13
16
|
expect(subject.send(param)).to eq(send(param))
|
@@ -16,8 +19,6 @@ describe Imap::Backup::Configuration::Account do
|
|
16
19
|
end
|
17
20
|
|
18
21
|
describe "#run" do
|
19
|
-
subject { described_class.new(store, account, highline) }
|
20
|
-
|
21
22
|
let(:highline_menu_class) do
|
22
23
|
Class.new do
|
23
24
|
attr_reader :choices
|
@@ -46,7 +47,7 @@ describe Imap::Backup::Configuration::Account do
|
|
46
47
|
let(:account) do
|
47
48
|
{
|
48
49
|
username: existing_email,
|
49
|
-
server:
|
50
|
+
server: current_server,
|
50
51
|
local_path: "/backup/path",
|
51
52
|
folders: [{name: "my_folder"}],
|
52
53
|
password: existing_password
|
@@ -60,7 +61,7 @@ describe Imap::Backup::Configuration::Account do
|
|
60
61
|
end
|
61
62
|
let(:existing_email) { "user@example.com" }
|
62
63
|
let(:new_email) { "foo@example.com" }
|
63
|
-
let(:
|
64
|
+
let(:current_server) { "imap.example.com" }
|
64
65
|
let(:existing_password) { "password" }
|
65
66
|
let(:other_email) { "other@example.com" }
|
66
67
|
let(:other_existing_path) { "/other/existing/path" }
|
@@ -136,7 +137,7 @@ describe Imap::Backup::Configuration::Account do
|
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
139
|
-
describe "email" do
|
140
|
+
describe "choosing 'modify email'" do
|
140
141
|
before do
|
141
142
|
allow(Imap::Backup::Configuration::Asker).
|
142
143
|
to receive(:email) { new_email }
|
@@ -146,7 +147,7 @@ describe Imap::Backup::Configuration::Account do
|
|
146
147
|
|
147
148
|
context "when the server is blank" do
|
148
149
|
[
|
149
|
-
["GMail", "foo@gmail.com",
|
150
|
+
["GMail", "foo@gmail.com", GMAIL_IMAP_SERVER],
|
150
151
|
["Fastmail", "bar@fastmail.fm", "imap.fastmail.com"],
|
151
152
|
["Fastmail", "bar@fastmail.com", "imap.fastmail.com"]
|
152
153
|
].each do |service, email, expected|
|
@@ -154,7 +155,7 @@ describe Imap::Backup::Configuration::Account do
|
|
154
155
|
let(:new_email) { email }
|
155
156
|
|
156
157
|
context "with nil" do
|
157
|
-
let(:
|
158
|
+
let(:current_server) { nil }
|
158
159
|
|
159
160
|
it "sets a default server" do
|
160
161
|
expect(account[:server]).to eq(expected)
|
@@ -162,7 +163,7 @@ describe Imap::Backup::Configuration::Account do
|
|
162
163
|
end
|
163
164
|
|
164
165
|
context "with an empty string" do
|
165
|
-
let(:
|
166
|
+
let(:current_server) { "" }
|
166
167
|
|
167
168
|
it "sets a default server" do
|
168
169
|
expect(account[:server]).to eq(expected)
|
@@ -172,7 +173,7 @@ describe Imap::Backup::Configuration::Account do
|
|
172
173
|
end
|
173
174
|
|
174
175
|
context "when the domain is unrecognized" do
|
175
|
-
let(:
|
176
|
+
let(:current_server) { nil }
|
176
177
|
let(:provider) do
|
177
178
|
instance_double(Email::Provider, provider: :default)
|
178
179
|
end
|
@@ -211,12 +212,18 @@ describe Imap::Backup::Configuration::Account do
|
|
211
212
|
end
|
212
213
|
end
|
213
214
|
|
214
|
-
describe "password" do
|
215
|
+
describe "choosing 'modify password'" do
|
215
216
|
let(:new_password) { "new_password" }
|
217
|
+
let(:gmail_oauth2) do
|
218
|
+
instance_double(Imap::Backup::Configuration::GmailOauth2, run: nil)
|
219
|
+
end
|
216
220
|
|
217
221
|
before do
|
218
222
|
allow(Imap::Backup::Configuration::Asker).
|
219
223
|
to receive(:password) { new_password }
|
224
|
+
allow(Imap::Backup::Configuration::GmailOauth2).
|
225
|
+
to receive(:new).
|
226
|
+
with(account) { gmail_oauth2 }
|
220
227
|
subject.run
|
221
228
|
menu.choices["modify password"].call
|
222
229
|
end
|
@@ -238,9 +245,17 @@ describe Imap::Backup::Configuration::Account do
|
|
238
245
|
|
239
246
|
include_examples "it doesn't flag the account as modified"
|
240
247
|
end
|
248
|
+
|
249
|
+
context "when the server is for GMail" do
|
250
|
+
let(:current_server) { GMAIL_IMAP_SERVER }
|
251
|
+
|
252
|
+
it "sets up GMail OAuth2" do
|
253
|
+
expect(gmail_oauth2).to have_received(:run)
|
254
|
+
end
|
255
|
+
end
|
241
256
|
end
|
242
257
|
|
243
|
-
describe "server" do
|
258
|
+
describe "choosing 'modify server'" do
|
244
259
|
let(:server) { "server" }
|
245
260
|
|
246
261
|
before do
|
@@ -258,7 +273,7 @@ describe Imap::Backup::Configuration::Account do
|
|
258
273
|
include_examples "it flags the account as modified"
|
259
274
|
end
|
260
275
|
|
261
|
-
describe "
|
276
|
+
describe "choosing 'modify backup path'" do
|
262
277
|
let(:new_backup_path) { "/new/path" }
|
263
278
|
|
264
279
|
before do
|
@@ -296,7 +311,7 @@ describe Imap::Backup::Configuration::Account do
|
|
296
311
|
include_examples "it flags the account as modified"
|
297
312
|
end
|
298
313
|
|
299
|
-
describe "folders" do
|
314
|
+
describe "choosing 'choose backup folders'" do
|
300
315
|
let(:chooser) do
|
301
316
|
instance_double(Imap::Backup::Configuration::FolderChooser, run: nil)
|
302
317
|
end
|
@@ -313,7 +328,7 @@ describe Imap::Backup::Configuration::Account do
|
|
313
328
|
end
|
314
329
|
end
|
315
330
|
|
316
|
-
describe "
|
331
|
+
describe "choosing 'test connection'" do
|
317
332
|
before do
|
318
333
|
allow(Imap::Backup::Configuration::ConnectionTester).
|
319
334
|
to receive(:test) { "All fine" }
|
@@ -328,7 +343,7 @@ describe Imap::Backup::Configuration::Account do
|
|
328
343
|
end
|
329
344
|
end
|
330
345
|
|
331
|
-
describe "
|
346
|
+
describe "choosing 'delete'" do
|
332
347
|
let(:confirmed) { true }
|
333
348
|
|
334
349
|
before do
|
@@ -355,5 +370,3 @@ describe Imap::Backup::Configuration::Account do
|
|
355
370
|
end
|
356
371
|
end
|
357
372
|
end
|
358
|
-
|
359
|
-
# rubocop:enable RSpec/NestedGroups
|