imap-backup 2.1.1 → 3.0.0

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -4
  3. data/.rubocop_todo.yml +29 -11
  4. data/.travis.yml +1 -1
  5. data/README.md +10 -13
  6. data/bin/imap-backup +5 -2
  7. data/docs/01-credentials-screen.png +0 -0
  8. data/docs/02-new-project.png +0 -0
  9. data/docs/03-initial-credentials-for-project.png +0 -0
  10. data/docs/04-credential-type-selection.png +0 -0
  11. data/docs/05-cant-create-without-consent-setup.png +0 -0
  12. data/docs/06-user-type-selection.png +0 -0
  13. data/docs/07-consent-screen-form.png +0 -0
  14. data/docs/08-app-scopes.png +0 -0
  15. data/docs/09-scope-selection.png +0 -0
  16. data/docs/10-updated-app-scopes.png +0 -0
  17. data/docs/11-test-users.png +0 -0
  18. data/docs/12-add-users.png +0 -0
  19. data/docs/13-create-oauth-client.png +0 -0
  20. data/docs/14-application-details.png +0 -0
  21. data/docs/16-initial-menu.png +0 -0
  22. data/docs/17-inputting-the-email-address.png +0 -0
  23. data/docs/18-choose-password.png +0 -0
  24. data/docs/19-supply-client-info.png +0 -0
  25. data/docs/20-choose-gmail-account.png +0 -0
  26. data/docs/21-accept-warnings.png +0 -0
  27. data/docs/22-grant-access.png +0 -0
  28. data/docs/24-confirm-choices.png +0 -0
  29. data/docs/25-success-code.png +0 -0
  30. data/docs/26-type-code-into-imap-backup.png +0 -0
  31. data/docs/27-success.png +0 -0
  32. data/docs/setting-up-gmail.md +166 -0
  33. data/imap-backup.gemspec +3 -9
  34. data/lib/email/mboxrd/message.rb +4 -3
  35. data/lib/email/provider.rb +3 -1
  36. data/lib/gmail/authenticator.rb +160 -0
  37. data/lib/google/auth/stores/in_memory_token_store.rb +9 -0
  38. data/lib/imap/backup.rb +2 -1
  39. data/lib/imap/backup/account/connection.rb +59 -34
  40. data/lib/imap/backup/account/folder.rb +10 -1
  41. data/lib/imap/backup/configuration/account.rb +9 -1
  42. data/lib/imap/backup/configuration/gmail_oauth2.rb +82 -0
  43. data/lib/imap/backup/configuration/setup.rb +4 -1
  44. data/lib/imap/backup/serializer/mbox.rb +4 -0
  45. data/lib/imap/backup/serializer/mbox_enumerator.rb +1 -1
  46. data/lib/imap/backup/serializer/mbox_store.rb +20 -4
  47. data/lib/imap/backup/uploader.rb +10 -2
  48. data/lib/imap/backup/version.rb +5 -4
  49. data/spec/features/backup_spec.rb +3 -3
  50. data/spec/features/helper.rb +1 -1
  51. data/spec/features/restore_spec.rb +75 -27
  52. data/spec/features/support/backup_directory.rb +2 -2
  53. data/spec/features/support/email_server.rb +1 -3
  54. data/spec/features/support/shared/message_fixtures.rb +8 -0
  55. data/spec/spec_helper.rb +1 -1
  56. data/spec/support/fixtures.rb +1 -1
  57. data/spec/unit/email/mboxrd/message_spec.rb +2 -8
  58. data/spec/unit/email/provider_spec.rb +2 -2
  59. data/spec/unit/gmail/authenticator_spec.rb +138 -0
  60. data/spec/unit/google/auth/stores/in_memory_token_store_spec.rb +15 -0
  61. data/spec/unit/imap/backup/account/connection_spec.rb +157 -79
  62. data/spec/unit/imap/backup/account/folder_spec.rb +30 -20
  63. data/spec/unit/imap/backup/configuration/account_spec.rb +65 -46
  64. data/spec/unit/imap/backup/configuration/asker_spec.rb +20 -17
  65. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +6 -10
  66. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +16 -10
  67. data/spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb +84 -0
  68. data/spec/unit/imap/backup/configuration/list_spec.rb +6 -3
  69. data/spec/unit/imap/backup/configuration/setup_spec.rb +89 -54
  70. data/spec/unit/imap/backup/configuration/store_spec.rb +18 -16
  71. data/spec/unit/imap/backup/downloader_spec.rb +14 -14
  72. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +6 -1
  73. data/spec/unit/imap/backup/serializer/mbox_spec.rb +62 -40
  74. data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +94 -35
  75. data/spec/unit/imap/backup/uploader_spec.rb +23 -7
  76. data/spec/unit/imap/backup/utils_spec.rb +10 -9
  77. metadata +68 -9
@@ -0,0 +1,15 @@
1
+ require "google/auth/stores/in_memory_token_store"
2
+
3
+ describe Google::Auth::Stores::InMemoryTokenStore do
4
+ KEY = "key".freeze
5
+ VALUE = "value".freeze
6
+
7
+ subject { described_class.new }
8
+
9
+ describe "#load" do
10
+ it "returns an item's value" do
11
+ subject[KEY] = VALUE
12
+ expect(subject.load(KEY)).to eq(VALUE)
13
+ end
14
+ end
15
+ end
@@ -1,58 +1,57 @@
1
- describe Imap::Backup::Account::Connection do
2
- def self.backup_folder
3
- "backup_folder"
4
- end
1
+ require "ostruct"
5
2
 
6
- def self.folder_config
7
- {name: backup_folder}
8
- end
3
+ describe Imap::Backup::Account::Connection do
4
+ BACKUP_FOLDER = "backup_folder".freeze
5
+ FOLDER_CONFIG = {name: BACKUP_FOLDER}.freeze
6
+ FOLDER_NAME = "my_folder".freeze
7
+ GMAIL_IMAP_SERVER = "imap.gmail.com".freeze
8
+ LOCAL_PATH = "local_path".freeze
9
+ LOCAL_UID = "local_uid".freeze
10
+ PASSWORD = "secret".freeze
11
+ ROOT_NAME = "foo".freeze
12
+ SERVER = "imap.example.com".freeze
13
+ USERNAME = "username@example.com".freeze
9
14
 
10
15
  subject { described_class.new(options) }
11
16
 
12
17
  let(:imap) do
13
- instance_double(Net::IMAP, login: nil, disconnect: nil)
18
+ instance_double(Net::IMAP, authenticate: nil, login: nil, disconnect: nil)
14
19
  end
15
20
  let(:imap_folders) { [] }
16
21
  let(:options) do
17
22
  {
18
- username: username,
19
- password: "password",
20
- local_path: local_path,
21
- folders: backup_folders
23
+ username: USERNAME,
24
+ password: PASSWORD,
25
+ local_path: LOCAL_PATH,
26
+ folders: backup_folders,
27
+ server: server
22
28
  }
23
29
  end
24
- let(:local_path) { "local_path" }
25
- let(:backup_folders) { [self.class.folder_config] }
26
- let(:username) { "username@gmail.com" }
30
+ let(:backup_folders) { [FOLDER_CONFIG] }
27
31
  let(:root_info) do
28
- instance_double(Net::IMAP::MailboxList, name: root_name)
32
+ instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)
29
33
  end
30
- let(:root_name) { "foo" }
31
34
  let(:serializer) do
32
35
  instance_double(
33
36
  Imap::Backup::Serializer::Mbox,
34
37
  folder: serialized_folder,
35
38
  force_uid_validity: nil,
36
39
  apply_uid_validity: new_uid_validity,
37
- uids: [local_uid]
40
+ uids: [LOCAL_UID]
38
41
  )
39
42
  end
40
43
  let(:serialized_folder) { nil }
44
+ let(:server) { SERVER }
41
45
  let(:new_uid_validity) { nil }
42
- let(:local_uid) { "local_uid" }
43
46
 
44
47
  before do
45
48
  allow(Net::IMAP).to receive(:new) { imap }
46
49
  allow(imap).to receive(:list).with("", "") { [root_info] }
47
- allow(imap).to receive(:list).with(root_name, "*") { imap_folders }
50
+ allow(imap).to receive(:list).with(ROOT_NAME, "*") { imap_folders }
48
51
  allow(Imap::Backup::Utils).to receive(:make_folder)
49
52
  end
50
53
 
51
54
  shared_examples "connects to IMAP" do
52
- it "sets up the IMAP connection" do
53
- expect(Net::IMAP).to have_received(:new)
54
- end
55
-
56
55
  it "logs in to the imap server" do
57
56
  expect(imap).to have_received(:login)
58
57
  end
@@ -60,18 +59,21 @@ describe Imap::Backup::Account::Connection do
60
59
 
61
60
  describe "#initialize" do
62
61
  [
63
- [:username, "username@gmail.com"],
64
- [:local_path, "local_path"],
65
- [:backup_folders, [folder_config]]
62
+ [:username, USERNAME],
63
+ [:password, PASSWORD],
64
+ [:local_path, LOCAL_PATH],
65
+ [:backup_folders, [FOLDER_CONFIG]],
66
+ [:server, SERVER]
66
67
  ].each do |attr, expected|
67
68
  it "expects #{attr}" do
68
- expect(subject.send(attr)).to eq(expected)
69
+ expect(subject.public_send(attr)).to eq(expected)
69
70
  end
70
71
  end
71
72
 
72
73
  it "creates the path" do
74
+ expect(Imap::Backup::Utils).to receive(:make_folder)
75
+
73
76
  subject.username
74
- expect(Imap::Backup::Utils).to have_received(:make_folder)
75
77
  end
76
78
  end
77
79
 
@@ -82,6 +84,61 @@ describe Imap::Backup::Account::Connection do
82
84
  expect(result).to eq(imap)
83
85
  end
84
86
 
87
+ it "uses the password" do
88
+ expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
89
+ end
90
+
91
+ context "with the GMail IMAP server" do
92
+ ACCESS_TOKEN = "access_token".freeze
93
+
94
+ let(:server) { GMAIL_IMAP_SERVER }
95
+ let(:refresh_token) { true }
96
+ let(:result) { nil }
97
+ let(:authenticator) do
98
+ instance_double(
99
+ Gmail::Authenticator,
100
+ credentials: credentials
101
+ )
102
+ end
103
+ let(:credentials) { OpenStruct.new(access_token: ACCESS_TOKEN) }
104
+
105
+ before do
106
+ allow(Gmail::Authenticator).
107
+ to receive(:refresh_token?) { refresh_token }
108
+ allow(Gmail::Authenticator).
109
+ to receive(:new).
110
+ with(email: USERNAME, token: PASSWORD) { authenticator }
111
+ end
112
+
113
+ context "when the password is our copy of a GMail refresh token" do
114
+ it "uses the OAuth2 access_token to authenticate" do
115
+ subject.imap
116
+
117
+ expect(imap).to have_received(:authenticate).with(
118
+ "XOAUTH2", USERNAME, ACCESS_TOKEN
119
+ )
120
+ end
121
+
122
+ context "when the refresh token is invalid" do
123
+ let(:credentials) { nil }
124
+
125
+ it "raises" do
126
+ expect { subject.imap }.to raise_error(String)
127
+ end
128
+ end
129
+ end
130
+
131
+ context "when the password is not our copy of a GMail refresh token" do
132
+ let(:refresh_token) { false }
133
+
134
+ it "uses the password" do
135
+ subject.imap
136
+
137
+ expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
138
+ end
139
+ end
140
+ end
141
+
85
142
  include_examples "connects to IMAP"
86
143
  end
87
144
 
@@ -102,16 +159,16 @@ describe Imap::Backup::Account::Connection do
102
159
  let(:remote_uid) { "remote_uid" }
103
160
 
104
161
  before do
105
- allow(Imap::Backup::Account::Folder).to receive(:new).and_return(folder)
162
+ allow(Imap::Backup::Account::Folder).to receive(:new) { folder }
106
163
  allow(Imap::Backup::Serializer::Mbox).to receive(:new) { serializer }
107
164
  end
108
165
 
109
166
  it "returns the names of folders" do
110
- expect(subject.status[0][:name]).to eq(self.class.backup_folder)
167
+ expect(subject.status[0][:name]).to eq(BACKUP_FOLDER)
111
168
  end
112
169
 
113
170
  it "returns local message uids" do
114
- expect(subject.status[0][:local]).to eq([local_uid])
171
+ expect(subject.status[0][:local]).to eq([LOCAL_UID])
115
172
  end
116
173
 
117
174
  it "retrieves the available uids" do
@@ -135,59 +192,59 @@ describe Imap::Backup::Account::Connection do
135
192
  before do
136
193
  allow(Imap::Backup::Downloader).
137
194
  to receive(:new).with(folder, serializer) { downloader }
195
+ allow(Imap::Backup::Account::Folder).to receive(:new).
196
+ with(subject, BACKUP_FOLDER) { folder }
197
+ allow(Imap::Backup::Serializer::Mbox).to receive(:new).
198
+ with(LOCAL_PATH, BACKUP_FOLDER) { serializer }
138
199
  end
139
200
 
140
201
  context "with supplied backup_folders" do
141
- before do
142
- allow(Imap::Backup::Account::Folder).to receive(:new).
143
- with(subject, self.class.backup_folder).and_return(folder)
144
- allow(Imap::Backup::Serializer::Mbox).to receive(:new).
145
- with(local_path, self.class.backup_folder).and_return(serializer)
146
- subject.run_backup
147
- end
148
-
149
202
  it "runs the downloader" do
150
- expect(downloader).to have_received(:run)
203
+ expect(downloader).to receive(:run)
204
+
205
+ subject.run_backup
151
206
  end
152
207
 
153
208
  context "when a folder does not exist" do
154
209
  let(:exists) { false }
155
210
 
156
211
  it "does not run the downloader" do
157
- expect(downloader).to_not have_received(:run)
212
+ expect(downloader).to_not receive(:run)
213
+
214
+ subject.run_backup
158
215
  end
159
216
  end
160
217
  end
161
218
 
162
219
  context "without supplied backup_folders" do
163
220
  let(:imap_folders) do
164
- [instance_double(Net::IMAP::MailboxList, name: "foo")]
221
+ [instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)]
165
222
  end
166
223
 
167
224
  before do
168
225
  allow(Imap::Backup::Account::Folder).to receive(:new).
169
- with(subject, "foo").and_return(folder)
226
+ with(subject, ROOT_NAME) { folder }
170
227
  allow(Imap::Backup::Serializer::Mbox).to receive(:new).
171
- with(local_path, "foo").and_return(serializer)
228
+ with(LOCAL_PATH, ROOT_NAME) { serializer }
172
229
  end
173
230
 
174
231
  context "when supplied backup_folders is nil" do
175
232
  let(:backup_folders) { nil }
176
233
 
177
- before { subject.run_backup }
178
-
179
234
  it "runs the downloader for each folder" do
180
- expect(downloader).to have_received(:run).exactly(:once)
235
+ expect(downloader).to receive(:run).exactly(:once)
236
+
237
+ subject.run_backup
181
238
  end
182
239
  end
183
240
 
184
241
  context "when supplied backup_folders is an empty list" do
185
242
  let(:backup_folders) { [] }
186
243
 
187
- before { subject.run_backup }
188
-
189
244
  it "runs the downloader for each folder" do
190
- expect(downloader).to have_received(:run).exactly(:once)
245
+ expect(downloader).to receive(:run).exactly(:once)
246
+
247
+ subject.run_backup
191
248
  end
192
249
  end
193
250
 
@@ -200,6 +257,12 @@ describe Imap::Backup::Account::Connection do
200
257
  end
201
258
  end
202
259
  end
260
+
261
+ context "when run" do
262
+ before { subject.run_backup }
263
+
264
+ include_examples "connects to IMAP"
265
+ end
203
266
  end
204
267
 
205
268
  describe "#restore" do
@@ -207,12 +270,12 @@ describe Imap::Backup::Account::Connection do
207
270
  instance_double(
208
271
  Imap::Backup::Account::Folder,
209
272
  create: nil,
210
- exist?: exists,
211
- name: "my_folder",
273
+ uids: uids,
274
+ name: FOLDER_NAME,
212
275
  uid_validity: uid_validity
213
276
  )
214
277
  end
215
- let(:exists) { true }
278
+ let(:uids) { [99] }
216
279
  let(:uid_validity) { 123 }
217
280
  let(:serialized_folder) { "old name" }
218
281
  let(:uploader) do
@@ -236,9 +299,9 @@ describe Imap::Backup::Account::Connection do
236
299
 
237
300
  before do
238
301
  allow(Imap::Backup::Account::Folder).to receive(:new).
239
- with(subject, "my_folder") { folder }
302
+ with(subject, FOLDER_NAME) { folder }
240
303
  allow(Imap::Backup::Serializer::Mbox).to receive(:new).
241
- with(anything, "my_folder") { serializer }
304
+ with(anything, FOLDER_NAME) { serializer }
242
305
  allow(Imap::Backup::Account::Folder).to receive(:new).
243
306
  with(subject, "new name") { updated_folder }
244
307
  allow(Imap::Backup::Serializer::Mbox).to receive(:new).
@@ -248,75 +311,90 @@ describe Imap::Backup::Account::Connection do
248
311
  allow(Imap::Backup::Uploader).to receive(:new).
249
312
  with(updated_folder, updated_serializer) { updated_uploader }
250
313
  allow(Pathname).to receive(:glob).
251
- and_yield(Pathname.new(File.join(local_path, "my_folder.imap")))
252
- subject.restore
314
+ and_yield(Pathname.new(File.join(LOCAL_PATH, "#{FOLDER_NAME}.imap")))
253
315
  end
254
316
 
255
317
  it "sets local uid validity" do
256
- expect(serializer).
257
- to have_received(:apply_uid_validity).with(uid_validity)
318
+ expect(serializer).to receive(:apply_uid_validity).with(uid_validity)
319
+
320
+ subject.restore
258
321
  end
259
322
 
260
- context "when folders exist" do
323
+ context "when folders exist with contents" do
261
324
  context "when the local folder is renamed" do
262
325
  let(:new_uid_validity) { "new name" }
263
326
 
264
327
  it "creates the new folder" do
265
- expect(updated_folder).to have_received(:create)
328
+ expect(updated_folder).to receive(:create)
329
+
330
+ subject.restore
266
331
  end
267
332
 
268
333
  it "sets the renamed folder's uid validity" do
269
334
  expect(updated_serializer).
270
- to have_received(:force_uid_validity).with("new uid validity")
335
+ to receive(:force_uid_validity).with("new uid validity")
336
+
337
+ subject.restore
271
338
  end
272
339
 
273
340
  it "creates the uploader with updated folder and serializer" do
274
- expect(updated_uploader).to have_received(:run)
341
+ expect(updated_uploader).to receive(:run)
342
+
343
+ subject.restore
275
344
  end
276
345
  end
277
346
 
278
347
  context "when the local folder is not renamed" do
279
348
  it "runs the uploader" do
280
- expect(uploader).to have_received(:run)
349
+ expect(uploader).to receive(:run)
350
+
351
+ subject.restore
281
352
  end
282
353
  end
283
354
  end
284
355
 
285
- context "when folders don't exist" do
286
- let(:exists) { false }
356
+ context "when folders don't exist or are empty" do
357
+ let(:uids) { [] }
287
358
 
288
359
  it "creates the folder" do
289
- expect(folder).to have_received(:create)
360
+ expect(folder).to receive(:create)
361
+
362
+ subject.restore
290
363
  end
291
364
 
292
- it "sets local uid validity" do
365
+ it "forces local uid validity" do
366
+ expect(serializer).to receive(:force_uid_validity).with(uid_validity)
367
+
368
+ subject.restore
293
369
  end
294
370
 
295
371
  it "runs the uploader" do
296
- expect(uploader).to have_received(:run)
372
+ expect(uploader).to receive(:run)
373
+
374
+ subject.restore
297
375
  end
298
376
  end
299
377
  end
300
378
 
301
379
  describe "#reconnect" do
302
- before { subject.reconnect }
303
-
304
380
  it "disconnects from the server" do
305
- expect(imap).to have_received(:disconnect)
381
+ expect(imap).to receive(:disconnect)
382
+
383
+ subject.reconnect
306
384
  end
307
385
 
308
386
  it "causes reconnection on future access" do
309
- allow(Net::IMAP).to receive(:new) { imap }
310
- subject.imap
311
- expect(Net::IMAP).to have_received(:new).twice
387
+ expect(Net::IMAP).to receive(:new)
388
+
389
+ subject.reconnect
312
390
  end
313
391
  end
314
392
 
315
393
  describe "#disconnect" do
316
- before { subject.disconnect }
317
-
318
394
  it "disconnects from the server" do
319
- expect(imap).to have_received(:disconnect)
395
+ expect(imap).to receive(:disconnect)
396
+
397
+ subject.disconnect
320
398
  end
321
399
  end
322
400
  end
@@ -28,7 +28,7 @@ describe Imap::Backup::Account::Folder do
28
28
  describe "#uids" do
29
29
  let(:uids) { [5678, 123] }
30
30
 
31
- before { allow(imap).to receive(:uid_search).and_return(uids) }
31
+ before { allow(imap).to receive(:uid_search) { uids } }
32
32
 
33
33
  it "lists available messages" do
34
34
  expect(subject.uids).to eq(uids.reverse)
@@ -43,6 +43,20 @@ describe Imap::Backup::Account::Folder do
43
43
  expect(subject.uids).to eq([])
44
44
  end
45
45
  end
46
+
47
+ context "with no SEARCH response in Net::IMAP" do
48
+ let(:no_method_error) do
49
+ NoMethodError.new("Somethimes SEARCH responses come out undefined")
50
+ end
51
+
52
+ before do
53
+ allow(imap).to receive(:examine).and_raise(no_method_error)
54
+ end
55
+
56
+ it "returns an empty array" do
57
+ expect(subject.uids).to eq([])
58
+ end
59
+ end
46
60
  end
47
61
 
48
62
  describe "#fetch" do
@@ -83,12 +97,6 @@ describe Imap::Backup::Account::Folder do
83
97
  expect(subject.fetch(123)).to be_nil
84
98
  end
85
99
  end
86
-
87
- it "sets the encoding on the message" do
88
- subject.fetch(123)
89
-
90
- expect(message_body).to have_received(:force_encoding).with("utf-8")
91
- end
92
100
  end
93
101
 
94
102
  describe "#folder" do
@@ -117,21 +125,22 @@ describe Imap::Backup::Account::Folder do
117
125
 
118
126
  describe "#create" do
119
127
  context "when the folder exists" do
120
- before { subject.create }
121
-
122
128
  it "is does not create the folder" do
123
- expect(imap).to_not have_received(:create)
129
+ expect(imap).to_not receive(:create)
130
+
131
+ subject.create
124
132
  end
125
133
  end
126
134
 
127
135
  context "when the folder doesn't exist" do
128
136
  before do
129
137
  allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
130
- subject.create
131
138
  end
132
139
 
133
140
  it "is does not create the folder" do
134
- expect(imap).to have_received(:create)
141
+ expect(imap).to receive(:create)
142
+
143
+ subject.create
135
144
  end
136
145
  end
137
146
  end
@@ -168,26 +177,27 @@ describe Imap::Backup::Account::Folder do
168
177
  let(:append_response) do
169
178
  OpenStruct.new(data: OpenStruct.new(code: OpenStruct.new(data: "1 2")))
170
179
  end
171
- let(:result) { subject.append(message) }
172
-
173
- before do
174
- result
175
- end
176
180
 
177
181
  it "appends the message" do
178
- expect(imap).to have_received(:append)
182
+ expect(imap).to receive(:append)
183
+
184
+ subject.append(message)
179
185
  end
180
186
 
181
187
  it "sets the date and time" do
182
- expect(imap).to have_received(:append).
188
+ expect(imap).to receive(:append).
183
189
  with(anything, anything, anything, message_date)
190
+
191
+ subject.append(message)
184
192
  end
185
193
 
186
194
  it "returns the new uid" do
187
- expect(result).to eq(2)
195
+ expect(subject.append(message)).to eq(2)
188
196
  end
189
197
 
190
198
  it "set the new uid validity" do
199
+ subject.append(message)
200
+
191
201
  expect(subject.uid_validity).to eq(1)
192
202
  end
193
203
  end