imap-backup 2.0.0 → 2.1.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec-all +2 -0
  3. data/.rubocop.yml +10 -1
  4. data/.travis.yml +1 -0
  5. data/README.md +1 -1
  6. data/Rakefile +0 -1
  7. data/bin/imap-backup +3 -9
  8. data/imap-backup.gemspec +5 -5
  9. data/lib/email/mboxrd/message.rb +2 -2
  10. data/lib/imap/backup/account/connection.rb +11 -3
  11. data/lib/imap/backup/account/folder.rb +11 -6
  12. data/lib/imap/backup/configuration/account.rb +7 -7
  13. data/lib/imap/backup/configuration/asker.rb +2 -1
  14. data/lib/imap/backup/configuration/connection_tester.rb +1 -1
  15. data/lib/imap/backup/configuration/folder_chooser.rb +32 -5
  16. data/lib/imap/backup/configuration/list.rb +2 -0
  17. data/lib/imap/backup/configuration/setup.rb +2 -1
  18. data/lib/imap/backup/configuration/store.rb +3 -6
  19. data/lib/imap/backup/downloader.rb +8 -7
  20. data/lib/imap/backup/serializer/mbox.rb +2 -1
  21. data/lib/imap/backup/serializer/mbox_store.rb +14 -6
  22. data/lib/imap/backup/uploader.rb +1 -0
  23. data/lib/imap/backup/utils.rb +11 -9
  24. data/lib/imap/backup/version.rb +1 -1
  25. data/spec/features/backup_spec.rb +6 -5
  26. data/spec/features/support/backup_directory.rb +5 -5
  27. data/spec/features/support/email_server.rb +11 -8
  28. data/spec/features/support/shared/connection_context.rb +2 -2
  29. data/spec/support/fixtures.rb +1 -1
  30. data/spec/support/higline_test_helpers.rb +1 -1
  31. data/spec/unit/email/mboxrd/message_spec.rb +51 -42
  32. data/spec/unit/email/provider_spec.rb +0 -2
  33. data/spec/unit/imap/backup/account/connection_spec.rb +18 -11
  34. data/spec/unit/imap/backup/account/folder_spec.rb +26 -12
  35. data/spec/unit/imap/backup/configuration/account_spec.rb +22 -19
  36. data/spec/unit/imap/backup/configuration/asker_spec.rb +30 -31
  37. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +16 -13
  38. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +45 -18
  39. data/spec/unit/imap/backup/configuration/list_spec.rb +8 -13
  40. data/spec/unit/imap/backup/configuration/setup_spec.rb +36 -30
  41. data/spec/unit/imap/backup/configuration/store_spec.rb +7 -4
  42. data/spec/unit/imap/backup/downloader_spec.rb +11 -7
  43. data/spec/unit/imap/backup/serializer/mbox_spec.rb +2 -5
  44. data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +4 -4
  45. data/spec/unit/imap/backup/uploader_spec.rb +0 -2
  46. data/spec/unit/imap/backup/utils_spec.rb +1 -3
  47. metadata +6 -6
@@ -1,15 +1,16 @@
1
- require "spec_helper"
2
-
3
1
  describe Imap::Backup::Configuration::ConnectionTester do
4
2
  context ".test" do
5
- let(:connection) { double("Imap::Backup::Account::Connection", imap: nil) }
3
+ let(:connection) do
4
+ instance_double(Imap::Backup::Account::Connection, imap: nil)
5
+ end
6
+ let(:result) { subject.test("foo") }
6
7
 
7
8
  before do
8
9
  allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
9
10
  end
10
11
 
11
12
  context "call" do
12
- before { @result = subject.test("foo") }
13
+ before { result }
13
14
 
14
15
  it "tries to connect" do
15
16
  expect(connection).to have_received(:imap)
@@ -17,34 +18,36 @@ describe Imap::Backup::Configuration::ConnectionTester do
17
18
  end
18
19
 
19
20
  context "success" do
20
- before { @result = subject.test("foo") }
21
+ before { result }
21
22
 
22
23
  it "returns success" do
23
- expect(@result).to match(/successful/)
24
+ expect(result).to match(/successful/)
24
25
  end
25
26
  end
26
27
 
27
28
  context "failure" do
28
29
  before do
29
30
  allow(connection).to receive(:imap).and_raise(error)
30
- @result = subject.test("foo")
31
+ result
31
32
  end
32
33
 
33
34
  context "no connection" do
34
35
  let(:error) do
35
- data = double("foo", text: "bar")
36
- Net::IMAP::NoResponseError.new(double("o", data: data))
36
+ data = OpenStruct.new(text: "bar")
37
+ response = OpenStruct.new(data: data)
38
+ Net::IMAP::NoResponseError.new(response)
37
39
  end
38
40
 
39
- it "returns success" do
40
- expect(@result).to match(/no response/i)
41
+ it "returns error" do
42
+ expect(result).to match(/no response/i)
41
43
  end
42
44
  end
43
45
 
44
46
  context "other" do
45
47
  let(:error) { "Error" }
46
- it "returns success" do
47
- expect(@result).to match(/unexpected error/i)
48
+
49
+ it "returns error" do
50
+ expect(result).to match(/unexpected error/i)
48
51
  end
49
52
  end
50
53
  end
@@ -1,22 +1,23 @@
1
- require "spec_helper"
2
-
3
1
  describe Imap::Backup::Configuration::FolderChooser do
4
2
  include HighLineTestHelpers
5
3
 
6
4
  context "#run" do
5
+ subject { described_class.new(account) }
6
+
7
7
  let(:connection) do
8
- double("Imap::Backup::Account::Connection", folders: remote_folders)
8
+ instance_double(
9
+ Imap::Backup::Account::Connection, folders: remote_folders
10
+ )
9
11
  end
10
12
  let(:account) { {folders: []} }
11
13
  let(:remote_folders) { [] }
12
-
13
- subject { described_class.new(account) }
14
+ let!(:highline_streams) { prepare_highline }
15
+ let(:input) { highline_streams[0] }
16
+ let(:output) { highline_streams[1] }
14
17
 
15
18
  before do
16
- allow(Imap::Backup::Account::Connection).
17
- to receive(:new).with(account) { connection }
18
- @input, @output = prepare_highline
19
- allow(subject).to receive(:system)
19
+ allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
20
+ allow(Kernel).to receive(:system)
20
21
  allow(Imap::Backup.logger).to receive(:warn)
21
22
  end
22
23
 
@@ -24,11 +25,11 @@ describe Imap::Backup::Configuration::FolderChooser do
24
25
  before { subject.run }
25
26
 
26
27
  it "clears the screen" do
27
- expect(subject).to have_received(:system).with("clear")
28
+ expect(Kernel).to have_received(:system).with("clear")
28
29
  end
29
30
 
30
- it "should show the menu" do
31
- expect(@output.string).to match %r{Add/remove folders}
31
+ it "shows the menu" do
32
+ expect(output.string).to match %r{Add/remove folders}
32
33
  end
33
34
  end
34
35
 
@@ -36,8 +37,12 @@ describe Imap::Backup::Configuration::FolderChooser do
36
37
  let(:account) { {folders: [{name: "my_folder"}]} }
37
38
  let(:remote_folders) do
38
39
  # this one is already backed up:
39
- folder1 = double("folder", name: "my_folder")
40
- folder2 = double("folder", name: "another_folder")
40
+ folder1 = instance_double(
41
+ Imap::Backup::Account::Folder, name: "my_folder"
42
+ )
43
+ folder2 = instance_double(
44
+ Imap::Backup::Account::Folder, name: "another_folder"
45
+ )
41
46
  [folder1, folder2]
42
47
  end
43
48
 
@@ -45,17 +50,17 @@ describe Imap::Backup::Configuration::FolderChooser do
45
50
  before { subject.run }
46
51
 
47
52
  it "shows folders which are being backed up" do
48
- expect(@output.string).to include("+ my_folder")
53
+ expect(output.string).to include("+ my_folder")
49
54
  end
50
55
 
51
56
  it "shows folders which are not being backed up" do
52
- expect(@output.string).to include("- another_folder")
57
+ expect(output.string).to include("- another_folder")
53
58
  end
54
59
  end
55
60
 
56
61
  context "adding folders" do
57
62
  before do
58
- allow(@input).to receive(:gets).and_return("2\n", "q\n")
63
+ allow(input).to receive(:gets).and_return("2\n", "q\n")
59
64
 
60
65
  subject.run
61
66
  end
@@ -69,7 +74,7 @@ describe Imap::Backup::Configuration::FolderChooser do
69
74
 
70
75
  context "removing folders" do
71
76
  before do
72
- allow(@input).to receive(:gets).and_return("1\n", "q\n")
77
+ allow(input).to receive(:gets).and_return("1\n", "q\n")
73
78
 
74
79
  subject.run
75
80
  end
@@ -82,6 +87,28 @@ describe Imap::Backup::Configuration::FolderChooser do
82
87
  end
83
88
  end
84
89
 
90
+ context "with missing remote folders" do
91
+ let(:account) do
92
+ {folders: [{name: "on_server"}, {name: "not_on_server"}]}
93
+ end
94
+ let(:remote_folders) do
95
+ [
96
+ instance_double(Imap::Backup::Account::Folder, name: "on_server")
97
+ ]
98
+ end
99
+
100
+ before do
101
+ allow(Kernel).to receive(:puts)
102
+ subject.run
103
+ end
104
+
105
+ specify "are removed from the account" do
106
+ expect(account[:folders]).to_not include(name: "not_on_server")
107
+ end
108
+
109
+ include_examples "it flags the account as modified"
110
+ end
111
+
85
112
  context "when folders are not available" do
86
113
  let(:remote_folders) { nil }
87
114
 
@@ -1,6 +1,6 @@
1
- require "spec_helper"
2
-
3
1
  describe Imap::Backup::Configuration::List do
2
+ subject { described_class.new }
3
+
4
4
  let(:accounts) do
5
5
  [
6
6
  {username: "a1@example.com"},
@@ -8,14 +8,14 @@ describe Imap::Backup::Configuration::List do
8
8
  ]
9
9
  end
10
10
  let(:store) do
11
- double("Imap::Backup::Configuration::Store", accounts: accounts)
11
+ instance_double(Imap::Backup::Configuration::Store, accounts: accounts)
12
12
  end
13
13
  let(:exists) { true }
14
14
  let(:connection1) do
15
- double("Imap::Backup::Account::Connection", disconnect: nil)
15
+ instance_double(Imap::Backup::Account::Connection, disconnect: nil)
16
16
  end
17
17
  let(:connection2) do
18
- double("Imap::Backup::Account::Connection", disconnect: nil)
18
+ instance_double(Imap::Backup::Account::Connection, disconnect: nil)
19
19
  end
20
20
 
21
21
  before do
@@ -28,11 +28,6 @@ describe Imap::Backup::Configuration::List do
28
28
  to receive(:new).with(accounts[1]) { connection2 }
29
29
  end
30
30
 
31
- subject { described_class.new }
32
-
33
- context "#initialize" do
34
- end
35
-
36
31
  context "#each_connection" do
37
32
  specify "calls the block with each account's connection" do
38
33
  connections = []
@@ -45,7 +40,7 @@ describe Imap::Backup::Configuration::List do
45
40
  context "with account parameter" do
46
41
  subject { described_class.new(["a2@example.com"]) }
47
42
 
48
- it "should only create requested accounts" do
43
+ it "only creates requested accounts" do
49
44
  connections = []
50
45
 
51
46
  subject.each_connection { |a| connections << a }
@@ -58,9 +53,9 @@ describe Imap::Backup::Configuration::List do
58
53
  let(:exists) { false }
59
54
 
60
55
  it "fails" do
61
- expect {
56
+ expect do
62
57
  subject.each_connection {}
63
- }.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
58
+ end.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
64
59
  end
65
60
  end
66
61
  end
@@ -1,4 +1,4 @@
1
- require "spec_helper"
1
+ # rubocop:disable RSpec/NestedGroups
2
2
 
3
3
  describe Imap::Backup::Configuration::Setup do
4
4
  include HighLineTestHelpers
@@ -12,39 +12,41 @@ describe Imap::Backup::Configuration::Setup do
12
12
  end
13
13
 
14
14
  context "#run" do
15
+ subject { described_class.new }
16
+
15
17
  let(:normal) { {username: "account@example.com"} }
16
18
  let(:accounts) { [normal] }
17
19
  let(:store) do
18
- double(
19
- "Imap::Backup::Configuration::Store",
20
- :accounts => accounts,
21
- :path => "/base/path",
22
- :save => nil,
23
- :debug? => debug,
24
- :debug= => nil,
25
- :modified? => modified,
20
+ instance_double(
21
+ Imap::Backup::Configuration::Store,
22
+ "accounts": accounts,
23
+ "path": "/base/path",
24
+ "save": nil,
25
+ "debug?": debug,
26
+ "debug=": nil,
27
+ "modified?": modified
26
28
  )
27
29
  end
28
30
  let(:debug) { false }
29
31
  let(:modified) { false }
32
+ let!(:highline_streams) { prepare_highline }
33
+ let(:input) { highline_streams[0] }
34
+ let(:output) { highline_streams[1] }
30
35
 
31
- before :each do
36
+ before do
32
37
  allow(Imap::Backup::Configuration::Store).to receive(:new) { store }
33
38
  allow(Imap::Backup).to receive(:setup_logging)
34
- @input, @output = prepare_highline
35
- allow(@input).to receive(:eof?).and_return(false)
36
- allow(@input).to receive(:gets).and_return("exit\n")
37
- allow(subject).to receive(:system)
39
+ allow(input).to receive(:eof?) { false }
40
+ allow(input).to receive(:gets) { "exit\n" }
41
+ allow(Kernel).to receive(:system)
38
42
  end
39
43
 
40
- subject { described_class.new }
41
-
42
44
  context "main menu" do
43
45
  before { subject.run }
44
46
 
45
47
  %w(add\ account save\ and\ exit exit\ without\ saving).each do |choice|
46
48
  it "includes #{choice}" do
47
- expect(@output.string).to include(choice)
49
+ expect(output.string).to include(choice)
48
50
  end
49
51
  end
50
52
  end
@@ -52,7 +54,7 @@ describe Imap::Backup::Configuration::Setup do
52
54
  it "clears the screen" do
53
55
  subject.run
54
56
 
55
- expect(subject).to have_received(:system).with("clear")
57
+ expect(Kernel).to have_received(:system).with("clear")
56
58
  end
57
59
 
58
60
  it "updates logging status" do
@@ -70,19 +72,19 @@ describe Imap::Backup::Configuration::Setup do
70
72
 
71
73
  context "normal accounts" do
72
74
  it "are listed" do
73
- expect(@output.string).to match /account@example.com/
75
+ expect(output.string).to match(/account@example.com/)
74
76
  end
75
77
  end
76
78
 
77
79
  context "modified accounts" do
78
80
  it "are flagged" do
79
- expect(@output.string).to match /modified@example.com \*/
81
+ expect(output.string).to match(/modified@example.com \*/)
80
82
  end
81
83
  end
82
84
 
83
85
  context "deleted accounts" do
84
86
  it "are hidden" do
85
- expect(@output.string).to_not match /delete@example.com/
87
+ expect(output.string).to_not match(/delete@example.com/)
86
88
  end
87
89
  end
88
90
  end
@@ -96,10 +98,12 @@ describe Imap::Backup::Configuration::Setup do
96
98
  folders: []
97
99
  }
98
100
  end
99
- let(:account) { double("Imap::Backup::Configuration::Account", run: nil) }
101
+ let(:account) do
102
+ instance_double(Imap::Backup::Configuration::Account, run: nil)
103
+ end
100
104
 
101
105
  before do
102
- allow(@input).to receive(:gets).and_return("add\n", "exit\n")
106
+ allow(input).to receive(:gets).and_return("add\n", "exit\n")
103
107
  allow(Imap::Backup::Configuration::Asker).to receive(:email).
104
108
  with(no_args).and_return("new@example.com")
105
109
  allow(Imap::Backup::Configuration::Account).to receive(:new).
@@ -120,12 +124,12 @@ describe Imap::Backup::Configuration::Setup do
120
124
  context "logging" do
121
125
  context "when debug logging is disabled" do
122
126
  before do
123
- allow(@input).to receive(:gets).and_return("start\n", "exit\n")
127
+ allow(input).to receive(:gets).and_return("start\n", "exit\n")
124
128
  subject.run
125
129
  end
126
130
 
127
131
  it "shows a menu item" do
128
- expect(@output.string).to include("start logging")
132
+ expect(output.string).to include("start logging")
129
133
  end
130
134
 
131
135
  context "when selected" do
@@ -143,17 +147,17 @@ describe Imap::Backup::Configuration::Setup do
143
147
  let(:debug) { true }
144
148
 
145
149
  before do
146
- allow(@input).to receive(:gets).and_return("stop\n", "exit\n")
150
+ allow(input).to receive(:gets).and_return("stop\n", "exit\n")
147
151
  subject.run
148
152
  end
149
153
 
150
154
  it "shows a menu item" do
151
- expect(@output.string).to include("stop logging")
155
+ expect(output.string).to include("stop logging")
152
156
  end
153
157
 
154
158
  context "when selected" do
155
159
  before do
156
- allow(@input).to receive(:gets).and_return("stop\n", "exit\n")
160
+ allow(input).to receive(:gets).and_return("stop\n", "exit\n")
157
161
  end
158
162
 
159
163
  it "unsets the debug flag" do
@@ -169,7 +173,7 @@ describe Imap::Backup::Configuration::Setup do
169
173
 
170
174
  context "when 'save' is selected" do
171
175
  before do
172
- allow(@input).to receive(:gets).and_return("save\n")
176
+ allow(input).to receive(:gets).and_return("save\n")
173
177
  subject.run
174
178
  end
175
179
 
@@ -184,7 +188,7 @@ describe Imap::Backup::Configuration::Setup do
184
188
 
185
189
  context "when 'exit without saving' is selected" do
186
190
  before do
187
- allow(@input).to receive(:gets).and_return("exit\n")
191
+ allow(input).to receive(:gets).and_return("exit\n")
188
192
 
189
193
  subject.run
190
194
  end
@@ -209,3 +213,5 @@ describe Imap::Backup::Configuration::Setup do
209
213
  end
210
214
  end
211
215
  end
216
+
217
+ # rubocop:enable RSpec/NestedGroups
@@ -1,6 +1,7 @@
1
- require "spec_helper"
2
1
  require "json"
3
2
 
3
+ # rubocop:disable RSpec/PredicateMatcher
4
+
4
5
  describe Imap::Backup::Configuration::Store do
5
6
  let(:directory) { "/base/path" }
6
7
  let(:file_path) { File.join(directory, "/config.json") }
@@ -130,8 +131,10 @@ describe Imap::Backup::Configuration::Store do
130
131
  end
131
132
 
132
133
  describe "#save" do
134
+ subject { described_class.new }
135
+
133
136
  let(:directory_exists) { false }
134
- let(:file) { double("File", write: nil) }
137
+ let(:file) { instance_double(File, write: nil) }
135
138
 
136
139
  before do
137
140
  allow(FileUtils).to receive(:mkdir)
@@ -140,8 +143,6 @@ describe Imap::Backup::Configuration::Store do
140
143
  allow(JSON).to receive(:pretty_generate).and_return("JSON output")
141
144
  end
142
145
 
143
- subject { described_class.new }
144
-
145
146
  it "creates the config directory" do
146
147
  subject.save
147
148
 
@@ -219,3 +220,5 @@ describe Imap::Backup::Configuration::Store do
219
220
  end
220
221
  end
221
222
  end
223
+
224
+ # rubocop:enable RSpec/PredicateMatcher
@@ -1,17 +1,21 @@
1
- require "spec_helper"
2
-
3
1
  describe Imap::Backup::Downloader do
4
2
  describe "#run" do
3
+ subject { described_class.new(folder, serializer) }
4
+
5
5
  let(:message) { {"RFC822" => "blah"} }
6
6
  let(:folder) do
7
- double("Imap::Backup::Account::Folder", fetch: message, name: "folder")
7
+ instance_double(
8
+ Imap::Backup::Account::Folder,
9
+ fetch: message,
10
+ name: "folder"
11
+ )
12
+ end
13
+ let(:folder_uids) { %w(111 222 333) }
14
+ let(:serializer) do
15
+ instance_double(Imap::Backup::Serializer::Mbox, save: nil)
8
16
  end
9
- let(:folder_uids) { ["111", "222", "333"] }
10
- let(:serializer) { double("Imap::Backup::Serializer", save: nil) }
11
17
  let(:serializer_uids) { ["222"] }
12
18
 
13
- subject { described_class.new(folder, serializer) }
14
-
15
19
  before do
16
20
  allow(folder).to receive(:uids).and_return(folder_uids)
17
21
  allow(serializer).to receive(:uids).and_return(serializer_uids)