webtranslateit-safe 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.autotest +3 -0
- data/.document +5 -0
- data/.github/dependabot.yml +26 -0
- data/.github/release-drafter.yml +36 -0
- data/.github/workflows/ci.yml +51 -0
- data/.github/workflows/release-drafter.yml +29 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +552 -0
- data/CHANGELOG +42 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +89 -0
- data/LICENSE.txt +22 -0
- data/README.markdown +237 -0
- data/Rakefile +8 -0
- data/TODO +31 -0
- data/bin/webtranslateit-safe +64 -0
- data/lib/extensions/mktmpdir.rb +45 -0
- data/lib/webtranslateit/safe/archive.rb +29 -0
- data/lib/webtranslateit/safe/backup.rb +27 -0
- data/lib/webtranslateit/safe/cloudfiles.rb +77 -0
- data/lib/webtranslateit/safe/config/builder.rb +100 -0
- data/lib/webtranslateit/safe/config/node.rb +79 -0
- data/lib/webtranslateit/safe/ftp.rb +85 -0
- data/lib/webtranslateit/safe/gpg.rb +52 -0
- data/lib/webtranslateit/safe/gzip.rb +29 -0
- data/lib/webtranslateit/safe/local.rb +55 -0
- data/lib/webtranslateit/safe/mongodump.rb +30 -0
- data/lib/webtranslateit/safe/mysqldump.rb +36 -0
- data/lib/webtranslateit/safe/pgdump.rb +36 -0
- data/lib/webtranslateit/safe/pipe.rb +23 -0
- data/lib/webtranslateit/safe/s3.rb +80 -0
- data/lib/webtranslateit/safe/sftp.rb +96 -0
- data/lib/webtranslateit/safe/sink.rb +40 -0
- data/lib/webtranslateit/safe/source.rb +51 -0
- data/lib/webtranslateit/safe/stream.rb +40 -0
- data/lib/webtranslateit/safe/svndump.rb +17 -0
- data/lib/webtranslateit/safe/tmp_file.rb +53 -0
- data/lib/webtranslateit/safe/version.rb +9 -0
- data/lib/webtranslateit/safe.rb +70 -0
- data/spec/integration/archive_integration_spec.rb +89 -0
- data/spec/integration/cleanup_spec.rb +62 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/webtranslateit/safe/archive_spec.rb +67 -0
- data/spec/webtranslateit/safe/cloudfiles_spec.rb +175 -0
- data/spec/webtranslateit/safe/config_spec.rb +307 -0
- data/spec/webtranslateit/safe/gpg_spec.rb +148 -0
- data/spec/webtranslateit/safe/gzip_spec.rb +64 -0
- data/spec/webtranslateit/safe/local_spec.rb +109 -0
- data/spec/webtranslateit/safe/mongodump_spec.rb +54 -0
- data/spec/webtranslateit/safe/mysqldump_spec.rb +83 -0
- data/spec/webtranslateit/safe/pgdump_spec.rb +45 -0
- data/spec/webtranslateit/safe/s3_spec.rb +168 -0
- data/spec/webtranslateit/safe/svndump_spec.rb +39 -0
- data/templates/script.rb +183 -0
- data/webtranslateit-safe.gemspec +32 -0
- metadata +149 -0
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WebTranslateIt::Safe::Config do
|
4
|
+
it 'parses example config' do
|
5
|
+
config = WebTranslateIt::Safe::Config::Node.new do
|
6
|
+
|
7
|
+
dry_run false
|
8
|
+
local_only true
|
9
|
+
verbose true
|
10
|
+
|
11
|
+
local do
|
12
|
+
path 'path'
|
13
|
+
end
|
14
|
+
|
15
|
+
s3 do
|
16
|
+
key 's3 key'
|
17
|
+
secret 'secret'
|
18
|
+
bucket 'bucket'
|
19
|
+
path 'path1'
|
20
|
+
end
|
21
|
+
|
22
|
+
sftp do
|
23
|
+
user 'sftp user'
|
24
|
+
password 'sftp password'
|
25
|
+
host 'sftp host'
|
26
|
+
end
|
27
|
+
|
28
|
+
gpg do
|
29
|
+
password 'astrails'
|
30
|
+
key 'gpg-key'
|
31
|
+
end
|
32
|
+
|
33
|
+
keep do
|
34
|
+
s3 20
|
35
|
+
local 4
|
36
|
+
end
|
37
|
+
|
38
|
+
mysqldump do
|
39
|
+
options '-ceKq --single-transaction --create-options'
|
40
|
+
|
41
|
+
user 'astrails'
|
42
|
+
password ''
|
43
|
+
host 'localhost'
|
44
|
+
port 3306
|
45
|
+
socket '/var/run/mysqld/mysqld.sock'
|
46
|
+
|
47
|
+
database :blog
|
48
|
+
|
49
|
+
database :production do
|
50
|
+
keep local: 3
|
51
|
+
|
52
|
+
gpg do
|
53
|
+
password 'custom-production-pass'
|
54
|
+
end
|
55
|
+
|
56
|
+
skip_tables [:logger_exceptions, :request_logs]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
pgdump do
|
62
|
+
options '-i -x -O'
|
63
|
+
|
64
|
+
user 'astrails'
|
65
|
+
password ''
|
66
|
+
host 'localhost'
|
67
|
+
port 5432
|
68
|
+
|
69
|
+
database :blog
|
70
|
+
|
71
|
+
database :production do
|
72
|
+
keep local: 3
|
73
|
+
|
74
|
+
skip_tables [:logger_exceptions, :request_logs]
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
svndump do
|
80
|
+
repo :my_repo do
|
81
|
+
repo_path '/home/svn/my_repo'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
tar do
|
86
|
+
archive 'git-repositories' do
|
87
|
+
files '/home/git/repositories'
|
88
|
+
end
|
89
|
+
|
90
|
+
archive 'etc-files' do
|
91
|
+
files '/etc'
|
92
|
+
exclude '/etc/puppet/other'
|
93
|
+
end
|
94
|
+
|
95
|
+
archive 'dot-configs' do
|
96
|
+
files '/home/*/.[^.]*'
|
97
|
+
end
|
98
|
+
|
99
|
+
archive 'blog' do
|
100
|
+
files '/var/www/blog.astrails.com/'
|
101
|
+
exclude ['/var/www/blog.astrails.com/log', '/var/www/blog.astrails.com/tmp']
|
102
|
+
end
|
103
|
+
|
104
|
+
archive :misc do
|
105
|
+
files ['/backup/*.rb']
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
mongodump do
|
110
|
+
host 'host'
|
111
|
+
database 'database'
|
112
|
+
user 'user'
|
113
|
+
password 'password'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
expected = {
|
118
|
+
'dry_run' => false,
|
119
|
+
'local_only' => true,
|
120
|
+
'verbose' => true,
|
121
|
+
|
122
|
+
'local' => {'path' => 'path'},
|
123
|
+
|
124
|
+
's3' => {
|
125
|
+
'key' => 's3 key',
|
126
|
+
'secret' => 'secret',
|
127
|
+
'bucket' => 'bucket',
|
128
|
+
'path' => 'path1'
|
129
|
+
},
|
130
|
+
|
131
|
+
'sftp' => {
|
132
|
+
'user' => 'sftp user',
|
133
|
+
'password' => 'sftp password',
|
134
|
+
'host' => 'sftp host'
|
135
|
+
},
|
136
|
+
|
137
|
+
'gpg' => {'password' => 'astrails', 'key' => 'gpg-key'},
|
138
|
+
|
139
|
+
'keep' => {'s3' => 20, 'local' => 4},
|
140
|
+
|
141
|
+
'mysqldump' => {
|
142
|
+
'options' => '-ceKq --single-transaction --create-options',
|
143
|
+
'user' => 'astrails',
|
144
|
+
'password' => '',
|
145
|
+
'host' => 'localhost',
|
146
|
+
'port' => 3306,
|
147
|
+
'socket' => '/var/run/mysqld/mysqld.sock',
|
148
|
+
|
149
|
+
'databases' => {
|
150
|
+
'blog' => {},
|
151
|
+
'production' => {
|
152
|
+
'keep' => {'local' => 3},
|
153
|
+
'gpg' => {'password' => 'custom-production-pass'},
|
154
|
+
'skip_tables' => ['logger_exceptions', 'request_logs']
|
155
|
+
}
|
156
|
+
}
|
157
|
+
},
|
158
|
+
|
159
|
+
'pgdump' => {
|
160
|
+
'options' => '-i -x -O',
|
161
|
+
'user' => 'astrails',
|
162
|
+
'password' => '',
|
163
|
+
'host' => 'localhost',
|
164
|
+
'port' => 5432,
|
165
|
+
|
166
|
+
'databases' => {
|
167
|
+
'blog' => {},
|
168
|
+
'production' => {
|
169
|
+
'keep' => {'local' => 3},
|
170
|
+
'skip_tables' => ['logger_exceptions', 'request_logs']
|
171
|
+
}
|
172
|
+
}
|
173
|
+
},
|
174
|
+
|
175
|
+
'svndump' => {
|
176
|
+
'repos' => {
|
177
|
+
'my_repo' => {
|
178
|
+
'repo_path' => '/home/svn/my_repo'
|
179
|
+
}
|
180
|
+
}
|
181
|
+
},
|
182
|
+
|
183
|
+
'tar' => {
|
184
|
+
'archives' => {
|
185
|
+
'git-repositories' => {'files' => ['/home/git/repositories']},
|
186
|
+
'etc-files' => {'files' => ['/etc'], 'exclude' => ['/etc/puppet/other']},
|
187
|
+
'dot-configs' => {'files' => ['/home/*/.[^.]*']},
|
188
|
+
'blog' => {
|
189
|
+
'files' => ['/var/www/blog.astrails.com/'],
|
190
|
+
'exclude' => ['/var/www/blog.astrails.com/log', '/var/www/blog.astrails.com/tmp']
|
191
|
+
},
|
192
|
+
'misc' => {'files' => ['/backup/*.rb']}
|
193
|
+
}
|
194
|
+
},
|
195
|
+
|
196
|
+
'mongodump' => {
|
197
|
+
'host' => 'host',
|
198
|
+
'databases' => {
|
199
|
+
'database' => {}
|
200
|
+
},
|
201
|
+
'user' => 'user',
|
202
|
+
'password' => 'password'
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
config.to_hash.should == expected
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'makes an array from multivalues' do
|
210
|
+
config = WebTranslateIt::Safe::Config::Node.new do
|
211
|
+
skip_tables 'a'
|
212
|
+
skip_tables 'b'
|
213
|
+
files '/foo'
|
214
|
+
files '/bar'
|
215
|
+
exclude '/foo/bar'
|
216
|
+
exclude '/foo/bar/baz'
|
217
|
+
end
|
218
|
+
|
219
|
+
expected = {
|
220
|
+
'skip_tables' => ['a', 'b'],
|
221
|
+
'files' => ['/foo', '/bar'],
|
222
|
+
'exclude' => ['/foo/bar', '/foo/bar/baz']
|
223
|
+
}
|
224
|
+
|
225
|
+
config.to_hash.should == expected
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'raises error on key duplication' do
|
229
|
+
proc do
|
230
|
+
WebTranslateIt::Safe::Config::Node.new do
|
231
|
+
path 'foo'
|
232
|
+
path 'bar'
|
233
|
+
end
|
234
|
+
end.should raise_error(ArgumentError, "duplicate value for 'path'")
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'accepts hash as data' do
|
238
|
+
WebTranslateIt::Safe::Config::Node.new do
|
239
|
+
tar do
|
240
|
+
archive 'blog', files: 'foo', exclude: ['aaa', 'bbb']
|
241
|
+
end
|
242
|
+
end.to_hash.should == {
|
243
|
+
'tar' => {
|
244
|
+
'archives' => {
|
245
|
+
'blog' => {
|
246
|
+
'files' => ['foo'],
|
247
|
+
'exclude' => ['aaa', 'bbb']
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
}
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'accepts hash as data and a block' do
|
255
|
+
WebTranslateIt::Safe::Config::Node.new do
|
256
|
+
tar do
|
257
|
+
archive 'blog', files: 'foo' do
|
258
|
+
exclude ['aaa', 'bbb']
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end.to_hash.should == {
|
262
|
+
'tar' => {
|
263
|
+
'archives' => {
|
264
|
+
'blog' => {
|
265
|
+
'files' => ['foo'],
|
266
|
+
'exclude' => ['aaa', 'bbb']
|
267
|
+
}
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'accepts multiple levels of data hash' do
|
274
|
+
config = WebTranslateIt::Safe::Config::Node.new nil, tar: {
|
275
|
+
s3: {bucket: '_bucket', key: '_key', secret: '_secret'},
|
276
|
+
keep: {s3: 2}
|
277
|
+
}
|
278
|
+
|
279
|
+
config.to_hash.should == {
|
280
|
+
'tar' => {
|
281
|
+
's3' => {'bucket' => '_bucket', 'key' => '_key', 'secret' => '_secret'},
|
282
|
+
'keep' => {'s3' => 2}
|
283
|
+
}
|
284
|
+
}
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'sets multi value as array' do
|
288
|
+
config = WebTranslateIt::Safe::Config::Node.new do
|
289
|
+
tar do
|
290
|
+
archive 'foo' do
|
291
|
+
files 'bar'
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
config.to_hash.should == {
|
297
|
+
'tar' => {
|
298
|
+
'archives' => {
|
299
|
+
'foo' => {
|
300
|
+
'files' => ['bar']
|
301
|
+
}
|
302
|
+
}
|
303
|
+
}
|
304
|
+
}
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WebTranslateIt::Safe::Gpg do
|
4
|
+
def def_backup
|
5
|
+
{
|
6
|
+
compressed: false,
|
7
|
+
command: 'command',
|
8
|
+
extension: '.foo',
|
9
|
+
filename: 'qweqwe'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def gpg(config = {}, backup = def_backup)
|
14
|
+
WebTranslateIt::Safe::Gpg.new(
|
15
|
+
WebTranslateIt::Safe::Config::Node.new(nil, config),
|
16
|
+
WebTranslateIt::Safe::Backup.new(backup)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:each) { WebTranslateIt::Safe::TmpFile.cleanup }
|
21
|
+
|
22
|
+
describe :process do
|
23
|
+
|
24
|
+
before(:each) do
|
25
|
+
@gpg = gpg
|
26
|
+
stub(@gpg).gpg_password_file { 'pwd-file' }
|
27
|
+
stub(@gpg).pipe { '|gpg -BLAH' }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'when active' do
|
31
|
+
before(:each) do
|
32
|
+
stub(@gpg).active? { true }
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'adds .gpg extension' do
|
36
|
+
mock(@gpg.backup.extension) << '.gpg'
|
37
|
+
@gpg.process
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'adds command pipe' do
|
41
|
+
mock(@gpg.backup.command) << (/\|gpg -BLAH/)
|
42
|
+
@gpg.process
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'sets compressed' do
|
46
|
+
mock(@gpg.backup).compressed = true
|
47
|
+
@gpg.process
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'when inactive' do
|
52
|
+
before(:each) do
|
53
|
+
stub(@gpg).active? { false }
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'does not touch extension' do
|
57
|
+
dont_allow(@gpg.backup.extension) << anything
|
58
|
+
@gpg.process
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'does not touch command' do
|
62
|
+
dont_allow(@gpg.backup.command) << anything
|
63
|
+
@gpg.process
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'does not touch compressed' do
|
67
|
+
dont_allow(@gpg.backup).compressed = anything
|
68
|
+
@gpg.process
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe :active? do
|
74
|
+
|
75
|
+
describe 'with key' do
|
76
|
+
it 'is true' do
|
77
|
+
expect(gpg(gpg: {key: :foo})).to be_active
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'with password' do
|
82
|
+
it 'is true' do
|
83
|
+
expect(gpg(gpg: {password: :foo})).to be_active
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'without key & password' do
|
88
|
+
it 'is false' do
|
89
|
+
expect(gpg).not_to be_active
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'with key & password' do
|
94
|
+
it 'raises RuntimeError' do
|
95
|
+
lambda {
|
96
|
+
gpg(gpg: {key: 'foo', password: 'bar'}).send :active?
|
97
|
+
}.should raise_error(RuntimeError, "can't use both gpg password and pubkey")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe :pipe do
|
103
|
+
|
104
|
+
describe 'with key' do
|
105
|
+
def kgpg(extra = {})
|
106
|
+
gpg({gpg: {key: 'foo', options: 'GPG-OPT'}.merge(extra), options: 'OPT'})
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'does not call gpg_password_file' do
|
110
|
+
g = kgpg
|
111
|
+
dont_allow(g).gpg_password_file(anything)
|
112
|
+
g.send(:pipe)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "uses '-r' and :options" do
|
116
|
+
kgpg.send(:pipe).should == '|gpg GPG-OPT -e -r foo'
|
117
|
+
end
|
118
|
+
|
119
|
+
it "uses the 'command' options" do
|
120
|
+
kgpg(command: 'other-gpg').send(:pipe).should == '|other-gpg GPG-OPT -e -r foo'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'with password' do
|
125
|
+
def pgpg(extra = {})
|
126
|
+
returning(gpg({gpg: {password: 'bar', options: 'GPG-OPT'}.merge(extra), options: 'OPT'})) do |g|
|
127
|
+
stub(g).gpg_password_file(anything) { 'pass-file' }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it "uses '--passphrase-file' and :options" do
|
132
|
+
pgpg.send(:pipe).should == '|gpg GPG-OPT -c --passphrase-file pass-file'
|
133
|
+
end
|
134
|
+
|
135
|
+
it "uses the 'command' options" do
|
136
|
+
pgpg(command: 'other-gpg').send(:pipe).should == '|other-gpg GPG-OPT -c --passphrase-file pass-file'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe :gpg_password_file do
|
142
|
+
it 'creates password file' do
|
143
|
+
file = gpg.send(:gpg_password_file, 'foo')
|
144
|
+
expect(File.exist?(file)).to be true
|
145
|
+
File.read(file).should == 'foo'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WebTranslateIt::Safe::Gzip do
|
4
|
+
|
5
|
+
def def_backup
|
6
|
+
{
|
7
|
+
compressed: false,
|
8
|
+
command: 'command',
|
9
|
+
extension: '.foo',
|
10
|
+
filename: 'qweqwe'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:each) { WebTranslateIt::Safe::TmpFile.cleanup }
|
15
|
+
|
16
|
+
def gzip(config = {}, backup = def_backup)
|
17
|
+
WebTranslateIt::Safe::Gzip.new(
|
18
|
+
@config = WebTranslateIt::Safe::Config::Node.new(nil, config),
|
19
|
+
@backup = WebTranslateIt::Safe::Backup.new(backup)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe :preocess do
|
24
|
+
|
25
|
+
describe 'when not yet compressed' do
|
26
|
+
before(:each) { @gzip = gzip }
|
27
|
+
|
28
|
+
it 'adds .gz extension' do
|
29
|
+
mock(@backup.extension) << '.gz'
|
30
|
+
@gzip.process
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'adds |gzip pipe' do
|
34
|
+
mock(@backup.command) << '|gzip'
|
35
|
+
@gzip.process
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'sets compressed' do
|
39
|
+
mock(@backup).compressed = true
|
40
|
+
@gzip.process
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'when already compressed' do
|
45
|
+
|
46
|
+
before(:each) { @gzip = gzip({}, extension: '.foo', command: 'foobar', compressed: true) }
|
47
|
+
|
48
|
+
it 'does not touch extension' do
|
49
|
+
@gzip.process
|
50
|
+
@backup.extension.should == '.foo'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not touch command' do
|
54
|
+
@gzip.process
|
55
|
+
@backup.command.should == 'foobar'
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'does not touch compressed' do
|
59
|
+
@gzip.process
|
60
|
+
@backup.compressed.should == true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WebTranslateIt::Safe::Local do
|
4
|
+
def def_config
|
5
|
+
{
|
6
|
+
local: {
|
7
|
+
path: '/:kind~:id~:timestamp'
|
8
|
+
},
|
9
|
+
keep: {
|
10
|
+
local: 2
|
11
|
+
}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def def_backup
|
16
|
+
{
|
17
|
+
kind: 'mysqldump',
|
18
|
+
id: 'blog',
|
19
|
+
timestamp: 'NoW',
|
20
|
+
compressed: true,
|
21
|
+
command: 'command',
|
22
|
+
extension: '.foo.gz',
|
23
|
+
filename: 'qweqwe'
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def local(config = def_config, backup = def_backup)
|
28
|
+
WebTranslateIt::Safe::Local.new(
|
29
|
+
@config = WebTranslateIt::Safe::Config::Node.new(nil, config),
|
30
|
+
@backup = WebTranslateIt::Safe::Backup.new(backup)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe :active? do
|
35
|
+
it 'is true' do
|
36
|
+
expect(local).to be_active
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe :path do
|
41
|
+
it 'raises RuntimeError when no path' do
|
42
|
+
lambda {
|
43
|
+
local({}).send :path
|
44
|
+
}.should raise_error(RuntimeError, 'missing :local/:path')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'uses local/path' do
|
48
|
+
local.send(:path).should == '/mysqldump~blog~NoW'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe :save do
|
53
|
+
before(:each) do
|
54
|
+
@local = local
|
55
|
+
stub(@local).system
|
56
|
+
stub(@local).full_path { 'file-path' }
|
57
|
+
stub(FileUtils).mkdir_p
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'calls system to save the file' do
|
61
|
+
mock(@local).system('command>file-path')
|
62
|
+
@local.send(:save)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'creates directory' do
|
66
|
+
mock(FileUtils).mkdir_p('/mysqldump~blog~NoW')
|
67
|
+
@local.send(:save)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'sets backup.path' do
|
71
|
+
mock(@backup).path = 'file-path'
|
72
|
+
@local.send(:save)
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'dry run' do
|
76
|
+
before(:each) { @local.config[:dry_run] = true }
|
77
|
+
|
78
|
+
it 'should not create directory'
|
79
|
+
it 'should not call system'
|
80
|
+
it 'sets backup.path' do
|
81
|
+
mock(@backup).path = 'file-path'
|
82
|
+
@local.send(:save)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe :cleanup do
|
88
|
+
before(:each) do
|
89
|
+
@files = [4, 1, 3, 2].map { |i| "/mysqldump~blog~NoW/qweqwe.#{i}" }
|
90
|
+
stub(File).file?(anything) { true }
|
91
|
+
stub(File).size(anything) { 1 }
|
92
|
+
stub(File).unlink
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'checks [:keep, :local]' do
|
96
|
+
@local = local(def_config.merge(keep: {}))
|
97
|
+
dont_allow(Dir).[]
|
98
|
+
@local.send :cleanup
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'deletes extra files' do
|
102
|
+
@local = local
|
103
|
+
mock(Dir).[]('/mysqldump~blog~NoW/qweqwe.*') { @files }
|
104
|
+
mock(File).unlink('/mysqldump~blog~NoW/qweqwe.1')
|
105
|
+
mock(File).unlink('/mysqldump~blog~NoW/qweqwe.2')
|
106
|
+
@local.send :cleanup
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WebTranslateIt::Safe::Mongodump do
|
4
|
+
def def_config
|
5
|
+
{
|
6
|
+
host: 'prod.example.com',
|
7
|
+
user: 'testuser',
|
8
|
+
password: 'p4ssw0rd'
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def mongodump(id = :foo, config = def_config)
|
13
|
+
WebTranslateIt::Safe::Mongodump.new(id, WebTranslateIt::Safe::Config::Node.new(nil, config))
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
stub(Time).now.stub!.strftime { 'NOW' }
|
18
|
+
@output_folder = File.join(WebTranslateIt::Safe::TmpFile.tmproot, 'mongodump')
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:each) { WebTranslateIt::Safe::TmpFile.cleanup }
|
22
|
+
|
23
|
+
describe :backup do
|
24
|
+
before(:each) do
|
25
|
+
@mongo = mongodump
|
26
|
+
end
|
27
|
+
|
28
|
+
{
|
29
|
+
id: 'foo',
|
30
|
+
kind: 'mongodump',
|
31
|
+
extension: '.tar',
|
32
|
+
filename: 'mongodump-foo.NOW'
|
33
|
+
}.each do |k, v|
|
34
|
+
it "sets #{k} to #{v}" do
|
35
|
+
@mongo.backup.send(k).should == v
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'sets the command' do
|
40
|
+
@mongo.backup.send(:command).should == "mongodump -q \"{xxxx : { \\$ne : 0 } }\" --db foo --host prod.example.com -u testuser -p p4ssw0rd --out #{@output_folder} && cd #{@output_folder} && tar cf - ."
|
41
|
+
end
|
42
|
+
|
43
|
+
{
|
44
|
+
host: '--host ',
|
45
|
+
user: '-u ',
|
46
|
+
password: '-p '
|
47
|
+
}.each do |key, v|
|
48
|
+
it "does not add #{key} to command if it is not present" do
|
49
|
+
@mongo = mongodump(:foo, def_config.reject! { |k, _v| k == key })
|
50
|
+
@mongo.backup.send(:command).should_not =~ /#{v}/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|