imap-backup 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)