imap-backup 5.2.0 → 6.0.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/README.md +9 -2
- data/docs/development.md +10 -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 +17 -105
- data/lib/imap/backup/account/folder.rb +9 -6
- data/lib/imap/backup/account.rb +36 -16
- data/lib/imap/backup/cli/backup.rb +1 -3
- data/lib/imap/backup/cli/folders.rb +3 -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 +5 -11
- 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 +6 -8
- data/lib/imap/backup/cli.rb +24 -3
- data/lib/imap/backup/configuration.rb +9 -21
- data/lib/imap/backup/downloader.rb +56 -34
- 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/directory.rb +37 -0
- data/lib/imap/backup/serializer/imap.rb +144 -0
- data/lib/imap/backup/serializer/mbox.rb +33 -88
- data/lib/imap/backup/serializer/mbox_enumerator.rb +2 -0
- data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
- data/lib/imap/backup/serializer/unused_name_finder.rb +25 -0
- data/lib/imap/backup/serializer.rb +160 -3
- data/lib/imap/backup/setup/account/header.rb +75 -0
- data/lib/imap/backup/setup/account.rb +41 -95
- 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 +2 -2
- data/lib/imap/backup/setup.rb +5 -4
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +41 -22
- data/lib/imap/backup/uploader.rb +46 -8
- data/lib/imap/backup/utils.rb +1 -1
- data/lib/imap/backup/version.rb +3 -3
- data/lib/imap/backup.rb +0 -2
- metadata +31 -105
- data/lib/imap/backup/serializer/mbox_store.rb +0 -217
- data/spec/features/backup_spec.rb +0 -108
- 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 -77
- 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 -405
- data/spec/unit/imap/backup/account/folder_spec.rb +0 -251
- data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -47
- data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
- data/spec/unit/imap/backup/cli/local_spec.rb +0 -81
- data/spec/unit/imap/backup/cli/utils_spec.rb +0 -62
- 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 -44
- 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/serializer/mbox_enumerator_spec.rb +0 -45
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -222
- data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +0 -329
- data/spec/unit/imap/backup/setup/account_spec.rb +0 -366
- 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_spec.rb +0 -301
- data/spec/unit/imap/backup/uploader_spec.rb +0 -54
- data/spec/unit/imap/backup/utils_spec.rb +0 -92
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
require "json"
|
|
2
|
-
require "os"
|
|
3
|
-
|
|
4
|
-
# rubocop:disable RSpec/PredicateMatcher
|
|
5
|
-
|
|
6
|
-
describe Imap::Backup::Configuration do
|
|
7
|
-
let(:directory) { "/base/path" }
|
|
8
|
-
let(:file_path) { File.join(directory, "/config.json") }
|
|
9
|
-
let(:file_exists) { true }
|
|
10
|
-
let(:directory_exists) { true }
|
|
11
|
-
let(:debug) { true }
|
|
12
|
-
let(:configuration) { data.to_json }
|
|
13
|
-
let(:data) { {debug: debug, accounts: accounts.map(&:to_h)} }
|
|
14
|
-
let(:accounts) { [account1, account2] }
|
|
15
|
-
let(:account1) { Imap::Backup::Account.new({username: "username1"}) }
|
|
16
|
-
let(:account2) { Imap::Backup::Account.new({username: "username2"}) }
|
|
17
|
-
|
|
18
|
-
before do
|
|
19
|
-
stub_const(
|
|
20
|
-
"Imap::Backup::Configuration::CONFIGURATION_DIRECTORY", directory
|
|
21
|
-
)
|
|
22
|
-
allow(File).to receive(:directory?).with(directory) { directory_exists }
|
|
23
|
-
allow(File).to receive(:exist?).and_call_original
|
|
24
|
-
allow(File).to receive(:exist?).with(file_path) { file_exists }
|
|
25
|
-
allow(Imap::Backup::Utils).
|
|
26
|
-
to receive(:stat).with(directory) { 0o700 }
|
|
27
|
-
allow(Imap::Backup::Utils).
|
|
28
|
-
to receive(:stat).with(file_path) { 0o600 }
|
|
29
|
-
allow(Imap::Backup::Utils).to receive(:check_permissions) { nil }
|
|
30
|
-
allow(File).to receive(:read).with(file_path) { configuration }
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe ".exist?" do
|
|
34
|
-
[true, false].each do |exists|
|
|
35
|
-
state = exists ? "exists" : "doesn't exist"
|
|
36
|
-
context "when the file #{state}" do
|
|
37
|
-
let(:file_exists) { exists }
|
|
38
|
-
|
|
39
|
-
it "returns #{exists}" do
|
|
40
|
-
expect(described_class.exist?).to eq(file_exists)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
describe "#path" do
|
|
47
|
-
it "is the directory containing the configuration file" do
|
|
48
|
-
expect(subject.path).to eq(directory)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
describe "#modified?" do
|
|
53
|
-
context "with modified accounts" do
|
|
54
|
-
before { subject.accounts[0].username = "changed" }
|
|
55
|
-
|
|
56
|
-
it "is true" do
|
|
57
|
-
expect(subject.modified?).to be_truthy
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
context "with accounts flagged 'delete'" do
|
|
62
|
-
before { subject.accounts[0].mark_for_deletion! }
|
|
63
|
-
|
|
64
|
-
it "is true" do
|
|
65
|
-
expect(subject.modified?).to be_truthy
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
context "without accounts flagged 'modified'" do
|
|
70
|
-
it "is false" do
|
|
71
|
-
expect(subject.modified?).to be_falsey
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
describe "#debug?" do
|
|
77
|
-
context "when the debug flag is true" do
|
|
78
|
-
it "is true" do
|
|
79
|
-
expect(subject.debug?).to be_truthy
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
context "when the debug flag is false" do
|
|
84
|
-
let(:debug) { false }
|
|
85
|
-
|
|
86
|
-
it "is false" do
|
|
87
|
-
expect(subject.debug?).to be_falsey
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
context "when the debug flag is missing" do
|
|
92
|
-
let(:data) { {accounts: accounts} }
|
|
93
|
-
|
|
94
|
-
it "is false" do
|
|
95
|
-
expect(subject.debug?).to be_falsey
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
context "when the debug flag is neither true nor false" do
|
|
100
|
-
let(:debug) { "hi" }
|
|
101
|
-
|
|
102
|
-
it "is false" do
|
|
103
|
-
expect(subject.debug?).to be_falsey
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
describe "#debug=" do
|
|
109
|
-
before { subject.debug = debug }
|
|
110
|
-
|
|
111
|
-
context "when the supplied value is true" do
|
|
112
|
-
it "sets the flag to true" do
|
|
113
|
-
expect(subject.debug?).to be_truthy
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
context "when the supplied value is false" do
|
|
118
|
-
let(:debug) { false }
|
|
119
|
-
|
|
120
|
-
it "sets the flag to false" do
|
|
121
|
-
expect(subject.debug?).to be_falsey
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
context "when the supplied value is neither true nor false" do
|
|
126
|
-
let(:debug) { "ciao" }
|
|
127
|
-
|
|
128
|
-
it "sets the flag to false" do
|
|
129
|
-
expect(subject.debug?).to be_falsey
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
describe "#save" do
|
|
135
|
-
subject { described_class.new }
|
|
136
|
-
|
|
137
|
-
let(:directory_exists) { false }
|
|
138
|
-
let(:file) { instance_double(File, write: nil) }
|
|
139
|
-
|
|
140
|
-
before do
|
|
141
|
-
allow(FileUtils).to receive(:mkdir)
|
|
142
|
-
allow(FileUtils).to receive(:chmod)
|
|
143
|
-
allow(File).to receive(:open).with(file_path, "w").and_yield(file)
|
|
144
|
-
allow(JSON).to receive(:pretty_generate) { "JSON output" }
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
it "creates the config directory" do
|
|
148
|
-
expect(FileUtils).to receive(:mkdir).with(directory)
|
|
149
|
-
|
|
150
|
-
subject.save
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
it "saves the configuration" do
|
|
154
|
-
expect(file).to receive(:write).with("JSON output")
|
|
155
|
-
|
|
156
|
-
subject.save
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
it "uses the Account#to_h method" do
|
|
160
|
-
allow(subject.accounts[0]).to receive(:to_h) { "Account1" }
|
|
161
|
-
allow(subject.accounts[1]).to receive(:to_h) { "Account2" }
|
|
162
|
-
|
|
163
|
-
expect(JSON).to receive(:pretty_generate).
|
|
164
|
-
with(hash_including({accounts: ["Account1", "Account2"]}))
|
|
165
|
-
|
|
166
|
-
subject.save
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
context "when accounts are to be deleted" do
|
|
170
|
-
let(:accounts) do
|
|
171
|
-
[
|
|
172
|
-
{name: "keep_me"},
|
|
173
|
-
{name: "delete_me", delete: true}
|
|
174
|
-
]
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
before do
|
|
178
|
-
allow(subject.accounts[0]).to receive(:to_h) { "Account1" }
|
|
179
|
-
allow(subject.accounts[1]).to receive(:to_h) { "Account2" }
|
|
180
|
-
subject.accounts[0].mark_for_deletion!
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
it "does not save them" do
|
|
184
|
-
expect(JSON).to receive(:pretty_generate).
|
|
185
|
-
with(hash_including({accounts: ["Account2"]}))
|
|
186
|
-
|
|
187
|
-
subject.save
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
context "when file permissions are too open" do
|
|
192
|
-
context "when on UNIX" do
|
|
193
|
-
before do
|
|
194
|
-
allow(OS).to receive(:windows?) { false }
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
it "sets them to 0600" do
|
|
198
|
-
expect(FileUtils).to receive(:chmod).with(0o600, file_path)
|
|
199
|
-
|
|
200
|
-
subject.save
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
context "when the configuration file is missing" do
|
|
206
|
-
let(:file_exists) { false }
|
|
207
|
-
|
|
208
|
-
it "doesn't fail" do
|
|
209
|
-
expect do
|
|
210
|
-
subject.save
|
|
211
|
-
end.to_not raise_error
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
context "when on UNIX" do
|
|
216
|
-
before do
|
|
217
|
-
allow(OS).to receive(:windows?) { false }
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
context "when the config file permissions are too lax" do
|
|
221
|
-
let(:file_exists) { true }
|
|
222
|
-
|
|
223
|
-
before do
|
|
224
|
-
allow(Imap::Backup::Utils).to receive(:check_permissions).
|
|
225
|
-
with(file_path, 0o600).and_raise("Error")
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
it "fails" do
|
|
229
|
-
expect do
|
|
230
|
-
subject.save
|
|
231
|
-
end.to raise_error(RuntimeError, "Error")
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
# rubocop:enable RSpec/PredicateMatcher
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
describe Imap::Backup::Downloader do
|
|
2
|
-
describe "#run" do
|
|
3
|
-
subject { described_class.new(folder, serializer) }
|
|
4
|
-
|
|
5
|
-
let(:body) { "blah" }
|
|
6
|
-
let(:folder) do
|
|
7
|
-
instance_double(
|
|
8
|
-
Imap::Backup::Account::Folder,
|
|
9
|
-
fetch_multi: [{uid: "111", body: body}],
|
|
10
|
-
name: "folder",
|
|
11
|
-
uids: folder_uids
|
|
12
|
-
)
|
|
13
|
-
end
|
|
14
|
-
let(:folder_uids) { %w(111 222 333) }
|
|
15
|
-
let(:serializer) do
|
|
16
|
-
instance_double(Imap::Backup::Serializer::Mbox, save: nil, uids: ["222"])
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
context "with fetched messages" do
|
|
20
|
-
specify "are saved" do
|
|
21
|
-
expect(serializer).to receive(:save).with("111", body)
|
|
22
|
-
|
|
23
|
-
subject.run
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
context "with messages which are already present" do
|
|
28
|
-
specify "are skipped" do
|
|
29
|
-
expect(serializer).to_not receive(:save).with("222", anything)
|
|
30
|
-
|
|
31
|
-
subject.run
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "with failed fetches" do
|
|
36
|
-
specify "are skipped" do
|
|
37
|
-
allow(folder).to receive(:fetch_multi) { nil }
|
|
38
|
-
expect(serializer).to_not receive(:save)
|
|
39
|
-
|
|
40
|
-
subject.run
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
require "net/imap"
|
|
2
|
-
|
|
3
|
-
module Imap::Backup
|
|
4
|
-
describe Logger do
|
|
5
|
-
describe ".setup_logging" do
|
|
6
|
-
let(:config) { instance_double(Configuration, debug?: debug) }
|
|
7
|
-
|
|
8
|
-
around do |example|
|
|
9
|
-
logger_previous = described_class.logger.level
|
|
10
|
-
net_imap_previous = Net::IMAP.debug
|
|
11
|
-
described_class.logger.level = 42
|
|
12
|
-
Net::IMAP.debug = 42
|
|
13
|
-
example.run
|
|
14
|
-
Net::IMAP.debug = net_imap_previous
|
|
15
|
-
described_class.logger.level = logger_previous
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
before do
|
|
19
|
-
allow(Configuration).to receive(:new) { config }
|
|
20
|
-
described_class.setup_logging
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context "when config.debug?" do
|
|
24
|
-
let(:debug) { true }
|
|
25
|
-
|
|
26
|
-
it "sets logger level to debug" do
|
|
27
|
-
expect(described_class.logger.level).to eq(::Logger::Severity::DEBUG)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it "sets the Net::IMAP debug flag" do
|
|
31
|
-
expect(Net::IMAP.debug).to be_a(TrueClass)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "when not config.debug?" do
|
|
36
|
-
let(:debug) { false }
|
|
37
|
-
|
|
38
|
-
it "sets logger level to error" do
|
|
39
|
-
expect(described_class.logger.level).to eq(::Logger::Severity::ERROR)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "doesn't set the Net::IMAP debug flag" do
|
|
43
|
-
expect(Net::IMAP.debug).to be_a(FalseClass)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
require "imap/backup/migrator"
|
|
2
|
-
|
|
3
|
-
module Imap::Backup
|
|
4
|
-
RSpec.describe Migrator do
|
|
5
|
-
subject { described_class.new(serializer, folder, reset: reset) }
|
|
6
|
-
|
|
7
|
-
let(:serializer) { instance_double(Serializer::MboxStore, uids: [1]) }
|
|
8
|
-
let(:folder) do
|
|
9
|
-
instance_double(
|
|
10
|
-
Account::Folder,
|
|
11
|
-
append: nil, clear: nil, create: nil, name: "name", uids: folder_uids
|
|
12
|
-
)
|
|
13
|
-
end
|
|
14
|
-
let(:folder_uids) { [] }
|
|
15
|
-
let(:reset) { false }
|
|
16
|
-
let(:messages) { [[1, message]] }
|
|
17
|
-
let(:message) { instance_double(Email::Mboxrd::Message, supplied_body: body) }
|
|
18
|
-
let(:body) { "body" }
|
|
19
|
-
|
|
20
|
-
before do
|
|
21
|
-
allow(serializer).to receive(:each_message) do
|
|
22
|
-
messages.enum_for(:each)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "creates the folder" do
|
|
27
|
-
subject.run
|
|
28
|
-
|
|
29
|
-
expect(folder).to have_received(:create)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it "uploads messages" do
|
|
33
|
-
subject.run
|
|
34
|
-
|
|
35
|
-
expect(folder).to have_received(:append).with(message)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
context "when the folder is not empty" do
|
|
39
|
-
let(:folder_uids) { [99] }
|
|
40
|
-
|
|
41
|
-
it "fails" do
|
|
42
|
-
expect do
|
|
43
|
-
subject.run
|
|
44
|
-
end.to raise_error(RuntimeError, /The destination folder 'name' is not empty/)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
context "when `reset` is true" do
|
|
48
|
-
let(:reset) { true }
|
|
49
|
-
|
|
50
|
-
it "clears the folder" do
|
|
51
|
-
subject.run
|
|
52
|
-
|
|
53
|
-
expect(folder).to have_received(:clear)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require "imap/backup/serializer/mbox_enumerator"
|
|
2
|
-
|
|
3
|
-
describe Imap::Backup::Serializer::MboxEnumerator do
|
|
4
|
-
subject { described_class.new(mbox_pathname) }
|
|
5
|
-
|
|
6
|
-
let(:mbox_pathname) { "/mbox/pathname" }
|
|
7
|
-
let(:mbox_file) { instance_double(File) }
|
|
8
|
-
let(:lines) { message1 + message2 + [nil] }
|
|
9
|
-
let(:message1) do
|
|
10
|
-
[
|
|
11
|
-
"From Frida\r\n",
|
|
12
|
-
"Hello\r\n"
|
|
13
|
-
]
|
|
14
|
-
end
|
|
15
|
-
let(:message2) do
|
|
16
|
-
[
|
|
17
|
-
"From John\r\n",
|
|
18
|
-
"Hi\r\n"
|
|
19
|
-
]
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
before do
|
|
23
|
-
allow(File).to receive(:open).and_call_original
|
|
24
|
-
allow(File).to receive(:open).with(mbox_pathname, "rb").and_yield(mbox_file)
|
|
25
|
-
allow(mbox_file).to receive(:gets).and_return(*lines)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
describe "#each" do
|
|
29
|
-
it "reads files as binary" do
|
|
30
|
-
expect(File).to receive(:open).with(mbox_pathname, "rb")
|
|
31
|
-
subject.each {}
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "yields messages" do
|
|
35
|
-
expect { |b| subject.each(&b) }.
|
|
36
|
-
to yield_successive_args(message1.join, message2.join)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
context "without a block" do
|
|
40
|
-
it "returns an Enumerator" do
|
|
41
|
-
expect(subject.each).to be_a(Enumerator)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
describe Imap::Backup::Serializer::Mbox do
|
|
2
|
-
subject { described_class.new(base_path, imap_folder) }
|
|
3
|
-
|
|
4
|
-
let(:base_path) { "/base/path" }
|
|
5
|
-
let(:store) do
|
|
6
|
-
instance_double(
|
|
7
|
-
Imap::Backup::Serializer::MboxStore,
|
|
8
|
-
add: nil,
|
|
9
|
-
rename: nil,
|
|
10
|
-
uids: nil,
|
|
11
|
-
uid_validity: existing_uid_validity,
|
|
12
|
-
"uid_validity=": nil,
|
|
13
|
-
update_uid: nil
|
|
14
|
-
)
|
|
15
|
-
end
|
|
16
|
-
let(:imap_folder) { "folder" }
|
|
17
|
-
let(:permissions) { 0o700 }
|
|
18
|
-
let(:dir_exists) { true }
|
|
19
|
-
let(:existing_uid_validity) { nil }
|
|
20
|
-
|
|
21
|
-
before do
|
|
22
|
-
allow(Imap::Backup::Utils).to receive(:make_folder)
|
|
23
|
-
allow(Imap::Backup::Utils).to receive(:mode) { permissions }
|
|
24
|
-
allow(Imap::Backup::Utils).to receive(:check_permissions) { true }
|
|
25
|
-
allow(File).to receive(:directory?) { dir_exists }
|
|
26
|
-
allow(FileUtils).to receive(:chmod)
|
|
27
|
-
allow(Imap::Backup::Serializer::MboxStore).to receive(:new) { store }
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
describe "folder path" do
|
|
31
|
-
context "when it has multiple elements" do
|
|
32
|
-
let(:imap_folder) { "folder/path" }
|
|
33
|
-
|
|
34
|
-
context "when the containing directory is missing" do
|
|
35
|
-
let(:dir_exists) { false }
|
|
36
|
-
|
|
37
|
-
it "is created" do
|
|
38
|
-
expect(Imap::Backup::Utils).to receive(:make_folder).
|
|
39
|
-
with(base_path, File.dirname(imap_folder), 0o700)
|
|
40
|
-
|
|
41
|
-
subject.uids
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
context "when permissions are incorrect" do
|
|
47
|
-
let(:permissions) { 0o777 }
|
|
48
|
-
|
|
49
|
-
it "corrects them" do
|
|
50
|
-
path = File.expand_path(File.join(base_path, File.dirname(imap_folder)))
|
|
51
|
-
expect(FileUtils).to receive(:chmod).with(0o700, path)
|
|
52
|
-
|
|
53
|
-
subject.uids
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
context "when permissons are correct" do
|
|
58
|
-
it "does nothing" do
|
|
59
|
-
expect(FileUtils).to_not receive(:chmod)
|
|
60
|
-
|
|
61
|
-
subject.uids
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
context "when it exists" do
|
|
66
|
-
it "is not created" do
|
|
67
|
-
expect(Imap::Backup::Utils).to_not receive(:make_folder).
|
|
68
|
-
with(base_path, File.dirname(imap_folder), 0o700)
|
|
69
|
-
|
|
70
|
-
subject.uids
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
describe "#apply_uid_validity" do
|
|
76
|
-
context "when the existing uid validity is unset" do
|
|
77
|
-
it "sets uid validity" do
|
|
78
|
-
expect(store).to receive(:uid_validity=).with("aaa")
|
|
79
|
-
|
|
80
|
-
subject.apply_uid_validity("aaa")
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "does not rename the store" do
|
|
84
|
-
expect(store).to_not receive(:rename)
|
|
85
|
-
|
|
86
|
-
subject.apply_uid_validity("aaa")
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "returns nil" do
|
|
90
|
-
expect(subject.apply_uid_validity("aaa")).to be_nil
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
context "when the uid validity is unchanged" do
|
|
95
|
-
let(:existing_uid_validity) { "aaa" }
|
|
96
|
-
|
|
97
|
-
it "does not set uid validity" do
|
|
98
|
-
expect(store).to_not receive(:uid_validity=)
|
|
99
|
-
|
|
100
|
-
subject.apply_uid_validity("aaa")
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
it "does not rename the store" do
|
|
104
|
-
expect(store).to_not receive(:rename)
|
|
105
|
-
|
|
106
|
-
subject.apply_uid_validity("aaa")
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it "returns nil" do
|
|
110
|
-
expect(subject.apply_uid_validity("aaa")).to be_nil
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
context "when the uid validity is changed" do
|
|
115
|
-
let(:existing_uid_validity) { "bbb" }
|
|
116
|
-
let(:existing_store) do
|
|
117
|
-
instance_double(Imap::Backup::Serializer::MboxStore)
|
|
118
|
-
end
|
|
119
|
-
let(:exists) { false }
|
|
120
|
-
|
|
121
|
-
before do
|
|
122
|
-
allow(Imap::Backup::Serializer::MboxStore).
|
|
123
|
-
to receive(:new).with(anything, /bbb/) { existing_store }
|
|
124
|
-
allow(existing_store).to receive(:exist?).and_return(exists, false)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it "sets uid validity" do
|
|
128
|
-
expect(store).to receive(:uid_validity=).with("aaa")
|
|
129
|
-
|
|
130
|
-
subject.apply_uid_validity("aaa")
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
context "when adding the uid validity does not cause a name clash" do
|
|
134
|
-
it "renames the store, adding the existing uid validity" do
|
|
135
|
-
expect(store).to receive(:rename).with("folder-bbb")
|
|
136
|
-
|
|
137
|
-
subject.apply_uid_validity("aaa")
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
it "returns the new name" do
|
|
141
|
-
expect(subject.apply_uid_validity("aaa")).to eq("folder-bbb")
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
context "when adding the uid validity causes a name clash" do
|
|
146
|
-
let(:exists) { true }
|
|
147
|
-
|
|
148
|
-
it "renames the store, adding the existing uid validity and a digit" do
|
|
149
|
-
expect(store).to receive(:rename).with("folder-bbb-1")
|
|
150
|
-
|
|
151
|
-
subject.apply_uid_validity("aaa")
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
it "returns the new name" do
|
|
155
|
-
expect(subject.apply_uid_validity("aaa")).to eq("folder-bbb-1")
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
describe "#force_uid_validity" do
|
|
162
|
-
it "sets the uid_validity" do
|
|
163
|
-
expect(store).to receive(:uid_validity=).with("66")
|
|
164
|
-
|
|
165
|
-
subject.force_uid_validity("66")
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
describe "#uids" do
|
|
170
|
-
it "calls the store" do
|
|
171
|
-
expect(store).to receive(:uids)
|
|
172
|
-
|
|
173
|
-
subject.uids
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
describe "#load" do
|
|
178
|
-
before { allow(store).to receive(:load).with("66") { "xxx" } }
|
|
179
|
-
|
|
180
|
-
it "returns the value loaded by the store" do
|
|
181
|
-
expect(subject.load("66")).to eq("xxx")
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
describe "#each_message" do
|
|
186
|
-
it "calls the store" do
|
|
187
|
-
expect(store).to receive(:each_message).with([1])
|
|
188
|
-
|
|
189
|
-
subject.each_message([1])
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
describe "#save" do
|
|
194
|
-
it "calls the store" do
|
|
195
|
-
expect(store).to receive(:add).with("foo", "bar")
|
|
196
|
-
|
|
197
|
-
subject.save("foo", "bar")
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
describe "#rename" do
|
|
202
|
-
it "calls the store" do
|
|
203
|
-
expect(store).to receive(:rename).with("foo")
|
|
204
|
-
|
|
205
|
-
subject.rename("foo")
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
it "updates the folder name" do
|
|
209
|
-
subject.rename("foo")
|
|
210
|
-
|
|
211
|
-
expect(subject.folder).to eq("foo")
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
describe "#update_uid" do
|
|
216
|
-
it "calls the store" do
|
|
217
|
-
expect(store).to receive(:update_uid).with("foo", "bar")
|
|
218
|
-
|
|
219
|
-
subject.update_uid("foo", "bar")
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
end
|