imap-backup 6.0.0.rc2 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/imap-backup.gemspec +5 -1
- data/lib/cli_coverage.rb +11 -11
- data/lib/email/provider/base.rb +2 -0
- data/lib/email/provider/unknown.rb +2 -0
- data/lib/email/provider.rb +2 -0
- data/lib/imap/backup/account/connection/backup_folders.rb +27 -0
- data/lib/imap/backup/account/connection/client_factory.rb +54 -0
- data/lib/imap/backup/account/connection/folder_names.rb +26 -0
- data/lib/imap/backup/account/connection.rb +11 -95
- data/lib/imap/backup/account/folder.rb +9 -6
- data/lib/imap/backup/account.rb +3 -5
- data/lib/imap/backup/cli/backup.rb +1 -3
- data/lib/imap/backup/cli/helpers.rb +24 -22
- data/lib/imap/backup/cli/local.rb +20 -13
- data/lib/imap/backup/cli/migrate.rb +4 -10
- data/lib/imap/backup/cli/restore.rb +8 -7
- data/lib/imap/backup/cli/setup.rb +10 -8
- data/lib/imap/backup/cli/stats.rb +78 -0
- data/lib/imap/backup/cli/status.rb +2 -2
- data/lib/imap/backup/cli/utils.rb +4 -6
- data/lib/imap/backup/cli.rb +24 -3
- data/lib/imap/backup/configuration.rb +9 -11
- data/lib/imap/backup/downloader.rb +48 -30
- data/lib/imap/backup/migrator.rb +5 -5
- data/lib/imap/backup/sanitizer.rb +3 -2
- data/lib/imap/backup/serializer/appender.rb +49 -0
- data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
- data/lib/imap/backup/serializer/unused_name_finder.rb +27 -0
- data/lib/imap/backup/serializer.rb +24 -78
- data/lib/imap/backup/setup/account/header.rb +75 -0
- data/lib/imap/backup/setup/account.rb +14 -91
- data/lib/imap/backup/setup/asker.rb +4 -15
- data/lib/imap/backup/setup/backup_path.rb +41 -0
- data/lib/imap/backup/setup/email.rb +45 -0
- data/lib/imap/backup/setup/folder_chooser.rb +3 -3
- data/lib/imap/backup/setup/helpers.rb +1 -1
- data/lib/imap/backup/setup.rb +5 -4
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +39 -20
- data/lib/imap/backup/uploader.rb +46 -8
- data/lib/imap/backup/utils.rb +1 -1
- data/lib/imap/backup/version.rb +1 -1
- data/lib/imap/backup.rb +0 -1
- metadata +31 -134
- data/spec/features/backup_spec.rb +0 -100
- data/spec/features/configuration/minimal_configuration.rb +0 -15
- data/spec/features/configuration/missing_configuration.rb +0 -14
- data/spec/features/folders_spec.rb +0 -36
- data/spec/features/helper.rb +0 -2
- data/spec/features/local/list_accounts_spec.rb +0 -12
- data/spec/features/local/list_emails_spec.rb +0 -21
- data/spec/features/local/list_folders_spec.rb +0 -21
- data/spec/features/local/show_an_email_spec.rb +0 -34
- data/spec/features/migrate_spec.rb +0 -35
- data/spec/features/remote/list_account_folders_spec.rb +0 -16
- data/spec/features/restore_spec.rb +0 -162
- data/spec/features/status_spec.rb +0 -43
- data/spec/features/support/aruba.rb +0 -78
- data/spec/features/support/backup_directory.rb +0 -43
- data/spec/features/support/email_server.rb +0 -110
- data/spec/features/support/shared/connection_context.rb +0 -14
- data/spec/features/support/shared/message_fixtures.rb +0 -16
- data/spec/fixtures/connection.yml +0 -7
- data/spec/spec_helper.rb +0 -15
- data/spec/support/fixtures.rb +0 -11
- data/spec/support/higline_test_helpers.rb +0 -8
- data/spec/support/silence_logging.rb +0 -7
- data/spec/unit/email/mboxrd/message_spec.rb +0 -177
- data/spec/unit/email/provider/apple_mail_spec.rb +0 -7
- data/spec/unit/email/provider/base_spec.rb +0 -11
- data/spec/unit/email/provider/fastmail_spec.rb +0 -7
- data/spec/unit/email/provider/gmail_spec.rb +0 -7
- data/spec/unit/email/provider_spec.rb +0 -27
- data/spec/unit/imap/backup/account/connection_spec.rb +0 -433
- data/spec/unit/imap/backup/account/folder_spec.rb +0 -261
- data/spec/unit/imap/backup/account_spec.rb +0 -246
- data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -58
- data/spec/unit/imap/backup/cli/backup_spec.rb +0 -19
- data/spec/unit/imap/backup/cli/folders_spec.rb +0 -39
- data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
- data/spec/unit/imap/backup/cli/local_spec.rb +0 -100
- data/spec/unit/imap/backup/cli/migrate_spec.rb +0 -80
- data/spec/unit/imap/backup/cli/restore_spec.rb +0 -67
- data/spec/unit/imap/backup/cli/setup_spec.rb +0 -17
- data/spec/unit/imap/backup/cli/utils_spec.rb +0 -125
- data/spec/unit/imap/backup/cli_spec.rb +0 -93
- data/spec/unit/imap/backup/client/apple_mail_spec.rb +0 -9
- data/spec/unit/imap/backup/client/default_spec.rb +0 -22
- data/spec/unit/imap/backup/configuration_spec.rb +0 -238
- data/spec/unit/imap/backup/downloader_spec.rb +0 -96
- data/spec/unit/imap/backup/logger_spec.rb +0 -48
- data/spec/unit/imap/backup/migrator_spec.rb +0 -58
- data/spec/unit/imap/backup/sanitizer_spec.rb +0 -42
- data/spec/unit/imap/backup/serializer/directory_spec.rb +0 -37
- data/spec/unit/imap/backup/serializer/imap_spec.rb +0 -218
- data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +0 -45
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -101
- data/spec/unit/imap/backup/serializer_spec.rb +0 -296
- data/spec/unit/imap/backup/setup/account_spec.rb +0 -461
- data/spec/unit/imap/backup/setup/asker_spec.rb +0 -137
- data/spec/unit/imap/backup/setup/connection_tester_spec.rb +0 -51
- data/spec/unit/imap/backup/setup/folder_chooser_spec.rb +0 -146
- data/spec/unit/imap/backup/setup/helpers_spec.rb +0 -15
- data/spec/unit/imap/backup/setup_spec.rb +0 -301
- data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +0 -116
- data/spec/unit/imap/backup/uploader_spec.rb +0 -54
- data/spec/unit/imap/backup/utils_spec.rb +0 -92
- data/spec/unit/retry_on_error_spec.rb +0 -34
@@ -1,162 +0,0 @@
|
|
1
|
-
require "features/helper"
|
2
|
-
|
3
|
-
RSpec.describe "restore", type: :aruba, docker: true do
|
4
|
-
include_context "imap-backup connection"
|
5
|
-
include_context "message-fixtures"
|
6
|
-
|
7
|
-
let(:local_backup_path) { File.expand_path("~/backup") }
|
8
|
-
let(:folder) { "my-stuff" }
|
9
|
-
let(:messages_as_mbox) do
|
10
|
-
message_as_mbox_entry(msg1) + message_as_mbox_entry(msg2)
|
11
|
-
end
|
12
|
-
let(:messages_as_server_messages) do
|
13
|
-
[message_as_server_message(msg1), message_as_server_message(msg2)]
|
14
|
-
end
|
15
|
-
let(:message_uids) { [msg1[:uid], msg2[:uid]] }
|
16
|
-
let(:existing_imap_content) { imap_data(uid_validity, message_uids).to_json }
|
17
|
-
let(:uid_validity) { 1234 }
|
18
|
-
|
19
|
-
let!(:pre) {}
|
20
|
-
let!(:setup) do
|
21
|
-
create_directory local_backup_path
|
22
|
-
File.write(imap_path(folder), existing_imap_content)
|
23
|
-
File.write(mbox_path(folder), messages_as_mbox)
|
24
|
-
create_config(accounts: [account.to_h])
|
25
|
-
|
26
|
-
run_command_and_stop("imap-backup restore #{account.username}")
|
27
|
-
end
|
28
|
-
let(:cleanup) do
|
29
|
-
server_delete_folder folder
|
30
|
-
end
|
31
|
-
|
32
|
-
after { cleanup }
|
33
|
-
|
34
|
-
context "when the folder doesn't exist" do
|
35
|
-
it "restores messages" do
|
36
|
-
messages = server_messages(folder).map { |m| server_message_to_body(m) }
|
37
|
-
expect(messages).to eq(messages_as_server_messages)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "updates local uids to match the new server ones" do
|
41
|
-
updated_imap_content = imap_parsed(folder)
|
42
|
-
expect(server_uids(folder)).to eq(updated_imap_content[:uids])
|
43
|
-
end
|
44
|
-
|
45
|
-
it "sets the backup uid_validity to match the new folder" do
|
46
|
-
updated_imap_content = imap_parsed(folder)
|
47
|
-
expect(updated_imap_content[:uid_validity]).
|
48
|
-
to eq(server_uid_validity(folder))
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "when the folder exists" do
|
53
|
-
let(:email3) { send_email folder, msg3 }
|
54
|
-
|
55
|
-
context "when the uid_validity matches" do
|
56
|
-
let(:pre) do
|
57
|
-
server_create_folder folder
|
58
|
-
email3
|
59
|
-
uid_validity
|
60
|
-
end
|
61
|
-
let(:messages_as_server_messages) do
|
62
|
-
[
|
63
|
-
message_as_server_message(msg3),
|
64
|
-
message_as_server_message(msg1),
|
65
|
-
message_as_server_message(msg2)
|
66
|
-
]
|
67
|
-
end
|
68
|
-
let(:uid_validity) { server_uid_validity(folder) }
|
69
|
-
|
70
|
-
it "appends to the existing folder" do
|
71
|
-
messages = server_messages(folder).map { |m| server_message_to_body(m) }
|
72
|
-
expect(messages).to eq(messages_as_server_messages)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
context "when the uid_validity doesn't match" do
|
77
|
-
context "when the folder is empty" do
|
78
|
-
let(:pre) do
|
79
|
-
server_create_folder folder
|
80
|
-
end
|
81
|
-
|
82
|
-
it "sets the backup uid_validity to match the folder" do
|
83
|
-
updated_imap_content = imap_parsed(folder)
|
84
|
-
expect(updated_imap_content[:uid_validity]).
|
85
|
-
to eq(server_uid_validity(folder))
|
86
|
-
end
|
87
|
-
|
88
|
-
it "uploads to the new folder" do
|
89
|
-
messages = server_messages(folder).map do |m|
|
90
|
-
server_message_to_body(m)
|
91
|
-
end
|
92
|
-
expect(messages).to eq(messages_as_server_messages)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context "when the folder has content" do
|
97
|
-
let(:new_folder) { "#{folder}-#{uid_validity}" }
|
98
|
-
let(:cleanup) do
|
99
|
-
server_delete_folder new_folder
|
100
|
-
super()
|
101
|
-
end
|
102
|
-
|
103
|
-
let(:pre) do
|
104
|
-
server_create_folder folder
|
105
|
-
email3
|
106
|
-
end
|
107
|
-
|
108
|
-
it "renames the backup" do
|
109
|
-
expect(mbox_content(new_folder)).to eq(messages_as_mbox)
|
110
|
-
end
|
111
|
-
|
112
|
-
it "leaves the existing folder as is" do
|
113
|
-
messages = server_messages(folder).map do |m|
|
114
|
-
server_message_to_body(m)
|
115
|
-
end
|
116
|
-
expect(messages).to eq([message_as_server_message(msg3)])
|
117
|
-
end
|
118
|
-
|
119
|
-
it "creates the new folder" do
|
120
|
-
expect(server_folders.map(&:name)).to include(new_folder)
|
121
|
-
end
|
122
|
-
|
123
|
-
it "sets the backup uid_validity to match the new folder" do
|
124
|
-
updated_imap_content = imap_parsed(new_folder)
|
125
|
-
expect(updated_imap_content[:uid_validity]).
|
126
|
-
to eq(server_uid_validity(new_folder))
|
127
|
-
end
|
128
|
-
|
129
|
-
it "uploads to the new folder" do
|
130
|
-
messages = server_messages(new_folder).map do |m|
|
131
|
-
server_message_to_body(m)
|
132
|
-
end
|
133
|
-
expect(messages).to eq(messages_as_server_messages)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
context "when non-Unicode encodings are used" do
|
140
|
-
let(:server_message) do
|
141
|
-
message_as_server_message(msg_iso8859)
|
142
|
-
end
|
143
|
-
let(:messages_as_mbox) do
|
144
|
-
message_as_mbox_entry(msg_iso8859)
|
145
|
-
end
|
146
|
-
let(:message_uids) { [uid_iso8859] }
|
147
|
-
let(:uid_validity) { server_uid_validity(folder) }
|
148
|
-
|
149
|
-
let(:pre) do
|
150
|
-
server_create_folder folder
|
151
|
-
uid_validity
|
152
|
-
end
|
153
|
-
|
154
|
-
it "maintains encodings" do
|
155
|
-
message =
|
156
|
-
server_messages(folder).
|
157
|
-
first["BODY[]"]
|
158
|
-
|
159
|
-
expect(message).to eq(server_message)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require "features/helper"
|
2
|
-
require "imap/backup/cli/status"
|
3
|
-
|
4
|
-
RSpec.describe "status", type: :feature, docker: true do
|
5
|
-
include_context "imap-backup connection"
|
6
|
-
include_context "message-fixtures"
|
7
|
-
|
8
|
-
context "when there are non-backed-up messages" do
|
9
|
-
let(:options) do
|
10
|
-
{accounts: "address@example.org"}
|
11
|
-
end
|
12
|
-
let(:folder) { "my-stuff" }
|
13
|
-
let(:backup_folders) { [{name: folder}] }
|
14
|
-
let(:email1) { send_email folder, msg1 }
|
15
|
-
let(:output) { StringIO.new }
|
16
|
-
|
17
|
-
before do
|
18
|
-
allow(Imap::Backup::CLI::Accounts).to receive(:new) { [account] }
|
19
|
-
server_create_folder folder
|
20
|
-
email1
|
21
|
-
end
|
22
|
-
|
23
|
-
around do |example|
|
24
|
-
stdout = $stdout
|
25
|
-
$stdout = output
|
26
|
-
example.run
|
27
|
-
$stdout = stdout
|
28
|
-
end
|
29
|
-
|
30
|
-
after do
|
31
|
-
FileUtils.rm_rf local_backup_path
|
32
|
-
delete_emails folder
|
33
|
-
server_delete_folder folder
|
34
|
-
connection.disconnect
|
35
|
-
end
|
36
|
-
|
37
|
-
it "prints the number" do
|
38
|
-
Imap::Backup::CLI::Status.new(options).run
|
39
|
-
|
40
|
-
expect(output.string).to eq("address@example.org\nmy-stuff: 1\n")
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
require "aruba/rspec"
|
2
|
-
|
3
|
-
require_relative "backup_directory"
|
4
|
-
require "imap/backup/serializer/mbox"
|
5
|
-
|
6
|
-
Aruba.configure do |config|
|
7
|
-
config.home_directory = File.expand_path("./tmp/home")
|
8
|
-
config.allow_absolute_paths = true
|
9
|
-
end
|
10
|
-
|
11
|
-
module ConfigurationHelpers
|
12
|
-
def config_path
|
13
|
-
File.expand_path("~/.imap-backup")
|
14
|
-
end
|
15
|
-
|
16
|
-
def create_config(accounts:, debug: false)
|
17
|
-
pathname = File.join(config_path, "config.json")
|
18
|
-
save_data = {
|
19
|
-
version: Imap::Backup::Configuration::VERSION,
|
20
|
-
accounts: accounts,
|
21
|
-
debug: debug
|
22
|
-
}
|
23
|
-
FileUtils.mkdir_p config_path
|
24
|
-
File.open(pathname, "w") { |f| f.write(JSON.pretty_generate(save_data)) }
|
25
|
-
FileUtils.chmod(0o600, pathname)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
module StoreHelpers
|
30
|
-
def store_email(
|
31
|
-
email:, folder:,
|
32
|
-
uid: 1,
|
33
|
-
from: "sender@example.com",
|
34
|
-
subject: "The Subject",
|
35
|
-
body: "body"
|
36
|
-
)
|
37
|
-
account = config.accounts.find { |a| a.username == email }
|
38
|
-
raise "Account not found" if !account
|
39
|
-
FileUtils.mkdir_p account.local_path
|
40
|
-
serializer = Imap::Backup::Serializer.new(account.local_path, folder)
|
41
|
-
serializer.force_uid_validity("42") if !serializer.uid_validity
|
42
|
-
serialized = to_serialized(from: from, subject: subject, body: body)
|
43
|
-
serializer.append uid, serialized
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_serialized(from:, subject:, body:)
|
47
|
-
body_and_headers = <<~BODY
|
48
|
-
From: #{from}
|
49
|
-
Subject: #{subject}
|
50
|
-
|
51
|
-
#{body}
|
52
|
-
BODY
|
53
|
-
end
|
54
|
-
|
55
|
-
def config
|
56
|
-
Imap::Backup::Configuration.new(
|
57
|
-
File.expand_path("~/.imap-backup/config.json")
|
58
|
-
)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
RSpec.configure do |config|
|
63
|
-
config.include ConfigurationHelpers, type: :aruba
|
64
|
-
config.include StoreHelpers, type: :aruba
|
65
|
-
config.include BackupDirectoryHelpers, type: :aruba
|
66
|
-
|
67
|
-
config.before(:suite) do
|
68
|
-
FileUtils.rm_rf "./tmp/home"
|
69
|
-
end
|
70
|
-
|
71
|
-
config.before(:example, type: :aruba) do
|
72
|
-
set_environment_variable("COVERAGE", "aruba")
|
73
|
-
end
|
74
|
-
|
75
|
-
config.after do
|
76
|
-
FileUtils.rm_rf "./tmp/home"
|
77
|
-
end
|
78
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module BackupDirectoryHelpers
|
2
|
-
def message_as_mbox_entry(options)
|
3
|
-
from = fixture("connection")[:username]
|
4
|
-
subject = options[:subject]
|
5
|
-
body = options[:body]
|
6
|
-
body_and_headers = <<~BODY
|
7
|
-
From: #{from}
|
8
|
-
Subject: #{subject}
|
9
|
-
|
10
|
-
#{body}
|
11
|
-
BODY
|
12
|
-
|
13
|
-
"From #{from}\n#{body_and_headers}\n"
|
14
|
-
end
|
15
|
-
|
16
|
-
def imap_data(uid_validity, uids)
|
17
|
-
{
|
18
|
-
version: 2,
|
19
|
-
uid_validity: uid_validity,
|
20
|
-
uids: uids
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def mbox_content(name)
|
25
|
-
File.read(mbox_path(name))
|
26
|
-
end
|
27
|
-
|
28
|
-
def mbox_path(name)
|
29
|
-
File.join(local_backup_path, "#{name}.mbox")
|
30
|
-
end
|
31
|
-
|
32
|
-
def imap_path(name)
|
33
|
-
File.join(local_backup_path, "#{name}.imap")
|
34
|
-
end
|
35
|
-
|
36
|
-
def imap_content(name)
|
37
|
-
File.read(imap_path(name))
|
38
|
-
end
|
39
|
-
|
40
|
-
def imap_parsed(name)
|
41
|
-
JSON.parse(imap_content(name), symbolize_names: true)
|
42
|
-
end
|
43
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
module EmailServerHelpers
|
2
|
-
REQUESTED_ATTRIBUTES = ["BODY[]"].freeze
|
3
|
-
DEFAULT_EMAIL = "address@example.org".freeze
|
4
|
-
|
5
|
-
def send_email(folder, options)
|
6
|
-
message = message_as_server_message(options)
|
7
|
-
imap.append(folder, message, nil, nil)
|
8
|
-
end
|
9
|
-
|
10
|
-
def message_as_server_message(options)
|
11
|
-
from = options[:from] || DEFAULT_EMAIL
|
12
|
-
subject = options[:subject]
|
13
|
-
body = options[:body]
|
14
|
-
|
15
|
-
<<~MESSAGE.gsub("\n", "\r\n")
|
16
|
-
From: #{from}
|
17
|
-
Subject: #{subject}
|
18
|
-
|
19
|
-
#{body}
|
20
|
-
|
21
|
-
MESSAGE
|
22
|
-
end
|
23
|
-
|
24
|
-
def server_messages(folder)
|
25
|
-
server_uids(folder).map do |uid|
|
26
|
-
server_fetch_email(folder, uid)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def server_message_to_body(message)
|
31
|
-
message["BODY[]"]
|
32
|
-
end
|
33
|
-
|
34
|
-
def server_fetch_email(folder, uid)
|
35
|
-
examine folder
|
36
|
-
|
37
|
-
fetch_data_items = imap.uid_fetch([uid.to_i], REQUESTED_ATTRIBUTES)
|
38
|
-
return nil if fetch_data_items.nil?
|
39
|
-
|
40
|
-
fetch_data_item = fetch_data_items[0]
|
41
|
-
fetch_data_item.attr
|
42
|
-
end
|
43
|
-
|
44
|
-
def delete_emails(folder)
|
45
|
-
imap.select(folder)
|
46
|
-
uids = imap.uid_search(["ALL"]).sort
|
47
|
-
imap.store(1..uids.size, "+FLAGS", [:Deleted])
|
48
|
-
imap.expunge
|
49
|
-
end
|
50
|
-
|
51
|
-
def examine(folder)
|
52
|
-
imap.examine(folder)
|
53
|
-
end
|
54
|
-
|
55
|
-
def server_uids(folder)
|
56
|
-
examine(folder)
|
57
|
-
imap.uid_search(["ALL"]).sort
|
58
|
-
end
|
59
|
-
|
60
|
-
def server_uid_validity(folder)
|
61
|
-
examine(folder)
|
62
|
-
imap.responses["UIDVALIDITY"][0]
|
63
|
-
end
|
64
|
-
|
65
|
-
def server_folders
|
66
|
-
imap.list(root, "*")
|
67
|
-
end
|
68
|
-
|
69
|
-
def root
|
70
|
-
root_info = imap.list("", "")[0]
|
71
|
-
root_info.name
|
72
|
-
end
|
73
|
-
|
74
|
-
def server_create_folder(folder)
|
75
|
-
imap.create(folder)
|
76
|
-
imap.disconnect
|
77
|
-
@imap = nil
|
78
|
-
end
|
79
|
-
|
80
|
-
def server_rename_folder(from, to)
|
81
|
-
imap.rename(from, to)
|
82
|
-
imap.disconnect
|
83
|
-
@imap = nil
|
84
|
-
end
|
85
|
-
|
86
|
-
def server_delete_folder(folder)
|
87
|
-
imap.delete folder
|
88
|
-
imap.disconnect
|
89
|
-
rescue StandardError => e
|
90
|
-
ensure
|
91
|
-
@imap = nil
|
92
|
-
end
|
93
|
-
|
94
|
-
def imap
|
95
|
-
@imap ||=
|
96
|
-
begin
|
97
|
-
connection = fixture("connection")
|
98
|
-
imap = Net::IMAP.new(
|
99
|
-
connection[:server], connection[:connection_options]
|
100
|
-
)
|
101
|
-
imap.login(connection[:username], connection[:password])
|
102
|
-
imap
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
RSpec.configure do |config|
|
108
|
-
config.include EmailServerHelpers, type: :aruba
|
109
|
-
config.include EmailServerHelpers, type: :feature
|
110
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
shared_context "imap-backup connection" do
|
2
|
-
let(:local_backup_path) { Dir.mktmpdir(nil, "tmp") }
|
3
|
-
let(:default_connection) { fixture("connection") }
|
4
|
-
let(:backup_folders) { nil }
|
5
|
-
let(:account) do
|
6
|
-
Imap::Backup::Account.new(
|
7
|
-
default_connection.merge(
|
8
|
-
local_path: local_backup_path,
|
9
|
-
folders: backup_folders
|
10
|
-
)
|
11
|
-
)
|
12
|
-
end
|
13
|
-
let(:connection) { Imap::Backup::Account::Connection.new(account) }
|
14
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
shared_context "message-fixtures" do
|
2
|
-
let(:uid1) { 123 }
|
3
|
-
let(:uid2) { 345 }
|
4
|
-
let(:uid3) { 567 }
|
5
|
-
let(:uid_iso8859) { 890 }
|
6
|
-
let(:msg1) { {uid: uid1, subject: "Test 1", body: "body 1\nHi"} }
|
7
|
-
let(:msg2) { {uid: uid2, subject: "Test 2", body: "body 2"} }
|
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
|
16
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require "rspec"
|
2
|
-
|
3
|
-
$LOAD_PATH << File.expand_path("../lib", __dir__)
|
4
|
-
|
5
|
-
support_glob = File.join(__dir__, "support", "**", "*.rb")
|
6
|
-
Dir[support_glob].sort.each { |f| require f }
|
7
|
-
|
8
|
-
require "simplecov"
|
9
|
-
|
10
|
-
SimpleCov.command_name "RSpec tests"
|
11
|
-
|
12
|
-
require "imap/backup"
|
13
|
-
require "imap/backup/cli"
|
14
|
-
|
15
|
-
silence_logging
|
data/spec/support/fixtures.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require "erb"
|
2
|
-
require "yaml"
|
3
|
-
|
4
|
-
def fixture(name)
|
5
|
-
spec_root = File.expand_path("..", File.dirname(__FILE__))
|
6
|
-
fixture_path = File.join(spec_root, "fixtures", "#{name}.yml")
|
7
|
-
content = File.read(fixture_path)
|
8
|
-
template = ERB.new(content)
|
9
|
-
yaml = template.result(binding)
|
10
|
-
YAML.safe_load(yaml, [Symbol])
|
11
|
-
end
|
@@ -1,177 +0,0 @@
|
|
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
|
29
|
-
|
30
|
-
describe Email::Mboxrd::Message do
|
31
|
-
subject { described_class.new(message_body) }
|
32
|
-
|
33
|
-
let(:from) { "me@example.com" }
|
34
|
-
let(:date) { DateTime.new(2012, 12, 13, 18, 23, 45) }
|
35
|
-
let(:message_body) do
|
36
|
-
instance_double(String, clone: cloned_message_body, force_encoding: nil)
|
37
|
-
end
|
38
|
-
let(:cloned_message_body) do
|
39
|
-
"Foo\nBar\nFrom at the beginning of the line\n>>From quoted"
|
40
|
-
end
|
41
|
-
let(:msg_good) do
|
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
|
49
|
-
end
|
50
|
-
|
51
|
-
let(:msg_bad_date) do
|
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
|
59
|
-
end
|
60
|
-
|
61
|
-
describe ".from_serialized" do
|
62
|
-
let(:serialized_message) { "From foo@a.com\n#{imap_message}" }
|
63
|
-
let(:imap_message) { "Delivered-To: me@example.com\nFrom Me\n" }
|
64
|
-
let!(:result) { described_class.from_serialized(serialized_message) }
|
65
|
-
|
66
|
-
it "returns the message" do
|
67
|
-
expect(result).to be_a(described_class)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "removes one level of > before From" do
|
71
|
-
expect(result.supplied_body).to eq(imap_message)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe "#to_serialized" do
|
76
|
-
let(:mail) { instance_double(Mail::Message, from: [from], date: date) }
|
77
|
-
|
78
|
-
before do
|
79
|
-
allow(Mail).to receive(:new).with(cloned_message_body) { mail }
|
80
|
-
end
|
81
|
-
|
82
|
-
it "adds a 'From ' line at the start" do
|
83
|
-
expected = "From #{from} #{date.asctime}\n"
|
84
|
-
expect(subject.to_serialized).to start_with(expected)
|
85
|
-
end
|
86
|
-
|
87
|
-
it "replaces existing 'From ' with '>From '" do
|
88
|
-
expect(subject.to_serialized).to include("\n>From at the beginning")
|
89
|
-
end
|
90
|
-
|
91
|
-
it "appends > before '>+From '" do
|
92
|
-
expect(subject.to_serialized).to include("\n>>>From quoted")
|
93
|
-
end
|
94
|
-
|
95
|
-
context "when date is missing" do
|
96
|
-
let(:date) { nil }
|
97
|
-
|
98
|
-
it "does no fail" do
|
99
|
-
expect { subject.to_serialized }.to_not raise_error
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "From" do
|
105
|
-
before do
|
106
|
-
# call original for these tests because we want to test the behaviour of
|
107
|
-
# class-under-test given different behaviour of the Mail parser
|
108
|
-
allow(Mail).to receive(:new).and_call_original
|
109
|
-
end
|
110
|
-
|
111
|
-
context "when original message 'from' is missing" do
|
112
|
-
let(:message_body) { msg_no_from }
|
113
|
-
|
114
|
-
it "'from' is empty string" do
|
115
|
-
expect(subject.to_serialized).to start_with("From \n")
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context "when original message 'from' is not a well-formed address" do
|
120
|
-
let(:message_body) { msg_bad_from }
|
121
|
-
|
122
|
-
it "'from' is empty string" do
|
123
|
-
expect(subject.to_serialized).to start_with("From \n")
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
context "when original message 'from' is nil and " \
|
128
|
-
"'envelope from' is nil and 'return path' is available" do
|
129
|
-
let(:message_body) { msg_no_from_but_return_path }
|
130
|
-
|
131
|
-
it "'return path' is used as 'from'" do
|
132
|
-
expect(subject.to_serialized).to start_with("From #{from}\n")
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context "with no from and a 'Sender'" do
|
137
|
-
let(:message_body) { msg_no_from_but_sender }
|
138
|
-
|
139
|
-
it "Sender is used as 'from'" do
|
140
|
-
expect(subject.to_serialized).to start_with("From #{from}\n")
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
describe "#date" do
|
146
|
-
let(:message_body) { msg_good }
|
147
|
-
|
148
|
-
it "returns the date" do
|
149
|
-
expect(subject.date).to eq(date)
|
150
|
-
end
|
151
|
-
|
152
|
-
context "with incorrect minutes and seconds" do
|
153
|
-
let(:message_body) { msg_bad_date }
|
154
|
-
|
155
|
-
it "returns nil" do
|
156
|
-
expect(subject.date).to be_nil
|
157
|
-
end
|
158
|
-
end
|
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
|
177
|
-
end
|