imap-backup 5.2.0 → 6.0.0.rc2
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/lib/cli_coverage.rb +1 -1
- data/lib/imap/backup/account/connection.rb +7 -11
- data/lib/imap/backup/account.rb +31 -11
- data/lib/imap/backup/cli/folders.rb +3 -3
- data/lib/imap/backup/cli/migrate.rb +3 -3
- data/lib/imap/backup/cli/utils.rb +2 -2
- data/lib/imap/backup/configuration.rb +1 -11
- data/lib/imap/backup/downloader.rb +13 -9
- data/lib/imap/backup/serializer/directory.rb +37 -0
- data/lib/imap/backup/serializer/imap.rb +120 -0
- data/lib/imap/backup/serializer/mbox.rb +23 -94
- data/lib/imap/backup/serializer/mbox_enumerator.rb +2 -0
- data/lib/imap/backup/serializer.rb +180 -3
- data/lib/imap/backup/setup/account.rb +52 -29
- data/lib/imap/backup/setup/helpers.rb +1 -1
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +1 -1
- data/lib/imap/backup/version.rb +3 -3
- data/lib/imap/backup.rb +0 -1
- data/spec/features/backup_spec.rb +8 -16
- data/spec/features/support/aruba.rb +4 -3
- data/spec/unit/imap/backup/account/connection_spec.rb +36 -8
- data/spec/unit/imap/backup/account/folder_spec.rb +10 -0
- data/spec/unit/imap/backup/account_spec.rb +246 -0
- data/spec/unit/imap/backup/cli/accounts_spec.rb +12 -1
- data/spec/unit/imap/backup/cli/backup_spec.rb +19 -0
- data/spec/unit/imap/backup/cli/folders_spec.rb +39 -0
- data/spec/unit/imap/backup/cli/local_spec.rb +26 -7
- data/spec/unit/imap/backup/cli/migrate_spec.rb +80 -0
- data/spec/unit/imap/backup/cli/restore_spec.rb +67 -0
- data/spec/unit/imap/backup/cli/setup_spec.rb +17 -0
- data/spec/unit/imap/backup/cli/utils_spec.rb +68 -5
- data/spec/unit/imap/backup/cli_spec.rb +93 -0
- data/spec/unit/imap/backup/client/apple_mail_spec.rb +9 -0
- data/spec/unit/imap/backup/configuration_spec.rb +2 -2
- data/spec/unit/imap/backup/downloader_spec.rb +59 -7
- data/spec/unit/imap/backup/migrator_spec.rb +1 -1
- data/spec/unit/imap/backup/sanitizer_spec.rb +42 -0
- data/spec/unit/imap/backup/serializer/directory_spec.rb +37 -0
- data/spec/unit/imap/backup/serializer/imap_spec.rb +218 -0
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +62 -183
- data/spec/unit/imap/backup/serializer_spec.rb +296 -0
- data/spec/unit/imap/backup/setup/account_spec.rb +120 -25
- data/spec/unit/imap/backup/setup/helpers_spec.rb +15 -0
- data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +116 -0
- data/spec/unit/imap/backup/uploader_spec.rb +1 -1
- data/spec/unit/retry_on_error_spec.rb +34 -0
- metadata +36 -7
- data/lib/imap/backup/serializer/mbox_store.rb +0 -217
- data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +0 -329
@@ -1,115 +1,44 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
|
3
|
-
require "imap/backup/serializer/mbox_store"
|
4
|
-
|
5
1
|
module Imap::Backup
|
6
2
|
class Serializer::Mbox
|
7
|
-
|
8
|
-
def_delegators :store, :mbox_pathname
|
3
|
+
attr_reader :folder_path
|
9
4
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(path, folder)
|
14
|
-
@path = path
|
15
|
-
@folder = folder
|
5
|
+
def initialize(folder_path)
|
6
|
+
@folder_path = folder_path
|
16
7
|
end
|
17
8
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
store.uid_validity = value
|
22
|
-
nil
|
23
|
-
when store.uid_validity == value
|
24
|
-
# NOOP
|
25
|
-
nil
|
26
|
-
else
|
27
|
-
apply_new_uid_validity value
|
9
|
+
def append(message)
|
10
|
+
File.open(pathname, "ab") do |file|
|
11
|
+
file.write message
|
28
12
|
end
|
29
13
|
end
|
30
14
|
|
31
|
-
def
|
32
|
-
|
15
|
+
def exist?
|
16
|
+
File.exist?(pathname)
|
33
17
|
end
|
34
18
|
|
35
|
-
def
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
def load(uid)
|
40
|
-
store.load(uid)
|
41
|
-
end
|
42
|
-
|
43
|
-
def each_message(uids)
|
44
|
-
store.each_message(uids)
|
45
|
-
end
|
46
|
-
|
47
|
-
def save(uid, message)
|
48
|
-
store.add(uid, message)
|
49
|
-
end
|
50
|
-
|
51
|
-
def rename(new_name)
|
52
|
-
@folder = new_name
|
53
|
-
store.rename new_name
|
54
|
-
end
|
19
|
+
def length
|
20
|
+
return nil if !exist?
|
55
21
|
|
56
|
-
|
57
|
-
store.update_uid old, new
|
22
|
+
File.stat(pathname).size
|
58
23
|
end
|
59
24
|
|
60
|
-
|
61
|
-
|
62
|
-
def store
|
63
|
-
@store ||=
|
64
|
-
begin
|
65
|
-
create_containing_directory
|
66
|
-
Serializer::MboxStore.new(path, folder)
|
67
|
-
end
|
25
|
+
def pathname
|
26
|
+
"#{folder_path}.mbox"
|
68
27
|
end
|
69
28
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
break if !test_store.exist?
|
78
|
-
|
79
|
-
digit += 1
|
29
|
+
def rename(new_path)
|
30
|
+
if exist?
|
31
|
+
old_pathname = pathname
|
32
|
+
@folder_path = new_path
|
33
|
+
File.rename(old_pathname, pathname)
|
34
|
+
else
|
35
|
+
@folder_path = new_path
|
80
36
|
end
|
81
|
-
rename_store new_name, value
|
82
|
-
end
|
83
|
-
|
84
|
-
def rename_store(new_name, value)
|
85
|
-
store.rename new_name
|
86
|
-
@store = nil
|
87
|
-
store.uid_validity = value
|
88
|
-
new_name
|
89
|
-
end
|
90
|
-
|
91
|
-
def relative_path
|
92
|
-
File.dirname(folder)
|
93
37
|
end
|
94
38
|
|
95
|
-
def
|
96
|
-
File.
|
97
|
-
|
98
|
-
|
99
|
-
def full_path
|
100
|
-
File.expand_path(containing_directory)
|
101
|
-
end
|
102
|
-
|
103
|
-
def create_containing_directory
|
104
|
-
if !File.directory?(full_path)
|
105
|
-
Utils.make_folder(
|
106
|
-
path, relative_path, Serializer::DIRECTORY_PERMISSIONS
|
107
|
-
)
|
108
|
-
end
|
109
|
-
|
110
|
-
if Utils.mode(full_path) !=
|
111
|
-
Serializer::DIRECTORY_PERMISSIONS
|
112
|
-
FileUtils.chmod Serializer::DIRECTORY_PERMISSIONS, full_path
|
39
|
+
def rewind(length)
|
40
|
+
File.open(pathname, File::RDWR | File::CREAT, 0o644) do |f|
|
41
|
+
f.truncate(length)
|
113
42
|
end
|
114
43
|
end
|
115
44
|
end
|
@@ -1,6 +1,183 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
require "email/mboxrd/message"
|
4
|
+
require "imap/backup/serializer/imap"
|
5
|
+
require "imap/backup/serializer/mbox"
|
6
|
+
require "imap/backup/serializer/mbox_enumerator"
|
7
|
+
|
1
8
|
module Imap::Backup
|
2
|
-
|
3
|
-
|
4
|
-
|
9
|
+
class Serializer
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def_delegator :mbox, :pathname, :mbox_pathname
|
13
|
+
def_delegators :imap, :uid_validity, :uids, :update_uid
|
14
|
+
|
15
|
+
attr_reader :folder
|
16
|
+
attr_reader :path
|
17
|
+
|
18
|
+
def initialize(path, folder)
|
19
|
+
@path = path
|
20
|
+
@folder = folder
|
21
|
+
end
|
22
|
+
|
23
|
+
def apply_uid_validity(value)
|
24
|
+
case
|
25
|
+
when uid_validity.nil?
|
26
|
+
imap.uid_validity = value
|
27
|
+
nil
|
28
|
+
when uid_validity == value
|
29
|
+
# NOOP
|
30
|
+
nil
|
31
|
+
else
|
32
|
+
apply_new_uid_validity value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def force_uid_validity(value)
|
37
|
+
imap.uid_validity = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def append(uid, message)
|
41
|
+
raise "Can't add messages without uid_validity" if !imap.uid_validity
|
42
|
+
|
43
|
+
uid = uid.to_i
|
44
|
+
if imap.include?(uid)
|
45
|
+
Logger.logger.debug(
|
46
|
+
"[#{folder}] message #{uid} already downloaded - skipping"
|
47
|
+
)
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
do_append uid, message
|
52
|
+
end
|
53
|
+
|
54
|
+
def load(uid_maybe_string)
|
55
|
+
uid = uid_maybe_string.to_i
|
56
|
+
message_index = imap.index(uid)
|
57
|
+
return nil if message_index.nil?
|
58
|
+
|
59
|
+
load_nth(message_index)
|
60
|
+
end
|
61
|
+
|
62
|
+
def load_nth(index)
|
63
|
+
enumerator = Serializer::MboxEnumerator.new(mbox.pathname)
|
64
|
+
enumerator.each.with_index do |raw, i|
|
65
|
+
next if i != index
|
66
|
+
|
67
|
+
return Email::Mboxrd::Message.from_serialized(raw)
|
68
|
+
end
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def each_message(required_uids)
|
73
|
+
return enum_for(:each_message, required_uids) if !block_given?
|
74
|
+
|
75
|
+
indexes = required_uids.each.with_object({}) do |uid_maybe_string, acc|
|
76
|
+
uid = uid_maybe_string.to_i
|
77
|
+
index = imap.index(uid)
|
78
|
+
acc[index] = uid if index
|
79
|
+
end
|
80
|
+
enumerator = Serializer::MboxEnumerator.new(mbox.pathname)
|
81
|
+
enumerator.each.with_index do |raw, i|
|
82
|
+
uid = indexes[i]
|
83
|
+
next if !uid
|
84
|
+
|
85
|
+
yield uid, Email::Mboxrd::Message.from_serialized(raw)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def rename(new_name)
|
90
|
+
# Initialize so we get memoized instances with the correct folder_path
|
91
|
+
mbox
|
92
|
+
imap
|
93
|
+
@folder = new_name
|
94
|
+
ensure_containing_directory
|
95
|
+
mbox.rename folder_path
|
96
|
+
imap.rename folder_path
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def do_append(uid, message)
|
102
|
+
mboxrd_message = Email::Mboxrd::Message.new(message)
|
103
|
+
initial = mbox.length || 0
|
104
|
+
mbox_appended = false
|
105
|
+
begin
|
106
|
+
mbox.append mboxrd_message.to_serialized
|
107
|
+
mbox_appended = true
|
108
|
+
imap.append uid
|
109
|
+
rescue StandardError => e
|
110
|
+
mbox.rewind(initial) if mbox_appended
|
111
|
+
|
112
|
+
message = <<-ERROR.gsub(/^\s*/m, "")
|
113
|
+
[#{folder}] failed to append message #{uid}:
|
114
|
+
#{message}. #{e}:
|
115
|
+
#{e.backtrace.join("\n")}"
|
116
|
+
ERROR
|
117
|
+
Logger.logger.warn message
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def mbox
|
122
|
+
@mbox ||=
|
123
|
+
begin
|
124
|
+
ensure_containing_directory
|
125
|
+
Serializer::Mbox.new(folder_path)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def imap
|
130
|
+
@imap ||=
|
131
|
+
begin
|
132
|
+
ensure_containing_directory
|
133
|
+
Serializer::Imap.new(folder_path)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def folder_path
|
138
|
+
folder_path_for(path, folder)
|
139
|
+
end
|
140
|
+
|
141
|
+
def folder_path_for(path, folder)
|
142
|
+
relative = File.join(path, folder)
|
143
|
+
File.expand_path(relative)
|
144
|
+
end
|
145
|
+
|
146
|
+
def ensure_containing_directory
|
147
|
+
relative = File.dirname(folder)
|
148
|
+
directory = Serializer::Directory.new(path, relative)
|
149
|
+
directory.ensure_exists
|
150
|
+
end
|
151
|
+
|
152
|
+
def apply_new_uid_validity(value)
|
153
|
+
new_name = rename_existing_folder
|
154
|
+
# Clear memoization so we get empty data
|
155
|
+
@mbox = nil
|
156
|
+
@imap = nil
|
157
|
+
imap.uid_validity = value
|
158
|
+
|
159
|
+
new_name
|
160
|
+
end
|
161
|
+
|
162
|
+
def rename_existing_folder
|
163
|
+
digit = 0
|
164
|
+
new_name = nil
|
165
|
+
loop do
|
166
|
+
extra = digit.zero? ? "" : "-#{digit}"
|
167
|
+
new_name = "#{folder}-#{imap.uid_validity}#{extra}"
|
168
|
+
new_folder_path = folder_path_for(path, new_name)
|
169
|
+
test_mbox = Serializer::Mbox.new(new_folder_path)
|
170
|
+
test_imap = Serializer::Imap.new(new_folder_path)
|
171
|
+
break if !test_mbox.exist? && !test_imap.exist?
|
172
|
+
|
173
|
+
digit += 1
|
174
|
+
end
|
175
|
+
|
176
|
+
previous = folder
|
177
|
+
rename(new_name)
|
178
|
+
@folder = previous
|
179
|
+
|
180
|
+
new_name
|
181
|
+
end
|
5
182
|
end
|
6
183
|
end
|
@@ -26,6 +26,7 @@ module Imap::Backup
|
|
26
26
|
modify_password menu
|
27
27
|
modify_backup_path menu
|
28
28
|
choose_folders menu
|
29
|
+
modify_multi_fetch_size menu
|
29
30
|
modify_server menu
|
30
31
|
modify_connection_options menu
|
31
32
|
test_connection menu
|
@@ -37,21 +38,30 @@ module Imap::Backup
|
|
37
38
|
|
38
39
|
def header(menu)
|
39
40
|
modified = account.modified? ? "*" : ""
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
|
42
|
+
if account.multi_fetch_size > 1
|
43
|
+
multi_fetch_size = "\nmulti-fetch #{account.multi_fetch_size}"
|
44
|
+
end
|
45
|
+
|
46
|
+
if account.connection_options
|
47
|
+
escaped =
|
48
|
+
JSON.generate(account.connection_options)
|
49
|
+
connection_options =
|
50
|
+
"\nconnection options '#{escaped}'"
|
51
|
+
space = " " * 12
|
52
|
+
else
|
53
|
+
connection_options = nil
|
54
|
+
space = " " * 4
|
55
|
+
end
|
56
|
+
|
47
57
|
menu.header = <<~HEADER.chomp
|
48
58
|
#{helpers.title_prefix} Account#{modified}
|
49
59
|
|
50
|
-
email
|
51
|
-
password
|
52
|
-
path
|
53
|
-
folders
|
54
|
-
server
|
60
|
+
email #{space}#{account.username}
|
61
|
+
password#{space}#{masked_password}
|
62
|
+
path #{space}#{account.local_path}
|
63
|
+
folders #{space}#{folders.map { |f| f[:name] }.join(', ')}#{multi_fetch_size}
|
64
|
+
server #{space}#{account.server}#{connection_options}
|
55
65
|
|
56
66
|
Choose an action
|
57
67
|
HEADER
|
@@ -70,12 +80,10 @@ module Imap::Backup
|
|
70
80
|
)
|
71
81
|
else
|
72
82
|
account.username = username
|
73
|
-
# rubocop:disable Style/IfUnlessModifier
|
74
83
|
default = default_server(username)
|
75
84
|
if default && (account.server.nil? || (account.server == ""))
|
76
85
|
account.server = default
|
77
86
|
end
|
78
|
-
# rubocop:enable Style/IfUnlessModifier
|
79
87
|
end
|
80
88
|
end
|
81
89
|
end
|
@@ -88,20 +96,6 @@ module Imap::Backup
|
|
88
96
|
end
|
89
97
|
end
|
90
98
|
|
91
|
-
def modify_server(menu)
|
92
|
-
menu.choice("modify server") do
|
93
|
-
server = highline.ask("server: ")
|
94
|
-
account.server = server if !server.nil?
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def modify_connection_options(menu)
|
99
|
-
menu.choice("modify connection options") do
|
100
|
-
connection_options = highline.ask("connections options (as JSON): ")
|
101
|
-
account.connection_options = connection_options if !connection_options.nil?
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
99
|
def path_modification_validator(path)
|
106
100
|
same = config.accounts.find do |a|
|
107
101
|
a.username != account.username && a.local_path == path
|
@@ -130,6 +124,35 @@ module Imap::Backup
|
|
130
124
|
end
|
131
125
|
end
|
132
126
|
|
127
|
+
def modify_multi_fetch_size(menu)
|
128
|
+
menu.choice("modify multi-fetch size (number of emails to fetch at a time)") do
|
129
|
+
size = highline.ask("size: ")
|
130
|
+
int = size.to_i
|
131
|
+
account.multi_fetch_size = int if int.positive?
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def modify_server(menu)
|
136
|
+
menu.choice("modify server") do
|
137
|
+
server = highline.ask("server: ")
|
138
|
+
account.server = server if !server.nil?
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def modify_connection_options(menu)
|
143
|
+
menu.choice("modify connection options") do
|
144
|
+
connection_options = highline.ask("connections options (as JSON): ")
|
145
|
+
if !connection_options.nil?
|
146
|
+
begin
|
147
|
+
account.connection_options = connection_options
|
148
|
+
rescue JSON::ParserError
|
149
|
+
Kernel.puts "Malformed JSON, please try again"
|
150
|
+
highline.ask "Press a key "
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
133
156
|
def test_connection(menu)
|
134
157
|
menu.choice("test connection") do
|
135
158
|
result = Setup::ConnectionTester.new(account).test
|
@@ -141,7 +164,7 @@ module Imap::Backup
|
|
141
164
|
def delete_account(menu)
|
142
165
|
menu.choice("delete") do
|
143
166
|
if highline.agree("Are you sure? (y/n) ")
|
144
|
-
account.mark_for_deletion
|
167
|
+
account.mark_for_deletion
|
145
168
|
throw :done
|
146
169
|
end
|
147
170
|
end
|
data/lib/imap/backup/version.rb
CHANGED
data/lib/imap/backup.rb
CHANGED
@@ -8,7 +8,6 @@ require "imap/backup/downloader"
|
|
8
8
|
require "imap/backup/logger"
|
9
9
|
require "imap/backup/uploader"
|
10
10
|
require "imap/backup/serializer"
|
11
|
-
require "imap/backup/serializer/mbox"
|
12
11
|
require "imap/backup/setup"
|
13
12
|
require "imap/backup/setup/account"
|
14
13
|
require "imap/backup/setup/asker"
|
@@ -70,10 +70,18 @@ RSpec.describe "backup", type: :aruba, docker: true do
|
|
70
70
|
expect(mbox_content(renamed_folder)).to eq(message_as_mbox_entry(msg3))
|
71
71
|
end
|
72
72
|
|
73
|
+
it "renames the old metadata file" do
|
74
|
+
expect(imap_parsed(renamed_folder)).to be_a Hash
|
75
|
+
end
|
76
|
+
|
73
77
|
it "downloads messages" do
|
74
78
|
expect(mbox_content(folder)).to eq(messages_as_mbox)
|
75
79
|
end
|
76
80
|
|
81
|
+
it "creates a metadata file" do
|
82
|
+
expect(imap_parsed(folder)).to be_a Hash
|
83
|
+
end
|
84
|
+
|
77
85
|
context "when a renamed local backup exists" do
|
78
86
|
let!(:pre) do
|
79
87
|
super()
|
@@ -88,21 +96,5 @@ RSpec.describe "backup", type: :aruba, docker: true do
|
|
88
96
|
end
|
89
97
|
end
|
90
98
|
end
|
91
|
-
|
92
|
-
context "when an unversioned .imap file is found" do
|
93
|
-
let!(:pre) do
|
94
|
-
create_directory local_backup_path
|
95
|
-
File.open(imap_path(folder), "w") { |f| f.write "old format imap" }
|
96
|
-
File.open(mbox_path(folder), "w") { |f| f.write "old format emails" }
|
97
|
-
end
|
98
|
-
|
99
|
-
it "replaces the .imap file with a versioned JSON file" do
|
100
|
-
expect(imap_metadata[:uids]).to eq(folder_uids)
|
101
|
-
end
|
102
|
-
|
103
|
-
it "does the download" do
|
104
|
-
expect(mbox_content(folder)).to eq(messages_as_mbox)
|
105
|
-
end
|
106
|
-
end
|
107
99
|
end
|
108
100
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "aruba/rspec"
|
2
2
|
|
3
3
|
require_relative "backup_directory"
|
4
|
+
require "imap/backup/serializer/mbox"
|
4
5
|
|
5
6
|
Aruba.configure do |config|
|
6
7
|
config.home_directory = File.expand_path("./tmp/home")
|
@@ -36,10 +37,10 @@ module StoreHelpers
|
|
36
37
|
account = config.accounts.find { |a| a.username == email }
|
37
38
|
raise "Account not found" if !account
|
38
39
|
FileUtils.mkdir_p account.local_path
|
39
|
-
|
40
|
-
|
40
|
+
serializer = Imap::Backup::Serializer.new(account.local_path, folder)
|
41
|
+
serializer.force_uid_validity("42") if !serializer.uid_validity
|
41
42
|
serialized = to_serialized(from: from, subject: subject, body: body)
|
42
|
-
|
43
|
+
serializer.append uid, serialized
|
43
44
|
end
|
44
45
|
|
45
46
|
def to_serialized(from:, subject:, body:)
|
@@ -24,21 +24,24 @@ describe Imap::Backup::Account::Connection do
|
|
24
24
|
let(:account) do
|
25
25
|
instance_double(
|
26
26
|
Imap::Backup::Account,
|
27
|
-
username:
|
27
|
+
username: username,
|
28
28
|
password: PASSWORD,
|
29
29
|
local_path: LOCAL_PATH,
|
30
30
|
folders: config_folders,
|
31
|
+
multi_fetch_size: multi_fetch_size,
|
31
32
|
server: server,
|
32
33
|
connection_options: nil
|
33
34
|
)
|
34
35
|
end
|
36
|
+
let(:username) { USERNAME }
|
35
37
|
let(:config_folders) { [FOLDER_CONFIG] }
|
38
|
+
let(:multi_fetch_size) { 1 }
|
36
39
|
let(:root_info) do
|
37
40
|
instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)
|
38
41
|
end
|
39
42
|
let(:serializer) do
|
40
43
|
instance_double(
|
41
|
-
Imap::Backup::Serializer
|
44
|
+
Imap::Backup::Serializer,
|
42
45
|
folder: serialized_folder,
|
43
46
|
force_uid_validity: nil,
|
44
47
|
apply_uid_validity: new_uid_validity,
|
@@ -87,6 +90,23 @@ describe Imap::Backup::Account::Connection do
|
|
87
90
|
end
|
88
91
|
end
|
89
92
|
|
93
|
+
context "when the provider is Apple" do
|
94
|
+
let(:username) { "user@mac.com" }
|
95
|
+
let(:apple_client) do
|
96
|
+
instance_double(
|
97
|
+
Imap::Backup::Client::AppleMail, login: nil
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
before do
|
102
|
+
allow(Imap::Backup::Client::AppleMail).to receive(:new) { apple_client }
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns the Apple client" do
|
106
|
+
expect(result).to eq(apple_client)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
90
110
|
context "when run" do
|
91
111
|
before { subject.client }
|
92
112
|
|
@@ -116,7 +136,7 @@ describe Imap::Backup::Account::Connection do
|
|
116
136
|
|
117
137
|
before do
|
118
138
|
allow(Imap::Backup::Account::Folder).to receive(:new) { folder }
|
119
|
-
allow(Imap::Backup::Serializer
|
139
|
+
allow(Imap::Backup::Serializer).to receive(:new) { serializer }
|
120
140
|
end
|
121
141
|
|
122
142
|
it "creates the path" do
|
@@ -150,16 +170,24 @@ describe Imap::Backup::Account::Connection do
|
|
150
170
|
let(:exists) { true }
|
151
171
|
let(:uid_validity) { 123 }
|
152
172
|
let(:downloader) { instance_double(Imap::Backup::Downloader, run: nil) }
|
173
|
+
let(:multi_fetch_size) { 10 }
|
153
174
|
|
154
175
|
before do
|
155
176
|
allow(Imap::Backup::Downloader).
|
156
177
|
to receive(:new).with(folder, serializer, anything) { downloader }
|
157
178
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
158
179
|
with(subject, BACKUP_FOLDER) { folder }
|
159
|
-
allow(Imap::Backup::Serializer
|
180
|
+
allow(Imap::Backup::Serializer).to receive(:new).
|
160
181
|
with(LOCAL_PATH, IMAP_FOLDER) { serializer }
|
161
182
|
end
|
162
183
|
|
184
|
+
it "passes the multi_fetch_size" do
|
185
|
+
subject.run_backup
|
186
|
+
|
187
|
+
expect(Imap::Backup::Downloader).to have_received(:new).
|
188
|
+
with(anything, anything, {multi_fetch_size: 10})
|
189
|
+
end
|
190
|
+
|
163
191
|
context "with supplied config_folders" do
|
164
192
|
it "runs the downloader" do
|
165
193
|
expect(downloader).to receive(:run)
|
@@ -184,7 +212,7 @@ describe Imap::Backup::Account::Connection do
|
|
184
212
|
before do
|
185
213
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
186
214
|
with(subject, ROOT_NAME) { folder }
|
187
|
-
allow(Imap::Backup::Serializer
|
215
|
+
allow(Imap::Backup::Serializer).to receive(:new).
|
188
216
|
with(LOCAL_PATH, ROOT_NAME) { serializer }
|
189
217
|
end
|
190
218
|
|
@@ -273,18 +301,18 @@ describe Imap::Backup::Account::Connection do
|
|
273
301
|
end
|
274
302
|
let(:updated_serializer) do
|
275
303
|
instance_double(
|
276
|
-
Imap::Backup::Serializer
|
304
|
+
Imap::Backup::Serializer, force_uid_validity: nil
|
277
305
|
)
|
278
306
|
end
|
279
307
|
|
280
308
|
before do
|
281
309
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
282
310
|
with(subject, FOLDER_NAME) { folder }
|
283
|
-
allow(Imap::Backup::Serializer
|
311
|
+
allow(Imap::Backup::Serializer).to receive(:new).
|
284
312
|
with(anything, FOLDER_NAME) { serializer }
|
285
313
|
allow(Imap::Backup::Account::Folder).to receive(:new).
|
286
314
|
with(subject, "new name") { updated_folder }
|
287
|
-
allow(Imap::Backup::Serializer
|
315
|
+
allow(Imap::Backup::Serializer).to receive(:new).
|
288
316
|
with(anything, "new name") { updated_serializer }
|
289
317
|
allow(Imap::Backup::Uploader).to receive(:new).
|
290
318
|
with(folder, serializer) { uploader }
|
@@ -64,6 +64,16 @@ describe Imap::Backup::Account::Folder do
|
|
64
64
|
expect(subject.uids).to eq([])
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
context "when the UID search fails" do
|
69
|
+
before do
|
70
|
+
allow(client).to receive(:uid_search).and_raise(NoMethodError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns an empty array" do
|
74
|
+
expect(subject.uids).to eq([])
|
75
|
+
end
|
76
|
+
end
|
67
77
|
end
|
68
78
|
|
69
79
|
describe "#fetch_multi" do
|