syncwrap 1.5.2 → 2.0.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.
- checksums.yaml +7 -0
- data/History.rdoc +19 -0
- data/Manifest.txt +82 -34
- data/README.rdoc +96 -48
- data/Rakefile +0 -65
- data/bin/syncwrap +27 -0
- data/examples/LAYOUT.rdoc +70 -0
- data/examples/Rakefile +16 -0
- data/examples/ec2.rb +44 -0
- data/examples/hello.rb +14 -0
- data/examples/hello_binding.rb +27 -0
- data/examples/jruby.rb +11 -0
- data/examples/private/aws.json +4 -0
- data/examples/rput.rb +24 -0
- data/examples/sync/home/bob/.ssh/authorized_keys +1 -0
- data/examples/sync/tmp/sample.erb +3 -0
- data/lib/syncwrap/amazon_ec2.rb +236 -0
- data/lib/syncwrap/amazon_ws.rb +308 -0
- data/lib/syncwrap/base.rb +4 -2
- data/lib/syncwrap/cli.rb +328 -0
- data/lib/syncwrap/component.rb +443 -0
- data/lib/syncwrap/components/commercial_jdk.rb +76 -0
- data/lib/syncwrap/components/cruby_vm.rb +144 -0
- data/lib/syncwrap/components/etc_hosts.rb +44 -0
- data/lib/syncwrap/{geminabox.rb → components/geminabox.rb} +12 -17
- data/lib/syncwrap/components/hashdot.rb +97 -0
- data/lib/syncwrap/components/iyyov.rb +144 -0
- data/lib/syncwrap/components/iyyov_daemon.rb +125 -0
- data/lib/syncwrap/components/jruby_vm.rb +122 -0
- data/lib/syncwrap/components/mdraid.rb +204 -0
- data/lib/syncwrap/components/network.rb +99 -0
- data/lib/syncwrap/components/open_jdk.rb +70 -0
- data/lib/syncwrap/components/postgresql.rb +159 -0
- data/lib/syncwrap/components/qpid.rb +303 -0
- data/lib/syncwrap/components/rhel.rb +71 -0
- data/lib/syncwrap/components/run_user.rb +99 -0
- data/lib/syncwrap/components/ubuntu.rb +85 -0
- data/lib/syncwrap/components/users.rb +200 -0
- data/lib/syncwrap/context.rb +260 -0
- data/lib/syncwrap/distro.rb +53 -60
- data/lib/syncwrap/formatter.rb +149 -0
- data/lib/syncwrap/host.rb +134 -0
- data/lib/syncwrap/main.rb +62 -0
- data/lib/syncwrap/path_util.rb +55 -0
- data/lib/syncwrap/rsync.rb +227 -0
- data/lib/syncwrap/ruby_support.rb +110 -0
- data/lib/syncwrap/shell.rb +207 -0
- data/lib/syncwrap.rb +367 -1
- data/{etc → sync/etc}/gemrc +1 -3
- data/sync/etc/hosts.erb +8 -0
- data/{etc/init.d/iyyov → sync/etc/init.d/iyyov.erb} +35 -7
- data/sync/etc/sysconfig/pgsql/postgresql.erb +2 -0
- data/sync/src/hashdot/Makefile.erb +98 -0
- data/sync/src/hashdot/profiles/default.hdp.erb +25 -0
- data/sync/src/hashdot/profiles/jruby-common.hdp +28 -0
- data/sync/src/hashdot/profiles/jruby-shortlived.hdp +9 -0
- data/sync/src/hashdot/profiles/jruby.hdp.erb +13 -0
- data/sync/src/hashdot/profiles/shortlived.hdp +6 -0
- data/sync/var/iyyov/default/config.rb +1 -0
- data/sync/var/iyyov/default/daemon.rb.erb +15 -0
- data/sync/var/iyyov/jobs.rb.erb +4 -0
- data/test/muddled_sync.rb +13 -0
- data/test/setup.rb +39 -0
- data/test/sync/d1/bar +1 -0
- data/test/sync/d1/foo.erb +1 -0
- data/test/sync/d3/d2/bar +1 -0
- data/test/sync/d3/d2/foo.erb +1 -0
- data/test/test_components.rb +108 -0
- data/test/test_context.rb +107 -0
- data/test/test_context_rput.rb +289 -0
- data/test/test_rsync.rb +138 -0
- data/test/test_shell.rb +233 -0
- data/test/test_space.rb +218 -0
- data/test/test_space_main.rb +40 -0
- data/test/zfile +1 -0
- metadata +204 -71
- data/etc/sysconfig/pgsql/postgresql +0 -2
- data/lib/syncwrap/aws.rb +0 -448
- data/lib/syncwrap/common.rb +0 -161
- data/lib/syncwrap/ec2.rb +0 -59
- data/lib/syncwrap/hashdot.rb +0 -70
- data/lib/syncwrap/iyyov.rb +0 -139
- data/lib/syncwrap/java.rb +0 -61
- data/lib/syncwrap/jruby.rb +0 -118
- data/lib/syncwrap/postgresql.rb +0 -135
- data/lib/syncwrap/qpid.rb +0 -251
- data/lib/syncwrap/remote_task.rb +0 -199
- data/lib/syncwrap/rhel.rb +0 -67
- data/lib/syncwrap/ubuntu.rb +0 -78
- data/lib/syncwrap/user_run.rb +0 -102
- data/test/test_syncwrap.rb +0 -202
- data/var/iyyov/jobs.rb +0 -11
- /data/{etc → sync/etc}/corosync/corosync.conf +0 -0
- /data/{etc → sync/etc}/corosync/uidgid.d/qpid +0 -0
- /data/{etc → sync/etc}/init.d/qpidd +0 -0
- /data/{etc → sync/etc}/sysctl.d/61-postgresql-shm.conf +0 -0
- /data/{usr/local → sync/jruby}/bin/jgem +0 -0
- /data/{postgresql → sync/postgresql}/rhel/pg_hba.conf +0 -0
- /data/{postgresql → sync/postgresql}/rhel/pg_ident.conf +0 -0
- /data/{postgresql → sync/postgresql}/rhel/postgresql.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/environment +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/pg_ctl.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/pg_hba.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/pg_ident.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/postgresql.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/start.conf +0 -0
- /data/{usr → sync/usr}/local/etc/qpidd.conf +0 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env jruby
|
|
2
|
+
#.hashdot.profile += jruby-shortlived
|
|
3
|
+
|
|
4
|
+
#--
|
|
5
|
+
# Copyright (c) 2011-2014 David Kellum
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
|
8
|
+
# may not use this file except in compliance with the License. You
|
|
9
|
+
# may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
16
|
+
# implied. See the License for the specific language governing
|
|
17
|
+
# permissions and limitations under the License.
|
|
18
|
+
#++
|
|
19
|
+
|
|
20
|
+
require_relative 'setup'
|
|
21
|
+
|
|
22
|
+
require 'syncwrap'
|
|
23
|
+
|
|
24
|
+
class TestContextRput < MiniTest::Unit::TestCase
|
|
25
|
+
include SyncWrap
|
|
26
|
+
|
|
27
|
+
VERBOSE = ARGV.include?( '--verbose' )
|
|
28
|
+
|
|
29
|
+
TEST_DIR = File.dirname( __FILE__ ).freeze
|
|
30
|
+
SYNC_DIR = File.join( TEST_DIR, 'sync' ).freeze
|
|
31
|
+
SYNC_PATHS = [ SYNC_DIR ].freeze
|
|
32
|
+
|
|
33
|
+
def setup
|
|
34
|
+
FileUtils.rm_rf( "#{TEST_DIR}/d1" )
|
|
35
|
+
FileUtils.rm_rf( "#{TEST_DIR}/d2" )
|
|
36
|
+
FileUtils.rm_rf( "#{TEST_DIR}/d3" )
|
|
37
|
+
FileUtils.rm_rf( "#{TEST_DIR}/baz" )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class TestContext < Context
|
|
41
|
+
attr_accessor :rsync_count
|
|
42
|
+
|
|
43
|
+
def initialize( *args )
|
|
44
|
+
@rsync_count = 0
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
def rsync( *args )
|
|
48
|
+
@rsync_count += 1
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def sp
|
|
54
|
+
@sp ||= Space.new.tap do |s|
|
|
55
|
+
s.merge_default_options( sync_paths: SYNC_PATHS,
|
|
56
|
+
erb_binding: binding_under_test )
|
|
57
|
+
s.merge_default_options( verbose: :v ) if VERBOSE
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_rput_file
|
|
62
|
+
host = sp.host( 'localhost' )
|
|
63
|
+
2.times do |i|
|
|
64
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
65
|
+
ctx.with do
|
|
66
|
+
changes = ctx.rput( 'd1/bar', "#{TEST_DIR}/d2/" )
|
|
67
|
+
if i == 0
|
|
68
|
+
assert_equal( %w[ bar ], changes.map { |c| c[1] } )
|
|
69
|
+
else
|
|
70
|
+
assert_empty( changes )
|
|
71
|
+
end
|
|
72
|
+
assert_equal( IO.read( "#{SYNC_DIR}/d1/bar" ),
|
|
73
|
+
IO.read( "#{TEST_DIR}/d2/bar" ) )
|
|
74
|
+
end
|
|
75
|
+
assert_equal( 1, ctx.rsync_count )
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_rput_file_sudo
|
|
80
|
+
skip unless TestOptions::SAFE_SUDO
|
|
81
|
+
host = sp.host( 'localhost' )
|
|
82
|
+
2.times do |i|
|
|
83
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
84
|
+
ctx.with do
|
|
85
|
+
changes = ctx.rput( 'd1/bar', "#{TEST_DIR}/d2/", user: ENV['USER'] )
|
|
86
|
+
if i == 0
|
|
87
|
+
assert_equal( %w[ bar ], changes.map { |c| c[1] } )
|
|
88
|
+
else
|
|
89
|
+
assert_empty( changes )
|
|
90
|
+
end
|
|
91
|
+
assert_equal( IO.read( "#{SYNC_DIR}/d1/bar" ),
|
|
92
|
+
IO.read( "#{TEST_DIR}/d2/bar" ) )
|
|
93
|
+
end
|
|
94
|
+
assert_equal( 1, ctx.rsync_count )
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_rput_erb_no_suffix
|
|
99
|
+
host = sp.host( 'localhost' )
|
|
100
|
+
2.times do |i|
|
|
101
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
102
|
+
ctx.with do
|
|
103
|
+
changes = ctx.rput( 'd1/foo', "#{TEST_DIR}/d2/" )
|
|
104
|
+
if i == 0
|
|
105
|
+
assert_equal( %w[ foo ], changes.map { |c| c[1] } )
|
|
106
|
+
else
|
|
107
|
+
assert_empty( changes )
|
|
108
|
+
end
|
|
109
|
+
assert_equal( "barfoobar\n",
|
|
110
|
+
IO.read( "#{TEST_DIR}/d2/foo" ) )
|
|
111
|
+
end
|
|
112
|
+
assert_equal( 1, ctx.rsync_count )
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_rput_erb_suffix
|
|
117
|
+
host = sp.host( 'localhost' )
|
|
118
|
+
2.times do |i|
|
|
119
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
120
|
+
ctx.with do
|
|
121
|
+
changes = ctx.rput( 'd1/foo.erb', "#{TEST_DIR}/d2/" )
|
|
122
|
+
if i == 0
|
|
123
|
+
assert_equal( %w[ foo ], changes.map { |c| c[1] } )
|
|
124
|
+
else
|
|
125
|
+
assert_empty( changes )
|
|
126
|
+
end
|
|
127
|
+
assert_equal( "barfoobar\n",
|
|
128
|
+
IO.read( "#{TEST_DIR}/d2/foo" ) )
|
|
129
|
+
end
|
|
130
|
+
assert_equal( 1, ctx.rsync_count )
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_rput_erb_rename
|
|
135
|
+
host = sp.host( 'localhost' )
|
|
136
|
+
2.times do |i|
|
|
137
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
138
|
+
ctx.with do
|
|
139
|
+
changes = ctx.rput( 'd1/foo.erb', "#{TEST_DIR}/baz" )
|
|
140
|
+
if i == 0
|
|
141
|
+
assert_equal( %w[ foo ], changes.map { |c| c[1] } )
|
|
142
|
+
refute( File.exist?( "#{TEST_DIR}/foo" ) )
|
|
143
|
+
else
|
|
144
|
+
assert_empty( changes )
|
|
145
|
+
end
|
|
146
|
+
assert_equal( "barfoobar\n",
|
|
147
|
+
IO.read( "#{TEST_DIR}/baz" ) )
|
|
148
|
+
end
|
|
149
|
+
assert_equal( 1, ctx.rsync_count )
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_rput_missing_dir
|
|
154
|
+
host = sp.host( 'localhost' )
|
|
155
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
156
|
+
begin
|
|
157
|
+
ctx.rput( 'nodir/', "#{TEST_DIR}/" )
|
|
158
|
+
flunk "Expected SourceNotFound exception"
|
|
159
|
+
rescue SourceNotFound => e
|
|
160
|
+
refute_match( /.erb/, e.message )
|
|
161
|
+
pass
|
|
162
|
+
end
|
|
163
|
+
assert_equal( 0, ctx.rsync_count )
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def test_rput_missing_file
|
|
167
|
+
host = sp.host( 'localhost' )
|
|
168
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
169
|
+
begin
|
|
170
|
+
ctx.rput( 'd1/goo', "#{TEST_DIR}/" )
|
|
171
|
+
flunk "Expected SourceNotFound exception"
|
|
172
|
+
rescue SourceNotFound => e
|
|
173
|
+
refute_match( /.erb/, e.message )
|
|
174
|
+
pass
|
|
175
|
+
end
|
|
176
|
+
assert_equal( 0, ctx.rsync_count )
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_rput_contents_with_erb
|
|
180
|
+
host = sp.host( 'localhost' )
|
|
181
|
+
2.times do |i|
|
|
182
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
183
|
+
ctx.with do
|
|
184
|
+
changes = ctx.rput( 'd1/', "#{TEST_DIR}/d2" )
|
|
185
|
+
if i == 0
|
|
186
|
+
assert_equal( %w[ ./ bar foo ], changes.map { |c| c[1] } )
|
|
187
|
+
else
|
|
188
|
+
assert_empty( changes )
|
|
189
|
+
end
|
|
190
|
+
assert_equal( IO.read( "#{SYNC_DIR}/d1/bar" ),
|
|
191
|
+
IO.read( "#{TEST_DIR}/d2/bar" ) )
|
|
192
|
+
assert_equal( "barfoobar\n",
|
|
193
|
+
IO.read( "#{TEST_DIR}/d2/foo" ) )
|
|
194
|
+
end
|
|
195
|
+
assert_equal( 1, ctx.rsync_count )
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def test_rput_dir_with_erb
|
|
200
|
+
host = sp.host( 'localhost' )
|
|
201
|
+
2.times do |i|
|
|
202
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
203
|
+
ctx.with do
|
|
204
|
+
changes = ctx.rput( 'd1', "#{TEST_DIR}" )
|
|
205
|
+
if i == 0
|
|
206
|
+
assert_equal( %w[ d1/ d1/bar d1/foo ], changes.map { |c| c[1] } )
|
|
207
|
+
else
|
|
208
|
+
assert_empty( changes )
|
|
209
|
+
end
|
|
210
|
+
refute( File.executable?( "#{TEST_DIR}/d1/bar" ) )
|
|
211
|
+
assert_equal( IO.read( "#{SYNC_DIR}/d1/bar" ),
|
|
212
|
+
IO.read( "#{TEST_DIR}/d1/bar" ) )
|
|
213
|
+
refute( File.executable?( "#{TEST_DIR}/d1/foo" ) )
|
|
214
|
+
assert_equal( "barfoobar\n",
|
|
215
|
+
IO.read( "#{TEST_DIR}/d1/foo" ) )
|
|
216
|
+
end
|
|
217
|
+
assert_equal( 1, ctx.rsync_count )
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def test_rput_subdir_with_erb
|
|
222
|
+
host = sp.host( 'localhost' )
|
|
223
|
+
2.times do |i|
|
|
224
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
225
|
+
ctx.with do
|
|
226
|
+
changes = ctx.rput( 'd3', "#{TEST_DIR}" )
|
|
227
|
+
if i == 0
|
|
228
|
+
assert_equal( %w[ d3/ d3/d2/ d3/d2/bar d3/d2/foo ],
|
|
229
|
+
changes.map { |c| c[1] } )
|
|
230
|
+
else
|
|
231
|
+
assert_empty( changes )
|
|
232
|
+
end
|
|
233
|
+
assert( File.executable?( "#{TEST_DIR}/d3/d2/bar" ) )
|
|
234
|
+
assert_equal( IO.read( "#{SYNC_DIR}/d3/d2/bar" ),
|
|
235
|
+
IO.read( "#{TEST_DIR}/d3/d2/bar" ) )
|
|
236
|
+
assert( File.executable?( "#{TEST_DIR}/d3/d2/foo" ) )
|
|
237
|
+
assert_equal( "barfoobar\n",
|
|
238
|
+
IO.read( "#{TEST_DIR}/d3/d2/foo" ) )
|
|
239
|
+
end
|
|
240
|
+
assert_equal( 1, ctx.rsync_count )
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def test_rput_subdir_contents_with_erb
|
|
245
|
+
host = sp.host( 'localhost' )
|
|
246
|
+
2.times do |i|
|
|
247
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
248
|
+
ctx.with do
|
|
249
|
+
changes = ctx.rput( 'd3/', "#{TEST_DIR}" )
|
|
250
|
+
if i == 0
|
|
251
|
+
assert_equal( %w[ d2/ d2/bar d2/foo ], changes.map { |c| c[1] } )
|
|
252
|
+
else
|
|
253
|
+
assert_empty( changes )
|
|
254
|
+
end
|
|
255
|
+
assert( File.executable?( "#{TEST_DIR}/d2/bar" ) )
|
|
256
|
+
assert_equal( IO.read( "#{SYNC_DIR}/d3/d2/bar" ),
|
|
257
|
+
IO.read( "#{TEST_DIR}/d2/bar" ) )
|
|
258
|
+
assert( File.executable?( "#{TEST_DIR}/d2/foo" ) )
|
|
259
|
+
assert_equal( "barfoobar\n",
|
|
260
|
+
IO.read( "#{TEST_DIR}/d2/foo" ) )
|
|
261
|
+
end
|
|
262
|
+
assert_equal( 1, ctx.rsync_count )
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def test_rput_erb_perm_change_only
|
|
267
|
+
host = sp.host( 'localhost' )
|
|
268
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
269
|
+
changes = ctx.rput( 'd3/', "#{TEST_DIR}" )
|
|
270
|
+
assert_equal( %w[ d2/ d2/bar d2/foo ], changes.map { |c| c[1] } )
|
|
271
|
+
assert( File.executable?( "#{TEST_DIR}/d2/foo" ) )
|
|
272
|
+
assert_equal( 1, ctx.rsync_count )
|
|
273
|
+
|
|
274
|
+
# Make the template target non-executable temporarily. On re-rput,
|
|
275
|
+
# only change is that file should have its exec bits reset.
|
|
276
|
+
ctx = TestContext.new( host, sp.default_options )
|
|
277
|
+
FileUtils.chmod( 0664, "#{TEST_DIR}/d2/foo" )
|
|
278
|
+
changes = ctx.rput( 'd3/', "#{TEST_DIR}" )
|
|
279
|
+
assert_equal( [ %w[ .f...p..... d2/foo ] ], changes )
|
|
280
|
+
assert( File.executable?( "#{TEST_DIR}/d2/foo" ) )
|
|
281
|
+
assert_equal( 1, ctx.rsync_count )
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def binding_under_test
|
|
285
|
+
var = "foo"
|
|
286
|
+
binding
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end
|
data/test/test_rsync.rb
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env jruby
|
|
2
|
+
#.hashdot.profile += jruby-shortlived
|
|
3
|
+
|
|
4
|
+
#--
|
|
5
|
+
# Copyright (c) 2011-2014 David Kellum
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
|
8
|
+
# may not use this file except in compliance with the License. You
|
|
9
|
+
# may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
16
|
+
# implied. See the License for the specific language governing
|
|
17
|
+
# permissions and limitations under the License.
|
|
18
|
+
#++
|
|
19
|
+
|
|
20
|
+
require_relative 'setup'
|
|
21
|
+
|
|
22
|
+
require 'syncwrap'
|
|
23
|
+
require 'syncwrap/rsync'
|
|
24
|
+
|
|
25
|
+
class TestRsync < MiniTest::Unit::TestCase
|
|
26
|
+
include SyncWrap::Rsync
|
|
27
|
+
|
|
28
|
+
def test_expand_implied_target
|
|
29
|
+
assert_expand( %w[ other/lang.sh /etc/],
|
|
30
|
+
%w[ other/lang.sh /etc/] )
|
|
31
|
+
|
|
32
|
+
assert_expand( %w[ etc/profile.d/lang.sh /etc/profile.d/ ],
|
|
33
|
+
%w[ etc/profile.d/lang.sh ] )
|
|
34
|
+
|
|
35
|
+
assert_expand( %w[ etc/profile.d/ /etc/profile.d/ ],
|
|
36
|
+
%w[ etc/profile.d/ ] )
|
|
37
|
+
|
|
38
|
+
assert_expand( %w[ etc/profile.d /etc/ ],
|
|
39
|
+
%w[ etc/profile.d ] )
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_user_options
|
|
43
|
+
assert_opts( [ '--rsync-path=sudo rsync' ], user: 'root' )
|
|
44
|
+
assert_opts( [ '--rsync-path=sudo rsync' ], user: :root )
|
|
45
|
+
assert_opts( [ '--rsync-path=sudo -u runr rsync' ], user: 'runr' )
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_exclude_options
|
|
49
|
+
assert_opts( %w[ --cvs-exclude ], excludes: :dev )
|
|
50
|
+
assert_opts( %w[ --cvs-exclude ], excludes: [ :dev ] )
|
|
51
|
+
assert_opts( %w[ --exclude=foo ], excludes: 'foo' )
|
|
52
|
+
assert_opts( %w[ --exclude=foo --exclude=bar ], excludes: %w[ foo bar ] )
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_ssh_options
|
|
56
|
+
assert_opts( [ '-e', 'ssh -l auser' ], ssh_user: 'auser' )
|
|
57
|
+
assert_opts( [], ssh_user_pem: 'key.pem' )
|
|
58
|
+
assert_opts( [ '-e', 'ssh -l auser -i key.pem' ],
|
|
59
|
+
ssh_user: 'auser', ssh_user_pem: 'key.pem' )
|
|
60
|
+
assert_opts( [ '-e', 'ssh -o foo=bar' ], ssh_options: {'foo'=>'bar'} )
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_other_options
|
|
64
|
+
assert_opts( %w[ -n ], dryrun: true )
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_localhost
|
|
68
|
+
args = rsync_args( 'localhost', ['d'], 'd/' )
|
|
69
|
+
assert_equal( %w[rsync -i -r -l -E -c -b d d/], args )
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def assert_expand( expected, args )
|
|
73
|
+
expanded = expand_implied_target( args )
|
|
74
|
+
assert_equal( expected, expanded.flatten, expanded )
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def assert_opts( expected, opts )
|
|
78
|
+
args = rsync_args( 'testhost', ['d'], 'd/', opts )
|
|
79
|
+
assert_equal( %w[rsync -i -r -l -E -c -b] +
|
|
80
|
+
expected +
|
|
81
|
+
%w[d testhost:d/],
|
|
82
|
+
args )
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
SYNC_DIR = File.join( SyncWrap::GEM_ROOT, 'sync' ).freeze
|
|
86
|
+
SYNC_PATHS = [ SYNC_DIR ].freeze
|
|
87
|
+
|
|
88
|
+
# Maintenance: We use gem's sync/src/hashdot template list for
|
|
89
|
+
# testing, so expect breakage if that changes.
|
|
90
|
+
SYNC_HASHDOT = ( SYNC_DIR + '/src/hashdot' ).freeze
|
|
91
|
+
|
|
92
|
+
def test_relativize
|
|
93
|
+
rel = relativize( SYNC_HASHDOT )
|
|
94
|
+
assert_operator( rel, :!=, SYNC_HASHDOT )
|
|
95
|
+
assert( File.identical?( SYNC_HASHDOT, rel ) )
|
|
96
|
+
assert_equal( rel, relativize( rel ) )
|
|
97
|
+
assert_equal( rel + '/', relativize( rel + '/' ) )
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_subpath
|
|
101
|
+
assert_equal( "", subpath( "d/", "d/f" ) )
|
|
102
|
+
assert_equal( "", subpath( "d", "d/f" ) )
|
|
103
|
+
assert_equal( "", subpath( "d/e/", "d/e/f" ) )
|
|
104
|
+
assert_equal( "", subpath( "d/e/d/", "d/e/d/f" ) )
|
|
105
|
+
assert_equal( "e", subpath( "d", "d/e/f" ) )
|
|
106
|
+
assert_equal( "e", subpath( "d/e", "d/e/f" ) )
|
|
107
|
+
assert_equal( "e/d", subpath( "d", "d/e/d/f" ) )
|
|
108
|
+
assert_equal( "e/d", subpath( "d/", "d/e/d/f" ) )
|
|
109
|
+
assert_equal( "e/d", subpath( "d/e" , "d/e/d/f" ) )
|
|
110
|
+
assert_equal( "d", subpath( "d/e/", "d/e/d/f" ) )
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def test_resolve_sources
|
|
114
|
+
src = resolve_source!( 'src/hashdot', SYNC_PATHS )
|
|
115
|
+
assert( File.identical?( SYNC_HASHDOT, src ), src )
|
|
116
|
+
assert( src[-1] != '/' )
|
|
117
|
+
|
|
118
|
+
src = resolve_source!( 'src/hashdot/', SYNC_PATHS )
|
|
119
|
+
assert( File.identical?( SYNC_HASHDOT, src ), src )
|
|
120
|
+
assert( src[-1] == '/' )
|
|
121
|
+
|
|
122
|
+
assert_raises( SyncWrap::SourceNotFound ) do
|
|
123
|
+
resolve_sources( [ 'src/hashdot', 'not/found' ], SYNC_PATHS )
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
src = resolve_source!( 'src/hashdot', [ '/bogus' ] + SYNC_PATHS )
|
|
127
|
+
assert( File.identical?( SYNC_HASHDOT, src ), src )
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_find_source_erbs
|
|
131
|
+
erbs = find_source_erbs( SYNC_HASHDOT ).sort
|
|
132
|
+
assert_equal( [ SYNC_HASHDOT + '/Makefile.erb',
|
|
133
|
+
SYNC_HASHDOT + '/profiles/default.hdp.erb',
|
|
134
|
+
SYNC_HASHDOT + '/profiles/jruby.hdp.erb' ],
|
|
135
|
+
erbs )
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
data/test/test_shell.rb
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env jruby
|
|
2
|
+
#.hashdot.profile += jruby-shortlived
|
|
3
|
+
|
|
4
|
+
#--
|
|
5
|
+
# Copyright (c) 2011-2014 David Kellum
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
|
8
|
+
# may not use this file except in compliance with the License. You
|
|
9
|
+
# may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
16
|
+
# implied. See the License for the specific language governing
|
|
17
|
+
# permissions and limitations under the License.
|
|
18
|
+
#++
|
|
19
|
+
|
|
20
|
+
require_relative 'setup'
|
|
21
|
+
|
|
22
|
+
require 'syncwrap/shell'
|
|
23
|
+
|
|
24
|
+
class TestShell < MiniTest::Unit::TestCase
|
|
25
|
+
include TestOptions
|
|
26
|
+
include SyncWrap::Shell
|
|
27
|
+
|
|
28
|
+
ZFILE = File.expand_path( "../zfile", __FILE__ )
|
|
29
|
+
|
|
30
|
+
def test_command_lines_cleanup
|
|
31
|
+
cmd = command_lines_cleanup( [ "", " a\nb", "\n c\n", "d m n \n \n" ] )
|
|
32
|
+
assert_equal( (%w[a b c] << "d m n").join( "\n" ), cmd )
|
|
33
|
+
|
|
34
|
+
cmd = <<-SH
|
|
35
|
+
if true; then
|
|
36
|
+
|
|
37
|
+
echo yep
|
|
38
|
+
else
|
|
39
|
+
echo huh
|
|
40
|
+
fi
|
|
41
|
+
SH
|
|
42
|
+
|
|
43
|
+
expected = [ "if true; then",
|
|
44
|
+
" echo yep",
|
|
45
|
+
"else",
|
|
46
|
+
" echo huh",
|
|
47
|
+
"fi" ].join( "\n" )
|
|
48
|
+
|
|
49
|
+
assert_equal( expected, command_lines_cleanup( cmd ) )
|
|
50
|
+
assert_equal( expected, command_lines_cleanup( expected ) )
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_ssh_opts
|
|
54
|
+
args = ssh_args( 'test', 'true', ssh_options: {'IdentitiesOnly' => 'yes'} )
|
|
55
|
+
assert_equal( %w[ ssh -o IdentitiesOnly=yes test ], args[0..3] )
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_capture_noop
|
|
59
|
+
exit_code, outputs = capture3( %w[bash -c true])
|
|
60
|
+
assert_equal( 0, exit_code )
|
|
61
|
+
assert_equal( [], outputs )
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_capture_error
|
|
65
|
+
exit_code, outputs = capture3( %w[bash -v -c] << "exit 33" )
|
|
66
|
+
assert_equal( 33, exit_code )
|
|
67
|
+
assert_equal( [[:err, "exit 33\n"]], outputs, outputs )
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_capture_output
|
|
71
|
+
exit_code, outputs = capture3( %w[bash -v -c] << "echo foo" )
|
|
72
|
+
assert_equal( 0, exit_code )
|
|
73
|
+
assert_equal( [ [:err, "echo foo\n"],
|
|
74
|
+
[:out, "foo\n"] ],
|
|
75
|
+
outputs.sort ) #order uncertain
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_capture_big
|
|
79
|
+
exit_code, outputs = capture3( %w[bash -v -c] << "dd if=#{ZFILE} bs=1M" )
|
|
80
|
+
assert_equal( 0, exit_code )
|
|
81
|
+
assert_equal( IO.read( ZFILE ), collect_stream( :out, outputs ) )
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_capture_output_interleaved
|
|
85
|
+
exit_code, outputs = capture3( sh_args( <<-'SH', sh_verbose: :v ))
|
|
86
|
+
echo foo
|
|
87
|
+
echo bar
|
|
88
|
+
SH
|
|
89
|
+
assert_equal( 0, exit_code )
|
|
90
|
+
assert_equal( "echo foo\necho bar\n",
|
|
91
|
+
collect_stream( :err, outputs ) )
|
|
92
|
+
assert_equal( "foo\nbar\n",
|
|
93
|
+
collect_stream( :out, outputs ) )
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_capture_output_coalesce
|
|
97
|
+
cmd = sh_args( <<-'SH', sh_verbose: :v, coalesce: true )
|
|
98
|
+
echo foo
|
|
99
|
+
echo bar
|
|
100
|
+
SH
|
|
101
|
+
unmerged = []
|
|
102
|
+
exit_code, merged = capture3( cmd ) do |stream, chunk|
|
|
103
|
+
unmerged << [ stream, chunk ]
|
|
104
|
+
end
|
|
105
|
+
assert_equal( 0, exit_code )
|
|
106
|
+
assert_equal( [[:err, "echo foo\nfoo\necho bar\nbar\n"]],
|
|
107
|
+
merged, merged )
|
|
108
|
+
post_merged = unmerged.map {|s,c| c}.inject( "", :+ )
|
|
109
|
+
assert_equal( merged[0][1], post_merged )
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_capture_multi_error
|
|
113
|
+
# Timing dependent, one or two reads will be received. Regardless,
|
|
114
|
+
# capture3 should combine them to a single read as shown
|
|
115
|
+
11.times do
|
|
116
|
+
exit_code, outputs = capture3( %w[bash -v -c] << "echo foo >&2")
|
|
117
|
+
assert_equal( 0, exit_code )
|
|
118
|
+
assert_equal( [[:err, "echo foo >&2\nfoo\n"]],
|
|
119
|
+
outputs, outputs )
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_shell_special_chars
|
|
124
|
+
exit_code, outputs = capture3( sh_args( <<-'SH' ) )
|
|
125
|
+
var=33
|
|
126
|
+
echo \# "!var" "\"$var\"" "\$" "#"
|
|
127
|
+
echo \$ '!var' '"$var"' '$' '#'
|
|
128
|
+
SH
|
|
129
|
+
assert_equal( 0, exit_code )
|
|
130
|
+
assert_equal( [[:out, ( "# !var \"33\" $ #\n" +
|
|
131
|
+
"$ !var \"$var\" $ #\n" )]],
|
|
132
|
+
outputs, outputs )
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def test_sudo
|
|
136
|
+
skip unless SAFE_SUDO
|
|
137
|
+
cmd = sudo_args( 'echo foo', user: :root )
|
|
138
|
+
exit_code, outputs = capture3( cmd )
|
|
139
|
+
assert_equal( 0, exit_code )
|
|
140
|
+
assert_equal( [[:out, "foo\n"]], outputs, outputs )
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_ssh
|
|
144
|
+
skip unless SAFE_SSH
|
|
145
|
+
cmd = ssh_args( SAFE_SSH, 'echo foo', sh_verbose: :v )
|
|
146
|
+
exit_code, outputs = capture3( cmd )
|
|
147
|
+
assert_equal( 0, exit_code )
|
|
148
|
+
# Timing dependend order:
|
|
149
|
+
assert_equal( [ [:err, "echo foo\n"],
|
|
150
|
+
[:out, "foo\n"] ],
|
|
151
|
+
outputs.sort ) #order uncertain
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def test_ssh_coalesce
|
|
155
|
+
skip unless SAFE_SSH
|
|
156
|
+
cmd = ssh_args( SAFE_SSH, <<-'SH', sh_verbose: :v, coalesce: true )
|
|
157
|
+
echo foo
|
|
158
|
+
echo bar
|
|
159
|
+
SH
|
|
160
|
+
unmerged = []
|
|
161
|
+
exit_code, merged = capture3( cmd ) do |stream, chunk|
|
|
162
|
+
unmerged << [ stream, chunk ]
|
|
163
|
+
end
|
|
164
|
+
assert_equal( 0, exit_code )
|
|
165
|
+
assert_equal( [[:err, "echo foo\nfoo\necho bar\nbar\n"]],
|
|
166
|
+
merged, merged )
|
|
167
|
+
post_merged = unmerged.map {|s,c| c}.inject( "", :+ )
|
|
168
|
+
assert_equal( merged[0][1], post_merged )
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def test_ssh_capture_big
|
|
172
|
+
skip unless SAFE_SSH
|
|
173
|
+
cmd = ssh_args( SAFE_SSH, "dd if=#{ZFILE} bs=1M" )
|
|
174
|
+
exit_code, outputs = capture3( cmd )
|
|
175
|
+
assert_equal( 0, exit_code )
|
|
176
|
+
assert_equal( IO.read( ZFILE ), collect_stream( :out, outputs ) )
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_ssh_capture_big_2
|
|
180
|
+
skip unless SAFE_SSH
|
|
181
|
+
cmd = ssh_args( SAFE_SSH, <<-SH, coalesce:true )
|
|
182
|
+
for i in {1..1000}; do
|
|
183
|
+
echo "this is to stdout"
|
|
184
|
+
echo "this is to stderr" >&2
|
|
185
|
+
done
|
|
186
|
+
SH
|
|
187
|
+
exit_code, outputs = capture3( cmd )
|
|
188
|
+
assert_equal( 36_000, collect_stream( :err, outputs ).length )
|
|
189
|
+
assert_equal( 0, collect_stream( :out, outputs ).length )
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_ssh_sudo
|
|
193
|
+
skip unless SAFE_SSH && SAFE_SSH_SUDO
|
|
194
|
+
cmd = ssh_args( SAFE_SSH, 'echo foo', sh_verbose: :v, user: :root )
|
|
195
|
+
exit_code, outputs = capture3( cmd )
|
|
196
|
+
assert_equal( 0, exit_code )
|
|
197
|
+
assert_equal( [ [:err, "echo foo\n"],
|
|
198
|
+
[:out, "foo\n" ] ],
|
|
199
|
+
outputs.sort ) #order uncertain
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_ssh_sudo_coalesce
|
|
203
|
+
skip unless SAFE_SSH && SAFE_SSH_SUDO
|
|
204
|
+
cmd = ssh_args( SAFE_SSH, <<-'SH', sh_verbose: :v, coalesce: true, user: :root )
|
|
205
|
+
echo foo
|
|
206
|
+
echo bar
|
|
207
|
+
SH
|
|
208
|
+
unmerged = []
|
|
209
|
+
exit_code, merged = capture3( cmd ) do |stream, chunk|
|
|
210
|
+
unmerged << [ stream, chunk ]
|
|
211
|
+
end
|
|
212
|
+
assert_equal( 0, exit_code )
|
|
213
|
+
assert_equal( [[:err, "echo foo\nfoo\necho bar\nbar\n"]],
|
|
214
|
+
merged, merged )
|
|
215
|
+
post_merged = unmerged.map {|s,c| c}.inject( "", :+ )
|
|
216
|
+
assert_equal( merged[0][1], post_merged )
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_ssh_sudo_escape
|
|
220
|
+
skip unless SAFE_SSH && SAFE_SSH_SUDO
|
|
221
|
+
cmd = ssh_args( SAFE_SSH, <<-'SH', user: :root )
|
|
222
|
+
var=33
|
|
223
|
+
echo \# "!var" "\"$var\"" "\$" "#"
|
|
224
|
+
echo \$ '!var' '"$var"' '$' '#'
|
|
225
|
+
SH
|
|
226
|
+
exit_code, outputs = capture3( cmd )
|
|
227
|
+
assert_equal( 0, exit_code )
|
|
228
|
+
assert_equal( [[:out, ( "# !var \"33\" $ #\n" +
|
|
229
|
+
"$ !var \"$var\" $ #\n" )]],
|
|
230
|
+
outputs, outputs )
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
end
|