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