buildr 1.3.0-java → 1.3.1-java

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.
@@ -71,7 +71,7 @@ module Buildr
71
71
 
72
72
  def initialize(xml) #:nodoc:
73
73
  @project = XmlSimple.xml_in(xml)
74
- @parent = POM.load(pom_to_hash(project["parent"].first)) if project["parent"]
74
+ @parent = POM.load(pom_to_hash(project["parent"].first).merge(:type=>'pom')) if project['parent']
75
75
  end
76
76
 
77
77
  # :call-seq:
@@ -201,6 +201,7 @@ module Buildr
201
201
  ant.classpath :path=>dependencies.join(File::PATH_SEPARATOR)
202
202
  (options[:properties] || []).each { |key, value| ant.sysproperty :key=>key, :value=>value }
203
203
  (options[:environment] || []).each { |key, value| ant.env :key=>key, :value=>value }
204
+ Array(options[:java_args]).each { |value| ant.jvmarg :value=>value }
204
205
  ant.formatter :type=>'plain'
205
206
  ant.formatter :type=>'plain', :usefile=>false # log test
206
207
  ant.formatter :type=>'xml'
@@ -24,8 +24,8 @@ module Buildr
24
24
  CMP_REGEX = Gem::Requirement::OP_RE.dup
25
25
  CMP_CHARS = CMP_PROCS.keys.join
26
26
  BOOL_CHARS = '\|\&\!'
27
- VER_CHARS = '\w\.'
28
-
27
+ VER_CHARS = '\w\.\-'
28
+
29
29
  class << self
30
30
  # is +str+ a version string?
31
31
  def version?(str)
@@ -496,13 +496,25 @@ module Buildr
496
496
 
497
497
  # Return an artifact spec without the version part.
498
498
  def unversioned_spec
499
- to_spec[/^([a-zA-Z._-]+(:[a-zA-Z._-]+){2,3})/]
499
+ str = to_spec
500
+ return nil if str =~ /^:+/
501
+ ary = str.split(':')
502
+ ary = ary[0...-1] if ary.size > 3
503
+ ary.join(':')
500
504
  end
501
505
 
502
506
  class << self
503
507
  # Return an artifact spec without the version part.
504
508
  def unversioned_spec(spec)
505
- spec.to_s[/^([a-zA-Z._-]+(:[a-zA-Z._-]+){2,3})/] || new(spec).unversioned_spec
509
+ str = spec.to_s
510
+ return nil if str =~ /^:+/
511
+ ary = str.split(':')
512
+ ary = ary[0...-1] if ary.size > 3
513
+ if ary.size > 2
514
+ ary.join(':')
515
+ else
516
+ new(spec).unversioned_spec
517
+ end
506
518
  end
507
519
  end
508
520
  end
@@ -65,14 +65,39 @@ namespace 'apache' do
65
65
  target = args.incubating ? "people.apache.org:/www/www.apache.org/dist/incubator/#{spec.name}/#{spec.version}-incubating" :
66
66
  "people.apache.org:/www/www.apache.org/dist/#{spec.name}/#{spec.version}"
67
67
  puts 'Uploading packages to Apache distro ...'
68
- sh 'rsync', '--progress', 'published/distro/*', target
68
+ host, remote_dir = target.split(':')
69
+ sh 'ssh', host, 'rm', '-rf', remote_dir rescue nil
70
+ sh 'ssh', host, 'mkdir', remote_dir
71
+ sh 'rsync', '--progress', '--recursive', 'published/distro/', target
69
72
  puts 'Done'
70
73
  end
71
74
 
72
-
73
- task 'distro-links'=>['staged/site', 'apache:sign'] do |task, args|
75
+ task 'distro-links'=>'staged/distro' do |task, args|
74
76
  url = args.incubating ? "http://www.apache.org/dist/incubator/#{spec.name}/#{spec.version}-incubating" :
75
77
  "http://www.apache.org/dist/#{spec.name}/#{spec.version}"
78
+ rows = FileList['staged/distro/*.{gem,tgz,zip}'].map { |pkg|
79
+ name, md5 = File.basename(pkg), MD5.file(pkg).to_s
80
+ %{| "#{name}":#{url}/#{name} | "#{md5}":#{url}/#{name}.md5 | "Sig":#{url}/#{name}.asc |}
81
+ }
82
+ textile = <<-TEXTILE
83
+ h3. #{spec.name} #{spec.version}#{args.incubating && "-incubating"} (#{Time.now.strftime('%Y-%m-%d')})
84
+
85
+ |_. Package |_. MD5 Checksum |_. PGP |
86
+ #{rows.join("\n")}
87
+
88
+ p>. ("Release signing keys":#{url}/KEYS)
89
+ TEXTILE
90
+ file_name = 'doc/pages/download.textile'
91
+ print "Adding download links to #{file_name} ... "
92
+ modified = File.read(file_name).sub(/h2.*binaries.*source.*/i) { |header| "#{header}\n\n#{textile}" }
93
+ File.open file_name, 'w' do |file|
94
+ file.write modified
95
+ end
96
+ puts 'Done'
97
+ end
98
+
99
+ =begin
100
+ task 'distro-links'=>['staged/site', 'apache:sign'] do |task, args|
76
101
  rows = FileList['staged/distro/*.{gem,tgz,zip}'].map { |pkg|
77
102
  name, md5 = File.basename(pkg), File.read("#{pkg}.md5").split.first
78
103
  <<-HTML
@@ -97,9 +122,9 @@ namespace 'apache' do
97
122
  file.write modified
98
123
  end
99
124
  end
125
+ =end
100
126
 
101
- file 'staged/site'=>'site' do
102
- mkpath 'staged'
127
+ file 'staged/site'=>['distro-links', 'staged', 'site'] do
103
128
  rm_rf 'staged/site'
104
129
  cp_r 'site', 'staged'
105
130
  end
@@ -109,7 +134,7 @@ namespace 'apache' do
109
134
  target = args.incubating ? "people.apache.org:/www/incubator.apache.org/#{spec.name}" :
110
135
  "people.apache.org:/www/#{spec.name}.apache.org"
111
136
  puts 'Uploading Apache Web site ...'
112
- sh 'rsync', '--progress', '--recursive', '--delete', 'published/distro/site/', target
137
+ sh 'rsync', '--progress', '--recursive', '--delete', 'published/site/', target
113
138
  puts 'Done'
114
139
  end
115
140
 
@@ -117,7 +142,7 @@ end
117
142
 
118
143
 
119
144
  task 'stage:check'=>['apache:license', 'apache:check']
120
- task 'stage:prepare'=>['staged/distro', 'staged/site', 'apache:distro-links'] do |task|
145
+ task 'stage:prepare'=>['staged/distro', 'staged/site'] do |task|
121
146
  # Since this requires input (passphrase), do it at the very end.
122
147
  task.enhance do
123
148
  task('apache:sign').invoke
@@ -40,7 +40,8 @@ namespace 'changelog' do
40
40
  end
41
41
 
42
42
  task 'wrapup'=>'CHANGELOG' do
43
- next_version = spec.version.to_ints.zip([0, 0, 1]).map { |a| a.inject(0) { |t,i| t + i } }.join('.')
43
+ next_version = spec.version.to_s.split('.').map { |v| v.to_i }.
44
+ zip([0, 0, 1]).map { |a| a.inject(0) { |t,i| t + i } }.join('.')
44
45
  print 'Adding new entry to CHANGELOG ... '
45
46
  modified = "#{next_version} (Pending)\n\n" + File.read('CHANGELOG')
46
47
  File.open 'CHANGELOG', 'w' do |file|
@@ -38,9 +38,11 @@ task 'release'=>['release:prepare', 'release:publish', 'release:wrapup']
38
38
 
39
39
 
40
40
  task 'next_version' do
41
+ next_version = spec.version.to_s.split('.').map { |v| v.to_i }.
42
+ zip([0, 0, 1]).map { |a| a.inject(0) { |t,i| t + i } }.join('.')
43
+
41
44
  ver_file = "lib/#{spec.name}.rb"
42
45
  if File.exist?(ver_file)
43
- next_version = spec.version.to_ints.zip([0, 0, 1]).map { |a| a.inject(0) { |t,i| t + i } }.join('.')
44
46
  print "Updating #{ver_file} to next version number (#{next_version}) ... "
45
47
  modified = File.read(ver_file).sub(/(VERSION\s*=\s*)(['"])(.*)\2/) { |line| "#{$1}#{$2}#{next_version}#{$2}" }
46
48
  File.open ver_file, 'w' do |file|
@@ -48,6 +50,16 @@ task 'next_version' do
48
50
  end
49
51
  puts 'Done'
50
52
  end
53
+
54
+ spec_file = "#{spec.name}.gemspec"
55
+ if File.exist?(spec_file)
56
+ print "Updating #{spec_file} to next version number (#{next_version}) ... "
57
+ modified = File.read(spec_file).sub(/(s(?:pec)?\.version\s*=\s*)(['"])(.*)\2/) { |line| "#{$1}#{$2}#{next_version}#{$2}" }
58
+ File.open spec_file, 'w' do |file|
59
+ file.write modified
60
+ end
61
+ puts 'Done'
62
+ end
51
63
  end
52
64
 
53
65
  task 'release:wrapup'=>'next_version'
@@ -29,14 +29,21 @@ end
29
29
 
30
30
  namespace 'rubyforge' do
31
31
 
32
- task 'release'=>'published' do |task|
32
+ file 'published/rubyforge'=>'published' do
33
+ mkdir 'published/rubyforge'
34
+ FileList['published/distro/*.{gem,tgz,zip}'].each do |pkg|
35
+ cp pkg, 'published/rubyforge/' + File.basename(pkg).sub(/-incubating/, '')
36
+ end
37
+ end
38
+
39
+ task 'release'=>'published/rubyforge' do |task|
33
40
  changes = FileList['published/CHANGES'].first
34
- files = FileList['published/*.{gem,tgz,zip}'].exclude(changes).existing
41
+ files = FileList['published/rubyforge/*.{gem,tgz,zip}'].exclude(changes).existing
35
42
  print "Uploading #{spec.version} to RubyForge ... "
36
43
  rubyforge = RubyForge.new
37
44
  rubyforge.login
38
45
  rubyforge.userconfig.merge!('release_changes'=>changes, 'preformatted' => true) if changes
39
- rubyforge.add_release spec.rubyforge_project.downcase, spec.name.downcase, spec.version, *files
46
+ rubyforge.add_release spec.rubyforge_project.downcase, spec.name.downcase, spec.version.to_s, *files
40
47
  puts 'Done'
41
48
  end
42
49
 
@@ -17,7 +17,7 @@
17
17
 
18
18
 
19
19
  require 'rubygems/source_info_cache'
20
-
20
+ require 'stringio' # for Gem::RemoteFetcher
21
21
 
22
22
  def windows?
23
23
  Config::CONFIG['host_os'] =~ /windows|cygwin|bccwin|cygwin|djgpp|mingw|mswin|wince/i
@@ -38,11 +38,12 @@ end
38
38
 
39
39
  def install_gem(name, ver_requirement = nil)
40
40
  dep = Gem::Dependency.new(name, ver_requirement)
41
+ rb_bin = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
41
42
  if Gem::SourceIndex.from_installed_gems.search(dep).empty?
42
- spec = Gem::SourceInfoCache.search(dep).last
43
+ spec = Gem::SourceInfoCache.search(dep, true, true).last
43
44
  fail "#{dep} not found in local or remote repository!" unless spec
44
45
  puts "Installing #{spec} ..."
45
- args = [Config::CONFIG['ruby_install_name'], '-S', 'gem', 'install', spec.name, '-v', spec.version.to_s]
46
+ args = [rb_bin, '-S', 'gem', 'install', spec.name, '-v', spec.version.to_s]
46
47
  args.unshift('sudo', 'env', 'JAVA_HOME=' + ENV['JAVA_HOME']) unless windows?
47
48
  sh *args
48
49
  end
@@ -210,6 +210,11 @@ describe Buildr, 'settings' do
210
210
  Buildr.settings.user.should == { 'foo'=>'bar' }
211
211
  end
212
212
 
213
+ it 'should return loaded settings.yml file' do
214
+ write 'home/.buildr/settings.yml', 'foo: bar'
215
+ Buildr.settings.user.should == { 'foo'=>'bar' }
216
+ end
217
+
213
218
  it 'should fail if settings.yaml file is not a hash' do
214
219
  write 'home/.buildr/settings.yaml', 'foo bar'
215
220
  lambda { Buildr.settings.user }.should raise_error(RuntimeError, /expecting.*settings.yaml/i)
@@ -231,6 +236,11 @@ describe Buildr, 'settings' do
231
236
  Buildr.settings.build.should == { 'foo'=>'bar' }
232
237
  end
233
238
 
239
+ it 'should return loaded build.yml file' do
240
+ write 'build.yml', 'foo: bar'
241
+ Buildr.settings.build.should == { 'foo'=>'bar' }
242
+ end
243
+
234
244
  it 'should fail if build.yaml file is not a hash' do
235
245
  write 'build.yaml', 'foo bar'
236
246
  lambda { Buildr.settings.build }.should raise_error(RuntimeError, /expecting.*build.yaml/i)
@@ -255,6 +265,14 @@ describe Buildr, 'settings' do
255
265
  Buildr.settings.profiles.should == { 'development'=> { 'foo'=>'bar' } }
256
266
  end
257
267
 
268
+ it 'should return loaded profiles.yml file' do
269
+ write 'profiles.yml', <<-YAML
270
+ development:
271
+ foo: bar
272
+ YAML
273
+ Buildr.settings.profiles.should == { 'development'=> { 'foo'=>'bar' } }
274
+ end
275
+
258
276
  it 'should fail if profiles.yaml file is not a hash' do
259
277
  write 'profiles.yaml', 'foo bar'
260
278
  lambda { Buildr.settings.profiles }.should raise_error(RuntimeError, /expecting.*profiles.yaml/i)
@@ -42,7 +42,6 @@ describe 'ArchiveTask', :shared=>true do
42
42
 
43
43
  def create_for_merge
44
44
  zip(@archive + '.src').include(@files).tap do |task|
45
- task.invoke
46
45
  yield task
47
46
  end
48
47
  end
@@ -424,6 +424,15 @@ describe Buildr, '#artifact' do
424
424
  artifact = artifact('group:id:jar:1.0').from('test.jar')
425
425
  lambda { artifact.invoke }.should change { File.exist?(artifact.to_s) }.to(true)
426
426
  end
427
+
428
+ it 'should reference artifacts defined on build.yaml by using ruby symbols' do
429
+ write 'build.yaml', <<-YAML
430
+ artifacts:
431
+ j2ee: geronimo-spec:geronimo-spec-j2ee:jar:1.4-rc4
432
+ YAML
433
+ Buildr.application.load_artifacts
434
+ artifact(:j2ee).to_s.pathmap('%f').should == 'geronimo-spec-j2ee-1.4-rc4.jar'
435
+ end
427
436
  end
428
437
 
429
438
 
@@ -411,10 +411,6 @@ describe Buildr::Filter do
411
411
  @filter.from('src').into('target').run.should be(false)
412
412
  end
413
413
 
414
- it 'should fail is source directory not set' do
415
- lambda { Filter.new.into('target').run }.should raise_error(RuntimeError, /No source directory/)
416
- end
417
-
418
414
  it 'should fail if source directory doesn\'t exist' do
419
415
  lambda { Filter.new.from('srced').into('target').run }.should raise_error(RuntimeError, /doesn't exist/)
420
416
  end
@@ -0,0 +1,38 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+ require File.join(File.dirname(__FILE__), 'spec_helpers')
17
+
18
+ describe ENV, 'JAVA_HOME on OS X' do
19
+ before do
20
+ @old_home, ENV['JAVA_HOME'] = ENV['JAVA_HOME'], nil
21
+ Config::CONFIG.should_receive(:[]).with('host_os').and_return('darwin0.9')
22
+ end
23
+
24
+ it 'should point to default JVM' do
25
+ load File.expand_path('../lib/buildr/java.rb')
26
+ ENV['JAVA_HOME'].should == '/System/Library/Frameworks/JavaVM.framework/Home'
27
+ end
28
+
29
+ it 'should use value of environment variable if specified' do
30
+ ENV['JAVA_HOME'] = '/System/Library/Frameworks/JavaVM.specified'
31
+ load File.expand_path('../lib/buildr/java.rb')
32
+ ENV['JAVA_HOME'].should == '/System/Library/Frameworks/JavaVM.specified'
33
+ end
34
+
35
+ after do
36
+ ENV['JAVA_HOME'] = @old_home
37
+ end
38
+ end
@@ -179,6 +179,18 @@ describe Buildr::JUnit do
179
179
  project('foo').test.invoke
180
180
  end
181
181
 
182
+ it 'should pass environment to JVM' do
183
+ write 'src/test/java/EnvironmentTest.java', <<-JAVA
184
+ public class EnvironmentTest extends junit.framework.TestCase {
185
+ public void testEnvironment() {
186
+ assertEquals("value", System.getenv("NAME"));
187
+ }
188
+ }
189
+ JAVA
190
+ define('foo').test.using :environment=>{ 'NAME'=>'value' }
191
+ project('foo').test.invoke
192
+ end
193
+
182
194
  it 'should set current directory' do
183
195
  mkpath 'baz'
184
196
  expected = File.expand_path('baz')
@@ -374,11 +374,13 @@ describe Buildr::Project, '#test' do
374
374
 
375
375
  it 'should inherit options from parent project' do
376
376
  define 'foo' do
377
- test.using :fail_on_failure=>false, :fork=>:each, :properties=>{ :foo=>'bar' }
377
+ test.using :fail_on_failure=>false, :fork=>:each, :properties=>{ :foo=>'bar' }, :environment=>{ 'config'=>'config.yaml' }
378
378
  define 'bar' do
379
+ test.using :junit
379
380
  test.options[:fail_on_failure].should be_false
380
381
  test.options[:fork].should == :each
381
382
  test.options[:properties][:foo].should == 'bar'
383
+ test.options[:environment]['config'].should == 'config.yaml'
382
384
  end
383
385
  end
384
386
  end
@@ -386,11 +388,13 @@ describe Buildr::Project, '#test' do
386
388
  it 'should clone options from parent project' do
387
389
  define 'foo' do
388
390
  define 'bar' do
389
- test.using :fail_on_failure=>false, :fork=>:each, :properties=>{ :foo=>'bar' }
391
+ test.using :fail_on_failure=>false, :fork=>:each, :properties=>{ :foo=>'bar' }, :environment=>{ 'config'=>'config.yaml' }
392
+ test.using :junit
390
393
  end.invoke
391
394
  test.options[:fail_on_failure].should be_true
392
395
  test.options[:fork].should == :once
393
- test.options[:other].should be_nil
396
+ test.options[:properties].should be_empty
397
+ test.options[:environment].should be_empty
394
398
  end
395
399
  end
396
400
  end
@@ -454,6 +458,7 @@ end
454
458
  describe Buildr::Project, 'test:resources' do
455
459
  it 'should ignore resources unless they exist' do
456
460
  define('foo').test.resources.sources.should be_empty
461
+ project('foo').test.resources.target.should be_nil
457
462
  end
458
463
 
459
464
  it 'should pick resources from src/test/resources if found' do
@@ -467,6 +472,11 @@ describe Buildr::Project, 'test:resources' do
467
472
  file('targeted/test/resources/foo').should contain('Foo')
468
473
  end
469
474
 
475
+ it 'should create target directory even if no files to copy' do
476
+ define('foo').test.resources.filter.into('resources')
477
+ lambda { file(File.expand_path('resources')).invoke }.should change { File.exist?('resources') }.to(true)
478
+ end
479
+
470
480
  it 'should execute alongside compile task' do
471
481
  task 'action'
472
482
  define('foo') { test.resources { task('action').invoke } }
@@ -221,7 +221,9 @@ describe URI::HTTP, '#read' do
221
221
  @proxy = 'http://john:smith@myproxy:8080'
222
222
  @domain = 'domain'
223
223
  @host_domain = "host.#{@domain}"
224
- @uri = URI("http://#{@host_domain}")
224
+ @path = "/foo/bar/baz"
225
+ @query = "?query"
226
+ @uri = URI("http://#{@host_domain}#{@path}#{@query}")
225
227
  @no_proxy_args = [@host_domain, 80]
226
228
  @proxy_args = @no_proxy_args + ['myproxy', 8080, 'john', 'smith']
227
229
  @http = mock('http')
@@ -297,4 +299,190 @@ describe URI::HTTP, '#read' do
297
299
  request.should_receive(:basic_auth).with('john', 'secret')
298
300
  URI("http://john:secret@#{@host_domain}").read
299
301
  end
302
+
303
+ it 'should include the query part when performing HTTP GET' do
304
+ # should this test be generalized or shared with any other URI subtypes?
305
+ Net::HTTP.stub!(:new).and_return(@http)
306
+ Net::HTTP::Get.should_receive(:new).with(/#{Regexp.escape(@query)}$/, nil)
307
+ @uri.read
308
+ end
309
+
310
+ end
311
+
312
+
313
+ describe URI::HTTP, '#write' do
314
+ before do
315
+ @content = 'Readme. Please!'
316
+ @uri = URI('http://john:secret@host.domain/foo/bar/baz.jar')
317
+ @http = mock('Net::HTTP')
318
+ @http.stub!(:request).and_return(Net::HTTPOK.new(nil, nil, nil))
319
+ Net::HTTP.stub!(:new).and_return(@http)
320
+ end
321
+
322
+ it 'should open connection to HTTP server' do
323
+ Net::HTTP.should_receive(:new).with('host.domain', 80).and_return(@http)
324
+ @uri.write @content
325
+ end
326
+
327
+ it 'should use HTTP basic authentication' do
328
+ @http.should_receive(:request) do |request|
329
+ request['authorization'].should == ('Basic ' + ['john:secret'].pack('m').delete("\r\n"))
330
+ Net::HTTPOK.new(nil, nil, nil)
331
+ end
332
+ @uri.write @content
333
+ end
334
+
335
+ it 'should use HTTPS if applicable' do
336
+ Net::HTTP.should_receive(:new).with('host.domain', 443).and_return(@http)
337
+ @http.should_receive(:use_ssl=).with(true)
338
+ URI(@uri.to_s.sub(/http/, 'https')).write @content
339
+ end
340
+
341
+ it 'should upload file with PUT request' do
342
+ @http.should_receive(:request) do |request|
343
+ request.should be_kind_of(Net::HTTP::Put)
344
+ Net::HTTPOK.new(nil, nil, nil)
345
+ end
346
+ @uri.write @content
347
+ end
348
+
349
+ it 'should set Content-Length header' do
350
+ @http.should_receive(:request) do |request|
351
+ request.content_length.should == @content.size
352
+ Net::HTTPOK.new(nil, nil, nil)
353
+ end
354
+ @uri.write @content
355
+ end
356
+
357
+ it 'should set Content-MD5 header' do
358
+ @http.should_receive(:request) do |request|
359
+ request['Content-MD5'].should == Digest::MD5.hexdigest(@content)
360
+ Net::HTTPOK.new(nil, nil, nil)
361
+ end
362
+ @uri.write @content
363
+ end
364
+
365
+ it 'should send entire content' do
366
+ @http.should_receive(:request) do |request|
367
+ body_stream = request.body_stream
368
+ body_stream.read(1024).should == @content
369
+ body_stream.read(1024).should be_nil
370
+ Net::HTTPOK.new(nil, nil, nil)
371
+ end
372
+ @uri.write @content
373
+ end
374
+
375
+ it 'should fail on 4xx response' do
376
+ @http.should_receive(:request) do |request|
377
+ Net::HTTPBadRequest.new(nil, nil, nil)
378
+ end
379
+ lambda { @uri.write @content }.should raise_error(RuntimeError, /failed to upload/i)
380
+ end
381
+
382
+ it 'should fail on 5xx response' do
383
+ @http.should_receive(:request) do |request|
384
+ Net::HTTPServiceUnavailable.new(nil, nil, nil)
385
+ end
386
+ lambda { @uri.write @content }.should raise_error(RuntimeError, /failed to upload/i)
387
+ end
388
+
389
+ end
390
+
391
+
392
+ describe URI::SFTP, '#read' do
393
+ before do
394
+ @uri = URI('sftp://john:secret@localhost/path/readme')
395
+ @content = 'Readme. Please!'
396
+
397
+ @ssh_session = mock('Net::SSH::Session')
398
+ @sftp_session = mock('Net::SFTP::Session')
399
+ @file_factory = mock('Net::SFTP::Operations::FileFactory')
400
+ Net::SSH.stub!(:start).with('localhost', 'john', :password=>'secret', :port=>22) do
401
+ Net::SFTP::Session.should_receive(:new).with(@ssh_session).and_yield(@sftp_session).and_return(@sftp_session)
402
+ @sftp_session.should_receive(:connect!).and_return(@sftp_session)
403
+ @sftp_session.should_receive(:loop)
404
+ @sftp_session.should_receive(:file).with.and_return(@file_factory)
405
+ @file_factory.stub!(:open)
406
+ @ssh_session.should_receive(:close)
407
+ @ssh_session
408
+ end
409
+ end
410
+
411
+ it 'should open connection to SFTP server' do
412
+ @uri.read
413
+ end
414
+
415
+ it 'should open file for reading' do
416
+ @file_factory.should_receive(:open).with('/path/readme', 'r')
417
+ @uri.read
418
+ end
419
+
420
+ it 'should read contents of file and return it' do
421
+ file = mock('Net::SFTP::Operations::File')
422
+ file.should_receive(:read).with(an_instance_of(Numeric)).once.and_return(@content, nil)
423
+ @file_factory.should_receive(:open).with('/path/readme', 'r').and_yield(file)
424
+ @uri.read.should eql(@content)
425
+ end
426
+
427
+ it 'should read contents of file and pass it to block' do
428
+ file = mock('Net::SFTP::Operations::File')
429
+ file.should_receive(:read).with(an_instance_of(Numeric)).once.and_return(@content, nil)
430
+ @file_factory.should_receive(:open).with('/path/readme', 'r').and_yield(file)
431
+ content = ''
432
+ @uri.read do |chunk|
433
+ content << chunk
434
+ end
435
+ content.should eql(@content)
436
+ end
437
+ end
438
+
439
+
440
+ describe URI::SFTP, '#write' do
441
+ before do
442
+ @uri = URI('sftp://john:secret@localhost/path/readme')
443
+ @content = 'Readme. Please!'
444
+
445
+ @ssh_session = mock('Net::SSH::Session')
446
+ @sftp_session = mock('Net::SFTP::Session')
447
+ @file_factory = mock('Net::SFTP::Operations::FileFactory')
448
+ Net::SSH.stub!(:start).with('localhost', 'john', :password=>'secret', :port=>22) do
449
+ Net::SFTP::Session.should_receive(:new).with(@ssh_session).and_yield(@sftp_session).and_return(@sftp_session)
450
+ @sftp_session.should_receive(:connect!).and_return(@sftp_session)
451
+ @sftp_session.should_receive(:loop)
452
+ @sftp_session.stub!(:mkdir)
453
+ @sftp_session.should_receive(:file).with.and_return(@file_factory)
454
+ @file_factory.stub!(:open)
455
+ @ssh_session.should_receive(:close)
456
+ @ssh_session
457
+ end
458
+ end
459
+
460
+ it 'should open connection to SFTP server' do
461
+ @uri.write @content
462
+ end
463
+
464
+ it 'should create path recursively on SFTP server' do
465
+ @sftp_session.should_receive(:mkdir).ordered.with('', {})
466
+ @sftp_session.should_receive(:mkdir).ordered.with('/path', {})
467
+ @uri.write @content
468
+ end
469
+
470
+ it 'should only create paths that don\'t exist' do
471
+ @sftp_session.should_receive(:realpath).any_number_of_times
472
+ @sftp_session.should_not_receive(:mkdir)
473
+ @uri.write @content
474
+ end
475
+
476
+ it 'should open file for writing' do
477
+ @file_factory.should_receive(:open).with('/path/readme', 'w')
478
+ @uri.write @content
479
+ end
480
+
481
+ it 'should write contents to file' do
482
+ file = mock('Net::SFTP::Operations::File')
483
+ file.should_receive(:write).with(@content)
484
+ @file_factory.should_receive(:open).with('/path/readme', 'w').and_yield(file)
485
+ @uri.write @content
486
+ end
487
+
300
488
  end