imap-backup 5.0.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 +8 -7
- data/bin/imap-backup +4 -0
- data/docs/development.md +10 -4
- data/imap-backup.gemspec +2 -7
- data/lib/cli_coverage.rb +18 -0
- data/lib/imap/backup/account/connection.rb +7 -11
- data/lib/imap/backup/account/folder.rb +0 -16
- 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/restore.rb +20 -4
- data/lib/imap/backup/cli/utils.rb +2 -2
- data/lib/imap/backup/cli.rb +6 -7
- 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 +2 -2
- data/lib/imap/backup.rb +0 -1
- data/spec/features/backup_spec.rb +22 -29
- data/spec/features/restore_spec.rb +8 -6
- data/spec/features/support/aruba.rb +12 -3
- data/spec/features/support/backup_directory.rb +0 -4
- data/spec/features/support/email_server.rb +0 -1
- data/spec/spec_helper.rb +4 -9
- data/spec/unit/imap/backup/account/connection_spec.rb +36 -8
- data/spec/unit/imap/backup/account/folder_spec.rb +18 -16
- 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 +60 -8
- data/spec/unit/imap/backup/logger_spec.rb +1 -1
- 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 +44 -37
- data/lib/imap/backup/serializer/mbox_store.rb +0 -217
- data/lib/thunderbird/install.rb +0 -16
- data/lib/thunderbird/local_folder.rb +0 -65
- data/lib/thunderbird/profile.rb +0 -30
- data/lib/thunderbird/profiles.rb +0 -71
- data/lib/thunderbird/subdirectory.rb +0 -93
- data/lib/thunderbird/subdirectory_placeholder.rb +0 -21
- data/lib/thunderbird.rb +0 -14
- data/spec/gather_rspec_coverage.rb +0 -1
- data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +0 -329
@@ -1,8 +1,9 @@
|
|
1
1
|
require "imap/backup/cli/accounts"
|
2
2
|
|
3
3
|
describe Imap::Backup::CLI::Accounts do
|
4
|
-
subject { described_class.new }
|
4
|
+
subject { described_class.new(required_accounts) }
|
5
5
|
|
6
|
+
let(:required_accounts) { [] }
|
6
7
|
let(:accounts) { [account1, account2] }
|
7
8
|
let(:account1) do
|
8
9
|
instance_double(
|
@@ -43,5 +44,15 @@ describe Imap::Backup::CLI::Accounts do
|
|
43
44
|
end.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
|
44
45
|
end
|
45
46
|
end
|
47
|
+
|
48
|
+
context "when an account list is provided" do
|
49
|
+
let(:required_accounts) { %w(a2@example.com) }
|
50
|
+
|
51
|
+
specify "calls the block with each account" do
|
52
|
+
result = subject.map { |a| a }
|
53
|
+
|
54
|
+
expect(result).to eq([account2])
|
55
|
+
end
|
56
|
+
end
|
46
57
|
end
|
47
58
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
describe CLI::Backup do
|
3
|
+
subject { described_class.new({}) }
|
4
|
+
|
5
|
+
let(:connection) { instance_double(Account::Connection, run_backup: nil) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
# rubocop:disable RSpec/SubjectStub
|
9
|
+
allow(subject).to receive(:each_connection).with([]).and_yield(connection)
|
10
|
+
# rubocop:enable RSpec/SubjectStub
|
11
|
+
end
|
12
|
+
|
13
|
+
it "runs the backup for each connection" do
|
14
|
+
subject.run
|
15
|
+
|
16
|
+
expect(connection).to have_received(:run_backup)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
describe CLI::Folders do
|
3
|
+
subject { described_class.new({}) }
|
4
|
+
|
5
|
+
let(:connection) do
|
6
|
+
instance_double(
|
7
|
+
Account::Connection, account: account, folder_names: folder_names
|
8
|
+
)
|
9
|
+
end
|
10
|
+
let(:account) { instance_double(Account, username: "user") }
|
11
|
+
let(:folder_names) { ["my-folder"] }
|
12
|
+
|
13
|
+
before do
|
14
|
+
allow(Kernel).to receive(:puts)
|
15
|
+
allow(Kernel).to receive(:warn)
|
16
|
+
# rubocop:disable RSpec/SubjectStub
|
17
|
+
allow(subject).to receive(:each_connection).with([]).and_yield(connection)
|
18
|
+
# rubocop:enable RSpec/SubjectStub
|
19
|
+
|
20
|
+
subject.run
|
21
|
+
end
|
22
|
+
|
23
|
+
it "lists folders" do
|
24
|
+
expect(Kernel).to have_received(:puts).with("\tmy-folder")
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the folder list is not fetched" do
|
28
|
+
let(:folder_names) { nil }
|
29
|
+
|
30
|
+
it "warns" do
|
31
|
+
expect(Kernel).to have_received(:warn).with(/Unable to list/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "doesn't fail" do
|
35
|
+
subject.run
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -23,20 +23,22 @@ describe Imap::Backup::CLI::Local do
|
|
23
23
|
let(:folder) { instance_double(Imap::Backup::Account::Folder, name: "bar") }
|
24
24
|
let(:serializer) do
|
25
25
|
instance_double(
|
26
|
-
Imap::Backup::Serializer
|
26
|
+
Imap::Backup::Serializer,
|
27
27
|
uids: uids,
|
28
|
-
each_message:
|
28
|
+
each_message: each_message
|
29
29
|
)
|
30
30
|
end
|
31
31
|
let(:uids) { ["123"] }
|
32
|
+
let(:each_message) { [[123, message]] }
|
32
33
|
let(:message) do
|
33
34
|
instance_double(
|
34
35
|
Email::Mboxrd::Message,
|
35
36
|
date: Date.today,
|
36
|
-
subject:
|
37
|
+
subject: message_subject,
|
37
38
|
supplied_body: "Supplied"
|
38
39
|
)
|
39
40
|
end
|
41
|
+
let(:message_subject) { "Ciao" }
|
40
42
|
let(:email) { "foo@example.com" }
|
41
43
|
|
42
44
|
before do
|
@@ -64,18 +66,35 @@ describe Imap::Backup::CLI::Local do
|
|
64
66
|
end
|
65
67
|
|
66
68
|
describe "list" do
|
67
|
-
|
68
|
-
subject.list(email, "bar")
|
69
|
+
before { subject.list(email, "bar") }
|
69
70
|
|
71
|
+
it "lists downloaded emails" do
|
70
72
|
expect(Kernel).to have_received(:puts).with(/Ciao/)
|
71
73
|
end
|
74
|
+
|
75
|
+
context "when the subject line is too long" do
|
76
|
+
let(:message_subject) { "A" * 70 }
|
77
|
+
|
78
|
+
it "is shortened" do
|
79
|
+
expect(Kernel).to have_received(:puts).with(/\sA{57}\.\.\./)
|
80
|
+
end
|
81
|
+
end
|
72
82
|
end
|
73
83
|
|
74
84
|
describe "show" do
|
75
|
-
|
76
|
-
subject.show(email, "bar", "123")
|
85
|
+
before { subject.show(email, "bar", uids.join(",")) }
|
77
86
|
|
87
|
+
it "prints a downloaded email" do
|
78
88
|
expect(Kernel).to have_received(:puts).with("Supplied")
|
79
89
|
end
|
90
|
+
|
91
|
+
context "when more than one email is requested" do
|
92
|
+
let(:uids) { %w(123 456) }
|
93
|
+
let(:each_message) { [[123, message], [456, message]] }
|
94
|
+
|
95
|
+
it "prints a header" do
|
96
|
+
expect(Kernel).to have_received(:puts).with(/\| UID: 123 /)
|
97
|
+
end
|
98
|
+
end
|
80
99
|
end
|
81
100
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
describe CLI::Migrate do
|
3
|
+
subject { described_class.new(source, destination, **options) }
|
4
|
+
|
5
|
+
let(:source) { "source" }
|
6
|
+
let(:destination) { "destination" }
|
7
|
+
let(:options) { {} }
|
8
|
+
let(:config) { instance_double(Configuration, accounts: [account1, account2]) }
|
9
|
+
let(:account1) { instance_double(Account, username: "source", local_path: "path") }
|
10
|
+
let(:account2) { instance_double(Account, username: "destination", connection: connection) }
|
11
|
+
let(:connection) { instance_double(Account::Connection) }
|
12
|
+
let(:migrator) { instance_double(Migrator, run: nil) }
|
13
|
+
let(:imap_pathname) { Pathname.new("path/foo.imap") }
|
14
|
+
|
15
|
+
before do
|
16
|
+
allow(Configuration).to receive(:new) { config }
|
17
|
+
allow(Pathname).to receive(:glob).and_yield(imap_pathname)
|
18
|
+
allow(Migrator).to receive(:new) { migrator }
|
19
|
+
allow(Account::Folder).to receive(:new).and_call_original
|
20
|
+
end
|
21
|
+
|
22
|
+
it "migrates each folder" do
|
23
|
+
subject.run
|
24
|
+
|
25
|
+
expect(migrator).to have_received(:run)
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when source and destination emails are the same" do
|
29
|
+
let(:destination) { "source" }
|
30
|
+
|
31
|
+
it "fails" do
|
32
|
+
expect do
|
33
|
+
subject.run
|
34
|
+
end.to raise_error(RuntimeError, /cannot be the same/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when the source account is not found" do
|
39
|
+
let(:source) { "unknown" }
|
40
|
+
|
41
|
+
it "fails" do
|
42
|
+
expect do
|
43
|
+
subject.run
|
44
|
+
end.to raise_error(RuntimeError, /does not exist/)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when the destination account is not found" do
|
49
|
+
let(:destination) { "unknown" }
|
50
|
+
|
51
|
+
it "fails" do
|
52
|
+
expect do
|
53
|
+
subject.run
|
54
|
+
end.to raise_error(RuntimeError, /does not exist/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when source_prefix is supplied" do
|
59
|
+
let(:options) { {source_prefix: "src/"} }
|
60
|
+
let(:imap_pathname) { Pathname.new("path/src/foo.imap") }
|
61
|
+
|
62
|
+
it "removes the prefix" do
|
63
|
+
subject.run
|
64
|
+
|
65
|
+
expect(Account::Folder).to have_received(:new).with(anything, "foo")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when destination_prefix is supplied" do
|
70
|
+
let(:options) { {destination_prefix: "dest/"} }
|
71
|
+
let(:imap_pathname) { Pathname.new("path/foo.imap") }
|
72
|
+
|
73
|
+
it "removes the prefix" do
|
74
|
+
subject.run
|
75
|
+
|
76
|
+
expect(Account::Folder).to have_received(:new).with(anything, "dest/foo")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# rubocop:disable RSpec/SubjectStub
|
2
|
+
module Imap::Backup
|
3
|
+
describe CLI::Restore do
|
4
|
+
subject { described_class.new(email, options) }
|
5
|
+
|
6
|
+
let(:connection) { instance_double(Account::Connection, restore: nil) }
|
7
|
+
|
8
|
+
describe "#run" do
|
9
|
+
context "when an email is provided" do
|
10
|
+
let(:email) { "email" }
|
11
|
+
let(:options) { {} }
|
12
|
+
|
13
|
+
before do
|
14
|
+
allow(subject).to receive(:connection).with(email) { connection }
|
15
|
+
|
16
|
+
subject.run
|
17
|
+
end
|
18
|
+
|
19
|
+
it "runs restore on the account" do
|
20
|
+
expect(connection).to have_received(:restore)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when neither an email nor a list of account names is provided" do
|
25
|
+
let(:email) { nil }
|
26
|
+
let(:options) { {} }
|
27
|
+
|
28
|
+
before do
|
29
|
+
allow(subject).to receive(:each_connection).with([]).and_yield(connection)
|
30
|
+
|
31
|
+
subject.run
|
32
|
+
end
|
33
|
+
|
34
|
+
it "runs restore on each account" do
|
35
|
+
expect(connection).to have_received(:restore)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when an email and a list of account names is provided" do
|
40
|
+
let(:email) { "email" }
|
41
|
+
let(:options) { {accounts: "email2"} }
|
42
|
+
|
43
|
+
it "fails" do
|
44
|
+
expect do
|
45
|
+
subject.run
|
46
|
+
end.to raise_error(RuntimeError, /Pass either an email or the --accounts option/)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when just a list of account names is provided" do
|
51
|
+
let(:email) { nil }
|
52
|
+
let(:options) { {accounts: "email2"} }
|
53
|
+
|
54
|
+
before do
|
55
|
+
allow(subject).to receive(:each_connection).with(["email2"]).and_yield(connection)
|
56
|
+
|
57
|
+
subject.run
|
58
|
+
end
|
59
|
+
|
60
|
+
it "runs restore on each account" do
|
61
|
+
expect(connection).to have_received(:restore)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# rubocop:enable RSpec/SubjectStub
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
describe CLI::Setup do
|
3
|
+
subject { described_class.new }
|
4
|
+
|
5
|
+
let(:setup) { instance_double(Setup, run: nil) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Setup).to receive(:new) { setup }
|
9
|
+
end
|
10
|
+
|
11
|
+
it "reruns the setup process" do
|
12
|
+
subject.run
|
13
|
+
|
14
|
+
expect(setup).to have_received(:run)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -11,7 +11,8 @@ module Imap::Backup
|
|
11
11
|
instance_double(
|
12
12
|
Account::Connection,
|
13
13
|
account: account,
|
14
|
-
backup_folders: [folder]
|
14
|
+
backup_folders: [folder],
|
15
|
+
local_folders: ["folder"]
|
15
16
|
)
|
16
17
|
end
|
17
18
|
let(:account) do
|
@@ -31,18 +32,80 @@ module Imap::Backup
|
|
31
32
|
end
|
32
33
|
let(:serializer) do
|
33
34
|
instance_double(
|
34
|
-
Serializer
|
35
|
+
Serializer,
|
35
36
|
uids: %w(123 789),
|
36
37
|
apply_uid_validity: nil,
|
37
|
-
|
38
|
+
append: nil
|
38
39
|
)
|
39
40
|
end
|
41
|
+
let(:exporter) { instance_double(Thunderbird::MailboxExporter, run: nil) }
|
40
42
|
let(:email) { "foo@example.com" }
|
41
43
|
|
42
44
|
before do
|
43
45
|
allow(CLI::Accounts).to receive(:new) { accounts }
|
44
46
|
allow(Account::Connection).to receive(:new) { connection }
|
45
|
-
allow(Serializer
|
47
|
+
allow(Serializer).to receive(:new) { serializer }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#export_to_thunderbird" do
|
51
|
+
let(:command) { subject.export_to_thunderbird(email) }
|
52
|
+
let(:options) { {} }
|
53
|
+
let(:profiles) { instance_double(Thunderbird::Profiles, installs: installs, profile: named_profile) }
|
54
|
+
let(:installs) { [install1] }
|
55
|
+
let(:install1) { instance_double(Thunderbird::Install, default: default_install) }
|
56
|
+
let(:default_install) { "default" }
|
57
|
+
let(:named_profile) { "named" }
|
58
|
+
|
59
|
+
before do
|
60
|
+
allow(Thunderbird::MailboxExporter).to receive(:new) { exporter }
|
61
|
+
allow(Thunderbird::Profiles).to receive(:new) { profiles }
|
62
|
+
# rubocop:disable RSpec/SubjectStub
|
63
|
+
allow(subject).to receive(:options) { options }
|
64
|
+
# rubocop:enable RSpec/SubjectStub
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when no profile_name is supplied" do
|
68
|
+
context "when no default Thunderbird profile is found" do
|
69
|
+
let(:default_install) { nil }
|
70
|
+
|
71
|
+
it "fails" do
|
72
|
+
expect do
|
73
|
+
command
|
74
|
+
end.to raise_error(RuntimeError, /Default .*? not found/)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when there is more than one install" do
|
79
|
+
let(:installs) { [install1, install2] }
|
80
|
+
let(:install2) { instance_double(Thunderbird::Install, default: default_install) }
|
81
|
+
|
82
|
+
it "fails" do
|
83
|
+
expect do
|
84
|
+
command
|
85
|
+
end.to raise_error(RuntimeError, /multiple installs.*?supply a profile name/m)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when a profile_name is supplied" do
|
91
|
+
let(:options) { {"profile" => "profile"} }
|
92
|
+
|
93
|
+
context "when the supplied profile_name is not found" do
|
94
|
+
let(:named_profile) { nil }
|
95
|
+
|
96
|
+
it "fails" do
|
97
|
+
expect do
|
98
|
+
command
|
99
|
+
end.to raise_error(RuntimeError, /profile 'profile' not found/)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "exports the profile" do
|
105
|
+
command
|
106
|
+
|
107
|
+
expect(exporter).to have_received(:run)
|
108
|
+
end
|
46
109
|
end
|
47
110
|
|
48
111
|
describe "ignore_history" do
|
@@ -55,7 +118,7 @@ module Imap::Backup
|
|
55
118
|
it "fills the local folder with fake emails" do
|
56
119
|
subject.ignore_history(email)
|
57
120
|
|
58
|
-
expect(serializer).to have_received(:
|
121
|
+
expect(serializer).to have_received(:append).with("456", /From: fake@email.com/)
|
59
122
|
end
|
60
123
|
end
|
61
124
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
RSpec.describe CLI do
|
3
|
+
describe ".exit_on_failure?" do
|
4
|
+
it "is true" do
|
5
|
+
expect(described_class.exit_on_failure?).to be true
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#backup" do
|
10
|
+
let(:backup) { instance_double(CLI::Backup, run: nil) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(CLI::Backup).to receive(:new) { backup }
|
14
|
+
|
15
|
+
subject.backup
|
16
|
+
end
|
17
|
+
|
18
|
+
it "runs Backup" do
|
19
|
+
expect(backup).to have_received(:run)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#folders" do
|
24
|
+
let(:folders) { instance_double(CLI::Folders, run: nil) }
|
25
|
+
|
26
|
+
before do
|
27
|
+
allow(CLI::Folders).to receive(:new) { folders }
|
28
|
+
|
29
|
+
subject.folders
|
30
|
+
end
|
31
|
+
|
32
|
+
it "runs folders" do
|
33
|
+
expect(folders).to have_received(:run)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#migrate" do
|
38
|
+
let(:migrate) { instance_double(CLI::Migrate, run: nil) }
|
39
|
+
|
40
|
+
before do
|
41
|
+
allow(CLI::Migrate).to receive(:new) { migrate }
|
42
|
+
|
43
|
+
subject.migrate("source", "destination")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "runs migrate" do
|
47
|
+
expect(migrate).to have_received(:run)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#restore" do
|
52
|
+
let(:restore) { instance_double(CLI::Restore, run: nil) }
|
53
|
+
|
54
|
+
before do
|
55
|
+
allow(CLI::Restore).to receive(:new) { restore }
|
56
|
+
|
57
|
+
subject.restore
|
58
|
+
end
|
59
|
+
|
60
|
+
it "runs restore" do
|
61
|
+
expect(restore).to have_received(:run)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#setup" do
|
66
|
+
let(:setup) { instance_double(CLI::Setup, run: nil) }
|
67
|
+
|
68
|
+
before do
|
69
|
+
allow(CLI::Setup).to receive(:new) { setup }
|
70
|
+
|
71
|
+
subject.setup
|
72
|
+
end
|
73
|
+
|
74
|
+
it "runs setup" do
|
75
|
+
expect(setup).to have_received(:run)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#status" do
|
80
|
+
let(:status) { instance_double(CLI::Status, run: nil) }
|
81
|
+
|
82
|
+
before do
|
83
|
+
allow(CLI::Status).to receive(:new) { status }
|
84
|
+
|
85
|
+
subject.status
|
86
|
+
end
|
87
|
+
|
88
|
+
it "runs status" do
|
89
|
+
expect(status).to have_received(:run)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -59,7 +59,7 @@ describe Imap::Backup::Configuration do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
context "with accounts flagged 'delete'" do
|
62
|
-
before { subject.accounts[0].mark_for_deletion
|
62
|
+
before { subject.accounts[0].mark_for_deletion }
|
63
63
|
|
64
64
|
it "is true" do
|
65
65
|
expect(subject.modified?).to be_truthy
|
@@ -177,7 +177,7 @@ describe Imap::Backup::Configuration do
|
|
177
177
|
before do
|
178
178
|
allow(subject.accounts[0]).to receive(:to_h) { "Account1" }
|
179
179
|
allow(subject.accounts[1]).to receive(:to_h) { "Account2" }
|
180
|
-
subject.accounts[0].mark_for_deletion
|
180
|
+
subject.accounts[0].mark_for_deletion
|
181
181
|
end
|
182
182
|
|
183
183
|
it "does not save them" do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
describe Imap::Backup::Downloader do
|
2
2
|
describe "#run" do
|
3
|
-
subject { described_class.new(folder, serializer) }
|
3
|
+
subject { described_class.new(folder, serializer, **options) }
|
4
4
|
|
5
5
|
let(:body) { "blah" }
|
6
6
|
let(:folder) do
|
@@ -8,17 +8,19 @@ describe Imap::Backup::Downloader do
|
|
8
8
|
Imap::Backup::Account::Folder,
|
9
9
|
fetch_multi: [{uid: "111", body: body}],
|
10
10
|
name: "folder",
|
11
|
-
uids:
|
11
|
+
uids: remote_uids
|
12
12
|
)
|
13
13
|
end
|
14
|
-
let(:
|
14
|
+
let(:remote_uids) { %w(111 222 333) }
|
15
15
|
let(:serializer) do
|
16
|
-
instance_double(Imap::Backup::Serializer
|
16
|
+
instance_double(Imap::Backup::Serializer, append: nil, uids: local_uids)
|
17
17
|
end
|
18
|
+
let(:local_uids) { ["222"] }
|
19
|
+
let(:options) { {} }
|
18
20
|
|
19
21
|
context "with fetched messages" do
|
20
22
|
specify "are saved" do
|
21
|
-
expect(serializer).to receive(:
|
23
|
+
expect(serializer).to receive(:append).with("111", body)
|
22
24
|
|
23
25
|
subject.run
|
24
26
|
end
|
@@ -26,7 +28,7 @@ describe Imap::Backup::Downloader do
|
|
26
28
|
|
27
29
|
context "with messages which are already present" do
|
28
30
|
specify "are skipped" do
|
29
|
-
expect(serializer).to_not receive(:
|
31
|
+
expect(serializer).to_not receive(:append).with("222", anything)
|
30
32
|
|
31
33
|
subject.run
|
32
34
|
end
|
@@ -34,11 +36,61 @@ describe Imap::Backup::Downloader do
|
|
34
36
|
|
35
37
|
context "with failed fetches" do
|
36
38
|
specify "are skipped" do
|
37
|
-
allow(folder).to receive(:
|
38
|
-
expect(serializer).to_not receive(:
|
39
|
+
allow(folder).to receive(:fetch_multi) { nil }
|
40
|
+
expect(serializer).to_not receive(:append)
|
39
41
|
|
40
42
|
subject.run
|
41
43
|
end
|
42
44
|
end
|
45
|
+
|
46
|
+
context "when the block size is greater than one" do
|
47
|
+
let(:remote_uids) { %w(111 999) }
|
48
|
+
let(:local_uids) { [] }
|
49
|
+
let(:options) { {multi_fetch_size: 2} }
|
50
|
+
|
51
|
+
context "when the first fetch fails" do
|
52
|
+
before do
|
53
|
+
allow(folder).to receive(:fetch_multi).with(["111", "999"]) { nil }
|
54
|
+
allow(folder).to receive(:fetch_multi).with(["111"]).
|
55
|
+
and_return([{uid: "111", body: body}]).
|
56
|
+
and_return([{uid: "999", body: body}])
|
57
|
+
|
58
|
+
subject.run
|
59
|
+
end
|
60
|
+
|
61
|
+
it "retries fetching messages singly" do
|
62
|
+
expect(serializer).to have_received(:append).with("111", body)
|
63
|
+
expect(serializer).to have_received(:append).with("999", body)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when no body is returned by the fetch" do
|
69
|
+
let(:remote_uids) { %w(111) }
|
70
|
+
|
71
|
+
before do
|
72
|
+
allow(folder).to receive(:fetch_multi).with(["111"]) { [{uid: "111", body: nil}] }
|
73
|
+
|
74
|
+
subject.run
|
75
|
+
end
|
76
|
+
|
77
|
+
it "skips the append" do
|
78
|
+
expect(serializer).to_not have_received(:append)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when the UID is not returned by the fetch" do
|
83
|
+
let(:remote_uids) { %w(111) }
|
84
|
+
|
85
|
+
before do
|
86
|
+
allow(folder).to receive(:fetch_multi).with(["111"]) { [{uid: nil, body: body}] }
|
87
|
+
|
88
|
+
subject.run
|
89
|
+
end
|
90
|
+
|
91
|
+
it "skips the append" do
|
92
|
+
expect(serializer).to_not have_received(:append)
|
93
|
+
end
|
94
|
+
end
|
43
95
|
end
|
44
96
|
end
|
@@ -4,7 +4,7 @@ module Imap::Backup
|
|
4
4
|
RSpec.describe Migrator do
|
5
5
|
subject { described_class.new(serializer, folder, reset: reset) }
|
6
6
|
|
7
|
-
let(:serializer) { instance_double(Serializer
|
7
|
+
let(:serializer) { instance_double(Serializer, uids: [1]) }
|
8
8
|
let(:folder) do
|
9
9
|
instance_double(
|
10
10
|
Account::Folder,
|