imap-backup 1.0.9 → 1.0.10

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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +1 -0
  3. data/Rakefile +0 -5
  4. data/imap-backup.gemspec +5 -5
  5. data/lib/email/mboxrd/message.rb +1 -1
  6. data/lib/imap/backup.rb +3 -1
  7. data/lib/imap/backup/account/connection.rb +9 -7
  8. data/lib/imap/backup/account/folder.rb +6 -4
  9. data/lib/imap/backup/configuration/account.rb +9 -7
  10. data/lib/imap/backup/configuration/asker.rb +7 -5
  11. data/lib/imap/backup/configuration/connection_tester.rb +5 -3
  12. data/lib/imap/backup/configuration/folder_chooser.rb +10 -8
  13. data/lib/imap/backup/configuration/list.rb +8 -6
  14. data/lib/imap/backup/configuration/setup.rb +7 -5
  15. data/lib/imap/backup/configuration/store.rb +7 -5
  16. data/lib/imap/backup/serializer/base.rb +2 -1
  17. data/lib/imap/backup/serializer/directory.rb +5 -3
  18. data/lib/imap/backup/serializer/mbox.rb +10 -5
  19. data/lib/imap/backup/utils.rb +23 -30
  20. data/lib/imap/backup/version.rb +7 -7
  21. data/spec/spec_helper.rb +10 -27
  22. data/spec/support/higline_test_helpers.rb +8 -0
  23. data/spec/support/silence_logging.rb +7 -0
  24. data/spec/unit/account/connection_spec.rb +1 -1
  25. data/spec/unit/account/folder_spec.rb +33 -52
  26. data/spec/unit/configuration/asker_spec.rb +46 -5
  27. data/spec/unit/configuration/folder_chooser_spec.rb +62 -102
  28. data/spec/unit/configuration/list_spec.rb +40 -48
  29. data/spec/unit/configuration/setup_spec.rb +41 -62
  30. data/spec/unit/configuration/store_spec.rb +107 -99
  31. data/spec/unit/downloader_spec.rb +8 -8
  32. data/spec/unit/email/mboxrd/message_spec.rb +9 -19
  33. data/spec/unit/serializer/base_spec.rb +7 -5
  34. data/spec/unit/serializer/directory_spec.rb +30 -38
  35. data/spec/unit/serializer/mbox_spec.rb +64 -58
  36. data/spec/unit/utils_spec.rb +67 -41
  37. metadata +107 -141
@@ -2,74 +2,66 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Imap::Backup::Configuration::List do
5
- let(:configuration_data) do
6
- {
7
- :accounts => [
8
- {
9
- :username => 'a1@example.com'
10
- },
11
- {
12
- :username => 'a2@example.com',
13
- },
14
- ]
15
- }
5
+ let(:accounts) do
6
+ [
7
+ {:username => 'a1@example.com'},
8
+ {:username => 'a2@example.com'},
9
+ ]
16
10
  end
17
- let(:store) { stub('Imap::Backup::Configuration::Store', :data => configuration_data) }
11
+ let(:store) do
12
+ double('Imap::Backup::Configuration::Store', :data => {:accounts => accounts})
13
+ end
14
+ let(:exists) { true }
18
15
 
19
16
  before do
20
- Imap::Backup::Configuration::Store.stub!(:new => store)
21
- Imap::Backup::Configuration::Store.stub!(:exist? => true)
17
+ allow(Imap::Backup::Configuration::Store).to receive(:new).and_return(store)
18
+ allow(Imap::Backup::Configuration::Store).to receive(:exist?).and_return(exists)
22
19
  end
23
20
 
21
+ subject { described_class.new }
22
+
24
23
  context '#initialize' do
25
- it 'fails if the configuration file is missing' do
26
- Imap::Backup::Configuration::Store.should_receive(:exist?).and_return(false)
24
+ context 'with account parameter' do
25
+ subject { described_class.new(['a2@example.com']) }
27
26
 
28
- expect {
29
- Imap::Backup::Configuration::List.new
30
- }.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
27
+ it 'should only create requested accounts' do
28
+ expect(subject.accounts).to eq([accounts[1]])
29
+ end
31
30
  end
32
31
 
33
- context 'with account parameter' do
34
- it 'should only create requested accounts' do
35
- configuration = Imap::Backup::Configuration::List.new(['a2@example.com'])
32
+ context 'without an account parameter' do
33
+ it 'selects all accounts' do
34
+ expect(subject.accounts).to eq(accounts)
35
+ end
36
+ end
36
37
 
37
- configuration.accounts.should == configuration_data[:accounts][1..1]
38
+ context 'when the configuration file is missing' do
39
+ let(:exists) { false }
40
+
41
+ it 'fails' do
42
+ expect {
43
+ described_class.new
44
+ }.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
38
45
  end
39
46
  end
40
47
  end
41
48
 
42
49
  context 'instance methods' do
43
- let(:connection) { stub('Imap::Backup::Account::Connection', :disconnect => nil) }
50
+ let(:connection1) { double('Imap::Backup::Account::Connection', :disconnect => nil) }
51
+ let(:connection2) { double('Imap::Backup::Account::Connection', :disconnect => nil) }
44
52
 
45
- subject { Imap::Backup::Configuration::List.new }
53
+ before do
54
+ allow(Imap::Backup::Account::Connection).to receive(:new).with(accounts[0]).and_return(connection1)
55
+ allow(Imap::Backup::Account::Connection).to receive(:new).with(accounts[1]).and_return(connection2)
56
+ end
46
57
 
47
58
  context '#each_connection' do
59
+ specify "calls the block with each account's connection" do
60
+ connections = []
48
61
 
49
- it 'should instantiate connections' do
50
- Imap::Backup::Account::Connection.should_receive(:new).with(configuration_data[:accounts][0]).and_return(connection)
51
- Imap::Backup::Account::Connection.should_receive(:new).with(configuration_data[:accounts][1]).and_return(connection)
52
-
53
- subject.each_connection{}
54
- end
55
-
56
- it 'should call the block' do
57
- Imap::Backup::Account::Connection.stub!(:new).and_return(connection)
58
- calls = 0
59
-
60
- subject.each_connection do |a|
61
- calls += 1
62
- a.should == connection
63
- end
64
- calls.should == 2
65
- end
66
-
67
- it 'should disconnect connections' do
68
- Imap::Backup::Account::Connection.stub!(:new).and_return(connection)
69
-
70
- connection.should_receive(:disconnect)
62
+ subject.each_connection { |a| connections << a }
71
63
 
72
- subject.each_connection {}
64
+ expect(connections).to eq([connection1, connection2])
73
65
  end
74
66
  end
75
67
  end
@@ -7,37 +7,41 @@ describe Imap::Backup::Configuration::Setup do
7
7
  context '#initialize' do
8
8
  context 'without a config file' do
9
9
  it 'works' do
10
- Imap::Backup::Configuration::Setup.new
10
+ described_class.new
11
11
  end
12
12
  end
13
13
  end
14
14
 
15
15
  context '#run' do
16
- before :each do
17
- prepare_store
18
- @input, @output = prepare_highline
19
- subject.stub(:system => nil)
16
+ let(:account1) { {:username => 'account@example.com'} }
17
+ let(:account) { double('Imap::Backup::Configuration::Account', :run => nil) }
18
+ let(:data) { {:accounts => [account1]} }
19
+ let(:store) do
20
+ double(
21
+ 'Imap::Backup::Configuration::Store',
22
+ :data => data,
23
+ :path => '/base/path'
24
+ )
20
25
  end
21
26
 
22
- def prepare_store
23
- @account1 = {:username => 'account@example.com'}
24
- @data = {:accounts => [@account1]}
25
- @store = stub('Imap::Backup::Configuration::Store', :data => @data, :path => '/base/path')
26
- Imap::Backup::Configuration::Store.stub!(:new).and_return(@store)
27
+ before :each do
28
+ allow(Imap::Backup::Configuration::Store).to receive(:new).and_return(store)
29
+ @input, @output = prepare_highline
30
+ allow(@input).to receive(:eof?).and_return(false)
31
+ allow(@input).to receive(:gets).and_return("q\n")
32
+ allow(subject).to receive(:system)
27
33
  end
28
34
 
29
- subject { Imap::Backup::Configuration::Setup.new }
35
+ subject { described_class.new }
30
36
 
31
- it 'should present a main menu' do
32
- @input.should_receive(:eof?).and_return(false)
33
- @input.should_receive(:gets).and_return("q\n")
37
+ context 'main menu' do
38
+ before { subject.run }
34
39
 
35
- subject.run
36
-
37
- @output.string.should =~ /Choose an action:/
38
- @output.string.should =~ /add account/
39
- @output.string.should =~ /save and exit/
40
- @output.string.should =~ /quit/
40
+ %w(add\ account save\ and\ exit quit).each do |choice|
41
+ it "includes #{choice}" do
42
+ expect(@output.string).to include(choice)
43
+ end
44
+ end
41
45
  end
42
46
 
43
47
  it 'clears the screen' do
@@ -52,57 +56,32 @@ describe Imap::Backup::Configuration::Setup do
52
56
  @output.string.should =~ /account@example.com/
53
57
  end
54
58
 
55
- it 'should edit accounts' do
56
- state = :initial
57
- @input.stub(:gets) do
58
- case state
59
- when :initial
60
- state = :editing
61
- "account@example.com\n"
62
- else
63
- "q\n"
64
- end
59
+ context 'adding accounts' do
60
+ let(:blank_account) do
61
+ {
62
+ :username => "new@example.com",
63
+ :password => "",
64
+ :local_path => "/base/path/new_example.com",
65
+ :folders => []
66
+ }
65
67
  end
66
68
 
67
- @account = stub('Imap::Backup::Configuration::Account')
68
- allow(Imap::Backup::Configuration::Account).to receive(:new).with(@store, @account1, anything).and_return(@account)
69
- @account.should_receive(:run).with()
69
+ before do
70
+ allow(@input).to receive(:gets).and_return("add\n", "q\n")
71
+ allow(Imap::Backup::Configuration::Asker).to receive(:email).with(no_args).and_return('new@example.com')
72
+ allow(Imap::Backup::Configuration::Account).to receive(:new).with(store, blank_account, anything).and_return(account)
70
73
 
71
- subject.run
72
- end
73
-
74
- it 'should add accounts' do
75
- state = :initial
76
- @input.stub(:gets) do
77
- case state
78
- when :initial
79
- state = :editing
80
- "add\n"
81
- else
82
- "q\n"
83
- end
74
+ subject.run
84
75
  end
85
76
 
86
- blank_account = {:username=>"new@example.com", :password=>"", :local_path=>"/base/path/new_example.com", :folders=>[]}
87
- Imap::Backup::Configuration::Asker.should_receive(:email).with().and_return('new@example.com')
88
- @account = stub('Imap::Backup::Configuration::Account')
89
- allow(Imap::Backup::Configuration::Account).to receive(:new).with(@store, blank_account, anything).and_return(@account)
90
- @account.should_receive(:run).once
91
-
92
- subject.run
93
-
94
- @data[:accounts].size.should == 2
95
- @data[:accounts][1].should == {
96
- :username => "new@example.com",
97
- :password => "",
98
- :local_path => "/base/path/new_example.com",
99
- :folders => []
100
- }
77
+ it 'adds account data' do
78
+ expect(data[:accounts][1]).to eq(blank_account)
79
+ end
101
80
  end
102
81
 
103
82
  it 'should save the configuration' do
104
83
  @input.should_receive(:gets).with().and_return("save\n")
105
- @store.should_receive(:save).with()
84
+ store.should_receive(:save).with()
106
85
 
107
86
  subject.run
108
87
  end
@@ -1,119 +1,111 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
+ require 'json'
3
4
 
4
5
  describe Imap::Backup::Configuration::Store do
5
- before :all do
6
- @configuration_directory = Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY
7
- Imap::Backup::Configuration::Store.instance_eval { remove_const :'CONFIGURATION_DIRECTORY' }
8
- Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY = '/base/path'
9
- end
10
-
11
- after :all do
12
- Imap::Backup::Configuration::Store.instance_eval { remove_const :'CONFIGURATION_DIRECTORY' }
13
- Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY = @configuration_directory
6
+ let(:file_path) { '/base/path/config.json' }
7
+ let(:file_exists) { true }
8
+ let(:directory) { '/base/path' }
9
+ let(:directory_exists) { true }
10
+ let(:data) { {:the => :config} }
11
+ let(:configuration) { data.to_json }
12
+
13
+ before do
14
+ stub_const('Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY', directory)
15
+ allow(File).to receive(:directory?).with(directory).and_return(directory_exists)
16
+ allow(File).to receive(:exist?).with(file_path).and_return(file_exists)
17
+ allow(File).to receive(:read).with(file_path).and_return(configuration)
18
+ allow(JSON).to receive(:parse).with(configuration, anything).and_return(data)
14
19
  end
15
20
 
16
21
  context '.exist?' do
17
- it 'checks if the file exists' do
18
- File.should_receive(:exist?).with('/base/path/config.json').and_return(true)
19
-
20
- Imap::Backup::Configuration::Store.exist?
22
+ [true, false].each do |exists|
23
+ state = exists ? 'exists' : "doesn't exist"
24
+ context "when the file #{state}" do
25
+ let(:file_exists) { exists }
26
+
27
+ it "returns #{exists}" do
28
+ expect(described_class.exist?).to eq(file_exists)
29
+ end
30
+ end
21
31
  end
22
32
  end
23
33
 
24
34
  context '#initialize' do
25
35
  before :each do
26
- Imap::Backup::Utils.stub!(:check_permissions => nil)
36
+ allow(Imap::Backup::Utils).to receive(:check_permissions).and_return(nil)
27
37
  end
28
38
 
29
- it 'should not fail if the configuration file is missing' do
30
- File.should_receive(:directory?).with('/base/path').and_return(true)
31
- File.should_receive(:exist?).with('/base/path/config.json').and_return(false)
39
+ context 'loading' do
40
+ subject { described_class.new }
32
41
 
33
- expect do
34
- Imap::Backup::Configuration::Store.new
35
- end.to_not raise_error
42
+ it 'sets data' do
43
+ expect(subject.data).to eq(data)
44
+ end
36
45
  end
37
46
 
38
- it 'should fail if the config file permissions are too lax' do
39
- File.stub!(:exist?).with('/base/path/config.json').and_return(true)
40
-
41
- Imap::Backup::Utils.should_receive(:check_permissions).with('/base/path/config.json', 0600).and_raise('Error')
47
+ context 'if the configuration file is missing' do
48
+ let(:file_exists) { false }
42
49
 
43
- expect do
44
- Imap::Backup::Configuration::Store.new
45
- end.to raise_error(RuntimeError, 'Error')
50
+ it "doesn't fail" do
51
+ expect do
52
+ described_class.new
53
+ end.to_not raise_error
54
+ end
46
55
  end
47
56
 
48
- it 'should load the config file' do
49
- File.stub!(:exist?).with('/base/path/config.json').and_return(true)
57
+ context 'if the config file permissions are too lax' do
58
+ let(:file_exists) { true }
50
59
 
51
- configuration = 'JSON string'
52
- File.should_receive(:read).with('/base/path/config.json').and_return(configuration)
53
- JSON.should_receive(:parse).with(configuration, :symbolize_names => true)
60
+ before do
61
+ allow(Imap::Backup::Utils).to receive(:check_permissions).with(file_path, 0600).and_raise('Error')
62
+ end
54
63
 
55
- Imap::Backup::Configuration::Store.new
64
+ it 'fails' do
65
+ expect do
66
+ described_class.new
67
+ end.to raise_error(RuntimeError, 'Error')
68
+ end
56
69
  end
57
70
  end
58
71
 
59
72
  context '#save' do
60
- before :each do
61
- # initialize
62
- File.stub!(:directory?).with('/base/path').and_return(false)
63
- File.stub!(:exist?).with('/base/path/config.json').and_return(false)
64
- # save
65
- @file = stub('File')
66
- File.stub!(:directory?).with('/base/path').and_return(false)
67
- FileUtils.stub!(:mkdir).with('/base/path')
68
- Imap::Backup::Utils.stub!(:stat).with('/base/path').and_return(0700)
69
- FileUtils.stub!(:chmod).with(0700, '/base/path')
70
- File.stub!(:open).with('/base/path/config.json', 'w') { |&b| b.call @file }
71
- JSON.stub!(:pretty_generate => 'JSON output')
72
- @file.stub!(:write).with('JSON output')
73
- FileUtils.stub!(:chmod).with(0600, '/base/path/config.json')
73
+ let(:directory_exists) { false }
74
+ let(:file_exists) { false }
75
+ let(:file) { double('File', :write => nil) }
76
+
77
+ before do
78
+ allow(FileUtils).to receive(:mkdir)
79
+ allow(FileUtils).to receive(:chmod)
80
+ allow(Imap::Backup::Utils).to receive(:stat).with(directory).and_return(0700)
81
+ allow(Imap::Backup::Utils).to receive(:stat).with(file_path).and_return(0600)
82
+ allow(File).to receive(:open).with(file_path, 'w') { |&b| b.call file }
83
+ allow(JSON).to receive(:pretty_generate).and_return('JSON output')
74
84
  end
75
85
 
76
- subject { Imap::Backup::Configuration::Store.new }
77
-
78
- it 'should create the config directory' do
79
- File.should_receive(:directory?).with('/base/path').and_return(false)
80
- FileUtils.should_receive(:mkdir).with('/base/path')
86
+ subject { described_class.new }
81
87
 
88
+ it 'creates the config directory' do
82
89
  subject.save
83
- end
84
90
 
85
- it 'should save the config file' do
86
- @file.should_receive(:write).with('JSON output')
91
+ expect(FileUtils).to have_received(:mkdir).with(directory)
92
+ end
87
93
 
94
+ it 'saves the configuration' do
88
95
  subject.save
89
- end
90
96
 
91
- it 'should set config perms to 0600' do
92
- FileUtils.should_receive(:chmod).with(0600, '/base/path/config.json')
97
+ expect(file).to have_received(:write).with('JSON output')
98
+ end
93
99
 
100
+ it 'sets config perms to 0600' do
94
101
  subject.save
102
+
103
+ expect(FileUtils).to have_received(:chmod).with(0600, file_path)
95
104
  end
96
105
 
97
106
  context 'saving accounts' do
98
- before :each do
99
- # initialize
100
- File.stub!(:exist?).with('/base/path/config.json').and_return(true)
101
- Imap::Backup::Utils.stub!(:check_permissions).with('/base/path/config.json', 0600)
102
- folders = [
103
- { :name => 'A folder' },
104
- ]
105
- File.stub!(:read).with('/base/path/config.json').and_return('xxx')
106
- JSON.stub!(:parse).with('xxx', :symbolize_names => true).and_return(configuration(folders))
107
- # save
108
- File.stub!(:directory?).with('/my/backup/path').and_return(false)
109
- FileUtils.stub!(:mkdir).with('/my/backup/path')
110
- Imap::Backup::Utils.stub!(:stat).with('/my/backup/path').and_return(0700)
111
- File.stub!(:directory?).with('/my/backup/path/A folder').and_return(false)
112
- FileUtils.stub!(:mkdir).with('/my/backup/path/A folder')
113
- Imap::Backup::Utils.stub!(:stat).with('/my/backup/path/A folder').and_return(0700)
114
- end
115
-
116
- def configuration(folders)
107
+ let(:folders) { [{ :name => 'A folder' }] }
108
+ let(:data) do
117
109
  {
118
110
  :accounts => [
119
111
  :local_path => '/my/backup/path',
@@ -121,40 +113,56 @@ describe Imap::Backup::Configuration::Store do
121
113
  ]
122
114
  }
123
115
  end
116
+ let(:file_exists) { true }
117
+ let(:a_folder_perms) { 0700 }
118
+
119
+ before do
120
+ allow(Imap::Backup::Utils).to receive(:check_permissions)
121
+ allow(File).to receive(:directory?).with('/my/backup/path').and_return(false)
122
+ allow(Imap::Backup::Utils).to receive(:stat).with('/my/backup/path').and_return(0700)
123
+ allow(File).to receive(:directory?).with('/my/backup/path/A folder').and_return(false)
124
+ allow(Imap::Backup::Utils).to receive(:stat).with('/my/backup/path/A folder').and_return(a_folder_perms)
125
+ end
124
126
 
125
- subject { Imap::Backup::Configuration::Store.new }
126
-
127
- it 'should create account directories' do
128
- File.should_receive(:directory?).with('/my/backup/path').and_return(false)
129
- FileUtils.should_receive(:mkdir).with('/my/backup/path')
130
-
127
+ it 'creates account directories' do
131
128
  subject.save
132
- end
133
129
 
134
- it 'should create folder directories' do
135
- File.should_receive(:directory?).with('/my/backup/path/A folder').and_return(false)
136
- FileUtils.should_receive(:mkdir).with('/my/backup/path/A folder')
130
+ expect(FileUtils).to have_received(:mkdir).with('/my/backup/path')
131
+ end
137
132
 
133
+ it 'creates folder directories' do
138
134
  subject.save
135
+
136
+ expect(FileUtils).to have_received(:mkdir).with('/my/backup/path/A folder')
139
137
  end
140
138
 
141
- it 'should set directory permissions, if necessary' do
142
- Imap::Backup::Utils.stub!(:stat).with('/my/backup/path/A folder').and_return(0755)
143
- FileUtils.should_receive(:chmod).with(0700, '/my/backup/path/A folder')
139
+ context 'when directory permissions are too open' do
140
+ let(:a_folder_perms) { 0755 }
144
141
 
145
- subject.save
142
+ it 'sets premissions' do
143
+ subject.save
144
+
145
+ expect(FileUtils).to have_received(:chmod).with(0700, '/my/backup/path/A folder')
146
+ end
146
147
  end
147
148
 
148
- it 'should create a path for folders with slashes' do
149
- folders = [{:name => 'folder/path'}]
150
- JSON.stub!(:parse).with('xxx', :symbolize_names => true).and_return(configuration(folders))
149
+ context 'when folders have slashes' do
150
+ let(:directory_exists) { true }
151
+ let(:folders) { [{:name => 'folder/path'}] }
151
152
 
152
- File.should_receive(:directory?).with('/my/backup/path/folder').and_return(true)
153
- Imap::Backup::Utils.should_receive(:stat).with('/my/backup/path/folder').and_return(0700)
154
- File.should_receive(:directory?).with('/my/backup/path/folder/path').and_return(true)
155
- Imap::Backup::Utils.should_receive(:stat).with('/my/backup/path/folder/path').and_return(0700)
153
+ before do
154
+ allow(File).to receive(:directory?).with('/my/backup/path/folder').and_return(true)
155
+ allow(Imap::Backup::Utils).to receive(:stat).with('/my/backup/path/folder').and_return(0700)
156
+ allow(File).to receive(:directory?).with('/my/backup/path/folder/path').and_return(false)
157
+ allow(Imap::Backup::Utils).to receive(:stat).with('/my/backup/path/folder/path').and_return(0700)
158
+ allow(FileUtils).to receive(:mkdir)
159
+ end
156
160
 
157
- subject.save
161
+ it 'creates subdirectories' do
162
+ subject.save
163
+
164
+ expect(FileUtils).to have_received(:mkdir).with('/my/backup/path/folder/path')
165
+ end
158
166
  end
159
167
  end
160
168
  end