imap-backup 2.0.0 → 2.1.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/.rspec-all +2 -0
- data/.rubocop.yml +10 -1
- data/.travis.yml +1 -0
- data/README.md +1 -1
- data/Rakefile +0 -1
- data/bin/imap-backup +3 -9
- data/imap-backup.gemspec +5 -5
- data/lib/email/mboxrd/message.rb +2 -2
- data/lib/imap/backup/account/connection.rb +11 -3
- data/lib/imap/backup/account/folder.rb +11 -6
- data/lib/imap/backup/configuration/account.rb +7 -7
- data/lib/imap/backup/configuration/asker.rb +2 -1
- data/lib/imap/backup/configuration/connection_tester.rb +1 -1
- data/lib/imap/backup/configuration/folder_chooser.rb +32 -5
- data/lib/imap/backup/configuration/list.rb +2 -0
- data/lib/imap/backup/configuration/setup.rb +2 -1
- data/lib/imap/backup/configuration/store.rb +3 -6
- data/lib/imap/backup/downloader.rb +8 -7
- data/lib/imap/backup/serializer/mbox.rb +2 -1
- data/lib/imap/backup/serializer/mbox_store.rb +14 -6
- data/lib/imap/backup/uploader.rb +1 -0
- data/lib/imap/backup/utils.rb +11 -9
- data/lib/imap/backup/version.rb +1 -1
- data/spec/features/backup_spec.rb +6 -5
- data/spec/features/support/backup_directory.rb +5 -5
- data/spec/features/support/email_server.rb +11 -8
- data/spec/features/support/shared/connection_context.rb +2 -2
- data/spec/support/fixtures.rb +1 -1
- data/spec/support/higline_test_helpers.rb +1 -1
- data/spec/unit/email/mboxrd/message_spec.rb +51 -42
- data/spec/unit/email/provider_spec.rb +0 -2
- data/spec/unit/imap/backup/account/connection_spec.rb +18 -11
- data/spec/unit/imap/backup/account/folder_spec.rb +26 -12
- data/spec/unit/imap/backup/configuration/account_spec.rb +22 -19
- data/spec/unit/imap/backup/configuration/asker_spec.rb +30 -31
- data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +16 -13
- data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +45 -18
- data/spec/unit/imap/backup/configuration/list_spec.rb +8 -13
- data/spec/unit/imap/backup/configuration/setup_spec.rb +36 -30
- data/spec/unit/imap/backup/configuration/store_spec.rb +7 -4
- data/spec/unit/imap/backup/downloader_spec.rb +11 -7
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +2 -5
- data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +4 -4
- data/spec/unit/imap/backup/uploader_spec.rb +0 -2
- data/spec/unit/imap/backup/utils_spec.rb +1 -3
- metadata +6 -6
@@ -1,5 +1,3 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
1
|
describe Imap::Backup::Account::Connection do
|
4
2
|
def self.backup_folder
|
5
3
|
"backup_folder"
|
@@ -9,6 +7,8 @@ describe Imap::Backup::Account::Connection do
|
|
9
7
|
{name: backup_folder}
|
10
8
|
end
|
11
9
|
|
10
|
+
subject { described_class.new(options) }
|
11
|
+
|
12
12
|
let(:imap) do
|
13
13
|
instance_double(Net::IMAP, login: nil, disconnect: nil)
|
14
14
|
end
|
@@ -18,7 +18,7 @@ describe Imap::Backup::Account::Connection do
|
|
18
18
|
username: username,
|
19
19
|
password: "password",
|
20
20
|
local_path: local_path,
|
21
|
-
folders: backup_folders
|
21
|
+
folders: backup_folders
|
22
22
|
}
|
23
23
|
end
|
24
24
|
let(:local_path) { "local_path" }
|
@@ -48,8 +48,6 @@ describe Imap::Backup::Account::Connection do
|
|
48
48
|
allow(Imap::Backup::Utils).to receive(:make_folder)
|
49
49
|
end
|
50
50
|
|
51
|
-
subject { described_class.new(options) }
|
52
|
-
|
53
51
|
shared_examples "connects to IMAP" do
|
54
52
|
it "sets up the IMAP connection" do
|
55
53
|
expect(Net::IMAP).to have_received(:new)
|
@@ -78,10 +76,10 @@ describe Imap::Backup::Account::Connection do
|
|
78
76
|
end
|
79
77
|
|
80
78
|
describe "#imap" do
|
81
|
-
|
79
|
+
let!(:result) { subject.imap }
|
82
80
|
|
83
81
|
it "returns the IMAP connection" do
|
84
|
-
expect(
|
82
|
+
expect(result).to eq(imap)
|
85
83
|
end
|
86
84
|
|
87
85
|
include_examples "connects to IMAP"
|
@@ -108,7 +106,7 @@ describe Imap::Backup::Account::Connection do
|
|
108
106
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new) { serializer }
|
109
107
|
end
|
110
108
|
|
111
|
-
it "
|
109
|
+
it "returns the names of folders" do
|
112
110
|
expect(subject.status[0][:name]).to eq(self.class.backup_folder)
|
113
111
|
end
|
114
112
|
|
@@ -116,7 +114,7 @@ describe Imap::Backup::Account::Connection do
|
|
116
114
|
expect(subject.status[0][:local]).to eq([local_uid])
|
117
115
|
end
|
118
116
|
|
119
|
-
it "
|
117
|
+
it "retrieves the available uids" do
|
120
118
|
expect(subject.status[0][:remote]).to eq([remote_uid])
|
121
119
|
end
|
122
120
|
end
|
@@ -126,9 +124,11 @@ describe Imap::Backup::Account::Connection do
|
|
126
124
|
instance_double(
|
127
125
|
Imap::Backup::Account::Folder,
|
128
126
|
name: "folder",
|
127
|
+
exist?: exists,
|
129
128
|
uid_validity: uid_validity
|
130
129
|
)
|
131
130
|
end
|
131
|
+
let(:exists) { true }
|
132
132
|
let(:uid_validity) { 123 }
|
133
133
|
let(:downloader) { instance_double(Imap::Backup::Downloader, run: nil) }
|
134
134
|
|
@@ -143,13 +143,20 @@ describe Imap::Backup::Account::Connection do
|
|
143
143
|
with(subject, self.class.backup_folder).and_return(folder)
|
144
144
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
145
145
|
with(local_path, self.class.backup_folder).and_return(serializer)
|
146
|
+
subject.run_backup
|
146
147
|
end
|
147
148
|
|
148
|
-
before { subject.run_backup }
|
149
|
-
|
150
149
|
it "runs the downloader" do
|
151
150
|
expect(downloader).to have_received(:run)
|
152
151
|
end
|
152
|
+
|
153
|
+
context "when a folder does not exist" do
|
154
|
+
let(:exists) { false }
|
155
|
+
|
156
|
+
it "does not run the downloader" do
|
157
|
+
expect(downloader).to_not have_received(:run)
|
158
|
+
end
|
159
|
+
end
|
153
160
|
end
|
154
161
|
|
155
162
|
context "without supplied backup_folders" do
|
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# rubocop:disable RSpec/PredicateMatcher
|
2
2
|
|
3
3
|
describe Imap::Backup::Account::Folder do
|
4
|
+
subject { described_class.new(connection, "my_folder") }
|
5
|
+
|
4
6
|
let(:imap) do
|
5
7
|
instance_double(
|
6
8
|
Net::IMAP,
|
@@ -10,21 +12,19 @@ describe Imap::Backup::Account::Folder do
|
|
10
12
|
responses: responses
|
11
13
|
)
|
12
14
|
end
|
13
|
-
let(:connection)
|
14
|
-
|
15
|
-
double("Data", text: "Unknown Mailbox: my_folder")
|
15
|
+
let(:connection) do
|
16
|
+
instance_double(Imap::Backup::Account::Connection, imap: imap)
|
16
17
|
end
|
17
|
-
let(:
|
18
|
-
|
18
|
+
let(:missing_mailbox_data) do
|
19
|
+
OpenStruct.new(text: "Unknown Mailbox: my_folder")
|
19
20
|
end
|
21
|
+
let(:missing_mailbox_response) { OpenStruct.new(data: missing_mailbox_data) }
|
20
22
|
let(:missing_mailbox_error) do
|
21
23
|
Net::IMAP::NoResponseError.new(missing_mailbox_response)
|
22
24
|
end
|
23
25
|
let(:responses) { [] }
|
24
26
|
let(:append_response) { nil }
|
25
27
|
|
26
|
-
subject { described_class.new(connection, "my_folder") }
|
27
|
-
|
28
28
|
context "#uids" do
|
29
29
|
let(:uids) { [5678, 123] }
|
30
30
|
|
@@ -46,7 +46,7 @@ describe Imap::Backup::Account::Folder do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
context "#fetch" do
|
49
|
-
let(:message_body) {
|
49
|
+
let(:message_body) { instance_double(String, force_encoding: nil) }
|
50
50
|
let(:attributes) { {"RFC822" => message_body, "other" => "xxx"} }
|
51
51
|
let(:fetch_data_item) do
|
52
52
|
instance_double(Net::IMAP::FetchData, attr: attributes)
|
@@ -134,6 +134,18 @@ describe Imap::Backup::Account::Folder do
|
|
134
134
|
it "is returned" do
|
135
135
|
expect(subject.uid_validity).to eq("uid validity")
|
136
136
|
end
|
137
|
+
|
138
|
+
context "when the folder doesn't exist" do
|
139
|
+
before do
|
140
|
+
allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "raises an error" do
|
144
|
+
expect do
|
145
|
+
subject.uid_validity
|
146
|
+
end.to raise_error(Imap::Backup::FolderNotFound)
|
147
|
+
end
|
148
|
+
end
|
137
149
|
end
|
138
150
|
|
139
151
|
context "#append" do
|
@@ -144,12 +156,12 @@ describe Imap::Backup::Account::Folder do
|
|
144
156
|
date: Time.now
|
145
157
|
)
|
146
158
|
end
|
147
|
-
let(:append_response)
|
159
|
+
let(:append_response) do
|
160
|
+
OpenStruct.new(data: OpenStruct.new(code: OpenStruct.new(data: "1 2")))
|
161
|
+
end
|
148
162
|
let(:result) { subject.append(message) }
|
149
163
|
|
150
164
|
before do
|
151
|
-
allow(append_response).
|
152
|
-
to receive_message_chain("data.code.data") { "1 2" }
|
153
165
|
result
|
154
166
|
end
|
155
167
|
|
@@ -166,3 +178,5 @@ describe Imap::Backup::Account::Folder do
|
|
166
178
|
end
|
167
179
|
end
|
168
180
|
end
|
181
|
+
|
182
|
+
# rubocop:enable RSpec/PredicateMatcher
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# rubocop:disable RSpec/NestedGroups
|
2
2
|
|
3
3
|
describe Imap::Backup::Configuration::Account do
|
4
4
|
class MockHighlineMenu
|
@@ -19,12 +19,12 @@ describe Imap::Backup::Configuration::Account do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
context "#initialize" do
|
22
|
+
subject { described_class.new(store, account, highline) }
|
23
|
+
|
22
24
|
let(:store) { "store" }
|
23
25
|
let(:account) { "account" }
|
24
26
|
let(:highline) { "highline" }
|
25
27
|
|
26
|
-
subject { described_class.new(store, account, highline) }
|
27
|
-
|
28
28
|
[:store, :account, :highline].each do |param|
|
29
29
|
it "expects #{param}" do
|
30
30
|
expect(subject.send(param)).to eq(send(param))
|
@@ -33,10 +33,12 @@ describe Imap::Backup::Configuration::Account do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
context "#run" do
|
36
|
-
|
36
|
+
subject { described_class.new(store, account, highline) }
|
37
|
+
|
38
|
+
let(:highline) { instance_double(HighLine) }
|
37
39
|
let(:menu) { MockHighlineMenu.new }
|
38
40
|
let(:store) do
|
39
|
-
|
41
|
+
instance_double(Imap::Backup::Configuration::Store, accounts: accounts)
|
40
42
|
end
|
41
43
|
let(:accounts) { [account, account1] }
|
42
44
|
let(:account) do
|
@@ -45,13 +47,13 @@ describe Imap::Backup::Configuration::Account do
|
|
45
47
|
server: existing_server,
|
46
48
|
local_path: "/backup/path",
|
47
49
|
folders: [{name: "my_folder"}],
|
48
|
-
password: existing_password
|
50
|
+
password: existing_password
|
49
51
|
}
|
50
52
|
end
|
51
53
|
let(:account1) do
|
52
54
|
{
|
53
55
|
username: other_email,
|
54
|
-
local_path: other_existing_path
|
56
|
+
local_path: other_existing_path
|
55
57
|
}
|
56
58
|
end
|
57
59
|
let(:existing_email) { "user@example.com" }
|
@@ -62,21 +64,19 @@ describe Imap::Backup::Configuration::Account do
|
|
62
64
|
let(:other_existing_path) { "/other/existing/path" }
|
63
65
|
|
64
66
|
before do
|
65
|
-
allow(
|
66
|
-
allow(
|
67
|
+
allow(Kernel).to receive(:system)
|
68
|
+
allow(Kernel).to receive(:puts)
|
67
69
|
allow(highline).to receive(:choose) do |&block|
|
68
70
|
block.call(menu)
|
69
71
|
throw :done
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
|
-
subject { described_class.new(store, account, highline) }
|
74
|
-
|
75
75
|
context "preparation" do
|
76
76
|
before { subject.run }
|
77
77
|
|
78
78
|
it "clears the screen" do
|
79
|
-
expect(
|
79
|
+
expect(Kernel).to have_received(:system).with("clear")
|
80
80
|
end
|
81
81
|
|
82
82
|
context "menu" do
|
@@ -96,7 +96,7 @@ describe Imap::Backup::Configuration::Account do
|
|
96
96
|
"test connection",
|
97
97
|
"delete",
|
98
98
|
"return to main menu",
|
99
|
-
"quit"
|
99
|
+
"quit" # TODO: quit is hidden
|
100
100
|
].each do |item|
|
101
101
|
before { subject.run }
|
102
102
|
|
@@ -180,7 +180,7 @@ describe Imap::Backup::Configuration::Account do
|
|
180
180
|
let(:new_email) { other_email }
|
181
181
|
|
182
182
|
it "indicates the error" do
|
183
|
-
expect(
|
183
|
+
expect(Kernel).to have_received(:puts).
|
184
184
|
with("There is already an account set up with that email address")
|
185
185
|
end
|
186
186
|
|
@@ -226,9 +226,6 @@ describe Imap::Backup::Configuration::Account do
|
|
226
226
|
|
227
227
|
before do
|
228
228
|
allow(highline).to receive(:ask).with("server: ").and_return(server)
|
229
|
-
end
|
230
|
-
|
231
|
-
before do
|
232
229
|
subject.run
|
233
230
|
menu.choices["modify server"].call
|
234
231
|
end
|
@@ -247,7 +244,7 @@ describe Imap::Backup::Configuration::Account do
|
|
247
244
|
@validator = nil
|
248
245
|
allow(
|
249
246
|
Imap::Backup::Configuration::Asker
|
250
|
-
).to receive(:backup_path) do |
|
247
|
+
).to receive(:backup_path) do |_path, validator|
|
251
248
|
@validator = validator
|
252
249
|
new_backup_path
|
253
250
|
end
|
@@ -260,14 +257,18 @@ describe Imap::Backup::Configuration::Account do
|
|
260
257
|
end
|
261
258
|
|
262
259
|
it "validates that the path is not used by other backups" do
|
260
|
+
# rubocop:disable RSpec/InstanceVariable
|
263
261
|
expect(@validator.call(other_existing_path)).to be_falsey
|
262
|
+
# rubocop:enable RSpec/InstanceVariable
|
264
263
|
end
|
265
264
|
|
266
265
|
include_examples "it flags the account as modified"
|
267
266
|
end
|
268
267
|
|
269
268
|
context "folders" do
|
270
|
-
let(:chooser)
|
269
|
+
let(:chooser) do
|
270
|
+
instance_double(Imap::Backup::Configuration::FolderChooser, run: nil)
|
271
|
+
end
|
271
272
|
|
272
273
|
before do
|
273
274
|
allow(Imap::Backup::Configuration::FolderChooser).
|
@@ -323,3 +324,5 @@ describe Imap::Backup::Configuration::Account do
|
|
323
324
|
end
|
324
325
|
end
|
325
326
|
end
|
327
|
+
|
328
|
+
# rubocop:enable RSpec/NestedGroups
|
@@ -1,34 +1,34 @@
|
|
1
|
-
|
1
|
+
# rubocop:disable Metrics/ModuleLength
|
2
2
|
|
3
3
|
module Imap::Backup
|
4
4
|
describe Configuration::Asker do
|
5
|
+
subject { described_class.new(highline) }
|
6
|
+
|
5
7
|
let(:highline) { double }
|
6
8
|
let(:query) do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
:
|
13
|
-
|
9
|
+
instance_double(
|
10
|
+
HighLine::Question,
|
11
|
+
"default=": nil,
|
12
|
+
"readline=": nil,
|
13
|
+
"validate=": nil,
|
14
|
+
"responses": {},
|
15
|
+
"echo=": nil
|
14
16
|
)
|
15
17
|
end
|
16
18
|
let(:answer) { "foo" }
|
17
19
|
|
18
20
|
before do
|
19
|
-
allow(Configuration::Setup).to receive(:highline)
|
21
|
+
allow(Configuration::Setup).to receive(:highline) { highline }
|
20
22
|
allow(highline).to receive(:ask) do |&b|
|
21
23
|
b.call query
|
22
24
|
answer
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
|
-
subject { described_class.new(highline) }
|
27
|
-
|
28
28
|
[
|
29
29
|
[:email, [], "email address"],
|
30
30
|
[:password, [], "password"],
|
31
|
-
[:backup_path,
|
31
|
+
[:backup_path, %w(x y), "backup directory"]
|
32
32
|
].each do |method, params, prompt|
|
33
33
|
context ".#{method}" do
|
34
34
|
it "asks for input" do
|
@@ -58,39 +58,35 @@ module Imap::Backup
|
|
58
58
|
context "#email" do
|
59
59
|
let(:email) { "email@example.com" }
|
60
60
|
let(:answer) { email }
|
61
|
+
let(:result) { subject.email }
|
61
62
|
|
62
|
-
before
|
63
|
-
@result = subject.email
|
64
|
-
end
|
63
|
+
before { result }
|
65
64
|
|
66
65
|
it "asks for an email" do
|
67
66
|
expect(highline).to have_received(:ask).with(/email/)
|
68
67
|
end
|
69
68
|
|
70
69
|
it "returns the address" do
|
71
|
-
expect(
|
70
|
+
expect(result).to eq(email)
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
74
|
context "#password" do
|
76
75
|
let(:password1) { "password" }
|
77
76
|
let(:password2) { "password" }
|
78
|
-
let(:answers) { [
|
79
|
-
let(:
|
80
|
-
let(:answer2) { false }
|
77
|
+
let(:answers) { [true, false] }
|
78
|
+
let(:result) { subject.password }
|
81
79
|
|
82
80
|
before do
|
83
|
-
|
84
|
-
allow(highline).to receive(:ask).
|
85
|
-
|
86
|
-
allow(highline).to receive(:ask).
|
87
|
-
with("repeat password: ").and_return(password2)
|
81
|
+
i = 0
|
82
|
+
allow(highline).to receive(:ask).with("password: ") { password1 }
|
83
|
+
allow(highline).to receive(:ask).with("repeat password: ") { password2 }
|
88
84
|
allow(highline).to receive(:agree) do
|
89
|
-
answer = answers[
|
90
|
-
|
85
|
+
answer = answers[i]
|
86
|
+
i += 1
|
91
87
|
answer
|
92
88
|
end
|
93
|
-
|
89
|
+
result
|
94
90
|
end
|
95
91
|
|
96
92
|
it "asks for a password" do
|
@@ -102,7 +98,7 @@ module Imap::Backup
|
|
102
98
|
end
|
103
99
|
|
104
100
|
it "returns the password" do
|
105
|
-
expect(
|
101
|
+
expect(result).to eq(password1)
|
106
102
|
end
|
107
103
|
|
108
104
|
context "different answers" do
|
@@ -110,7 +106,7 @@ module Imap::Backup
|
|
110
106
|
|
111
107
|
it "asks to continue" do
|
112
108
|
expect(highline).to have_received(:agree).
|
113
|
-
at_least(
|
109
|
+
at_least(:once).with(/Continue\?/)
|
114
110
|
end
|
115
111
|
end
|
116
112
|
end
|
@@ -118,13 +114,14 @@ module Imap::Backup
|
|
118
114
|
context "#backup_path" do
|
119
115
|
let(:path) { "/path" }
|
120
116
|
let(:answer) { path }
|
117
|
+
let(:result) { subject.backup_path("", //) }
|
121
118
|
|
122
119
|
before do
|
123
120
|
allow(highline).to receive(:ask) do |&b|
|
124
121
|
b.call query
|
125
122
|
path
|
126
123
|
end
|
127
|
-
|
124
|
+
result
|
128
125
|
end
|
129
126
|
|
130
127
|
it "asks for a directory" do
|
@@ -132,8 +129,10 @@ module Imap::Backup
|
|
132
129
|
end
|
133
130
|
|
134
131
|
it "returns the path" do
|
135
|
-
expect(
|
132
|
+
expect(result).to eq(path)
|
136
133
|
end
|
137
134
|
end
|
138
135
|
end
|
139
136
|
end
|
137
|
+
|
138
|
+
# rubocop:enable Metrics/ModuleLength
|