imap-backup 2.2.2 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|