imap-backup 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/README.md +6 -2
  4. data/bin/imap-backup +1 -1
  5. data/lib/email/mboxrd/message.rb +0 -1
  6. data/lib/imap/backup/account/connection.rb +28 -21
  7. data/lib/imap/backup/account/folder.rb +0 -1
  8. data/lib/imap/backup/serializer/mbox_enumerator.rb +1 -1
  9. data/lib/imap/backup/uploader.rb +10 -1
  10. data/lib/imap/backup/version.rb +2 -2
  11. data/spec/features/restore_spec.rb +75 -27
  12. data/spec/features/support/email_server.rb +1 -3
  13. data/spec/features/support/shared/message_fixtures.rb +8 -0
  14. data/spec/unit/email/mboxrd/message_spec.rb +0 -6
  15. data/spec/unit/imap/backup/account/connection_spec.rb +58 -43
  16. data/spec/unit/imap/backup/account/folder_spec.rb +16 -20
  17. data/spec/unit/imap/backup/configuration/account_spec.rb +31 -25
  18. data/spec/unit/imap/backup/configuration/asker_spec.rb +20 -17
  19. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +6 -10
  20. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +16 -10
  21. data/spec/unit/imap/backup/configuration/list_spec.rb +6 -3
  22. data/spec/unit/imap/backup/configuration/setup_spec.rb +40 -25
  23. data/spec/unit/imap/backup/configuration/store_spec.rb +18 -16
  24. data/spec/unit/imap/backup/downloader_spec.rb +14 -14
  25. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +6 -1
  26. data/spec/unit/imap/backup/serializer/mbox_spec.rb +54 -40
  27. data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +49 -31
  28. data/spec/unit/imap/backup/uploader_spec.rb +20 -7
  29. data/spec/unit/imap/backup/utils_spec.rb +8 -9
  30. metadata +2 -2
@@ -20,11 +20,11 @@ describe Imap::Backup::Configuration::Store do
20
20
  allow(File).to receive(:exist?).and_call_original
21
21
  allow(File).to receive(:exist?).with(file_path) { file_exists }
22
22
  allow(Imap::Backup::Utils).
23
- to receive(:stat).with(directory).and_return(0o700)
23
+ to receive(:stat).with(directory) { 0o700 }
24
24
  allow(Imap::Backup::Utils).
25
- to receive(:stat).with(file_path).and_return(0o600)
26
- allow(Imap::Backup::Utils).to receive(:check_permissions).and_return(nil)
27
- allow(File).to receive(:read).with(file_path).and_return(configuration)
25
+ to receive(:stat).with(file_path) { 0o600 }
26
+ allow(Imap::Backup::Utils).to receive(:check_permissions) { nil }
27
+ allow(File).to receive(:read).with(file_path) { configuration }
28
28
  end
29
29
 
30
30
  describe ".exist?" do
@@ -140,19 +140,19 @@ describe Imap::Backup::Configuration::Store do
140
140
  allow(FileUtils).to receive(:mkdir)
141
141
  allow(FileUtils).to receive(:chmod)
142
142
  allow(File).to receive(:open).with(file_path, "w").and_yield(file)
143
- allow(JSON).to receive(:pretty_generate).and_return("JSON output")
143
+ allow(JSON).to receive(:pretty_generate) { "JSON output" }
144
144
  end
145
145
 
146
146
  it "creates the config directory" do
147
- subject.save
147
+ expect(FileUtils).to receive(:mkdir).with(directory)
148
148
 
149
- expect(FileUtils).to have_received(:mkdir).with(directory)
149
+ subject.save
150
150
  end
151
151
 
152
152
  it "saves the configuration" do
153
- subject.save
153
+ expect(file).to receive(:write).with("JSON output")
154
154
 
155
- expect(file).to have_received(:write).with("JSON output")
155
+ subject.save
156
156
  end
157
157
 
158
158
  context "when accounts are modified" do
@@ -164,7 +164,9 @@ describe Imap::Backup::Configuration::Store do
164
164
  expected = Marshal.load(Marshal.dump(data))
165
165
  expected[:accounts][0].delete(:modified)
166
166
 
167
- expect(JSON).to have_received(:pretty_generate).with(expected)
167
+ expect(JSON).to receive(:pretty_generate).with(expected)
168
+
169
+ subject.save
168
170
  end
169
171
  end
170
172
 
@@ -176,21 +178,21 @@ describe Imap::Backup::Configuration::Store do
176
178
  ]
177
179
  end
178
180
 
179
- before { subject.save }
180
-
181
181
  it "does not save them" do
182
182
  expected = Marshal.load(Marshal.dump(data))
183
183
  expected[:accounts].pop
184
184
 
185
- expect(JSON).to have_received(:pretty_generate).with(expected)
185
+ expect(JSON).to receive(:pretty_generate).with(expected)
186
+
187
+ subject.save
186
188
  end
187
189
  end
188
190
 
189
191
  context "when file permissions are too open" do
190
- before { subject.save }
191
-
192
192
  it "sets them to 0600" do
193
- expect(FileUtils).to have_received(:chmod).with(0o600, file_path)
193
+ expect(FileUtils).to receive(:chmod).with(0o600, file_path)
194
+
195
+ subject.save
194
196
  end
195
197
  end
196
198
 
@@ -7,37 +7,37 @@ describe Imap::Backup::Downloader do
7
7
  instance_double(
8
8
  Imap::Backup::Account::Folder,
9
9
  fetch: message,
10
- name: "folder"
10
+ name: "folder",
11
+ uids: folder_uids
11
12
  )
12
13
  end
13
14
  let(:folder_uids) { %w(111 222 333) }
14
15
  let(:serializer) do
15
- instance_double(Imap::Backup::Serializer::Mbox, save: nil)
16
- end
17
- let(:serializer_uids) { ["222"] }
18
-
19
- before do
20
- allow(folder).to receive(:uids).and_return(folder_uids)
21
- allow(serializer).to receive(:uids).and_return(serializer_uids)
22
- allow(folder).to receive(:fetch).with("333").and_return(nil)
23
- subject.run
16
+ instance_double(Imap::Backup::Serializer::Mbox, save: nil, uids: ["222"])
24
17
  end
25
18
 
26
19
  context "with fetched messages" do
27
- it "are saved" do
28
- expect(serializer).to have_received(:save).with("111", message)
20
+ specify "are saved" do
21
+ expect(serializer).to receive(:save).with("111", message)
22
+
23
+ subject.run
29
24
  end
30
25
  end
31
26
 
32
27
  context "with messages which are already present" do
33
28
  specify "are skipped" do
34
- expect(serializer).to_not have_received(:save).with("222", anything)
29
+ expect(serializer).to_not receive(:save).with("222", anything)
30
+
31
+ subject.run
35
32
  end
36
33
  end
37
34
 
38
35
  context "with failed fetches" do
39
36
  specify "are skipped" do
40
- expect(serializer).to_not have_received(:save).with("333", anything)
37
+ allow(folder).to receive(:fetch).with("333") { nil }
38
+ expect(serializer).to_not receive(:save).with("333", anything)
39
+
40
+ subject.run
41
41
  end
42
42
  end
43
43
  end
@@ -21,11 +21,16 @@ describe Imap::Backup::Serializer::MboxEnumerator do
21
21
 
22
22
  before do
23
23
  allow(File).to receive(:open).and_call_original
24
- allow(File).to receive(:open).with(mbox_pathname).and_yield(mbox_file)
24
+ allow(File).to receive(:open).with(mbox_pathname, "rb").and_yield(mbox_file)
25
25
  allow(mbox_file).to receive(:gets).and_return(*lines)
26
26
  end
27
27
 
28
28
  describe "#each" do
29
+ it "reads files as binary" do
30
+ expect(File).to receive(:open).with(mbox_pathname, "rb")
31
+ subject.each {}
32
+ end
33
+
29
34
  it "yields messages" do
30
35
  expect { |b| subject.each(&b) }.
31
36
  to yield_successive_args(message1.join, message2.join)
@@ -28,8 +28,6 @@ describe Imap::Backup::Serializer::Mbox do
28
28
  end
29
29
 
30
30
  describe "folder path" do
31
- before { subject.uids }
32
-
33
31
  context "when it has multiple elements" do
34
32
  let(:imap_folder) { "folder/path" }
35
33
 
@@ -37,8 +35,10 @@ describe Imap::Backup::Serializer::Mbox do
37
35
  let(:dir_exists) { false }
38
36
 
39
37
  it "is created" do
40
- expect(Imap::Backup::Utils).to have_received(:make_folder).
38
+ expect(Imap::Backup::Utils).to receive(:make_folder).
41
39
  with(base_path, File.dirname(imap_folder), 0o700)
40
+
41
+ subject.uids
42
42
  end
43
43
  end
44
44
  end
@@ -48,57 +48,66 @@ describe Imap::Backup::Serializer::Mbox do
48
48
 
49
49
  it "corrects them" do
50
50
  path = File.expand_path(File.join(base_path, File.dirname(imap_folder)))
51
- expect(FileUtils).to have_received(:chmod).with(0o700, path)
51
+ expect(FileUtils).to receive(:chmod).with(0o700, path)
52
+
53
+ subject.uids
52
54
  end
53
55
  end
54
56
 
55
57
  context "when permissons are correct" do
56
58
  it "does nothing" do
57
- expect(FileUtils).to_not have_received(:chmod)
59
+ expect(FileUtils).to_not receive(:chmod)
60
+
61
+ subject.uids
58
62
  end
59
63
  end
60
64
 
61
65
  context "when it exists" do
62
66
  it "is not created" do
63
- expect(Imap::Backup::Utils).to_not have_received(:make_folder).
67
+ expect(Imap::Backup::Utils).to_not receive(:make_folder).
64
68
  with(base_path, File.dirname(imap_folder), 0o700)
69
+
70
+ subject.uids
65
71
  end
66
72
  end
67
73
  end
68
74
 
69
75
  describe "#apply_uid_validity" do
70
- let(:result) { subject.apply_uid_validity("aaa") }
71
-
72
76
  context "when the existing uid validity is unset" do
73
- let!(:result) { super() }
74
-
75
77
  it "sets uid validity" do
76
- expect(store).to have_received(:uid_validity=).with("aaa")
78
+ expect(store).to receive(:uid_validity=).with("aaa")
79
+
80
+ subject.apply_uid_validity("aaa")
77
81
  end
78
82
 
79
83
  it "does not rename the store" do
80
- expect(store).to_not have_received(:rename)
84
+ expect(store).to_not receive(:rename)
85
+
86
+ subject.apply_uid_validity("aaa")
81
87
  end
82
88
 
83
89
  it "returns nil" do
84
- expect(result).to be_nil
90
+ expect(subject.apply_uid_validity("aaa")).to be_nil
85
91
  end
86
92
  end
87
93
 
88
94
  context "when the uid validity is unchanged" do
89
- let!(:result) { super() }
90
95
  let(:existing_uid_validity) { "aaa" }
91
96
 
92
97
  it "does not set uid validity" do
93
- expect(store).to_not have_received(:uid_validity=)
98
+ expect(store).to_not receive(:uid_validity=)
99
+
100
+ subject.apply_uid_validity("aaa")
94
101
  end
95
102
 
96
103
  it "does not rename the store" do
97
- expect(store).to_not have_received(:rename)
104
+ expect(store).to_not receive(:rename)
105
+
106
+ subject.apply_uid_validity("aaa")
98
107
  end
99
108
 
100
109
  it "returns nil" do
101
- expect(result).to be_nil
110
+ expect(subject.apply_uid_validity("aaa")).to be_nil
102
111
  end
103
112
  end
104
113
 
@@ -113,20 +122,23 @@ describe Imap::Backup::Serializer::Mbox do
113
122
  allow(Imap::Backup::Serializer::MboxStore).
114
123
  to receive(:new).with(anything, /bbb/) { existing_store }
115
124
  allow(existing_store).to receive(:exist?).and_return(exists, false)
116
- result
117
125
  end
118
126
 
119
127
  it "sets uid validity" do
120
- expect(store).to have_received(:uid_validity=).with("aaa")
128
+ expect(store).to receive(:uid_validity=).with("aaa")
129
+
130
+ subject.apply_uid_validity("aaa")
121
131
  end
122
132
 
123
133
  context "when adding the uid validity does not cause a name clash" do
124
134
  it "renames the store, adding the existing uid validity" do
125
- expect(store).to have_received(:rename).with("folder.bbb")
135
+ expect(store).to receive(:rename).with("folder.bbb")
136
+
137
+ subject.apply_uid_validity("aaa")
126
138
  end
127
139
 
128
140
  it "returns the new name" do
129
- expect(result).to eq("folder.bbb")
141
+ expect(subject.apply_uid_validity("aaa")).to eq("folder.bbb")
130
142
  end
131
143
  end
132
144
 
@@ -134,67 +146,69 @@ describe Imap::Backup::Serializer::Mbox do
134
146
  let(:exists) { true }
135
147
 
136
148
  it "renames the store, adding the existing uid validity and a digit" do
137
- expect(store).to have_received(:rename).with("folder.bbb.1")
149
+ expect(store).to receive(:rename).with("folder.bbb.1")
150
+
151
+ subject.apply_uid_validity("aaa")
138
152
  end
139
153
 
140
154
  it "returns the new name" do
141
- expect(result).to eq("folder.bbb.1")
155
+ expect(subject.apply_uid_validity("aaa")).to eq("folder.bbb.1")
142
156
  end
143
157
  end
144
158
  end
145
159
  end
146
160
 
147
161
  describe "#force_uid_validity" do
148
- before { subject.force_uid_validity("66") }
149
-
150
162
  it "sets the uid_validity" do
151
- expect(store).to have_received(:uid_validity=).with("66")
163
+ expect(store).to receive(:uid_validity=).with("66")
164
+
165
+ subject.force_uid_validity("66")
152
166
  end
153
167
  end
154
168
 
155
169
  describe "#uids" do
156
170
  it "calls the store" do
157
- subject.uids
171
+ expect(store).to receive(:uids)
158
172
 
159
- expect(store).to have_received(:uids)
173
+ subject.uids
160
174
  end
161
175
  end
162
176
 
163
177
  describe "#load" do
164
- let(:result) { subject.load("66") }
165
-
166
178
  before { allow(store).to receive(:load).with("66") { "xxx" } }
167
179
 
168
180
  it "returns the value loaded by the store" do
169
- expect(result).to eq("xxx")
181
+ expect(subject.load("66")).to eq("xxx")
170
182
  end
171
183
  end
172
184
 
173
185
  describe "#save" do
174
- before { subject.save("foo", "bar") }
175
-
176
186
  it "calls the store" do
177
- expect(store).to have_received(:add).with("foo", "bar")
187
+ expect(store).to receive(:add).with("foo", "bar")
188
+
189
+ subject.save("foo", "bar")
178
190
  end
179
191
  end
180
192
 
181
193
  describe "#rename" do
182
- before { subject.rename("foo") }
183
-
184
194
  it "calls the store" do
185
- expect(store).to have_received(:rename).with("foo")
195
+ expect(store).to receive(:rename).with("foo")
196
+
197
+ subject.rename("foo")
186
198
  end
187
199
 
188
200
  it "updates the folder name" do
201
+ subject.rename("foo")
202
+
189
203
  expect(subject.folder).to eq("foo")
190
204
  end
191
205
  end
192
206
 
193
207
  describe "#update_uid" do
194
- before { subject.update_uid("foo", "bar") }
195
-
196
208
  it "calls the store" do
197
- expect(store).to have_received(:update_uid).with("foo", "bar")
209
+ expect(store).to receive(:update_uid).with("foo", "bar")
210
+
211
+ subject.update_uid("foo", "bar")
198
212
  end
199
213
  end
200
214
  end
@@ -51,14 +51,16 @@ describe Imap::Backup::Serializer::MboxStore do
51
51
  }.to_json
52
52
  end
53
53
 
54
- before { subject.uid_validity = new_uid_validity }
55
-
56
54
  it "sets uid_validity" do
55
+ subject.uid_validity = new_uid_validity
56
+
57
57
  expect(subject.uid_validity).to eq(new_uid_validity)
58
58
  end
59
59
 
60
60
  it "writes the imap file" do
61
- expect(imap_file).to have_received(:write).with(updated_imap_content)
61
+ expect(imap_file).to receive(:write).with(updated_imap_content)
62
+
63
+ subject.uid_validity = new_uid_validity
62
64
  end
63
65
  end
64
66
 
@@ -80,22 +82,26 @@ describe Imap::Backup::Serializer::MboxStore do
80
82
  allow(JSON).to receive(:parse).and_raise(JSON::ParserError)
81
83
  end
82
84
 
83
- let!(:result) { subject.uids }
84
-
85
85
  it "returns an empty Array" do
86
- expect(result).to eq([])
86
+ expect(subject.uids).to eq([])
87
87
  end
88
88
 
89
89
  it "deletes the imap file" do
90
- expect(File).to have_received(:unlink).with(imap_pathname)
90
+ expect(File).to receive(:unlink).with(imap_pathname)
91
+
92
+ subject.uids
91
93
  end
92
94
 
93
95
  it "deletes the mbox file" do
94
- expect(File).to have_received(:unlink).with(mbox_pathname)
96
+ expect(File).to receive(:unlink).with(mbox_pathname)
97
+
98
+ subject.uids
95
99
  end
96
100
 
97
101
  it "writes a blank mbox file" do
98
- expect(mbox_file).to have_received(:write).with("")
102
+ expect(mbox_file).to receive(:write).with("")
103
+
104
+ subject.uids
99
105
  end
100
106
  end
101
107
 
@@ -126,28 +132,29 @@ describe Imap::Backup::Serializer::MboxStore do
126
132
  end
127
133
 
128
134
  before do
129
- allow(Email::Mboxrd::Message).to receive(:new).and_return(message)
135
+ allow(Email::Mboxrd::Message).to receive(:new) { message }
130
136
  allow(File).to receive(:open).with(mbox_pathname, "ab") { mbox_file }
131
137
  end
132
138
 
133
139
  it "saves the message to the mbox" do
134
- subject.add(message_uid, "The\nemail\n")
140
+ expect(mbox_file).to receive(:write).with(mbox_formatted_message)
135
141
 
136
- expect(mbox_file).to have_received(:write).with(mbox_formatted_message)
142
+ subject.add(message_uid, "The\nemail\n")
137
143
  end
138
144
 
139
145
  it "saves the uid to the imap file" do
140
- subject.add(message_uid, "The\nemail\n")
146
+ expect(imap_file).to receive(:write).with(updated_imap_content)
141
147
 
142
- expect(imap_file).to have_received(:write).with(updated_imap_content)
148
+ subject.add(message_uid, "The\nemail\n")
143
149
  end
144
150
 
145
151
  context "when the message is already downloaded" do
146
152
  let(:uids) { [999] }
147
153
 
148
154
  it "skips the message" do
155
+ expect(mbox_file).to_not receive(:write)
156
+
149
157
  subject.add(message_uid, "The\nemail\n")
150
- expect(mbox_file).to_not have_received(:write)
151
158
  end
152
159
  end
153
160
 
@@ -157,8 +164,9 @@ describe Imap::Backup::Serializer::MboxStore do
157
164
  end
158
165
 
159
166
  it "skips the message" do
167
+ expect(mbox_file).to_not receive(:write)
168
+
160
169
  subject.add(message_uid, "The\nemail\n")
161
- expect(mbox_file).to_not have_received(:write)
162
170
  end
163
171
 
164
172
  it "does not fail" do
@@ -171,7 +179,6 @@ describe Imap::Backup::Serializer::MboxStore do
171
179
 
172
180
  describe "#load" do
173
181
  let(:uid) { "1" }
174
- let(:result) { subject.load(uid) }
175
182
  let(:enumerator) do
176
183
  instance_double(Imap::Backup::Serializer::MboxEnumerator)
177
184
  end
@@ -189,14 +196,14 @@ describe Imap::Backup::Serializer::MboxStore do
189
196
  end
190
197
 
191
198
  it "returns the message" do
192
- expect(result.supplied_body).to eq("ciao")
199
+ expect(subject.load(uid).supplied_body).to eq("ciao")
193
200
  end
194
201
 
195
202
  context "when the UID is unknown" do
196
203
  let(:uid) { "99" }
197
204
 
198
205
  it "returns nil" do
199
- expect(result).to be_nil
206
+ expect(subject.load(uid)).to be_nil
200
207
  end
201
208
  end
202
209
  end
@@ -211,34 +218,40 @@ describe Imap::Backup::Serializer::MboxStore do
211
218
  }.to_json
212
219
  end
213
220
 
214
- before { subject.update_uid(old_uid, "999") }
215
-
216
221
  it "updates the stored UID" do
217
- expect(imap_file).to have_received(:write).with(updated_imap_content)
222
+ expect(imap_file).to receive(:write).with(updated_imap_content)
223
+
224
+ subject.update_uid(old_uid, "999")
218
225
  end
219
226
 
220
227
  context "when the UID is unknown" do
221
228
  let(:old_uid) { "42" }
222
229
 
223
230
  it "does nothing" do
224
- expect(imap_file).to_not have_received(:write)
231
+ expect(imap_file).to_not receive(:write)
232
+
233
+ subject.update_uid(old_uid, "999")
225
234
  end
226
235
  end
227
236
  end
228
237
 
229
238
  describe "#reset" do
230
- before { subject.reset }
231
-
232
239
  it "deletes the imap file" do
233
- expect(File).to have_received(:unlink).with(imap_pathname)
240
+ expect(File).to receive(:unlink).with(imap_pathname)
241
+
242
+ subject.reset
234
243
  end
235
244
 
236
245
  it "deletes the mbox file" do
237
- expect(File).to have_received(:unlink).with(mbox_pathname)
246
+ expect(File).to receive(:unlink).with(mbox_pathname)
247
+
248
+ subject.reset
238
249
  end
239
250
 
240
251
  it "writes a blank mbox file" do
241
- expect(mbox_file).to have_received(:write).with("")
252
+ expect(mbox_file).to receive(:write).with("")
253
+
254
+ subject.reset
242
255
  end
243
256
  end
244
257
 
@@ -252,18 +265,23 @@ describe Imap::Backup::Serializer::MboxStore do
252
265
  allow(File).to receive(:rename).and_call_original
253
266
  allow(File).to receive(:rename).with(imap_pathname, new_imap_name)
254
267
  allow(File).to receive(:rename).with(mbox_pathname, new_mbox_name)
255
- subject.rename(new_name)
256
268
  end
257
269
 
258
270
  it "renames the imap file" do
259
- expect(File).to have_received(:rename).with(imap_pathname, new_imap_name)
271
+ expect(File).to receive(:rename).with(imap_pathname, new_imap_name)
272
+
273
+ subject.rename(new_name)
260
274
  end
261
275
 
262
276
  it "renames the mbox file" do
263
- expect(File).to have_received(:rename).with(mbox_pathname, new_mbox_name)
277
+ expect(File).to receive(:rename).with(mbox_pathname, new_mbox_name)
278
+
279
+ subject.rename(new_name)
264
280
  end
265
281
 
266
282
  it "updates the folder name" do
283
+ subject.rename(new_name)
284
+
267
285
  expect(subject.folder).to eq(new_name)
268
286
  end
269
287
  end