imap-backup 2.0.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rspec-all +2 -0
  4. data/.rubocop.yml +15 -2
  5. data/.rubocop_todo.yml +58 -0
  6. data/.travis.yml +15 -2
  7. data/README.md +14 -22
  8. data/Rakefile +6 -3
  9. data/bin/imap-backup +5 -11
  10. data/imap-backup.gemspec +10 -6
  11. data/lib/email/mboxrd/message.rb +16 -16
  12. data/lib/imap/backup/account/connection.rb +38 -22
  13. data/lib/imap/backup/account/folder.rb +23 -7
  14. data/lib/imap/backup/configuration/account.rb +25 -21
  15. data/lib/imap/backup/configuration/asker.rb +3 -2
  16. data/lib/imap/backup/configuration/connection_tester.rb +1 -1
  17. data/lib/imap/backup/configuration/folder_chooser.rb +32 -5
  18. data/lib/imap/backup/configuration/list.rb +2 -0
  19. data/lib/imap/backup/configuration/setup.rb +2 -1
  20. data/lib/imap/backup/configuration/store.rb +3 -6
  21. data/lib/imap/backup/downloader.rb +8 -7
  22. data/lib/imap/backup/serializer/mbox.rb +44 -25
  23. data/lib/imap/backup/serializer/mbox_enumerator.rb +31 -0
  24. data/lib/imap/backup/serializer/mbox_store.rb +35 -32
  25. data/lib/imap/backup/uploader.rb +11 -2
  26. data/lib/imap/backup/utils.rb +11 -9
  27. data/lib/imap/backup/version.rb +2 -2
  28. data/spec/features/backup_spec.rb +6 -5
  29. data/spec/features/helper.rb +1 -1
  30. data/spec/features/restore_spec.rb +75 -27
  31. data/spec/features/support/backup_directory.rb +7 -7
  32. data/spec/features/support/email_server.rb +15 -11
  33. data/spec/features/support/shared/connection_context.rb +2 -2
  34. data/spec/features/support/shared/message_fixtures.rb +8 -0
  35. data/spec/spec_helper.rb +1 -1
  36. data/spec/support/fixtures.rb +2 -2
  37. data/spec/support/higline_test_helpers.rb +1 -1
  38. data/spec/unit/email/mboxrd/message_spec.rb +73 -53
  39. data/spec/unit/email/provider_spec.rb +3 -5
  40. data/spec/unit/imap/backup/account/connection_spec.rb +82 -59
  41. data/spec/unit/imap/backup/account/folder_spec.rb +75 -37
  42. data/spec/unit/imap/backup/configuration/account_spec.rb +95 -61
  43. data/spec/unit/imap/backup/configuration/asker_spec.rb +43 -45
  44. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +21 -22
  45. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +66 -33
  46. data/spec/unit/imap/backup/configuration/list_spec.rb +32 -11
  47. data/spec/unit/imap/backup/configuration/setup_spec.rb +97 -56
  48. data/spec/unit/imap/backup/configuration/store_spec.rb +30 -25
  49. data/spec/unit/imap/backup/downloader_spec.rb +28 -26
  50. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +45 -0
  51. data/spec/unit/imap/backup/serializer/mbox_spec.rb +109 -51
  52. data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +232 -20
  53. data/spec/unit/imap/backup/uploader_spec.rb +23 -9
  54. data/spec/unit/imap/backup/utils_spec.rb +14 -15
  55. data/spec/unit/imap/backup_spec.rb +28 -0
  56. metadata +13 -7
@@ -1,6 +1,6 @@
1
1
  module EmailServerHelpers
2
- REQUESTED_ATTRIBUTES = ["RFC822", "FLAGS", "INTERNALDATE"]
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
- #{body}
15
+ <<~MESSAGE.gsub("\n", "\r\n")
16
+ From: #{from}
17
+ Subject: #{subject}
19
18
 
20
- EOT
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
- attributes = fetch_data_item.attr
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 .. uids.size, "+FLAGS", [:Deleted])
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
@@ -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
@@ -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 + ".yml")
3
+ fixture_path = File.join(spec_root, "fixtures", "#{name}.yml")
4
4
  fixture = File.read(fixture_path)
5
- YAML.load(fixture)
5
+ YAML.safe_load(fixture, [Symbol])
6
6
  end
@@ -1,6 +1,6 @@
1
1
  module HighLineTestHelpers
2
2
  def prepare_highline
3
- @input = double("stdin", eof?: false, gets: "q\n")
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
- require "spec_helper"
2
-
3
- msg_no_from = %Q|Delivered-To: you@example.com
4
- From: example <www.example.com>
5
- To: FirstName LastName <you@example.com>
6
- Subject: Re: no subject|
7
-
8
- msg_bad_from = %Q|Delivered-To: you@example.com
9
- from: "FirstName LastName (TEXT)" <"TEXT*" <no-reply@example.com>>
10
- To: FirstName LastName <you@example.com>
11
- Subject: Re: no subject|
12
-
13
- msg_no_from_but_return_path = %Q|Delivered-To: you@example.com
14
- From: example <www.example.com>
15
- To: FirstName LastName <you@example.com>
16
- Return-Path: <me@example.com>
17
- Subject: Re: no subject|
18
-
19
- msg_no_from_but_sender = %Q|Delivered-To: you@example.com
20
- To: FirstName LastName <you@example.com>
21
- Subject: Re: no subject
22
- Sender: FistName LastName <me@example.com>|
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
- double("Body", clone: cloned_message_body, force_encoding: nil)
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
- %Q|Delivered-To: you@example.com
35
- From: Foo <foo@example.com>
36
- To: FirstName LastName <you@example.com>
37
- Date: #{date.rfc822}
38
- Subject: Re: no subject|
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
- %Q|Delivered-To: you@example.com
43
- From: Foo <foo@example.com>
44
- To: FirstName LastName <you@example.com>
45
- Date: Mon,5 May 2014 08:97:99 GMT
46
- Subject: Re: no subject|
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(@result).to be_a(described_class)
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(@result.supplied_body).to eq(imap_message)
71
+ expect(result.supplied_body).to eq(imap_message)
63
72
  end
64
73
  end
65
74
 
66
- context "#to_serialized" do
67
- let(:mail) { double("Mail", from: [from], date: date) }
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).and_return(mail)
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
- context "#from" do
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 string but not well-formed address" do
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 " + from + "\n")
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 " + from + "\n")
140
+ expect(subject.to_serialized).to start_with("From #{from}\n")
138
141
  end
139
142
  end
140
143
  end
141
144
 
142
- context "#date" do
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
- set_uid_validity: new_uid_validity,
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
- context "#initialize" do
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
- before { @result = subject.imap }
76
+ let!(:result) { subject.imap }
82
77
 
83
78
  it "returns the IMAP connection" do
84
- expect(@result).to eq(imap)
79
+ expect(result).to eq(imap)
85
80
  end
86
81
 
87
82
  include_examples "connects to IMAP"
88
83
  end
89
84
 
90
- context "#folders" do
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
- context "#status" do
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).and_return(folder)
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 "should return the names of folders" do
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 "should retrieve the available uids" do
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
- context "#run_backup" do
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).and_return(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).and_return(serializer)
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 have_received(:run)
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").and_return(folder)
169
+ with(subject, "foo") { folder }
163
170
  allow(Imap::Backup::Serializer::Mbox).to receive(:new).
164
- with(local_path, "foo").and_return(serializer)
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 have_received(:run).exactly(:once)
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 have_received(:run).exactly(:once)
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
- context "#restore" do
205
+ describe "#restore" do
199
206
  let(:folder) do
200
207
  instance_double(
201
208
  Imap::Backup::Account::Folder,
202
209
  create: nil,
203
- exist?: exists,
210
+ uids: uids,
204
211
  name: "my_folder",
205
212
  uid_validity: uid_validity
206
213
  )
207
214
  end
208
- let(:exists) { true }
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 have_received(:set_uid_validity).with(uid_validity)
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 have_received(:create)
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 have_received(:force_uid_validity).with("new uid validity")
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 have_received(:run)
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 have_received(:run)
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(:exists) { false }
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 have_received(:create)
297
+ expect(folder).to receive(:create)
298
+
299
+ subject.restore
282
300
  end
283
301
 
284
- it "sets local uid validity" do
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 have_received(:run)
309
+ expect(uploader).to receive(:run)
310
+
311
+ subject.restore
289
312
  end
290
313
  end
291
314
  end
292
315
 
293
- context "#reconnect" do
294
- before { subject.reconnect }
295
-
316
+ describe "#reconnect" do
296
317
  it "disconnects from the server" do
297
- expect(imap).to have_received(:disconnect)
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
- allow(Net::IMAP).to receive(:new) { imap }
302
- subject.imap
303
- expect(Net::IMAP).to have_received(:new).twice
324
+ expect(Net::IMAP).to receive(:new)
325
+
326
+ subject.reconnect
304
327
  end
305
328
  end
306
329
 
307
- context "#disconnect" do
308
- before { subject.disconnect }
309
-
330
+ describe "#disconnect" do
310
331
  it "disconnects from the server" do
311
- expect(imap).to have_received(:disconnect)
332
+ expect(imap).to receive(:disconnect)
333
+
334
+ subject.disconnect
312
335
  end
313
336
  end
314
337
  end