imap-backup 6.0.0.rc2 → 6.0.0
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/imap-backup.gemspec +5 -1
- data/lib/cli_coverage.rb +11 -11
- data/lib/email/provider/base.rb +2 -0
- data/lib/email/provider/unknown.rb +2 -0
- data/lib/email/provider.rb +2 -0
- data/lib/imap/backup/account/connection/backup_folders.rb +27 -0
- data/lib/imap/backup/account/connection/client_factory.rb +54 -0
- data/lib/imap/backup/account/connection/folder_names.rb +26 -0
- data/lib/imap/backup/account/connection.rb +11 -95
- data/lib/imap/backup/account/folder.rb +9 -6
- data/lib/imap/backup/account.rb +3 -5
- data/lib/imap/backup/cli/backup.rb +1 -3
- data/lib/imap/backup/cli/helpers.rb +24 -22
- data/lib/imap/backup/cli/local.rb +20 -13
- data/lib/imap/backup/cli/migrate.rb +4 -10
- data/lib/imap/backup/cli/restore.rb +8 -7
- data/lib/imap/backup/cli/setup.rb +10 -8
- data/lib/imap/backup/cli/stats.rb +78 -0
- data/lib/imap/backup/cli/status.rb +2 -2
- data/lib/imap/backup/cli/utils.rb +4 -6
- data/lib/imap/backup/cli.rb +24 -3
- data/lib/imap/backup/configuration.rb +9 -11
- data/lib/imap/backup/downloader.rb +48 -30
- data/lib/imap/backup/migrator.rb +5 -5
- data/lib/imap/backup/sanitizer.rb +3 -2
- data/lib/imap/backup/serializer/appender.rb +49 -0
- data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
- data/lib/imap/backup/serializer/unused_name_finder.rb +27 -0
- data/lib/imap/backup/serializer.rb +24 -78
- data/lib/imap/backup/setup/account/header.rb +75 -0
- data/lib/imap/backup/setup/account.rb +14 -91
- data/lib/imap/backup/setup/asker.rb +4 -15
- data/lib/imap/backup/setup/backup_path.rb +41 -0
- data/lib/imap/backup/setup/email.rb +45 -0
- data/lib/imap/backup/setup/folder_chooser.rb +3 -3
- data/lib/imap/backup/setup/helpers.rb +1 -1
- data/lib/imap/backup/setup.rb +5 -4
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +39 -20
- data/lib/imap/backup/uploader.rb +46 -8
- data/lib/imap/backup/utils.rb +1 -1
- data/lib/imap/backup/version.rb +1 -1
- data/lib/imap/backup.rb +0 -1
- metadata +31 -134
- data/spec/features/backup_spec.rb +0 -100
- data/spec/features/configuration/minimal_configuration.rb +0 -15
- data/spec/features/configuration/missing_configuration.rb +0 -14
- data/spec/features/folders_spec.rb +0 -36
- data/spec/features/helper.rb +0 -2
- data/spec/features/local/list_accounts_spec.rb +0 -12
- data/spec/features/local/list_emails_spec.rb +0 -21
- data/spec/features/local/list_folders_spec.rb +0 -21
- data/spec/features/local/show_an_email_spec.rb +0 -34
- data/spec/features/migrate_spec.rb +0 -35
- data/spec/features/remote/list_account_folders_spec.rb +0 -16
- data/spec/features/restore_spec.rb +0 -162
- data/spec/features/status_spec.rb +0 -43
- data/spec/features/support/aruba.rb +0 -78
- data/spec/features/support/backup_directory.rb +0 -43
- data/spec/features/support/email_server.rb +0 -110
- data/spec/features/support/shared/connection_context.rb +0 -14
- data/spec/features/support/shared/message_fixtures.rb +0 -16
- data/spec/fixtures/connection.yml +0 -7
- data/spec/spec_helper.rb +0 -15
- data/spec/support/fixtures.rb +0 -11
- data/spec/support/higline_test_helpers.rb +0 -8
- data/spec/support/silence_logging.rb +0 -7
- data/spec/unit/email/mboxrd/message_spec.rb +0 -177
- data/spec/unit/email/provider/apple_mail_spec.rb +0 -7
- data/spec/unit/email/provider/base_spec.rb +0 -11
- data/spec/unit/email/provider/fastmail_spec.rb +0 -7
- data/spec/unit/email/provider/gmail_spec.rb +0 -7
- data/spec/unit/email/provider_spec.rb +0 -27
- data/spec/unit/imap/backup/account/connection_spec.rb +0 -433
- data/spec/unit/imap/backup/account/folder_spec.rb +0 -261
- data/spec/unit/imap/backup/account_spec.rb +0 -246
- data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -58
- data/spec/unit/imap/backup/cli/backup_spec.rb +0 -19
- data/spec/unit/imap/backup/cli/folders_spec.rb +0 -39
- data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
- data/spec/unit/imap/backup/cli/local_spec.rb +0 -100
- data/spec/unit/imap/backup/cli/migrate_spec.rb +0 -80
- data/spec/unit/imap/backup/cli/restore_spec.rb +0 -67
- data/spec/unit/imap/backup/cli/setup_spec.rb +0 -17
- data/spec/unit/imap/backup/cli/utils_spec.rb +0 -125
- data/spec/unit/imap/backup/cli_spec.rb +0 -93
- data/spec/unit/imap/backup/client/apple_mail_spec.rb +0 -9
- data/spec/unit/imap/backup/client/default_spec.rb +0 -22
- data/spec/unit/imap/backup/configuration_spec.rb +0 -238
- data/spec/unit/imap/backup/downloader_spec.rb +0 -96
- data/spec/unit/imap/backup/logger_spec.rb +0 -48
- data/spec/unit/imap/backup/migrator_spec.rb +0 -58
- data/spec/unit/imap/backup/sanitizer_spec.rb +0 -42
- data/spec/unit/imap/backup/serializer/directory_spec.rb +0 -37
- data/spec/unit/imap/backup/serializer/imap_spec.rb +0 -218
- data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +0 -45
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -101
- data/spec/unit/imap/backup/serializer_spec.rb +0 -296
- data/spec/unit/imap/backup/setup/account_spec.rb +0 -461
- data/spec/unit/imap/backup/setup/asker_spec.rb +0 -137
- data/spec/unit/imap/backup/setup/connection_tester_spec.rb +0 -51
- data/spec/unit/imap/backup/setup/folder_chooser_spec.rb +0 -146
- data/spec/unit/imap/backup/setup/helpers_spec.rb +0 -15
- data/spec/unit/imap/backup/setup_spec.rb +0 -301
- data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +0 -116
- data/spec/unit/imap/backup/uploader_spec.rb +0 -54
- data/spec/unit/imap/backup/utils_spec.rb +0 -92
- data/spec/unit/retry_on_error_spec.rb +0 -34
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
# rubocop:disable RSpec/PredicateMatcher
|
|
2
|
-
|
|
3
|
-
describe Imap::Backup::Account::Folder do
|
|
4
|
-
FOLDER_NAME = "Gelöscht".freeze
|
|
5
|
-
ENCODED_FOLDER_NAME = "Gel&APY-scht".freeze
|
|
6
|
-
|
|
7
|
-
subject { described_class.new(connection, FOLDER_NAME) }
|
|
8
|
-
|
|
9
|
-
let(:client) do
|
|
10
|
-
instance_double(
|
|
11
|
-
Imap::Backup::Client::Default,
|
|
12
|
-
append: append_response,
|
|
13
|
-
create: nil,
|
|
14
|
-
examine: nil,
|
|
15
|
-
expunge: nil,
|
|
16
|
-
responses: responses,
|
|
17
|
-
select: nil,
|
|
18
|
-
uid_store: nil
|
|
19
|
-
)
|
|
20
|
-
end
|
|
21
|
-
let(:connection) do
|
|
22
|
-
instance_double(Imap::Backup::Account::Connection, client: client)
|
|
23
|
-
end
|
|
24
|
-
let(:missing_mailbox_data) do
|
|
25
|
-
OpenStruct.new(text: "Unknown Mailbox: #{FOLDER_NAME}")
|
|
26
|
-
end
|
|
27
|
-
let(:missing_mailbox_response) { OpenStruct.new(data: missing_mailbox_data) }
|
|
28
|
-
let(:missing_mailbox_error) do
|
|
29
|
-
Net::IMAP::NoResponseError.new(missing_mailbox_response)
|
|
30
|
-
end
|
|
31
|
-
let(:responses) { [] }
|
|
32
|
-
let(:append_response) { nil }
|
|
33
|
-
let(:uids) { [5678, 123] }
|
|
34
|
-
|
|
35
|
-
before { allow(client).to receive(:uid_search) { uids } }
|
|
36
|
-
|
|
37
|
-
describe "#uids" do
|
|
38
|
-
it "lists available messages" do
|
|
39
|
-
expect(subject.uids).to eq(uids.reverse)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
context "with missing mailboxes" do
|
|
43
|
-
before do
|
|
44
|
-
allow(client).to receive(:examine).
|
|
45
|
-
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "returns an empty array" do
|
|
49
|
-
expect(subject.uids).to eq([])
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
context "with no SEARCH response in Net::IMAP" do
|
|
54
|
-
let(:no_method_error) do
|
|
55
|
-
NoMethodError.new("Somethimes SEARCH responses come out undefined")
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
before do
|
|
59
|
-
allow(client).to receive(:examine).
|
|
60
|
-
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "returns an empty array" do
|
|
64
|
-
expect(subject.uids).to eq([])
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
context "when the UID search fails" do
|
|
69
|
-
before do
|
|
70
|
-
allow(client).to receive(:uid_search).and_raise(NoMethodError)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "returns an empty array" do
|
|
74
|
-
expect(subject.uids).to eq([])
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
describe "#fetch_multi" do
|
|
80
|
-
let(:message_body) { instance_double(String, force_encoding: nil) }
|
|
81
|
-
let(:attributes) { {"UID" => "uid", "BODY[]" => message_body, "other" => "xxx"} }
|
|
82
|
-
let(:fetch_data_item) do
|
|
83
|
-
instance_double(Net::IMAP::FetchData, attr: attributes)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
before { allow(client).to receive(:uid_fetch) { [fetch_data_item] } }
|
|
87
|
-
|
|
88
|
-
it "returns the uid and message" do
|
|
89
|
-
expect(subject.fetch_multi([123])).to eq([{uid: "uid", body: message_body}])
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
context "when the server responds with nothing" do
|
|
93
|
-
before { allow(client).to receive(:uid_fetch) { nil } }
|
|
94
|
-
|
|
95
|
-
it "is nil" do
|
|
96
|
-
expect(subject.fetch_multi([123])).to be_nil
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
context "when the mailbox doesn't exist" do
|
|
101
|
-
before do
|
|
102
|
-
allow(client).to receive(:examine).
|
|
103
|
-
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it "is nil" do
|
|
107
|
-
expect(subject.fetch_multi([123])).to be_nil
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
context "when the first fetch_uid attempts fail" do
|
|
112
|
-
before do
|
|
113
|
-
outcomes = [-> { raise EOFError }, -> { [fetch_data_item] }]
|
|
114
|
-
allow(client).to receive(:uid_fetch) { outcomes.shift.call }
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "retries" do
|
|
118
|
-
subject.fetch_multi([123])
|
|
119
|
-
|
|
120
|
-
expect(client).to have_received(:uid_fetch).twice
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
it "succeeds" do
|
|
124
|
-
subject.fetch_multi([123])
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
describe "#folder" do
|
|
130
|
-
it "is the name" do
|
|
131
|
-
expect(subject.folder).to eq(FOLDER_NAME)
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
describe "#exist?" do
|
|
136
|
-
context "when the folder exists" do
|
|
137
|
-
it "is true" do
|
|
138
|
-
expect(subject.exist?).to be_truthy
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
context "when the folder doesn't exist" do
|
|
143
|
-
before do
|
|
144
|
-
allow(client).to receive(:examine).
|
|
145
|
-
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
it "is false" do
|
|
149
|
-
expect(subject.exist?).to be_falsey
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
describe "#create" do
|
|
155
|
-
context "when the folder exists" do
|
|
156
|
-
it "is does not create the folder" do
|
|
157
|
-
expect(client).to_not receive(:create)
|
|
158
|
-
|
|
159
|
-
subject.create
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
context "when the folder doesn't exist" do
|
|
164
|
-
before do
|
|
165
|
-
allow(client).to receive(:examine).
|
|
166
|
-
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
it "creates the folder" do
|
|
170
|
-
expect(client).to receive(:create)
|
|
171
|
-
|
|
172
|
-
subject.create
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
it "encodes the folder name" do
|
|
176
|
-
expect(client).to receive(:create).with(ENCODED_FOLDER_NAME)
|
|
177
|
-
|
|
178
|
-
subject.create
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
describe "#uid_validity" do
|
|
184
|
-
let(:responses) { {"UIDVALIDITY" => ["x", "uid validity"]} }
|
|
185
|
-
|
|
186
|
-
it "is returned" do
|
|
187
|
-
expect(subject.uid_validity).to eq("uid validity")
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
context "when the folder doesn't exist" do
|
|
191
|
-
before do
|
|
192
|
-
allow(client).to receive(:examine).
|
|
193
|
-
with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
it "raises an error" do
|
|
197
|
-
expect do
|
|
198
|
-
subject.uid_validity
|
|
199
|
-
end.to raise_error(Imap::Backup::FolderNotFound)
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
describe "#append" do
|
|
205
|
-
let(:message) do
|
|
206
|
-
instance_double(
|
|
207
|
-
Email::Mboxrd::Message,
|
|
208
|
-
imap_body: "imap body",
|
|
209
|
-
date: message_date
|
|
210
|
-
)
|
|
211
|
-
end
|
|
212
|
-
let(:message_date) { Time.new(2010, 10, 10, 9, 15, 22, 0) }
|
|
213
|
-
let(:append_response) do
|
|
214
|
-
OpenStruct.new(data: OpenStruct.new(code: OpenStruct.new(data: "1 2")))
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
it "appends the message" do
|
|
218
|
-
expect(client).to receive(:append)
|
|
219
|
-
|
|
220
|
-
subject.append(message)
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
it "sets the date and time" do
|
|
224
|
-
expect(client).to receive(:append).
|
|
225
|
-
with(anything, anything, anything, message_date)
|
|
226
|
-
|
|
227
|
-
subject.append(message)
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
it "returns the new uid" do
|
|
231
|
-
expect(subject.append(message)).to eq(2)
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
it "set the new uid validity" do
|
|
235
|
-
subject.append(message)
|
|
236
|
-
|
|
237
|
-
expect(subject.uid_validity).to eq(1)
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
describe "#clear" do
|
|
242
|
-
before do
|
|
243
|
-
subject.clear
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
it "uses select to have read-write access" do
|
|
247
|
-
expect(client).to have_received(:select)
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
it "marks all emails as deleted" do
|
|
251
|
-
expect(client).
|
|
252
|
-
to have_received(:uid_store).with(uids.sort, "+FLAGS", [:Deleted])
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
it "deletes marked emails" do
|
|
256
|
-
expect(client).to have_received(:expunge)
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
# rubocop:enable RSpec/PredicateMatcher
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
module Imap::Backup
|
|
2
|
-
describe Account do
|
|
3
|
-
subject { described_class.new(options) }
|
|
4
|
-
|
|
5
|
-
let(:options) { {username: "user", password: "pwd"} }
|
|
6
|
-
|
|
7
|
-
describe "#changes" do
|
|
8
|
-
it "lists changes" do
|
|
9
|
-
subject.username = "new"
|
|
10
|
-
|
|
11
|
-
expect(subject.changes).to eq(username: {from: "user", to: "new"})
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
context "when more than one change is made" do
|
|
15
|
-
it "retains the last one" do
|
|
16
|
-
subject.username = "first"
|
|
17
|
-
subject.username = "second"
|
|
18
|
-
|
|
19
|
-
expect(subject.changes).to eq(username: {from: "user", to: "second"})
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context "when a value is reset to its original value" do
|
|
24
|
-
it "removes the change" do
|
|
25
|
-
subject.username = "changed"
|
|
26
|
-
subject.username = "user"
|
|
27
|
-
|
|
28
|
-
expect(subject.changes).to eq({})
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe "#connection" do
|
|
34
|
-
it "returns a Connection for the Account" do
|
|
35
|
-
result = subject.connection
|
|
36
|
-
|
|
37
|
-
expect(result).to be_a(Account::Connection)
|
|
38
|
-
expect(result.account).to be subject
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
describe "#valid?" do
|
|
43
|
-
context "with username and password" do
|
|
44
|
-
it "is true" do
|
|
45
|
-
expect(subject.valid?).to be true
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
context "without a username" do
|
|
50
|
-
let(:options) { {password: "pwd"} }
|
|
51
|
-
|
|
52
|
-
it "is false" do
|
|
53
|
-
expect(subject.valid?).to be false
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
context "without a password" do
|
|
58
|
-
let(:options) { {username: "user"} }
|
|
59
|
-
|
|
60
|
-
it "is false" do
|
|
61
|
-
expect(subject.valid?).to be false
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
describe "#modified?" do
|
|
67
|
-
context "with changes" do
|
|
68
|
-
it "is true" do
|
|
69
|
-
subject.username = "new"
|
|
70
|
-
|
|
71
|
-
expect(subject.modified?).to be true
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
context "without changes" do
|
|
76
|
-
it "is false" do
|
|
77
|
-
expect(subject.modified?).to be false
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
describe "#clear_changes" do
|
|
83
|
-
it "clears changes" do
|
|
84
|
-
subject.username = "new"
|
|
85
|
-
subject.clear_changes
|
|
86
|
-
|
|
87
|
-
expect(subject.changes).to eq({})
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
describe "#mark_for_deletion" do
|
|
92
|
-
it "sets marked_for_deletion" do
|
|
93
|
-
subject.mark_for_deletion
|
|
94
|
-
|
|
95
|
-
expect(subject.marked_for_deletion?).to be true
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
describe "#marked_for_deletion?" do
|
|
100
|
-
it "defaults to false" do
|
|
101
|
-
expect(subject.marked_for_deletion?).to be false
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
describe "#to_h" do
|
|
106
|
-
it "returns a Hash representation" do
|
|
107
|
-
expect(subject.to_h).to eq({username: "user", password: "pwd"})
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
context "when local_path is set" do
|
|
111
|
-
let(:options) { {username: "user", password: "pwd", local_path: "local_path"} }
|
|
112
|
-
|
|
113
|
-
it "includes local_path" do
|
|
114
|
-
expect(subject.to_h).to include({local_path: "local_path"})
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
context "when folders is set" do
|
|
119
|
-
let(:options) { {username: "user", password: "pwd", folders: ["folder"]} }
|
|
120
|
-
|
|
121
|
-
it "includes folders" do
|
|
122
|
-
expect(subject.to_h).to include({folders: ["folder"]})
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
context "when multi_fetch_size is set" do
|
|
127
|
-
let(:options) { {username: "user", password: "pwd", multi_fetch_size: "3"} }
|
|
128
|
-
|
|
129
|
-
it "includes multi_fetch_size" do
|
|
130
|
-
expect(subject.to_h).to include({multi_fetch_size: 3})
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
context "when server is set" do
|
|
135
|
-
let(:options) { {username: "user", password: "pwd", server: "server"} }
|
|
136
|
-
|
|
137
|
-
it "includes server" do
|
|
138
|
-
expect(subject.to_h).to include({server: "server"})
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
context "when connection_options is set" do
|
|
143
|
-
let(:options) { {username: "user", password: "pwd", connection_options: "foo"} }
|
|
144
|
-
|
|
145
|
-
it "includes connection_options" do
|
|
146
|
-
expect(subject.to_h).to include({connection_options: "foo"})
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
describe "#multi_fetch_size" do
|
|
152
|
-
let(:options) { {username: "user", password: "pwd", multi_fetch_size: multi_fetch_size} }
|
|
153
|
-
let(:multi_fetch_size) { 10 }
|
|
154
|
-
|
|
155
|
-
it "returns the initialized value" do
|
|
156
|
-
expect(subject.multi_fetch_size).to eq(10)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
context "when the initialized value is a string representation of a positive number" do
|
|
160
|
-
let(:multi_fetch_size) { "10" }
|
|
161
|
-
|
|
162
|
-
it "returns one" do
|
|
163
|
-
expect(subject.multi_fetch_size).to eq(10)
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
context "when the initialized value is not a number" do
|
|
168
|
-
let(:multi_fetch_size) { "ciao" }
|
|
169
|
-
|
|
170
|
-
it "returns one" do
|
|
171
|
-
expect(subject.multi_fetch_size).to eq(1)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
context "when the initialized value is not a positive number" do
|
|
176
|
-
let(:multi_fetch_size) { "-99" }
|
|
177
|
-
|
|
178
|
-
it "returns one" do
|
|
179
|
-
expect(subject.multi_fetch_size).to eq(1)
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
[
|
|
185
|
-
[:username, "username", "username"],
|
|
186
|
-
[:password, "password", "password"],
|
|
187
|
-
[:local_path, "local_path", "local_path"],
|
|
188
|
-
[:multi_fetch_size, "2", 2],
|
|
189
|
-
[:server, "server", "server"],
|
|
190
|
-
[:folders, ["folder"], ["folder"]],
|
|
191
|
-
[:connection_options, '{"some": "option"}', {"some" => "option"}]
|
|
192
|
-
].each do |attribute, value, expected|
|
|
193
|
-
describe "##{attribute}=" do
|
|
194
|
-
let(:options) { {} }
|
|
195
|
-
|
|
196
|
-
before { subject.send(:"#{attribute}=", value) }
|
|
197
|
-
|
|
198
|
-
it "sets the #{attribute}" do
|
|
199
|
-
expect(subject.send(attribute)).to eq(expected)
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
it "adds a change" do
|
|
203
|
-
expect(subject.changes).to eq(attribute => {from: nil, to: expected})
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
if attribute == :folders
|
|
207
|
-
context "when the supplied value is not an Array" do
|
|
208
|
-
it "fails" do
|
|
209
|
-
expect do
|
|
210
|
-
subject.folders = "aaa"
|
|
211
|
-
end.to raise_error(RuntimeError, /must be an Array/)
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
if attribute == :multi_fetch_size
|
|
217
|
-
context "when the supplied value is not a number" do
|
|
218
|
-
before { subject.multi_fetch_size = "ciao" }
|
|
219
|
-
|
|
220
|
-
it "sets multi_fetch_size to one" do
|
|
221
|
-
expect(subject.multi_fetch_size).to eq(1)
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
context "when the supplied value is not a positive number" do
|
|
226
|
-
before { subject.multi_fetch_size = "-1" }
|
|
227
|
-
|
|
228
|
-
it "sets multi_fetch_size to one" do
|
|
229
|
-
expect(subject.multi_fetch_size).to eq(1)
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
if attribute == :connection_options
|
|
235
|
-
context "when the supplied value is not valid JSON" do
|
|
236
|
-
it "fails" do
|
|
237
|
-
expect do
|
|
238
|
-
subject.connection_options = "NOT JSON"
|
|
239
|
-
end.to raise_error(JSON::ParserError)
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
require "imap/backup/cli/accounts"
|
|
2
|
-
|
|
3
|
-
describe Imap::Backup::CLI::Accounts do
|
|
4
|
-
subject { described_class.new(required_accounts) }
|
|
5
|
-
|
|
6
|
-
let(:required_accounts) { [] }
|
|
7
|
-
let(:accounts) { [account1, account2] }
|
|
8
|
-
let(:account1) do
|
|
9
|
-
instance_double(
|
|
10
|
-
Imap::Backup::Account,
|
|
11
|
-
username: "a1@example.com"
|
|
12
|
-
)
|
|
13
|
-
end
|
|
14
|
-
let(:account2) do
|
|
15
|
-
instance_double(
|
|
16
|
-
Imap::Backup::Account,
|
|
17
|
-
username: "a2@example.com"
|
|
18
|
-
)
|
|
19
|
-
end
|
|
20
|
-
let(:store) do
|
|
21
|
-
instance_double(Imap::Backup::Configuration, accounts: accounts)
|
|
22
|
-
end
|
|
23
|
-
let(:exists) { true }
|
|
24
|
-
|
|
25
|
-
before do
|
|
26
|
-
allow(Imap::Backup::Configuration).to receive(:new) { store }
|
|
27
|
-
allow(Imap::Backup::Configuration).
|
|
28
|
-
to receive(:exist?) { exists }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
describe "#each" do
|
|
32
|
-
specify "calls the block with each account" do
|
|
33
|
-
result = subject.map { |a| a }
|
|
34
|
-
|
|
35
|
-
expect(result).to eq(accounts)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
context "when the configuration file is missing" do
|
|
39
|
-
let(:exists) { false }
|
|
40
|
-
|
|
41
|
-
it "fails" do
|
|
42
|
-
expect do
|
|
43
|
-
subject.each {}
|
|
44
|
-
end.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
context "when an account list is provided" do
|
|
49
|
-
let(:required_accounts) { %w(a2@example.com) }
|
|
50
|
-
|
|
51
|
-
specify "calls the block with each account" do
|
|
52
|
-
result = subject.map { |a| a }
|
|
53
|
-
|
|
54
|
-
expect(result).to eq([account2])
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module Imap::Backup
|
|
2
|
-
describe CLI::Backup do
|
|
3
|
-
subject { described_class.new({}) }
|
|
4
|
-
|
|
5
|
-
let(:connection) { instance_double(Account::Connection, run_backup: nil) }
|
|
6
|
-
|
|
7
|
-
before do
|
|
8
|
-
# rubocop:disable RSpec/SubjectStub
|
|
9
|
-
allow(subject).to receive(:each_connection).with([]).and_yield(connection)
|
|
10
|
-
# rubocop:enable RSpec/SubjectStub
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "runs the backup for each connection" do
|
|
14
|
-
subject.run
|
|
15
|
-
|
|
16
|
-
expect(connection).to have_received(:run_backup)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
module Imap::Backup
|
|
2
|
-
describe CLI::Folders do
|
|
3
|
-
subject { described_class.new({}) }
|
|
4
|
-
|
|
5
|
-
let(:connection) do
|
|
6
|
-
instance_double(
|
|
7
|
-
Account::Connection, account: account, folder_names: folder_names
|
|
8
|
-
)
|
|
9
|
-
end
|
|
10
|
-
let(:account) { instance_double(Account, username: "user") }
|
|
11
|
-
let(:folder_names) { ["my-folder"] }
|
|
12
|
-
|
|
13
|
-
before do
|
|
14
|
-
allow(Kernel).to receive(:puts)
|
|
15
|
-
allow(Kernel).to receive(:warn)
|
|
16
|
-
# rubocop:disable RSpec/SubjectStub
|
|
17
|
-
allow(subject).to receive(:each_connection).with([]).and_yield(connection)
|
|
18
|
-
# rubocop:enable RSpec/SubjectStub
|
|
19
|
-
|
|
20
|
-
subject.run
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it "lists folders" do
|
|
24
|
-
expect(Kernel).to have_received(:puts).with("\tmy-folder")
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
context "when the folder list is not fetched" do
|
|
28
|
-
let(:folder_names) { nil }
|
|
29
|
-
|
|
30
|
-
it "warns" do
|
|
31
|
-
expect(Kernel).to have_received(:warn).with(/Unable to list/)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "doesn't fail" do
|
|
35
|
-
subject.run
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
require "imap/backup/cli/helpers"
|
|
2
|
-
|
|
3
|
-
module Imap::Backup
|
|
4
|
-
class WithHelpers
|
|
5
|
-
include CLI::Helpers
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
RSpec.describe CLI::Helpers do
|
|
9
|
-
subject { WithHelpers.new }
|
|
10
|
-
|
|
11
|
-
let(:accounts) { instance_double(CLI::Accounts) }
|
|
12
|
-
let(:email) { "email@example.com" }
|
|
13
|
-
let(:account1) { instance_double(Account, username: email, connection: "c1") }
|
|
14
|
-
let(:account2) { instance_double(Account, username: "foo", connection: "c2") }
|
|
15
|
-
let(:items) { [account1, account2] }
|
|
16
|
-
|
|
17
|
-
before do
|
|
18
|
-
allow(CLI::Accounts).to receive(:new) { accounts }
|
|
19
|
-
allow(accounts).to receive(:each).
|
|
20
|
-
and_yield(account1).
|
|
21
|
-
and_yield(account2)
|
|
22
|
-
allow(accounts).to receive(:find) do |&block|
|
|
23
|
-
items.find { |a| block.call(a) }
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
describe ".symbolized" do
|
|
28
|
-
let(:arguments) { {"foo" => 1, "bar" => 2} }
|
|
29
|
-
let(:result) { subject.symbolized(arguments) }
|
|
30
|
-
|
|
31
|
-
it "converts string keys to symbols" do
|
|
32
|
-
expect(result.keys).to eq([:foo, :bar])
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "when keys have hyphens" do
|
|
36
|
-
let(:arguments) { {"some-option"=> 3} }
|
|
37
|
-
|
|
38
|
-
it "replaces them with underscores" do
|
|
39
|
-
expect(result.keys).to eq([:some_option])
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
describe ".account" do
|
|
45
|
-
it "returns any account with a matching username" do
|
|
46
|
-
expect(subject.account(email)).to eq(account1)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
context "when no match is found" do
|
|
50
|
-
let(:items) { [account2] }
|
|
51
|
-
it "fails" do
|
|
52
|
-
expect do
|
|
53
|
-
subject.account(email)
|
|
54
|
-
end.to raise_error(RuntimeError, /not a configured account/)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe ".connection" do
|
|
60
|
-
it "returns the connection for any account with a matching username" do
|
|
61
|
-
result = subject.connection(email)
|
|
62
|
-
expect(result).to be_a(Account::Connection)
|
|
63
|
-
expect(result.account).to eq(account1)
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
describe ".each_connection" do
|
|
68
|
-
it "yields each connection" do
|
|
69
|
-
expect { |b| subject.each_connection([email, "foo"], &b) }.
|
|
70
|
-
to yield_successive_args("c1", "c2")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
context "when there is no configuration" do
|
|
74
|
-
before do
|
|
75
|
-
allow(accounts).to receive(:each).
|
|
76
|
-
and_raise(Imap::Backup::ConfigurationNotFound)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "fails" do
|
|
80
|
-
expect do
|
|
81
|
-
subject.each_connection([email])
|
|
82
|
-
end.to raise_error(RuntimeError, /not configured/)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|