syncwrap 1.5.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/History.rdoc +19 -0
  3. data/Manifest.txt +82 -34
  4. data/README.rdoc +96 -48
  5. data/Rakefile +0 -65
  6. data/bin/syncwrap +27 -0
  7. data/examples/LAYOUT.rdoc +70 -0
  8. data/examples/Rakefile +16 -0
  9. data/examples/ec2.rb +44 -0
  10. data/examples/hello.rb +14 -0
  11. data/examples/hello_binding.rb +27 -0
  12. data/examples/jruby.rb +11 -0
  13. data/examples/private/aws.json +4 -0
  14. data/examples/rput.rb +24 -0
  15. data/examples/sync/home/bob/.ssh/authorized_keys +1 -0
  16. data/examples/sync/tmp/sample.erb +3 -0
  17. data/lib/syncwrap/amazon_ec2.rb +236 -0
  18. data/lib/syncwrap/amazon_ws.rb +308 -0
  19. data/lib/syncwrap/base.rb +4 -2
  20. data/lib/syncwrap/cli.rb +328 -0
  21. data/lib/syncwrap/component.rb +443 -0
  22. data/lib/syncwrap/components/commercial_jdk.rb +76 -0
  23. data/lib/syncwrap/components/cruby_vm.rb +144 -0
  24. data/lib/syncwrap/components/etc_hosts.rb +44 -0
  25. data/lib/syncwrap/{geminabox.rb → components/geminabox.rb} +12 -17
  26. data/lib/syncwrap/components/hashdot.rb +97 -0
  27. data/lib/syncwrap/components/iyyov.rb +144 -0
  28. data/lib/syncwrap/components/iyyov_daemon.rb +125 -0
  29. data/lib/syncwrap/components/jruby_vm.rb +122 -0
  30. data/lib/syncwrap/components/mdraid.rb +204 -0
  31. data/lib/syncwrap/components/network.rb +99 -0
  32. data/lib/syncwrap/components/open_jdk.rb +70 -0
  33. data/lib/syncwrap/components/postgresql.rb +159 -0
  34. data/lib/syncwrap/components/qpid.rb +303 -0
  35. data/lib/syncwrap/components/rhel.rb +71 -0
  36. data/lib/syncwrap/components/run_user.rb +99 -0
  37. data/lib/syncwrap/components/ubuntu.rb +85 -0
  38. data/lib/syncwrap/components/users.rb +200 -0
  39. data/lib/syncwrap/context.rb +260 -0
  40. data/lib/syncwrap/distro.rb +53 -60
  41. data/lib/syncwrap/formatter.rb +149 -0
  42. data/lib/syncwrap/host.rb +134 -0
  43. data/lib/syncwrap/main.rb +62 -0
  44. data/lib/syncwrap/path_util.rb +55 -0
  45. data/lib/syncwrap/rsync.rb +227 -0
  46. data/lib/syncwrap/ruby_support.rb +110 -0
  47. data/lib/syncwrap/shell.rb +207 -0
  48. data/lib/syncwrap.rb +367 -1
  49. data/{etc → sync/etc}/gemrc +1 -3
  50. data/sync/etc/hosts.erb +8 -0
  51. data/{etc/init.d/iyyov → sync/etc/init.d/iyyov.erb} +35 -7
  52. data/sync/etc/sysconfig/pgsql/postgresql.erb +2 -0
  53. data/sync/src/hashdot/Makefile.erb +98 -0
  54. data/sync/src/hashdot/profiles/default.hdp.erb +25 -0
  55. data/sync/src/hashdot/profiles/jruby-common.hdp +28 -0
  56. data/sync/src/hashdot/profiles/jruby-shortlived.hdp +9 -0
  57. data/sync/src/hashdot/profiles/jruby.hdp.erb +13 -0
  58. data/sync/src/hashdot/profiles/shortlived.hdp +6 -0
  59. data/sync/var/iyyov/default/config.rb +1 -0
  60. data/sync/var/iyyov/default/daemon.rb.erb +15 -0
  61. data/sync/var/iyyov/jobs.rb.erb +4 -0
  62. data/test/muddled_sync.rb +13 -0
  63. data/test/setup.rb +39 -0
  64. data/test/sync/d1/bar +1 -0
  65. data/test/sync/d1/foo.erb +1 -0
  66. data/test/sync/d3/d2/bar +1 -0
  67. data/test/sync/d3/d2/foo.erb +1 -0
  68. data/test/test_components.rb +108 -0
  69. data/test/test_context.rb +107 -0
  70. data/test/test_context_rput.rb +289 -0
  71. data/test/test_rsync.rb +138 -0
  72. data/test/test_shell.rb +233 -0
  73. data/test/test_space.rb +218 -0
  74. data/test/test_space_main.rb +40 -0
  75. data/test/zfile +1 -0
  76. metadata +204 -71
  77. data/etc/sysconfig/pgsql/postgresql +0 -2
  78. data/lib/syncwrap/aws.rb +0 -448
  79. data/lib/syncwrap/common.rb +0 -161
  80. data/lib/syncwrap/ec2.rb +0 -59
  81. data/lib/syncwrap/hashdot.rb +0 -70
  82. data/lib/syncwrap/iyyov.rb +0 -139
  83. data/lib/syncwrap/java.rb +0 -61
  84. data/lib/syncwrap/jruby.rb +0 -118
  85. data/lib/syncwrap/postgresql.rb +0 -135
  86. data/lib/syncwrap/qpid.rb +0 -251
  87. data/lib/syncwrap/remote_task.rb +0 -199
  88. data/lib/syncwrap/rhel.rb +0 -67
  89. data/lib/syncwrap/ubuntu.rb +0 -78
  90. data/lib/syncwrap/user_run.rb +0 -102
  91. data/test/test_syncwrap.rb +0 -202
  92. data/var/iyyov/jobs.rb +0 -11
  93. /data/{etc → sync/etc}/corosync/corosync.conf +0 -0
  94. /data/{etc → sync/etc}/corosync/uidgid.d/qpid +0 -0
  95. /data/{etc → sync/etc}/init.d/qpidd +0 -0
  96. /data/{etc → sync/etc}/sysctl.d/61-postgresql-shm.conf +0 -0
  97. /data/{usr/local → sync/jruby}/bin/jgem +0 -0
  98. /data/{postgresql → sync/postgresql}/rhel/pg_hba.conf +0 -0
  99. /data/{postgresql → sync/postgresql}/rhel/pg_ident.conf +0 -0
  100. /data/{postgresql → sync/postgresql}/rhel/postgresql.conf +0 -0
  101. /data/{postgresql → sync/postgresql}/ubuntu/environment +0 -0
  102. /data/{postgresql → sync/postgresql}/ubuntu/pg_ctl.conf +0 -0
  103. /data/{postgresql → sync/postgresql}/ubuntu/pg_hba.conf +0 -0
  104. /data/{postgresql → sync/postgresql}/ubuntu/pg_ident.conf +0 -0
  105. /data/{postgresql → sync/postgresql}/ubuntu/postgresql.conf +0 -0
  106. /data/{postgresql → sync/postgresql}/ubuntu/start.conf +0 -0
  107. /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
@@ -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
@@ -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