imap-backup 2.0.0 → 2.2.2
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 +0 -1
- data/.rspec-all +2 -0
- data/.rubocop.yml +15 -2
- data/.rubocop_todo.yml +58 -0
- data/.travis.yml +15 -2
- data/README.md +14 -22
- data/Rakefile +6 -3
- data/bin/imap-backup +5 -11
- data/imap-backup.gemspec +10 -6
- data/lib/email/mboxrd/message.rb +16 -16
- data/lib/imap/backup/account/connection.rb +38 -22
- data/lib/imap/backup/account/folder.rb +23 -7
- data/lib/imap/backup/configuration/account.rb +25 -21
- data/lib/imap/backup/configuration/asker.rb +3 -2
- 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 +44 -25
- data/lib/imap/backup/serializer/mbox_enumerator.rb +31 -0
- data/lib/imap/backup/serializer/mbox_store.rb +35 -32
- data/lib/imap/backup/uploader.rb +11 -2
- data/lib/imap/backup/utils.rb +11 -9
- data/lib/imap/backup/version.rb +2 -2
- data/spec/features/backup_spec.rb +6 -5
- data/spec/features/helper.rb +1 -1
- data/spec/features/restore_spec.rb +75 -27
- data/spec/features/support/backup_directory.rb +7 -7
- data/spec/features/support/email_server.rb +15 -11
- data/spec/features/support/shared/connection_context.rb +2 -2
- data/spec/features/support/shared/message_fixtures.rb +8 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/fixtures.rb +2 -2
- data/spec/support/higline_test_helpers.rb +1 -1
- data/spec/unit/email/mboxrd/message_spec.rb +73 -53
- data/spec/unit/email/provider_spec.rb +3 -5
- data/spec/unit/imap/backup/account/connection_spec.rb +82 -59
- data/spec/unit/imap/backup/account/folder_spec.rb +75 -37
- data/spec/unit/imap/backup/configuration/account_spec.rb +95 -61
- data/spec/unit/imap/backup/configuration/asker_spec.rb +43 -45
- data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +21 -22
- data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +66 -33
- data/spec/unit/imap/backup/configuration/list_spec.rb +32 -11
- data/spec/unit/imap/backup/configuration/setup_spec.rb +97 -56
- data/spec/unit/imap/backup/configuration/store_spec.rb +30 -25
- data/spec/unit/imap/backup/downloader_spec.rb +28 -26
- data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +45 -0
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +109 -51
- data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +232 -20
- data/spec/unit/imap/backup/uploader_spec.rb +23 -9
- data/spec/unit/imap/backup/utils_spec.rb +14 -15
- data/spec/unit/imap/backup_spec.rb +28 -0
- metadata +13 -7
@@ -1,6 +1,6 @@
|
|
1
1
|
module EmailServerHelpers
|
2
|
-
REQUESTED_ATTRIBUTES =
|
3
|
-
DEFAULT_EMAIL = "address@example.org"
|
2
|
+
REQUESTED_ATTRIBUTES = %w(RFC822 FLAGS INTERNALDATE).freeze
|
3
|
+
DEFAULT_EMAIL = "address@example.org".freeze
|
4
4
|
|
5
5
|
def send_email(folder, options)
|
6
6
|
message = message_as_server_message(options)
|
@@ -11,13 +11,14 @@ module EmailServerHelpers
|
|
11
11
|
from = options[:from] || DEFAULT_EMAIL
|
12
12
|
subject = options[:subject]
|
13
13
|
body = options[:body]
|
14
|
-
message = <<-EOT.gsub("\n", "\r\n")
|
15
|
-
From: #{from}
|
16
|
-
Subject: #{subject}
|
17
14
|
|
18
|
-
|
15
|
+
<<~MESSAGE.gsub("\n", "\r\n")
|
16
|
+
From: #{from}
|
17
|
+
Subject: #{subject}
|
19
18
|
|
20
|
-
|
19
|
+
#{body}
|
20
|
+
|
21
|
+
MESSAGE
|
21
22
|
end
|
22
23
|
|
23
24
|
def server_messages(folder)
|
@@ -32,18 +33,18 @@ Subject: #{subject}
|
|
32
33
|
|
33
34
|
def server_fetch_email(folder, uid)
|
34
35
|
examine folder
|
36
|
+
|
35
37
|
fetch_data_items = imap.uid_fetch([uid.to_i], REQUESTED_ATTRIBUTES)
|
36
38
|
return nil if fetch_data_items.nil?
|
39
|
+
|
37
40
|
fetch_data_item = fetch_data_items[0]
|
38
|
-
|
39
|
-
attributes["RFC822"].force_encoding("utf-8")
|
40
|
-
attributes
|
41
|
+
fetch_data_item.attr
|
41
42
|
end
|
42
43
|
|
43
44
|
def delete_emails(folder)
|
44
45
|
imap.select(folder)
|
45
46
|
uids = imap.uid_search(["ALL"]).sort
|
46
|
-
imap.store(1
|
47
|
+
imap.store(1..uids.size, "+FLAGS", [:Deleted])
|
47
48
|
imap.expunge
|
48
49
|
end
|
49
50
|
|
@@ -82,6 +83,9 @@ Subject: #{subject}
|
|
82
83
|
def server_delete_folder(folder)
|
83
84
|
imap.delete folder
|
84
85
|
imap.disconnect
|
86
|
+
rescue StandardError => e
|
87
|
+
puts e.to_s
|
88
|
+
ensure
|
85
89
|
@imap = nil
|
86
90
|
end
|
87
91
|
|
@@ -3,10 +3,10 @@ shared_context "imap-backup connection" do
|
|
3
3
|
let(:default_connection) { fixture("connection") }
|
4
4
|
let(:backup_folders) { nil }
|
5
5
|
let(:connection_options) do
|
6
|
-
default_connection.merge(
|
6
|
+
default_connection.merge(
|
7
7
|
local_path: local_backup_path,
|
8
8
|
folders: backup_folders
|
9
|
-
|
9
|
+
)
|
10
10
|
end
|
11
11
|
let(:connection) { Imap::Backup::Account::Connection.new(connection_options) }
|
12
12
|
end
|
@@ -2,7 +2,15 @@ shared_context "message-fixtures" do
|
|
2
2
|
let(:uid1) { 123 }
|
3
3
|
let(:uid2) { 345 }
|
4
4
|
let(:uid3) { 567 }
|
5
|
+
let(:uid_iso8859) { 890 }
|
5
6
|
let(:msg1) { {uid: uid1, subject: "Test 1", body: "body 1\nHi"} }
|
6
7
|
let(:msg2) { {uid: uid2, subject: "Test 2", body: "body 2"} }
|
7
8
|
let(:msg3) { {uid: uid3, subject: "Test 3", body: "body 3"} }
|
9
|
+
let(:msg_iso8859) do
|
10
|
+
{
|
11
|
+
uid: uid_iso8859,
|
12
|
+
subject: "iso8859 Body",
|
13
|
+
body: "Ma, perchè?".encode(Encoding::ISO_8859_1).force_encoding("binary")
|
14
|
+
}
|
15
|
+
end
|
8
16
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -7,7 +7,7 @@ spec_path = File.dirname(__FILE__)
|
|
7
7
|
$LOAD_PATH << File.expand_path("../lib", spec_path)
|
8
8
|
|
9
9
|
support_glob = File.join(spec_path, "support", "**", "*.rb")
|
10
|
-
Dir[support_glob].each { |f| require f }
|
10
|
+
Dir[support_glob].sort.each { |f| require f }
|
11
11
|
|
12
12
|
require "simplecov"
|
13
13
|
SimpleCov.start do
|
data/spec/support/fixtures.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
def fixture(name)
|
2
2
|
spec_root = File.expand_path("..", File.dirname(__FILE__))
|
3
|
-
fixture_path = File.join(spec_root, "fixtures", name
|
3
|
+
fixture_path = File.join(spec_root, "fixtures", "#{name}.yml")
|
4
4
|
fixture = File.read(fixture_path)
|
5
|
-
YAML.
|
5
|
+
YAML.safe_load(fixture, [Symbol])
|
6
6
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module HighLineTestHelpers
|
2
2
|
def prepare_highline
|
3
|
-
@input =
|
3
|
+
@input = instance_double(IO, eof?: false, gets: "q\n")
|
4
4
|
@output = StringIO.new
|
5
5
|
Imap::Backup::Configuration::Setup.highline = HighLine.new(@input, @output)
|
6
6
|
[@input, @output]
|
@@ -1,79 +1,82 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
msg_bad_from =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
1
|
+
msg_no_from = <<~NO_FROM
|
2
|
+
Delivered-To: you@example.com
|
3
|
+
From: example <www.example.com>
|
4
|
+
To: FirstName LastName <you@example.com>
|
5
|
+
Subject: Re: no subject
|
6
|
+
NO_FROM
|
7
|
+
|
8
|
+
msg_bad_from = <<~BAD_FROM
|
9
|
+
Delivered-To: you@example.com
|
10
|
+
from: "FirstName LastName (TEXT)" <"TEXT*" <no-reply@example.com>>
|
11
|
+
To: FirstName LastName <you@example.com>
|
12
|
+
Subject: Re: no subject
|
13
|
+
BAD_FROM
|
14
|
+
|
15
|
+
msg_no_from_but_return_path = <<~RETURN_PATH
|
16
|
+
Delivered-To: you@example.com
|
17
|
+
From: example <www.example.com>
|
18
|
+
To: FirstName LastName <you@example.com>
|
19
|
+
Return-Path: <me@example.com>
|
20
|
+
Subject: Re: no subject
|
21
|
+
RETURN_PATH
|
22
|
+
|
23
|
+
msg_no_from_but_sender = <<~NOT_SENDER
|
24
|
+
Delivered-To: you@example.com
|
25
|
+
To: FirstName LastName <you@example.com>
|
26
|
+
Subject: Re: no subject
|
27
|
+
Sender: FistName LastName <me@example.com>
|
28
|
+
NOT_SENDER
|
23
29
|
|
24
30
|
describe Email::Mboxrd::Message do
|
31
|
+
subject { described_class.new(message_body) }
|
32
|
+
|
25
33
|
let(:from) { "me@example.com" }
|
26
34
|
let(:date) { DateTime.new(2012, 12, 13, 18, 23, 45) }
|
27
35
|
let(:message_body) do
|
28
|
-
|
36
|
+
instance_double(String, clone: cloned_message_body, force_encoding: nil)
|
29
37
|
end
|
30
38
|
let(:cloned_message_body) do
|
31
39
|
"Foo\nBar\nFrom at the beginning of the line\n>>From quoted"
|
32
40
|
end
|
33
41
|
let(:msg_good) do
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
<<~GOOD
|
43
|
+
Delivered-To: you@example.com
|
44
|
+
From: Foo <foo@example.com>
|
45
|
+
To: FirstName LastName <you@example.com>
|
46
|
+
Date: #{date.rfc822}
|
47
|
+
Subject: Re: no subject
|
48
|
+
GOOD
|
39
49
|
end
|
40
50
|
|
41
51
|
let(:msg_bad_date) do
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
52
|
+
<<~BAD
|
53
|
+
Delivered-To: you@example.com
|
54
|
+
From: Foo <foo@example.com>
|
55
|
+
To: FirstName LastName <you@example.com>
|
56
|
+
Date: Mon,5 May 2014 08:97:99 GMT
|
57
|
+
Subject: Re: no subject
|
58
|
+
BAD
|
47
59
|
end
|
48
60
|
|
49
|
-
subject { described_class.new(message_body) }
|
50
|
-
|
51
61
|
describe ".from_serialized" do
|
52
62
|
let(:serialized_message) { "From foo@a.com\n#{imap_message}" }
|
53
63
|
let(:imap_message) { "Delivered-To: me@example.com\nFrom Me\n" }
|
54
|
-
|
55
|
-
before { @result = described_class.from_serialized(serialized_message) }
|
64
|
+
let!(:result) { described_class.from_serialized(serialized_message) }
|
56
65
|
|
57
66
|
it "returns the message" do
|
58
|
-
expect(
|
67
|
+
expect(result).to be_a(described_class)
|
59
68
|
end
|
60
69
|
|
61
70
|
it "removes one level of > before From" do
|
62
|
-
expect(
|
71
|
+
expect(result.supplied_body).to eq(imap_message)
|
63
72
|
end
|
64
73
|
end
|
65
74
|
|
66
|
-
|
67
|
-
let(:mail) {
|
75
|
+
describe "#to_serialized" do
|
76
|
+
let(:mail) { instance_double(Mail::Message, from: [from], date: date) }
|
68
77
|
|
69
78
|
before do
|
70
|
-
allow(Mail).to receive(:new).with(cloned_message_body)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "does not modify the message" do
|
74
|
-
subject.to_serialized
|
75
|
-
|
76
|
-
expect(message_body).to_not have_received(:force_encoding).with("binary")
|
79
|
+
allow(Mail).to receive(:new).with(cloned_message_body) { mail }
|
77
80
|
end
|
78
81
|
|
79
82
|
it "adds a 'From ' line at the start" do
|
@@ -98,7 +101,7 @@ Subject: Re: no subject|
|
|
98
101
|
end
|
99
102
|
end
|
100
103
|
|
101
|
-
|
104
|
+
describe "From" do
|
102
105
|
before do
|
103
106
|
# call original for these tests because we want to test the behaviour of
|
104
107
|
# class-under-test given different behaviour of the Mail parser
|
@@ -113,7 +116,7 @@ Subject: Re: no subject|
|
|
113
116
|
end
|
114
117
|
end
|
115
118
|
|
116
|
-
context "when original message 'from' is a
|
119
|
+
context "when original message 'from' is not a well-formed address" do
|
117
120
|
let(:message_body) { msg_bad_from }
|
118
121
|
|
119
122
|
it "'from' is empty string" do
|
@@ -126,7 +129,7 @@ Subject: Re: no subject|
|
|
126
129
|
let(:message_body) { msg_no_from_but_return_path }
|
127
130
|
|
128
131
|
it "'return path' is used as 'from'" do
|
129
|
-
expect(subject.to_serialized).to start_with("From
|
132
|
+
expect(subject.to_serialized).to start_with("From #{from}\n")
|
130
133
|
end
|
131
134
|
end
|
132
135
|
|
@@ -134,12 +137,12 @@ Subject: Re: no subject|
|
|
134
137
|
let(:message_body) { msg_no_from_but_sender }
|
135
138
|
|
136
139
|
it "Sender is used as 'from'" do
|
137
|
-
expect(subject.to_serialized).to start_with("From
|
140
|
+
expect(subject.to_serialized).to start_with("From #{from}\n")
|
138
141
|
end
|
139
142
|
end
|
140
143
|
end
|
141
144
|
|
142
|
-
|
145
|
+
describe "#date" do
|
143
146
|
let(:message_body) { msg_good }
|
144
147
|
|
145
148
|
it "returns the date" do
|
@@ -154,4 +157,21 @@ Subject: Re: no subject|
|
|
154
157
|
end
|
155
158
|
end
|
156
159
|
end
|
160
|
+
|
161
|
+
describe "#imap_body" do
|
162
|
+
let(:message_body) { "Ciao" }
|
163
|
+
|
164
|
+
it "returns the supplied body" do
|
165
|
+
expect(subject.imap_body).to eq(message_body)
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when newlines are not IMAP standard" do
|
169
|
+
let(:message_body) { "Ciao\nHello" }
|
170
|
+
let(:corrected) { "Ciao\r\nHello" }
|
171
|
+
|
172
|
+
it "corrects them" do
|
173
|
+
expect(subject.imap_body).to eq(corrected)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
157
177
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
1
|
describe Email::Provider do
|
2
|
+
subject { described_class.new(:gmail) }
|
3
|
+
|
4
4
|
describe ".for_address" do
|
5
|
-
context "known providers" do
|
5
|
+
context "with known providers" do
|
6
6
|
[
|
7
7
|
["gmail.com", :gmail],
|
8
8
|
["fastmail.fm", :fastmail]
|
@@ -22,8 +22,6 @@ describe Email::Provider do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
subject { described_class.new(:gmail) }
|
26
|
-
|
27
25
|
describe "#options" do
|
28
26
|
it "returns options" do
|
29
27
|
expect(subject.options).to be_a(Hash)
|
@@ -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" }
|
@@ -33,7 +33,7 @@ describe Imap::Backup::Account::Connection do
|
|
33
33
|
Imap::Backup::Serializer::Mbox,
|
34
34
|
folder: serialized_folder,
|
35
35
|
force_uid_validity: nil,
|
36
|
-
|
36
|
+
apply_uid_validity: new_uid_validity,
|
37
37
|
uids: [local_uid]
|
38
38
|
)
|
39
39
|
end
|
@@ -48,19 +48,13 @@ 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
|
-
it "sets up the IMAP connection" do
|
55
|
-
expect(Net::IMAP).to have_received(:new)
|
56
|
-
end
|
57
|
-
|
58
52
|
it "logs in to the imap server" do
|
59
53
|
expect(imap).to have_received(:login)
|
60
54
|
end
|
61
55
|
end
|
62
56
|
|
63
|
-
|
57
|
+
describe "#initialize" do
|
64
58
|
[
|
65
59
|
[:username, "username@gmail.com"],
|
66
60
|
[:local_path, "local_path"],
|
@@ -72,22 +66,23 @@ describe Imap::Backup::Account::Connection do
|
|
72
66
|
end
|
73
67
|
|
74
68
|
it "creates the path" do
|
69
|
+
expect(Imap::Backup::Utils).to receive(:make_folder)
|
70
|
+
|
75
71
|
subject.username
|
76
|
-
expect(Imap::Backup::Utils).to have_received(:make_folder)
|
77
72
|
end
|
78
73
|
end
|
79
74
|
|
80
75
|
describe "#imap" do
|
81
|
-
|
76
|
+
let!(:result) { subject.imap }
|
82
77
|
|
83
78
|
it "returns the IMAP connection" do
|
84
|
-
expect(
|
79
|
+
expect(result).to eq(imap)
|
85
80
|
end
|
86
81
|
|
87
82
|
include_examples "connects to IMAP"
|
88
83
|
end
|
89
84
|
|
90
|
-
|
85
|
+
describe "#folders" do
|
91
86
|
let(:imap_folders) do
|
92
87
|
[instance_double(Net::IMAP::MailboxList)]
|
93
88
|
end
|
@@ -97,18 +92,18 @@ describe Imap::Backup::Account::Connection do
|
|
97
92
|
end
|
98
93
|
end
|
99
94
|
|
100
|
-
|
95
|
+
describe "#status" do
|
101
96
|
let(:folder) do
|
102
97
|
instance_double(Imap::Backup::Account::Folder, uids: [remote_uid])
|
103
98
|
end
|
104
99
|
let(:remote_uid) { "remote_uid" }
|
105
100
|
|
106
101
|
before do
|
107
|
-
allow(Imap::Backup::Account::Folder).to receive(:new)
|
102
|
+
allow(Imap::Backup::Account::Folder).to receive(:new) { folder }
|
108
103
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new) { serializer }
|
109
104
|
end
|
110
105
|
|
111
|
-
it "
|
106
|
+
it "returns the names of folders" do
|
112
107
|
expect(subject.status[0][:name]).to eq(self.class.backup_folder)
|
113
108
|
end
|
114
109
|
|
@@ -116,19 +111,21 @@ describe Imap::Backup::Account::Connection do
|
|
116
111
|
expect(subject.status[0][:local]).to eq([local_uid])
|
117
112
|
end
|
118
113
|
|
119
|
-
it "
|
114
|
+
it "retrieves the available uids" do
|
120
115
|
expect(subject.status[0][:remote]).to eq([remote_uid])
|
121
116
|
end
|
122
117
|
end
|
123
118
|
|
124
|
-
|
119
|
+
describe "#run_backup" do
|
125
120
|
let(:folder) do
|
126
121
|
instance_double(
|
127
122
|
Imap::Backup::Account::Folder,
|
128
123
|
name: "folder",
|
124
|
+
exist?: exists,
|
129
125
|
uid_validity: uid_validity
|
130
126
|
)
|
131
127
|
end
|
128
|
+
let(:exists) { true }
|
132
129
|
let(:uid_validity) { 123 }
|
133
130
|
let(:downloader) { instance_double(Imap::Backup::Downloader, run: nil) }
|
134
131
|
|
@@ -140,15 +137,25 @@ describe Imap::Backup::Account::Connection do
|
|
140
137
|
context "with supplied backup_folders" do
|
141
138
|
before do
|
142
139
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
143
|
-
with(subject, self.class.backup_folder)
|
140
|
+
with(subject, self.class.backup_folder) { folder }
|
144
141
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
145
|
-
with(local_path, self.class.backup_folder)
|
142
|
+
with(local_path, self.class.backup_folder) { serializer }
|
146
143
|
end
|
147
144
|
|
148
|
-
before { subject.run_backup }
|
149
|
-
|
150
145
|
it "runs the downloader" do
|
151
|
-
expect(downloader).to
|
146
|
+
expect(downloader).to receive(:run)
|
147
|
+
|
148
|
+
subject.run_backup
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when a folder does not exist" do
|
152
|
+
let(:exists) { false }
|
153
|
+
|
154
|
+
it "does not run the downloader" do
|
155
|
+
expect(downloader).to_not receive(:run)
|
156
|
+
|
157
|
+
subject.run_backup
|
158
|
+
end
|
152
159
|
end
|
153
160
|
end
|
154
161
|
|
@@ -159,28 +166,28 @@ describe Imap::Backup::Account::Connection do
|
|
159
166
|
|
160
167
|
before do
|
161
168
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
162
|
-
with(subject, "foo")
|
169
|
+
with(subject, "foo") { folder }
|
163
170
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new).
|
164
|
-
with(local_path, "foo")
|
171
|
+
with(local_path, "foo") { serializer }
|
165
172
|
end
|
166
173
|
|
167
174
|
context "when supplied backup_folders is nil" do
|
168
175
|
let(:backup_folders) { nil }
|
169
176
|
|
170
|
-
before { subject.run_backup }
|
171
|
-
|
172
177
|
it "runs the downloader for each folder" do
|
173
|
-
expect(downloader).to
|
178
|
+
expect(downloader).to receive(:run).exactly(:once)
|
179
|
+
|
180
|
+
subject.run_backup
|
174
181
|
end
|
175
182
|
end
|
176
183
|
|
177
184
|
context "when supplied backup_folders is an empty list" do
|
178
185
|
let(:backup_folders) { [] }
|
179
186
|
|
180
|
-
before { subject.run_backup }
|
181
|
-
|
182
187
|
it "runs the downloader for each folder" do
|
183
|
-
expect(downloader).to
|
188
|
+
expect(downloader).to receive(:run).exactly(:once)
|
189
|
+
|
190
|
+
subject.run_backup
|
184
191
|
end
|
185
192
|
end
|
186
193
|
|
@@ -195,17 +202,17 @@ describe Imap::Backup::Account::Connection do
|
|
195
202
|
end
|
196
203
|
end
|
197
204
|
|
198
|
-
|
205
|
+
describe "#restore" do
|
199
206
|
let(:folder) do
|
200
207
|
instance_double(
|
201
208
|
Imap::Backup::Account::Folder,
|
202
209
|
create: nil,
|
203
|
-
|
210
|
+
uids: uids,
|
204
211
|
name: "my_folder",
|
205
212
|
uid_validity: uid_validity
|
206
213
|
)
|
207
214
|
end
|
208
|
-
let(:
|
215
|
+
let(:uids) { [99] }
|
209
216
|
let(:uid_validity) { 123 }
|
210
217
|
let(:serialized_folder) { "old name" }
|
211
218
|
let(:uploader) do
|
@@ -242,73 +249,89 @@ describe Imap::Backup::Account::Connection do
|
|
242
249
|
with(updated_folder, updated_serializer) { updated_uploader }
|
243
250
|
allow(Pathname).to receive(:glob).
|
244
251
|
and_yield(Pathname.new(File.join(local_path, "my_folder.imap")))
|
245
|
-
subject.restore
|
246
252
|
end
|
247
253
|
|
248
254
|
it "sets local uid validity" do
|
249
|
-
expect(serializer).to
|
255
|
+
expect(serializer).to receive(:apply_uid_validity).with(uid_validity)
|
256
|
+
|
257
|
+
subject.restore
|
250
258
|
end
|
251
259
|
|
252
|
-
context "when folders exist" do
|
260
|
+
context "when folders exist with contents" do
|
253
261
|
context "when the local folder is renamed" do
|
254
262
|
let(:new_uid_validity) { "new name" }
|
255
263
|
|
256
264
|
it "creates the new folder" do
|
257
|
-
expect(updated_folder).to
|
265
|
+
expect(updated_folder).to receive(:create)
|
266
|
+
|
267
|
+
subject.restore
|
258
268
|
end
|
259
269
|
|
260
270
|
it "sets the renamed folder's uid validity" do
|
261
271
|
expect(updated_serializer).
|
262
|
-
to
|
272
|
+
to receive(:force_uid_validity).with("new uid validity")
|
273
|
+
|
274
|
+
subject.restore
|
263
275
|
end
|
264
276
|
|
265
277
|
it "creates the uploader with updated folder and serializer" do
|
266
|
-
expect(updated_uploader).to
|
278
|
+
expect(updated_uploader).to receive(:run)
|
279
|
+
|
280
|
+
subject.restore
|
267
281
|
end
|
268
282
|
end
|
269
283
|
|
270
284
|
context "when the local folder is not renamed" do
|
271
285
|
it "runs the uploader" do
|
272
|
-
expect(uploader).to
|
286
|
+
expect(uploader).to receive(:run)
|
287
|
+
|
288
|
+
subject.restore
|
273
289
|
end
|
274
290
|
end
|
275
291
|
end
|
276
292
|
|
277
|
-
context "when folders don't exist" do
|
278
|
-
let(:
|
293
|
+
context "when folders don't exist or are empty" do
|
294
|
+
let(:uids) { [] }
|
279
295
|
|
280
296
|
it "creates the folder" do
|
281
|
-
expect(folder).to
|
297
|
+
expect(folder).to receive(:create)
|
298
|
+
|
299
|
+
subject.restore
|
282
300
|
end
|
283
301
|
|
284
|
-
it "
|
302
|
+
it "forces local uid validity" do
|
303
|
+
expect(serializer).to receive(:force_uid_validity).with(uid_validity)
|
304
|
+
|
305
|
+
subject.restore
|
285
306
|
end
|
286
307
|
|
287
308
|
it "runs the uploader" do
|
288
|
-
expect(uploader).to
|
309
|
+
expect(uploader).to receive(:run)
|
310
|
+
|
311
|
+
subject.restore
|
289
312
|
end
|
290
313
|
end
|
291
314
|
end
|
292
315
|
|
293
|
-
|
294
|
-
before { subject.reconnect }
|
295
|
-
|
316
|
+
describe "#reconnect" do
|
296
317
|
it "disconnects from the server" do
|
297
|
-
expect(imap).to
|
318
|
+
expect(imap).to receive(:disconnect)
|
319
|
+
|
320
|
+
subject.reconnect
|
298
321
|
end
|
299
322
|
|
300
323
|
it "causes reconnection on future access" do
|
301
|
-
|
302
|
-
|
303
|
-
|
324
|
+
expect(Net::IMAP).to receive(:new)
|
325
|
+
|
326
|
+
subject.reconnect
|
304
327
|
end
|
305
328
|
end
|
306
329
|
|
307
|
-
|
308
|
-
before { subject.disconnect }
|
309
|
-
|
330
|
+
describe "#disconnect" do
|
310
331
|
it "disconnects from the server" do
|
311
|
-
expect(imap).to
|
332
|
+
expect(imap).to receive(:disconnect)
|
333
|
+
|
334
|
+
subject.disconnect
|
312
335
|
end
|
313
336
|
end
|
314
337
|
end
|