imap-backup 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|