itrigga-net_helper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "hpricot"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "rcov", ">= 0"
13
+ gem 'rspec'
14
+ gem 'json_pure'
15
+ gem 'itrigga-core_ext', ">= 0"
16
+ gem "fastercsv", ">= 1.5.4"
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ fastercsv (1.5.4)
6
+ git (1.2.5)
7
+ hpricot (0.8.4)
8
+ itrigga-core_ext (0.1.0)
9
+ jeweler (1.6.4)
10
+ bundler (~> 1.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ json_pure (1.5.1)
14
+ rake (0.8.7)
15
+ rcov (0.9.9)
16
+ rspec (2.5.0)
17
+ rspec-core (~> 2.5.0)
18
+ rspec-expectations (~> 2.5.0)
19
+ rspec-mocks (~> 2.5.0)
20
+ rspec-core (2.5.1)
21
+ rspec-expectations (2.5.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.5.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.0.0)
30
+ fastercsv (>= 1.5.4)
31
+ hpricot
32
+ itrigga-core_ext
33
+ jeweler (~> 1.6.4)
34
+ json_pure
35
+ rcov
36
+ rspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Al Davidson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = net_helper
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to net_helper
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Al Davidson. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "itrigga-net_helper"
18
+ gem.homepage = "http://gems.itrigga.com/trigga-net_helper"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Wrapper around Net::HTTP to provide retries, redirects, etc}
21
+ gem.description = %Q{Provides various more convenient wrappers around Net::HTTP methods}
22
+ gem.email = "aldavidson@trigga.com"
23
+ gem.authors = ["Al Davidson"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "net_helper #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,217 @@
1
+ require 'uri'
2
+ require 'hpricot'
3
+ require 'json'
4
+ require 'cgi'
5
+ require 'timeout'
6
+ require 'net/http'
7
+
8
+ module Itrigga
9
+ module NetHelper
10
+
11
+ module_function
12
+
13
+ def do_get(url, time_out=5, retries_on_timeout=5, max_redirects = 3)
14
+ retrycount = 0
15
+ resp = nil
16
+ begin
17
+ resp = get_with_timeout( url, time_out )
18
+
19
+ handle_response( url, resp, retries_on_timeout, max_redirects )
20
+
21
+ rescue Timeout::Error
22
+ if(retrycount.to_i < retries_on_timeout.to_i)
23
+ retrycount+=1
24
+ retry
25
+ else
26
+ raise IOError.new( "HTTP request timed out #{retrycount} times" )
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ def get_with_timeout( url, time_out)
33
+ resp = timeout(time_out) do
34
+ Net::HTTP.get_response(URI.parse(url))
35
+ end
36
+ resp
37
+ end
38
+
39
+
40
+ def handle_response( url, resp, retries_on_timeout=5, max_redirects = 3 )
41
+ if resp.is_a? Net::HTTPSuccess then resp.body
42
+ elsif resp.is_a? Net::HTTPRedirection
43
+ if max_redirects > 0
44
+ do_get( URI.parse(url).merge(resp['location']).to_s, retries_on_timeout, max_redirects - 1 )
45
+ else
46
+ raise IOError.new("too many redirects!")
47
+ end
48
+ else
49
+ resp.error!
50
+ end
51
+ end
52
+
53
+
54
+ def get( options = {} )
55
+ opts = {:timeout=>5, :retries_on_timeout=>5, :max_redirects => 3, :headers=>{} }.merge(options)
56
+ raise ArgumentError.new(":url is required" ) unless opts[:url]
57
+
58
+ if (opts[:username] || opts[:headers]).to_s.empty?
59
+ do_get(opts[:url], opts[:timeout], opts[:retries_on_timeout], opts[:max_redirects])
60
+ else
61
+
62
+ retrycount = 0
63
+ resp = begin
64
+ timeout( opts[:timeout] ) do
65
+ raw_get(opts)
66
+ end
67
+ rescue TimeoutError
68
+ if(retrycount < opts[:retries_on_timeout])
69
+ retrycount+=1
70
+ retry
71
+ else
72
+ raise IOError.new( "HTTP request timed out #{retrycount} times" )
73
+ end
74
+ end
75
+ resp
76
+ end
77
+ end
78
+
79
+ def raw_get(opts)
80
+ resp = nil
81
+ establish_session_if_needed(opts)
82
+
83
+ if opts[:username]
84
+ resp = get_with_auth(opts)
85
+ retries = 0
86
+ while resp.is_a? Net::HTTPRedirection do
87
+ retries += 1
88
+ raise IOError.new( "HTTP request timed out #{retries} times" ) if retries > (opts[:max_redirects] || 3)
89
+
90
+ resp = get_with_auth(opts.merge(:parsed_url=>URI.parse(resp['location'])))
91
+ end
92
+
93
+ resp.body
94
+
95
+ else
96
+ response = opts[:http_session].request_get(opts[:parsed_url].path, opts[:headers])
97
+ response.body
98
+ end
99
+ end
100
+
101
+ def get_with_auth( opts )
102
+ establish_session_if_needed(opts)
103
+
104
+ req = Net::HTTP::Get.new(opts[:parsed_url].path)
105
+ req.basic_auth( opts[:username], opts[:password] ) if opts[:username]
106
+ resp = opts[:http_session].request(req, opts[:headers])
107
+ end
108
+
109
+ def establish_session_if_needed(opts)
110
+ opts[:parsed_url] ||= URI.parse(opts[:url])
111
+ opts[:http_session] ||= Net::HTTP.new(opts[:parsed_url].host, opts[:parsed_url].port)
112
+ opts[:http_session].use_ssl = true if opts[:parsed_url].scheme == 'https'
113
+ end
114
+
115
+ def query_string( h, opts={:encode_values=>false, :skip_empty=>false} )
116
+ params = []
117
+ h.each{ |k,v|
118
+ params << "#{k.to_s}=#{ opts[:encode_values] ? url_encode(v) : v }" unless v.to_s.empty? && opts[:skip_empty]
119
+ }
120
+ params.sort.join('&')
121
+ end
122
+
123
+ def url_encode( s )
124
+ URI.escape( s.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]") )
125
+ end
126
+
127
+ def discover_favicon_url(root_url, time_out = 5)
128
+ favicon_urls = ['favicon.ico'] + discover_icon_hrefs(root_url)
129
+ favicon_urls.compact.each do |url|
130
+ abs_url = URI.join(root_url, url).to_s
131
+ return abs_url if get_with_timeout( abs_url, time_out ).is_a?(Net::HTTPSuccess)
132
+ end
133
+ nil
134
+ end
135
+
136
+ def discover_icon_hrefs(url)
137
+ pd = open(url) { |f| parse_with_hpricot(f) }
138
+ links = pd.search("//link[@rel='shortcut icon']") + pd.search("//link[@rel='icon']")
139
+ links.map{ |link| link.attributes['href'] }.compact.to_a
140
+ end
141
+
142
+ # Have difficulty mocking/stubbing the top-level Hpricot call
143
+ # This wrapper makes it testable
144
+ def parse_with_hpricot(html)
145
+ Hpricot.parse(html)
146
+ end
147
+
148
+ def ip_of(server)
149
+ IPSocket::getaddress(server)
150
+ end
151
+
152
+ # uses the url shortener service defined for this site
153
+ # by default will use bit.ly
154
+ def shorten_url(raw_url,attempts = 0)
155
+
156
+ return raw_url if attempts > 3
157
+
158
+ url = self.format_url_shortener_api_url(raw_url)
159
+
160
+ begin
161
+ response = NetHelper.get :url => url
162
+ rescue Exception => e
163
+ sleep 10 unless defined?(RAILS_ENV) && RAILS_ENV == "test"
164
+ return shorten_url(raw_url,attempts+1)
165
+ end
166
+
167
+ data = JSON.parse(response).recursive_symbolize_keys!
168
+
169
+
170
+ if data[:status_code] == 200
171
+ return data[:data][:url]
172
+ else # theres been a problem, try again if we have tries left
173
+
174
+ sleep 10 unless defined?(RAILS_ENV) && RAILS_ENV == "test"
175
+ return shorten_url(raw_url,attempts+1)
176
+
177
+ end
178
+
179
+ end
180
+
181
+ # parses the :url template for the url shortener service
182
+ def format_url_shortener_api_url(raw_url, config_hash)
183
+ escaped_url = CGI::escape(raw_url)
184
+ config_hash[:url].gsub("{{username}}",config_hash[:username] || "").gsub("{{api_key}}",config_hash[:api_key] || "").gsub("{{raw_url}}",escaped_url)
185
+ end
186
+
187
+ #
188
+ # Transfer a file using scp between servers
189
+ #
190
+ # Options:
191
+ # :host - the target server name. Hash. Must have keys:
192
+ # => :port - the port on which to connect
193
+ # => :ssh_key_path - the absolute path to the ssh key file which it will use to connect
194
+ # => :user - the user to connect as
195
+ # => :host - the hostname to connect to
196
+ # :target_path - the absolute path on the target server to put the file
197
+ # :file - the file to transfer. Must be an absolute path to the file
198
+ #
199
+ def transfer_file_scp(opts = {})
200
+
201
+ raise ArgumentError.new("File '#{opts[:file]}' does not exist!") unless opts[:file] && File.exist?(opts[:file])
202
+ raise ArgumentError.new("host is required") unless opts[:host]
203
+ raise ArgumentError.new("No target_path defined") unless opts[:target_path]
204
+
205
+ #host = TRIGGA_CONFIG.hosts.detect{|host| host[:display_name].to_s == opts[:target].to_s}
206
+
207
+ # now that everything checks out make sure the destination dir path exists. If not then create it
208
+ command = "ssh -p#{opts[:host][:port]} -i #{opts[:host][:ssh_key_path]} #{opts[:host][:user]}@#{opts[:host][:host]} 'mkdir -p #{File.dirname(opts[:target_path])}'"
209
+ `#{command}`
210
+
211
+ # now transfer the file across
212
+ command = "scp -P#{opts[:host][:port]} -i #{opts[:host][:ssh_key_path]} #{opts[:file]} #{opts[:host][:user]}@#{opts[:host][:host]}:#{opts[:target_path]}"
213
+ `#{command}`
214
+
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,454 @@
1
+ require 'spec_helper'
2
+ require 'trigga/core_ext'
3
+
4
+ describe "Itrigga::NetHelper" do
5
+ before(:each) do
6
+ @mock_response = mock("response")
7
+ @mock_response.stub!(:body).and_return("body")
8
+ end
9
+
10
+ describe "do_get" do
11
+ it "should get the HTTP response" do
12
+ Itrigga::NetHelper.stub!(:handle_response).and_return("")
13
+ Net::HTTP.should_receive( :get_response ).with( URI.parse("http://some.com") ).and_return(@mock_response)
14
+ Itrigga::NetHelper.do_get( "http://some.com" )
15
+ end
16
+
17
+ it "should call handle_response with the response" do
18
+ Net::HTTP.stub!( :get_response ).with( URI.parse("http://some.com") ).and_return(@mock_response)
19
+ Itrigga::NetHelper.should_receive(:handle_response).and_return("")
20
+ Itrigga::NetHelper.do_get( "http://some.com" )
21
+ end
22
+
23
+
24
+ describe "when the GET takes longer than time_out seconds" do
25
+ before(:each) do
26
+ Itrigga::NetHelper.stub!(:get_with_timeout).and_raise( TimeoutError.new("expected timeout") )
27
+ end
28
+
29
+ describe "when it has retried < retries_on_timeout times" do
30
+ it "should retry" do
31
+ Itrigga::NetHelper.should_receive(:get_with_timeout).exactly(3).times
32
+ # NOTE: the important expectation is the above one!
33
+ lambda {
34
+ Itrigga::NetHelper.do_get( "http://some.com", 1, 2 )
35
+ }.should raise_error( IOError )
36
+ end
37
+ end
38
+
39
+ describe "when it has retried retries_on_timeout times" do
40
+ it "should raise an IOError" do
41
+ lambda {
42
+ Itrigga::NetHelper.do_get( "http://some.com", 0, 2 )
43
+ }.should raise_error( IOError )
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ describe "handle_response" do
51
+
52
+ describe "when the response is OK" do
53
+ before(:each) do
54
+ @mock_response.stub!(:is_a?).with(Net::HTTPSuccess).and_return true
55
+ end
56
+
57
+ it "should return the response body" do
58
+ Itrigga::NetHelper.handle_response("http://some.com", @mock_response).should == "body"
59
+ end
60
+ end
61
+
62
+ describe "when the response is a redirect" do
63
+ before(:each) do
64
+ @mock_response.stub!(:is_a?).with(Net::HTTPSuccess).and_return false
65
+ @mock_response.stub!(:is_a?).with(Net::HTTPRedirection).and_return true
66
+ @mock_response.stub!(:[]).with('location').and_return("http://some.redirect")
67
+ end
68
+
69
+ describe "when redirects > 0" do
70
+ it "should recurse" do
71
+ Itrigga::NetHelper.should_receive(:do_get)
72
+ Itrigga::NetHelper.handle_response("http://some.com", @mock_response)
73
+ end
74
+
75
+ it "should pass the location field from the response as the url, and the same timeout" do
76
+ Itrigga::NetHelper.should_receive(:do_get).with( "http://some.redirect", 23, anything )
77
+ Itrigga::NetHelper.handle_response( "http://some.com", @mock_response, 23)
78
+ end
79
+
80
+ it "should pass redirects - 1 as the redirects param" do
81
+ Itrigga::NetHelper.should_receive(:do_get).with( anything, anything, 15 )
82
+ Itrigga::NetHelper.handle_response( "http://some.com", @mock_response, 23, 16)
83
+ end
84
+
85
+ describe "when the response location is relative" do
86
+ before(:each) do
87
+ @mock_response.stub!(:[]).with('location').and_return("/some/relative/path?param=567")
88
+ end
89
+
90
+ it "should pass on the absolute url" do
91
+ Itrigga::NetHelper.should_receive(:do_get).with( "http://some.com/some/relative/path?param=567", anything, anything )
92
+ Itrigga::NetHelper.handle_response( "http://some.com/some_other/path.xml?id=123", @mock_response, 23, 16)
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "when redirects = 0" do
98
+ it "should raise an IOError" do
99
+ lambda {
100
+ Itrigga::NetHelper.handle_response( "http://some.com", @mock_response, 23, 0)
101
+ }.should raise_error( IOError )
102
+ end
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ describe "query_string" do
109
+ it "should return a string" do
110
+ Itrigga::NetHelper.query_string( 'blart' => 'flange' ).should be_a(String)
111
+ end
112
+
113
+ it "should map the given hash to query string format" do
114
+ Itrigga::NetHelper.query_string( 'blart'=>'flange').should == "blart=flange"
115
+ end
116
+
117
+ it "should sort the keys" do
118
+ Itrigga::NetHelper.query_string( :c=>1, :b=>2, :a=>3 ).should == "a=3&b=2&c=1"
119
+ end
120
+
121
+ it "should join each key/value pair with an ampersand" do
122
+ Itrigga::NetHelper.query_string( 'blart'=>'flange', 'donkey' => 'monkey').should == "blart=flange&donkey=monkey"
123
+ end
124
+
125
+ it "should transform sym keys to strings" do
126
+ Itrigga::NetHelper.query_string( :blart=>'flange').should == "blart=flange"
127
+ end
128
+
129
+ it "should render nils as empty values" do
130
+ Itrigga::NetHelper.query_string( 'blart'=>nil).should == "blart="
131
+ end
132
+
133
+ describe "when :encode_values is true" do
134
+ it "should url encode each value" do
135
+ Itrigga::NetHelper.query_string( {'blart'=>'flange & more flange'}, :encode_values=>true ).should == "blart=flange%20%26%20more%20flange"
136
+ end
137
+ end
138
+
139
+ describe "when :skip_empty is true" do
140
+ it "should not include empty-valued fields" do
141
+ Itrigga::NetHelper.query_string( {:c=>1, :b=>nil, :a=>''}, :skip_empty=>true ).should == "c=1"
142
+ end
143
+ end
144
+ end
145
+
146
+ describe "discover_favicon_url" do
147
+ before(:each) do
148
+ @url = "http://blart.com"
149
+ Itrigga::NetHelper.stub!(:discover_icon_hrefs).with(@url).and_return([])
150
+ Itrigga::NetHelper.stub!(:get_with_timeout).and_return("")
151
+ end
152
+
153
+ it "should get the given url joined with favicon.ico" do
154
+ Itrigga::NetHelper.should_receive(:get_with_timeout).with("http://blart.com/favicon.ico", anything).and_return("")
155
+ Itrigga::NetHelper.discover_favicon_url("http://blart.com")
156
+ end
157
+
158
+ it "should call discover_icon_hrefs" do
159
+ Itrigga::NetHelper.should_receive(:discover_icon_hrefs).with(@url).and_return([])
160
+ Itrigga::NetHelper.discover_favicon_url(@url)
161
+ end
162
+
163
+
164
+
165
+
166
+ context "each discovered href" do
167
+ context "when the get is a success" do
168
+ before(:each) do
169
+ Itrigga::NetHelper.stub!(:discover_icon_hrefs).with(@url).and_return(["/some/bad/path.ico", "/some/good/path.ico"])
170
+ @mock_404 = mock("404"); @mock_200 = mock("200")
171
+ @mock_404.stub!(:is_a?).with(Net::HTTPSuccess).and_return(false)
172
+ @mock_200.stub!(:is_a?).with(Net::HTTPSuccess).and_return(true)
173
+ Itrigga::NetHelper.stub!(:get_with_timeout).and_return( @mock_404, @mock_404, @mock_200 )
174
+ end
175
+
176
+ it "should return the href joined onto the root url" do
177
+ Itrigga::NetHelper.discover_favicon_url(@url).should == "http://blart.com/some/good/path.ico"
178
+ end
179
+ end
180
+ end
181
+
182
+ end
183
+ describe "discover_icon_hrefs" do
184
+ before(:each) do
185
+ @html = <<-HTML
186
+ <html>
187
+ <head>
188
+ <link rel="icon" href="http://an.absolute/url" />
189
+ <link rel="icon" href="relative/url" />
190
+ </head>
191
+ </html>
192
+ HTML
193
+ @url = "http://blart.com"
194
+ @mock_doc = mock("hpricot doc")
195
+ @mock_doc.stub!(:search).and_return([])
196
+ Itrigga::NetHelper.stub!(:open).with("http://blart.com").and_yield(@html)
197
+ end
198
+
199
+ it "should open the given url" do
200
+ Itrigga::NetHelper.should_receive(:open).with("http://blart.com").and_yield(@html)
201
+ Itrigga::NetHelper.discover_icon_hrefs(@url)
202
+ end
203
+ it "should parse the given url with hpricot" do
204
+ Itrigga::NetHelper.should_receive(:parse_with_hpricot).with(@html).and_return(@mock_doc)
205
+ Itrigga::NetHelper.discover_icon_hrefs(@url)
206
+ end
207
+
208
+ it "should search for links with a rel='shortcut icon'" do
209
+ Itrigga::NetHelper.stub!(:parse_with_hpricot).with(@html).and_return(@mock_doc)
210
+ @mock_doc.should_receive(:search).with("//link[@rel='shortcut icon']").and_return([])
211
+ Itrigga::NetHelper.discover_icon_hrefs(@url)
212
+ end
213
+
214
+ it "should search for links with a rel='icon'" do
215
+ Itrigga::NetHelper.stub!(:parse_with_hpricot).with(@html).and_return(@mock_doc)
216
+ @mock_doc.should_receive(:search).with("//link[@rel='shortcut icon']").and_return([])
217
+ Itrigga::NetHelper.discover_icon_hrefs(@url)
218
+ end
219
+
220
+ it "should return the collected href attributes" do
221
+ Itrigga::NetHelper.discover_icon_hrefs(@url).should == ["http://an.absolute/url", "relative/url"]
222
+ end
223
+
224
+ end
225
+
226
+ describe "raw_get" do
227
+ before(:each) do
228
+ Itrigga::NetHelper.stub!(:get_with_auth).and_return( 'body' )
229
+ Itrigga::NetHelper.stub!(:establish_session_if_needed)
230
+ @mock_session = mock("http session")
231
+ @mock_session.stub!(:request_get).and_return( @mock_response = mock('request_get response') )
232
+ @mock_response.stub!(:body).and_return('response body')
233
+ @mock_parsed_url = mock("parsed url")
234
+ @mock_parsed_url.stub!(:host).and_return("host")
235
+ @mock_parsed_url.stub!(:path).and_return("path")
236
+ @mock_parsed_url.stub!(:port).and_return("port")
237
+
238
+ @mock_response = mock('response')
239
+ @mock_response.stub!(:is_a?).with(Net::HTTPRedirection).and_return(false)
240
+ @mock_response.stub!(:body).and_return('cheese')
241
+ end
242
+
243
+ it "should call establish_session_if_needed with the given opts" do
244
+ Itrigga::NetHelper.should_receive(:establish_session_if_needed).with(hash_including(:blart=>'flange'))
245
+ Itrigga::NetHelper.raw_get(:blart=>'flange', :http_session=>@mock_session, :parsed_url=>@mock_parsed_url)
246
+ end
247
+
248
+ context "when given a :username" do
249
+ it "should call get_with_auth with the given options" do
250
+ Itrigga::NetHelper.should_receive(:get_with_auth).with(hash_including(:username=>'dave')).and_return(@mock_response)
251
+ Itrigga::NetHelper.raw_get(:username=>'dave')
252
+ end
253
+
254
+ it "should return the result of get_with_auth" do
255
+ Itrigga::NetHelper.stub!(:get_with_auth).with(hash_including(:username=>'dave')).and_return(@mock_response)
256
+ Itrigga::NetHelper.raw_get(:username=>'dave').should == 'cheese'
257
+ end
258
+
259
+ context "when response is a redirection" do
260
+ before(:each) do
261
+ @mock_response.stub!(:is_a?).with(Net::HTTPRedirection).and_return(true, false)
262
+ @mock_response.stub!(:[]).with('location').and_return("http://cheesefish.com")
263
+ URI.stub!(:parse).with("http://cheesefish.com").and_return(@mock_parsed_url = mock('parsed url'))
264
+ end
265
+
266
+ it "should follow the redirect" do
267
+ URI.should_receive(:parse).with("http://cheesefish.com").and_return(@mock_parsed_url = mock('parsed url'))
268
+ Itrigga::NetHelper.should_receive(:get_with_auth).twice.and_return(@mock_response)
269
+ Itrigga::NetHelper.raw_get(:username=>'dave')
270
+ end
271
+ end
272
+ end
273
+
274
+ context "when not given a :username" do
275
+ it "should call request_get on the http session with the :parsed_url's path and :headers" do
276
+ @mock_session.should_receive(:request_get).with( 'path', {:donkey=>'dipstick'}).and_return(@mock_response)
277
+ Itrigga::NetHelper.raw_get( :parsed_url=>@mock_parsed_url, :http_session=>@mock_session, :headers=>{:donkey=>'dipstick'} )
278
+ end
279
+
280
+ it "should return the result of calling body on the request_get's response" do
281
+ Itrigga::NetHelper.raw_get(:parsed_url=>@mock_parsed_url, :http_session=>@mock_session).should == 'response body'
282
+ end
283
+ end
284
+
285
+ end
286
+
287
+ describe "get_with_auth" do
288
+ before(:each) do
289
+ Itrigga::NetHelper.stub!(:establish_session_if_needed)
290
+ @mock_get = mock('get')
291
+ @mock_get.stub!(:basic_auth)
292
+ Net::HTTP::Get.stub!(:new).and_return(@mock_get)
293
+ @mock_parsed_url = mock("parsed url")
294
+ @mock_parsed_url.stub!(:host).and_return("host")
295
+ @mock_parsed_url.stub!(:path).and_return("path")
296
+ @mock_parsed_url.stub!(:port).and_return("port")
297
+ @mock_session = mock("http session")
298
+ @mock_session.stub!(:request).and_return("request response")
299
+ end
300
+
301
+ it "should call establish_session_if_needed with the given opts" do
302
+ Itrigga::NetHelper.should_receive(:establish_session_if_needed).with(hash_including(:blart=>'flange'))
303
+ Itrigga::NetHelper.get_with_auth(:blart=>'flange', :parsed_url=>@mock_parsed_url, :http_session=>@mock_session)
304
+ end
305
+
306
+ it "should create a new Net::HTTP::Get with the path of the :parsed_url" do
307
+ Net::HTTP::Get.should_receive(:new).with('path').and_return(@mock_get)
308
+ Itrigga::NetHelper.get_with_auth(:blart=>'flange', :parsed_url=>@mock_parsed_url, :http_session=>@mock_session)
309
+ end
310
+
311
+ it "should call basic_auth on the get, passing :username and :password from the given params" do
312
+ @mock_get.should_receive(:basic_auth).with( 'username', 'password' )
313
+ Itrigga::NetHelper.get_with_auth(:username=>'username', :password=>'password', :parsed_url=>@mock_parsed_url, :http_session=>@mock_session)
314
+ end
315
+
316
+ it "should call request on the http_session with the get, and any given :headers" do
317
+ @mock_session.should_receive(:request).with(@mock_get, {:header1=>'value1'})
318
+ Itrigga::NetHelper.get_with_auth(:http_session=>@mock_session, :headers=>{:header1=>'value1'}, :parsed_url=>@mock_parsed_url, :http_session=>@mock_session )
319
+ end
320
+
321
+ it "should return the result of the request" do
322
+ @mock_session.should_receive(:request).with(@mock_get, {:header1=>'value1'}).and_return("cheese")
323
+ Itrigga::NetHelper.get_with_auth(:http_session=>@mock_session, :headers=>{:header1=>'value1'}, :parsed_url=>@mock_parsed_url, :http_session=>@mock_session ).should == "cheese"
324
+ end
325
+ end
326
+
327
+ describe "establish_session_if_needed" do
328
+ before(:each) do
329
+ @mock_parsed_url = mock("parsed url")
330
+ @mock_parsed_url.stub!(:host).and_return("host")
331
+ @mock_parsed_url.stub!(:port).and_return("port")
332
+ @mock_parsed_url.stub!(:scheme).and_return("scheme")
333
+ @mock_session = mock('http session')
334
+ @mock_session.stub!(:use_ssl=)
335
+ Net::HTTP.stub!(:new).and_return(@mock_session)
336
+ end
337
+
338
+ context "When not given a :parsed_url" do
339
+ it "should set :parsed_url to URI.parse(:url)" do
340
+ URI.should_receive(:parse).with("URL").and_return(@mock_parsed_url)
341
+ Itrigga::NetHelper.establish_session_if_needed(:url=>"URL")
342
+ end
343
+ end
344
+
345
+ context "When not given a :http_session" do
346
+ it "should set :http_session to a new Net::HTTP with the parsed_url's host and port" do
347
+ Net::HTTP.should_receive(:new).with("host", "port").and_return(@mock_session)
348
+ Itrigga::NetHelper.establish_session_if_needed(:parsed_url=>@mock_parsed_url)
349
+ end
350
+ end
351
+
352
+ context "when the :parsed_url's scheme is https" do
353
+ before(:each) do
354
+ @mock_parsed_url.stub!(:scheme).and_return("https")
355
+ end
356
+
357
+ it "should set use_ssl=true on the http session" do
358
+ @mock_session.should_receive(:use_ssl=).with(true)
359
+ Itrigga::NetHelper.establish_session_if_needed(:parsed_url=>@mock_parsed_url)
360
+ end
361
+ end
362
+ end
363
+
364
+ describe "shorten_url" do
365
+ before do
366
+ @raw_url = "http://very_long_url_goes_here.com"
367
+ @shortened_url = "http://url_goes_here.com"
368
+ Itrigga::NetHelper.stub!(:format_url_shortener_api_url).and_return("http://myshorturl.com")
369
+ Itrigga::NetHelper.stub!(:get).and_return("{\"status_code\":200,\"data\":{\"url\":\"#{@shortened_url}\"}}")
370
+ end
371
+
372
+ describe "with valid input" do
373
+ it "should call format_url_shortener_api_url" do
374
+ Itrigga::NetHelper.should_receive(:format_url_shortener_api_url).with(@raw_url)
375
+ Itrigga::NetHelper.shorten_url(@raw_url)
376
+ end
377
+
378
+ it "should return a short url" do
379
+ Itrigga::NetHelper.shorten_url(@raw_url).should == @shortened_url
380
+ end
381
+
382
+ it "should return raw_url on web request timesout" do
383
+ Itrigga::NetHelper.stub!(:get).and_raise(Exception)
384
+ Itrigga::NetHelper.shorten_url(@raw_url).should == @raw_url
385
+ end
386
+
387
+ it "should return raw url for anything other than a status 200" do
388
+ Itrigga::NetHelper.stub!(:get).and_return("{\"status_code\":500,\"data\":{\"url\":\"#{@shortened_url}\"}}")
389
+ Itrigga::NetHelper.shorten_url(@raw_url).should == @raw_url
390
+ end
391
+
392
+ end
393
+ end
394
+
395
+ describe "format_url_shortener_api_url" do
396
+ before do
397
+ @raw_url = "http://very_long_url_goes_here.com"
398
+ @config_hash = ( {:url => "{{raw_url}}", :username => "a", :api_key => "123"} )
399
+ end
400
+
401
+ it "should return the api url" do
402
+ Itrigga::NetHelper.format_url_shortener_api_url(@raw_url, @config_hash).should == "http%3A%2F%2Fvery_long_url_goes_here.com"
403
+ end
404
+
405
+ it "should url encode the raw_url" do
406
+ CGI.should_receive(:escape).with(@raw_url).and_return("http%3A%2F%2Fvery_long_url_goes_here.com")
407
+ Itrigga::NetHelper.format_url_shortener_api_url(@raw_url, @config_hash)
408
+ end
409
+ end
410
+
411
+
412
+ describe "transfer_file_scp" do
413
+ before(:each) do
414
+ @host = { :display_name => "display_name", :port => 123, :user => "user", :host => "hostname", :ssh_key_path => "key_file_path" }
415
+ Itrigga::NetHelper.stub!(:'`').and_return(true)
416
+ File.stub!(:exist?).and_return(true)
417
+ end
418
+
419
+ it "should raise error if no file in opts" do
420
+ lambda { Itrigga::NetHelper.transfer_file_scp(:host=>@host) }.should raise_error(ArgumentError)
421
+ end
422
+
423
+ it "should raise error if file in opts does not exist" do
424
+ File.stub!(:exist?).and_return(false)
425
+ lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile", :host=>@host) }.should raise_error(ArgumentError)
426
+ end
427
+
428
+ it "should raise error if no host in opts" do
429
+ lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile") }.should raise_error(ArgumentError)
430
+ end
431
+
432
+ it "should raise error if no target_path in opts" do
433
+ lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile", :host=>@host) }.should raise_error(ArgumentError)
434
+ end
435
+
436
+ it "should not raise an error if the host exists" do
437
+ lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile", :host=>@host, :target_path => "/path/goes/here/to/file.xml")}.should_not raise_error
438
+ end
439
+
440
+ it "should call ssh to create dir path with the correct string" do
441
+ opts = {:target => "display_name", :file => "a_file_name", :target_path => "/path/goes/here/to/file.xml", :host=>@host}
442
+ Itrigga::NetHelper.should_receive(:'`').with("ssh -p123 -i key_file_path user@hostname 'mkdir -p /path/goes/here/to'")
443
+ Itrigga::NetHelper.transfer_file_scp(opts)
444
+ end
445
+
446
+ it "should call scp with the correct string" do
447
+ opts = {:target => "display_name", :file => "a_file_name", :target_path => "/path/goes/here/to/file.xml", :host=>@host}
448
+ Itrigga::NetHelper.should_receive(:'`').with("scp -P123 -i key_file_path a_file_name user@hostname:/path/goes/here/to/file.xml")
449
+ Itrigga::NetHelper.transfer_file_scp(opts)
450
+ end
451
+
452
+ end
453
+
454
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'rspec'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'itrigga/net_helper'
16
+
17
+ RSpec.configure do |config|
18
+ # some (optional) config here
19
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'net_helper'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestNetHelper < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,195 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itrigga-net_helper
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Al Davidson
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-20 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :development
23
+ prerelease: false
24
+ name: hpricot
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ requirement: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ type: :development
37
+ prerelease: false
38
+ name: bundler
39
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 23
45
+ segments:
46
+ - 1
47
+ - 0
48
+ - 0
49
+ version: 1.0.0
50
+ requirement: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ type: :development
53
+ prerelease: false
54
+ name: jeweler
55
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 7
61
+ segments:
62
+ - 1
63
+ - 6
64
+ - 4
65
+ version: 1.6.4
66
+ requirement: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ type: :development
69
+ prerelease: false
70
+ name: rcov
71
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirement: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ type: :development
83
+ prerelease: false
84
+ name: rspec
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirement: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ type: :development
97
+ prerelease: false
98
+ name: json_pure
99
+ version_requirements: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ requirement: *id006
109
+ - !ruby/object:Gem::Dependency
110
+ type: :development
111
+ prerelease: false
112
+ name: itrigga-core_ext
113
+ version_requirements: &id007 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ requirement: *id007
123
+ - !ruby/object:Gem::Dependency
124
+ type: :development
125
+ prerelease: false
126
+ name: fastercsv
127
+ version_requirements: &id008 !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 11
133
+ segments:
134
+ - 1
135
+ - 5
136
+ - 4
137
+ version: 1.5.4
138
+ requirement: *id008
139
+ description: Provides various more convenient wrappers around Net::HTTP methods
140
+ email: aldavidson@trigga.com
141
+ executables: []
142
+
143
+ extensions: []
144
+
145
+ extra_rdoc_files:
146
+ - LICENSE.txt
147
+ - README.rdoc
148
+ files:
149
+ - Gemfile
150
+ - Gemfile.lock
151
+ - LICENSE.txt
152
+ - README.rdoc
153
+ - Rakefile
154
+ - VERSION
155
+ - lib/itrigga/net_helper.rb
156
+ - spec/net_helper_spec.rb
157
+ - spec/spec_helper.rb
158
+ - test/helper.rb
159
+ - test/test_net_helper.rb
160
+ has_rdoc: true
161
+ homepage: http://gems.itrigga.com/trigga-net_helper
162
+ licenses:
163
+ - MIT
164
+ post_install_message:
165
+ rdoc_options: []
166
+
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ hash: 3
175
+ segments:
176
+ - 0
177
+ version: "0"
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ none: false
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ hash: 3
184
+ segments:
185
+ - 0
186
+ version: "0"
187
+ requirements: []
188
+
189
+ rubyforge_project:
190
+ rubygems_version: 1.3.7
191
+ signing_key:
192
+ specification_version: 3
193
+ summary: Wrapper around Net::HTTP to provide retries, redirects, etc
194
+ test_files: []
195
+