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.
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