backup-agoddard 3.0.27
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.
- data/.gitignore +8 -0
- data/.travis.yml +10 -0
- data/Gemfile +28 -0
- data/Guardfile +23 -0
- data/LICENSE.md +24 -0
- data/README.md +478 -0
- data/backup.gemspec +32 -0
- data/bin/backup +11 -0
- data/lib/backup.rb +133 -0
- data/lib/backup/archive.rb +117 -0
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/cleaner.rb +121 -0
- data/lib/backup/cli/helpers.rb +93 -0
- data/lib/backup/cli/utility.rb +255 -0
- data/lib/backup/compressor/base.rb +35 -0
- data/lib/backup/compressor/bzip2.rb +50 -0
- data/lib/backup/compressor/custom.rb +53 -0
- data/lib/backup/compressor/gzip.rb +50 -0
- data/lib/backup/compressor/lzma.rb +52 -0
- data/lib/backup/compressor/pbzip2.rb +59 -0
- data/lib/backup/config.rb +174 -0
- data/lib/backup/configuration.rb +33 -0
- data/lib/backup/configuration/helpers.rb +130 -0
- data/lib/backup/configuration/store.rb +24 -0
- data/lib/backup/database/base.rb +53 -0
- data/lib/backup/database/mongodb.rb +230 -0
- data/lib/backup/database/mysql.rb +160 -0
- data/lib/backup/database/postgresql.rb +144 -0
- data/lib/backup/database/redis.rb +136 -0
- data/lib/backup/database/riak.rb +67 -0
- data/lib/backup/dependency.rb +108 -0
- data/lib/backup/encryptor/base.rb +29 -0
- data/lib/backup/encryptor/gpg.rb +760 -0
- data/lib/backup/encryptor/open_ssl.rb +72 -0
- data/lib/backup/errors.rb +124 -0
- data/lib/backup/hooks.rb +68 -0
- data/lib/backup/logger.rb +152 -0
- data/lib/backup/model.rb +409 -0
- data/lib/backup/notifier/base.rb +81 -0
- data/lib/backup/notifier/campfire.rb +155 -0
- data/lib/backup/notifier/hipchat.rb +93 -0
- data/lib/backup/notifier/mail.rb +206 -0
- data/lib/backup/notifier/prowl.rb +65 -0
- data/lib/backup/notifier/pushover.rb +88 -0
- data/lib/backup/notifier/twitter.rb +70 -0
- data/lib/backup/package.rb +47 -0
- data/lib/backup/packager.rb +100 -0
- data/lib/backup/pipeline.rb +110 -0
- data/lib/backup/splitter.rb +75 -0
- data/lib/backup/storage/base.rb +99 -0
- data/lib/backup/storage/cloudfiles.rb +87 -0
- data/lib/backup/storage/cycler.rb +117 -0
- data/lib/backup/storage/dropbox.rb +178 -0
- data/lib/backup/storage/ftp.rb +119 -0
- data/lib/backup/storage/local.rb +82 -0
- data/lib/backup/storage/ninefold.rb +116 -0
- data/lib/backup/storage/rsync.rb +149 -0
- data/lib/backup/storage/s3.rb +94 -0
- data/lib/backup/storage/scp.rb +99 -0
- data/lib/backup/storage/sftp.rb +108 -0
- data/lib/backup/syncer/base.rb +46 -0
- data/lib/backup/syncer/cloud/base.rb +247 -0
- data/lib/backup/syncer/cloud/cloud_files.rb +78 -0
- data/lib/backup/syncer/cloud/s3.rb +68 -0
- data/lib/backup/syncer/rsync/base.rb +49 -0
- data/lib/backup/syncer/rsync/local.rb +55 -0
- data/lib/backup/syncer/rsync/pull.rb +36 -0
- data/lib/backup/syncer/rsync/push.rb +116 -0
- data/lib/backup/template.rb +46 -0
- data/lib/backup/version.rb +43 -0
- data/spec-live/.gitignore +6 -0
- data/spec-live/README +7 -0
- data/spec-live/backups/config.rb +83 -0
- data/spec-live/backups/config.yml.template +46 -0
- data/spec-live/backups/models.rb +184 -0
- data/spec-live/compressor/custom_spec.rb +30 -0
- data/spec-live/compressor/gzip_spec.rb +30 -0
- data/spec-live/encryptor/gpg_keys.rb +239 -0
- data/spec-live/encryptor/gpg_spec.rb +287 -0
- data/spec-live/notifier/mail_spec.rb +121 -0
- data/spec-live/spec_helper.rb +151 -0
- data/spec-live/storage/dropbox_spec.rb +151 -0
- data/spec-live/storage/local_spec.rb +83 -0
- data/spec-live/storage/scp_spec.rb +193 -0
- data/spec-live/syncer/cloud/s3_spec.rb +124 -0
- data/spec/archive_spec.rb +335 -0
- data/spec/cleaner_spec.rb +312 -0
- data/spec/cli/helpers_spec.rb +301 -0
- data/spec/cli/utility_spec.rb +411 -0
- data/spec/compressor/base_spec.rb +52 -0
- data/spec/compressor/bzip2_spec.rb +217 -0
- data/spec/compressor/custom_spec.rb +106 -0
- data/spec/compressor/gzip_spec.rb +217 -0
- data/spec/compressor/lzma_spec.rb +123 -0
- data/spec/compressor/pbzip2_spec.rb +165 -0
- data/spec/config_spec.rb +321 -0
- data/spec/configuration/helpers_spec.rb +247 -0
- data/spec/configuration/store_spec.rb +39 -0
- data/spec/configuration_spec.rb +62 -0
- data/spec/database/base_spec.rb +63 -0
- data/spec/database/mongodb_spec.rb +510 -0
- data/spec/database/mysql_spec.rb +411 -0
- data/spec/database/postgresql_spec.rb +353 -0
- data/spec/database/redis_spec.rb +334 -0
- data/spec/database/riak_spec.rb +176 -0
- data/spec/dependency_spec.rb +51 -0
- data/spec/encryptor/base_spec.rb +40 -0
- data/spec/encryptor/gpg_spec.rb +909 -0
- data/spec/encryptor/open_ssl_spec.rb +148 -0
- data/spec/errors_spec.rb +306 -0
- data/spec/hooks_spec.rb +35 -0
- data/spec/logger_spec.rb +367 -0
- data/spec/model_spec.rb +694 -0
- data/spec/notifier/base_spec.rb +104 -0
- data/spec/notifier/campfire_spec.rb +217 -0
- data/spec/notifier/hipchat_spec.rb +211 -0
- data/spec/notifier/mail_spec.rb +316 -0
- data/spec/notifier/prowl_spec.rb +138 -0
- data/spec/notifier/pushover_spec.rb +123 -0
- data/spec/notifier/twitter_spec.rb +153 -0
- data/spec/package_spec.rb +61 -0
- data/spec/packager_spec.rb +213 -0
- data/spec/pipeline_spec.rb +259 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/splitter_spec.rb +120 -0
- data/spec/storage/base_spec.rb +166 -0
- data/spec/storage/cloudfiles_spec.rb +254 -0
- data/spec/storage/cycler_spec.rb +247 -0
- data/spec/storage/dropbox_spec.rb +480 -0
- data/spec/storage/ftp_spec.rb +271 -0
- data/spec/storage/local_spec.rb +259 -0
- data/spec/storage/ninefold_spec.rb +343 -0
- data/spec/storage/rsync_spec.rb +362 -0
- data/spec/storage/s3_spec.rb +245 -0
- data/spec/storage/scp_spec.rb +233 -0
- data/spec/storage/sftp_spec.rb +244 -0
- data/spec/syncer/base_spec.rb +109 -0
- data/spec/syncer/cloud/base_spec.rb +515 -0
- data/spec/syncer/cloud/cloud_files_spec.rb +181 -0
- data/spec/syncer/cloud/s3_spec.rb +174 -0
- data/spec/syncer/rsync/base_spec.rb +98 -0
- data/spec/syncer/rsync/local_spec.rb +149 -0
- data/spec/syncer/rsync/pull_spec.rb +98 -0
- data/spec/syncer/rsync/push_spec.rb +333 -0
- data/spec/version_spec.rb +21 -0
- data/templates/cli/utility/archive +25 -0
- data/templates/cli/utility/compressor/bzip2 +4 -0
- data/templates/cli/utility/compressor/custom +11 -0
- data/templates/cli/utility/compressor/gzip +4 -0
- data/templates/cli/utility/compressor/lzma +10 -0
- data/templates/cli/utility/compressor/pbzip2 +10 -0
- data/templates/cli/utility/config +32 -0
- data/templates/cli/utility/database/mongodb +18 -0
- data/templates/cli/utility/database/mysql +21 -0
- data/templates/cli/utility/database/postgresql +17 -0
- data/templates/cli/utility/database/redis +16 -0
- data/templates/cli/utility/database/riak +11 -0
- data/templates/cli/utility/encryptor/gpg +27 -0
- data/templates/cli/utility/encryptor/openssl +9 -0
- data/templates/cli/utility/model.erb +23 -0
- data/templates/cli/utility/notifier/campfire +12 -0
- data/templates/cli/utility/notifier/hipchat +15 -0
- data/templates/cli/utility/notifier/mail +22 -0
- data/templates/cli/utility/notifier/prowl +11 -0
- data/templates/cli/utility/notifier/pushover +11 -0
- data/templates/cli/utility/notifier/twitter +13 -0
- data/templates/cli/utility/splitter +7 -0
- data/templates/cli/utility/storage/cloud_files +22 -0
- data/templates/cli/utility/storage/dropbox +20 -0
- data/templates/cli/utility/storage/ftp +12 -0
- data/templates/cli/utility/storage/local +7 -0
- data/templates/cli/utility/storage/ninefold +9 -0
- data/templates/cli/utility/storage/rsync +11 -0
- data/templates/cli/utility/storage/s3 +19 -0
- data/templates/cli/utility/storage/scp +11 -0
- data/templates/cli/utility/storage/sftp +11 -0
- data/templates/cli/utility/syncer/cloud_files +46 -0
- data/templates/cli/utility/syncer/rsync_local +12 -0
- data/templates/cli/utility/syncer/rsync_pull +17 -0
- data/templates/cli/utility/syncer/rsync_push +17 -0
- data/templates/cli/utility/syncer/s3 +43 -0
- data/templates/general/links +11 -0
- data/templates/general/version.erb +2 -0
- data/templates/notifier/mail/failure.erb +9 -0
- data/templates/notifier/mail/success.erb +7 -0
- data/templates/notifier/mail/warning.erb +9 -0
- data/templates/storage/dropbox/authorization_url.erb +6 -0
- data/templates/storage/dropbox/authorized.erb +4 -0
- data/templates/storage/dropbox/cache_file_written.erb +10 -0
- metadata +277 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../../../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe Backup::Syncer::RSync::Local do
|
|
6
|
+
let(:syncer) do
|
|
7
|
+
Backup::Syncer::RSync::Local.new do |rsync|
|
|
8
|
+
rsync.path = "~/my_backups"
|
|
9
|
+
rsync.mirror = true
|
|
10
|
+
rsync.additional_options = ['--opt-a', '--opt-b']
|
|
11
|
+
|
|
12
|
+
rsync.directories do |directory|
|
|
13
|
+
directory.add "/some/directory"
|
|
14
|
+
directory.add "~/home/directory"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'should be a subclass of Syncer::RSync::Base' do
|
|
20
|
+
Backup::Syncer::RSync::Local.
|
|
21
|
+
superclass.should == Backup::Syncer::RSync::Base
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '#initialize' do
|
|
25
|
+
after { Backup::Syncer::RSync::Local.clear_defaults! }
|
|
26
|
+
|
|
27
|
+
it 'should load pre-configured defaults through Syncer::Base' do
|
|
28
|
+
Backup::Syncer::RSync::Local.any_instance.expects(:load_defaults!)
|
|
29
|
+
syncer
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'when no pre-configured defaults have been set' do
|
|
33
|
+
it 'should use the values given' do
|
|
34
|
+
syncer.path.should == '~/my_backups'
|
|
35
|
+
syncer.mirror.should == true
|
|
36
|
+
syncer.directories.should == ["/some/directory", "~/home/directory"]
|
|
37
|
+
syncer.additional_options.should == ['--opt-a', '--opt-b']
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'should use default values if none are given' do
|
|
41
|
+
syncer = Backup::Syncer::RSync::Local.new
|
|
42
|
+
|
|
43
|
+
# from Syncer::Base
|
|
44
|
+
syncer.path.should == 'backups'
|
|
45
|
+
syncer.mirror.should == false
|
|
46
|
+
syncer.directories.should == []
|
|
47
|
+
|
|
48
|
+
# from Syncer::RSync::Base
|
|
49
|
+
syncer.additional_options.should == []
|
|
50
|
+
end
|
|
51
|
+
end # context 'when no pre-configured defaults have been set'
|
|
52
|
+
|
|
53
|
+
context 'when pre-configured defaults have been set' do
|
|
54
|
+
before do
|
|
55
|
+
Backup::Syncer::RSync::Local.defaults do |rsync|
|
|
56
|
+
rsync.path = 'some_path'
|
|
57
|
+
rsync.mirror = 'some_mirror'
|
|
58
|
+
rsync.additional_options = 'some_additional_options'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should use pre-configured defaults' do
|
|
63
|
+
syncer = Backup::Syncer::RSync::Local.new
|
|
64
|
+
|
|
65
|
+
syncer.path.should == 'some_path'
|
|
66
|
+
syncer.mirror.should == 'some_mirror'
|
|
67
|
+
syncer.directories.should == []
|
|
68
|
+
syncer.additional_options.should == 'some_additional_options'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'should override pre-configured defaults' do
|
|
72
|
+
syncer = Backup::Syncer::RSync::Local.new do |rsync|
|
|
73
|
+
rsync.path = 'new_path'
|
|
74
|
+
rsync.mirror = 'new_mirror'
|
|
75
|
+
rsync.additional_options = 'new_additional_options'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
syncer.path.should == 'new_path'
|
|
79
|
+
syncer.mirror.should == 'new_mirror'
|
|
80
|
+
syncer.directories.should == []
|
|
81
|
+
syncer.additional_options.should == 'new_additional_options'
|
|
82
|
+
end
|
|
83
|
+
end # context 'when pre-configured defaults have been set'
|
|
84
|
+
end # describe '#initialize'
|
|
85
|
+
|
|
86
|
+
describe '#perform!' do
|
|
87
|
+
let(:s) { sequence '' }
|
|
88
|
+
|
|
89
|
+
before do
|
|
90
|
+
syncer.expects(:utility).with(:rsync).returns('rsync')
|
|
91
|
+
syncer.expects(:options).returns('options_output')
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'should sync two directories' do
|
|
95
|
+
Backup::Logger.expects(:message).in_sequence(s).with(
|
|
96
|
+
"Syncer::RSync::Local started syncing the following directories:\n" +
|
|
97
|
+
" /some/directory\n" +
|
|
98
|
+
" ~/home/directory"
|
|
99
|
+
)
|
|
100
|
+
syncer.expects(:run).in_sequence(s).with(
|
|
101
|
+
"rsync options_output '/some/directory' " +
|
|
102
|
+
"'#{ File.expand_path('~/home/directory') }' " +
|
|
103
|
+
"'#{ File.expand_path('~/my_backups') }'"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
syncer.perform!
|
|
107
|
+
end
|
|
108
|
+
end # describe '#perform!'
|
|
109
|
+
|
|
110
|
+
describe '#dest_path' do
|
|
111
|
+
it 'should return @path expanded' do
|
|
112
|
+
syncer.send(:dest_path).should == File.expand_path('~/my_backups')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'should set @dest_path' do
|
|
116
|
+
syncer.send(:dest_path)
|
|
117
|
+
syncer.instance_variable_get(:@dest_path).should ==
|
|
118
|
+
File.expand_path('~/my_backups')
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'should return @dest_path if already set' do
|
|
122
|
+
syncer.instance_variable_set(:@dest_path, 'foo')
|
|
123
|
+
syncer.send(:dest_path).should == 'foo'
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe '#options' do
|
|
128
|
+
context 'when @mirror is true' do
|
|
129
|
+
it 'should return the options with mirroring enabled' do
|
|
130
|
+
syncer.send(:options).should == '--archive --delete --opt-a --opt-b'
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context 'when @mirror is false' do
|
|
135
|
+
before { syncer.mirror = false }
|
|
136
|
+
it 'should return the options without mirroring enabled' do
|
|
137
|
+
syncer.send(:options).should == '--archive --opt-a --opt-b'
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context 'when no additional options are given' do
|
|
142
|
+
before { syncer.additional_options = [] }
|
|
143
|
+
it 'should return the options without additional options' do
|
|
144
|
+
syncer.send(:options).should == '--archive --delete'
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../../../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe Backup::Syncer::RSync::Pull do
|
|
6
|
+
let(:syncer) do
|
|
7
|
+
Backup::Syncer::RSync::Pull.new do |rsync|
|
|
8
|
+
rsync.username = 'my_username'
|
|
9
|
+
rsync.password = 'my_password'
|
|
10
|
+
rsync.ip = '123.45.678.90'
|
|
11
|
+
rsync.port = 22
|
|
12
|
+
rsync.compress = true
|
|
13
|
+
rsync.path = "~/my_backups"
|
|
14
|
+
|
|
15
|
+
rsync.directories do |directory|
|
|
16
|
+
directory.add "/some/directory"
|
|
17
|
+
directory.add "~/home/directory"
|
|
18
|
+
directory.add "another/directory"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
rsync.mirror = true
|
|
22
|
+
rsync.additional_options = ['--opt-a', '--opt-b']
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should be a subclass of RSync::Push' do
|
|
27
|
+
Backup::Syncer::RSync::Pull.superclass.should == Backup::Syncer::RSync::Push
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#perform!' do
|
|
31
|
+
let(:s) { sequence '' }
|
|
32
|
+
|
|
33
|
+
it 'should perform the RSync::Pull operation on two directories' do
|
|
34
|
+
syncer.expects(:utility).times(3).with(:rsync).returns('rsync')
|
|
35
|
+
syncer.expects(:options).times(3).returns('options_output')
|
|
36
|
+
|
|
37
|
+
syncer.expects(:write_password_file!).in_sequence(s)
|
|
38
|
+
|
|
39
|
+
# first directory - uses the given full path
|
|
40
|
+
Backup::Logger.expects(:message).in_sequence(s).with(
|
|
41
|
+
"Syncer::RSync::Pull started syncing '/some/directory'."
|
|
42
|
+
)
|
|
43
|
+
syncer.expects(:run).in_sequence(s).with(
|
|
44
|
+
"rsync options_output 'my_username@123.45.678.90:/some/directory' " +
|
|
45
|
+
"'#{ File.expand_path('~/my_backups') }'"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# second directory - removes leading '~'
|
|
49
|
+
Backup::Logger.expects(:message).in_sequence(s).with(
|
|
50
|
+
"Syncer::RSync::Pull started syncing '~/home/directory'."
|
|
51
|
+
)
|
|
52
|
+
syncer.expects(:run).in_sequence(s).with(
|
|
53
|
+
"rsync options_output 'my_username@123.45.678.90:home/directory' " +
|
|
54
|
+
"'#{ File.expand_path('~/my_backups') }'"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# third directory - does not expand path
|
|
58
|
+
Backup::Logger.expects(:message).in_sequence(s).with(
|
|
59
|
+
"Syncer::RSync::Pull started syncing 'another/directory'."
|
|
60
|
+
)
|
|
61
|
+
syncer.expects(:run).in_sequence(s).with(
|
|
62
|
+
"rsync options_output 'my_username@123.45.678.90:another/directory' " +
|
|
63
|
+
"'#{ File.expand_path('~/my_backups') }'"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
syncer.expects(:remove_password_file!).in_sequence(s)
|
|
67
|
+
|
|
68
|
+
syncer.perform!
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'should ensure passoword file removal' do
|
|
72
|
+
syncer.expects(:write_password_file!).raises('error message')
|
|
73
|
+
syncer.expects(:remove_password_file!)
|
|
74
|
+
|
|
75
|
+
expect do
|
|
76
|
+
syncer.perform!
|
|
77
|
+
end.to raise_error(RuntimeError, 'error message')
|
|
78
|
+
end
|
|
79
|
+
end # describe '#perform!'
|
|
80
|
+
|
|
81
|
+
describe '#dest_path' do
|
|
82
|
+
it 'should return @path expanded' do
|
|
83
|
+
syncer.send(:dest_path).should == File.expand_path('~/my_backups')
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'should set @dest_path' do
|
|
87
|
+
syncer.send(:dest_path)
|
|
88
|
+
syncer.instance_variable_get(:@dest_path).should ==
|
|
89
|
+
File.expand_path('~/my_backups')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'should return @dest_path if already set' do
|
|
93
|
+
syncer.instance_variable_set(:@dest_path, 'foo')
|
|
94
|
+
syncer.send(:dest_path).should == 'foo'
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../../../spec_helper.rb', __FILE__)
|
|
4
|
+
|
|
5
|
+
describe Backup::Syncer::RSync::Push do
|
|
6
|
+
let(:syncer) do
|
|
7
|
+
Backup::Syncer::RSync::Push.new do |rsync|
|
|
8
|
+
rsync.username = 'my_username'
|
|
9
|
+
rsync.password = 'my_password'
|
|
10
|
+
rsync.ip = '123.45.678.90'
|
|
11
|
+
rsync.port = 22
|
|
12
|
+
rsync.compress = true
|
|
13
|
+
rsync.path = "~/my_backups"
|
|
14
|
+
|
|
15
|
+
rsync.directories do |directory|
|
|
16
|
+
directory.add "/some/directory"
|
|
17
|
+
directory.add "~/home/directory"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
rsync.mirror = true
|
|
21
|
+
rsync.additional_options = ['--opt-a', '--opt-b']
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should be a subclass of Syncer::RSync::Base' do
|
|
26
|
+
Backup::Syncer::RSync::Push.
|
|
27
|
+
superclass.should == Backup::Syncer::RSync::Base
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#initialize' do
|
|
31
|
+
after { Backup::Syncer::RSync::Push.clear_defaults! }
|
|
32
|
+
|
|
33
|
+
it 'should load pre-configured defaults through Syncer::Base' do
|
|
34
|
+
Backup::Syncer::RSync::Push.any_instance.expects(:load_defaults!)
|
|
35
|
+
syncer
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'when no pre-configured defaults have been set' do
|
|
39
|
+
it 'should use the values given' do
|
|
40
|
+
syncer.path.should == '~/my_backups'
|
|
41
|
+
syncer.mirror.should == true
|
|
42
|
+
syncer.directories.should == ["/some/directory", "~/home/directory"]
|
|
43
|
+
syncer.additional_options.should == ['--opt-a', '--opt-b']
|
|
44
|
+
|
|
45
|
+
syncer.username.should == 'my_username'
|
|
46
|
+
syncer.password.should == 'my_password'
|
|
47
|
+
syncer.ip.should == '123.45.678.90'
|
|
48
|
+
syncer.port.should == 22
|
|
49
|
+
syncer.compress.should == true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should use default values if none are given' do
|
|
53
|
+
syncer = Backup::Syncer::RSync::Push.new
|
|
54
|
+
|
|
55
|
+
# from Syncer::Base
|
|
56
|
+
syncer.path.should == 'backups'
|
|
57
|
+
syncer.mirror.should == false
|
|
58
|
+
syncer.directories.should == []
|
|
59
|
+
|
|
60
|
+
# from Syncer::RSync::Base
|
|
61
|
+
syncer.additional_options.should == []
|
|
62
|
+
|
|
63
|
+
syncer.username.should == nil
|
|
64
|
+
syncer.password.should == nil
|
|
65
|
+
syncer.ip.should == nil
|
|
66
|
+
syncer.port.should == 22
|
|
67
|
+
syncer.compress.should == false
|
|
68
|
+
end
|
|
69
|
+
end # context 'when no pre-configured defaults have been set'
|
|
70
|
+
|
|
71
|
+
context 'when pre-configured defaults have been set' do
|
|
72
|
+
before do
|
|
73
|
+
Backup::Syncer::RSync::Push.defaults do |rsync|
|
|
74
|
+
rsync.path = 'some_path'
|
|
75
|
+
rsync.mirror = 'some_mirror'
|
|
76
|
+
rsync.additional_options = 'some_additional_options'
|
|
77
|
+
|
|
78
|
+
rsync.username = 'some_username'
|
|
79
|
+
rsync.password = 'some_password'
|
|
80
|
+
rsync.ip = 'some_ip'
|
|
81
|
+
rsync.port = 'some_port'
|
|
82
|
+
rsync.compress = 'some_compress'
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'should use pre-configured defaults' do
|
|
87
|
+
syncer = Backup::Syncer::RSync::Push.new
|
|
88
|
+
|
|
89
|
+
syncer.path.should == 'some_path'
|
|
90
|
+
syncer.mirror.should == 'some_mirror'
|
|
91
|
+
syncer.directories.should == []
|
|
92
|
+
syncer.additional_options.should == 'some_additional_options'
|
|
93
|
+
|
|
94
|
+
syncer.username.should == 'some_username'
|
|
95
|
+
syncer.password.should == 'some_password'
|
|
96
|
+
syncer.ip.should == 'some_ip'
|
|
97
|
+
syncer.port.should == 'some_port'
|
|
98
|
+
syncer.compress.should == 'some_compress'
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'should override pre-configured defaults' do
|
|
102
|
+
syncer = Backup::Syncer::RSync::Push.new do |rsync|
|
|
103
|
+
rsync.path = 'new_path'
|
|
104
|
+
rsync.mirror = 'new_mirror'
|
|
105
|
+
rsync.additional_options = 'new_additional_options'
|
|
106
|
+
|
|
107
|
+
rsync.username = 'new_username'
|
|
108
|
+
rsync.password = 'new_password'
|
|
109
|
+
rsync.ip = 'new_ip'
|
|
110
|
+
rsync.port = 'new_port'
|
|
111
|
+
rsync.compress = 'new_compress'
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
syncer.path.should == 'new_path'
|
|
115
|
+
syncer.mirror.should == 'new_mirror'
|
|
116
|
+
syncer.directories.should == []
|
|
117
|
+
syncer.additional_options.should == 'new_additional_options'
|
|
118
|
+
|
|
119
|
+
syncer.username.should == 'new_username'
|
|
120
|
+
syncer.password.should == 'new_password'
|
|
121
|
+
syncer.ip.should == 'new_ip'
|
|
122
|
+
syncer.port.should == 'new_port'
|
|
123
|
+
syncer.compress.should == 'new_compress'
|
|
124
|
+
end
|
|
125
|
+
end # context 'when pre-configured defaults have been set'
|
|
126
|
+
end # describe '#initialize'
|
|
127
|
+
|
|
128
|
+
describe '#perform!' do
|
|
129
|
+
let(:s) { sequence '' }
|
|
130
|
+
|
|
131
|
+
before do
|
|
132
|
+
syncer.expects(:utility).with(:rsync).returns('rsync')
|
|
133
|
+
syncer.expects(:options).returns('options_output')
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'should sync two directories' do
|
|
137
|
+
syncer.expects(:write_password_file!).in_sequence(s)
|
|
138
|
+
|
|
139
|
+
Backup::Logger.expects(:message).in_sequence(s).with(
|
|
140
|
+
"Syncer::RSync::Push started syncing the following directories:\n" +
|
|
141
|
+
" /some/directory\n" +
|
|
142
|
+
" ~/home/directory"
|
|
143
|
+
)
|
|
144
|
+
syncer.expects(:run).in_sequence(s).with(
|
|
145
|
+
"rsync options_output '/some/directory' " +
|
|
146
|
+
"'#{ File.expand_path('~/home/directory') }' " +
|
|
147
|
+
"'my_username@123.45.678.90:my_backups'"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
syncer.expects(:remove_password_file!).in_sequence(s)
|
|
151
|
+
|
|
152
|
+
syncer.perform!
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it 'should ensure passoword file removal' do
|
|
156
|
+
syncer.expects(:write_password_file!).in_sequence(s)
|
|
157
|
+
|
|
158
|
+
Backup::Logger.expects(:message).in_sequence(s)
|
|
159
|
+
syncer.expects(:run).in_sequence(s).raises('error message')
|
|
160
|
+
|
|
161
|
+
syncer.expects(:remove_password_file!).in_sequence(s)
|
|
162
|
+
|
|
163
|
+
expect do
|
|
164
|
+
syncer.perform!
|
|
165
|
+
end.to raise_error(RuntimeError, 'error message')
|
|
166
|
+
end
|
|
167
|
+
end # describe '#perform!'
|
|
168
|
+
|
|
169
|
+
describe '#dest_path' do
|
|
170
|
+
it 'should remove any preceeding "~/" from @path' do
|
|
171
|
+
syncer.send(:dest_path).should == 'my_backups'
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'should set @dest_path' do
|
|
175
|
+
syncer.send(:dest_path)
|
|
176
|
+
syncer.instance_variable_get(:@dest_path).should == 'my_backups'
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'should return @dest_path if already set' do
|
|
180
|
+
syncer.instance_variable_set(:@dest_path, 'foo')
|
|
181
|
+
syncer.send(:dest_path).should == 'foo'
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe '#options' do
|
|
186
|
+
let(:pwdfile) { mock }
|
|
187
|
+
|
|
188
|
+
context 'when @compress is true' do
|
|
189
|
+
it 'should return the options string with compression enabled' do
|
|
190
|
+
syncer.send(:options).should ==
|
|
191
|
+
"--archive --delete --compress -e 'ssh -p 22' --opt-a --opt-b"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
context 'when @compress is false' do
|
|
196
|
+
before { syncer.compress = false }
|
|
197
|
+
it 'should return the options string without compression enabled' do
|
|
198
|
+
syncer.send(:options).should ==
|
|
199
|
+
"--archive --delete -e 'ssh -p 22' --opt-a --opt-b"
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
context 'when a @password_file is set' do
|
|
204
|
+
before do
|
|
205
|
+
syncer.instance_variable_set(:@password_file, pwdfile)
|
|
206
|
+
pwdfile.expects(:path).returns('/path/to/pwdfile')
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it 'should return the options string with the password_option' do
|
|
210
|
+
syncer.send(:options).should ==
|
|
211
|
+
"--archive --delete --compress -e 'ssh -p 22' " +
|
|
212
|
+
"--password-file='/path/to/pwdfile' --opt-a --opt-b"
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
context 'when no @additional_options are set' do
|
|
217
|
+
before { syncer.additional_options = [] }
|
|
218
|
+
|
|
219
|
+
it 'should return the options string without additional options' do
|
|
220
|
+
syncer.send(:options).should ==
|
|
221
|
+
"--archive --delete --compress -e 'ssh -p 22'"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
end # describe '#options'
|
|
226
|
+
|
|
227
|
+
describe '#compress_option' do
|
|
228
|
+
context 'when @compress is true' do
|
|
229
|
+
it 'should return the compression flag' do
|
|
230
|
+
syncer.send(:compress_option).should == '--compress'
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
context 'when @compress is false' do
|
|
235
|
+
before { syncer.compress = false }
|
|
236
|
+
it 'should return nil' do
|
|
237
|
+
syncer.send(:compress_option).should be_nil
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
describe '#port_option' do
|
|
243
|
+
before { syncer.port = 40 }
|
|
244
|
+
it 'should return the option string with the defined port' do
|
|
245
|
+
syncer.send(:port_option).should == "-e 'ssh -p 40'"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
describe '#password_option' do
|
|
250
|
+
let(:pwdfile) { mock }
|
|
251
|
+
|
|
252
|
+
context 'when @password_file is set' do
|
|
253
|
+
before do
|
|
254
|
+
syncer.instance_variable_set(:@password_file, pwdfile)
|
|
255
|
+
pwdfile.expects(:path).returns('/path/to/pwdfile')
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it 'should return the option string' do
|
|
259
|
+
syncer.send(:password_option).should ==
|
|
260
|
+
"--password-file='/path/to/pwdfile'"
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
context 'when @password_file is not set' do
|
|
265
|
+
it 'should return nil' do
|
|
266
|
+
syncer.send(:password_option).should be_nil
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
describe '#write_password_file!' do
|
|
272
|
+
let(:pwdfile) { mock }
|
|
273
|
+
let(:s) { sequence '' }
|
|
274
|
+
|
|
275
|
+
context 'when a @password is set' do
|
|
276
|
+
it 'should create, write and close a temporary password file' do
|
|
277
|
+
Tempfile.expects(:new).in_sequence(s).
|
|
278
|
+
with('backup-rsync-password').
|
|
279
|
+
returns(pwdfile)
|
|
280
|
+
pwdfile.expects(:write).in_sequence(s).with('my_password')
|
|
281
|
+
pwdfile.expects(:close).in_sequence(s)
|
|
282
|
+
|
|
283
|
+
syncer.send(:write_password_file!)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it 'should set @password_file to a file containing the password' do
|
|
287
|
+
syncer.send(:write_password_file!)
|
|
288
|
+
file = syncer.instance_variable_get(:@password_file)
|
|
289
|
+
File.exist?(file.path).should be_true
|
|
290
|
+
File.read(file.path).should == 'my_password'
|
|
291
|
+
|
|
292
|
+
# cleanup
|
|
293
|
+
file.delete
|
|
294
|
+
file.path.should be_nil
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
context 'when a @password is not set' do
|
|
299
|
+
before { syncer.password = nil }
|
|
300
|
+
it 'should return nil' do
|
|
301
|
+
Tempfile.expects(:new).never
|
|
302
|
+
pwdfile.expects(:write).never
|
|
303
|
+
pwdfile.expects(:close).never
|
|
304
|
+
syncer.send(:write_password_file!).should be_nil
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
describe '#remove_password_file!' do
|
|
310
|
+
let(:pwdfile) { mock }
|
|
311
|
+
|
|
312
|
+
context 'when @password_file is set' do
|
|
313
|
+
before do
|
|
314
|
+
syncer.instance_variable_set(:@password_file, pwdfile)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it 'should delete the file and reset @password_file' do
|
|
318
|
+
pwdfile.expects(:delete)
|
|
319
|
+
syncer.send(:remove_password_file!)
|
|
320
|
+
syncer.instance_variable_get(:@password_file).should be_nil
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
context 'when @password_file is not set' do
|
|
325
|
+
it 'should return nil' do
|
|
326
|
+
pwdfile.expects(:delete).never
|
|
327
|
+
syncer.send(:remove_password_file!).should be_nil
|
|
328
|
+
syncer.instance_variable_get(:@password_file).should be_nil
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
end
|