rsolr 0.13.0.pre → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +48 -29
- data/VERSION +1 -1
- data/lib/rsolr/char.rb +9 -0
- data/lib/rsolr/client.rb +80 -58
- data/lib/rsolr/error.rb +122 -0
- data/lib/rsolr/http.rb +106 -0
- data/lib/rsolr/uri.rb +55 -0
- data/lib/rsolr/xml.rb +161 -0
- data/lib/rsolr.rb +18 -39
- data/spec/api/rsolr_client_spec.rb +195 -0
- data/spec/api/rsolr_error_spec.rb +4 -0
- data/spec/api/rsolr_http_spec.rb +4 -0
- data/spec/api/rsolr_spec.rb +11 -23
- data/spec/api/rsolr_uri_spec.rb +70 -0
- data/spec/api/{message_spec.rb → rsolr_xml_spec.rb} +5 -4
- metadata +14 -18
- data/lib/rsolr/connection/httpable.rb +0 -101
- data/lib/rsolr/connection/net_http.rb +0 -30
- data/lib/rsolr/connection/utils.rb +0 -74
- data/lib/rsolr/connection.rb +0 -9
- data/lib/rsolr/message/document.rb +0 -48
- data/lib/rsolr/message/field.rb +0 -20
- data/lib/rsolr/message/generator.rb +0 -89
- data/lib/rsolr/message.rb +0 -8
- data/spec/api/client_spec.rb +0 -115
- data/spec/api/connection/httpable_spec.rb +0 -157
- data/spec/api/connection/net_http_spec.rb +0 -137
- data/spec/api/connection/utils_spec.rb +0 -84
- data/spec/integration/http_errors_spec.rb +0 -12
@@ -1,101 +0,0 @@
|
|
1
|
-
# A module that defines the interface and top-level logic for http based connection classes.
|
2
|
-
# Httpable provides URL parsing and handles proxy logic.
|
3
|
-
|
4
|
-
module RSolr::Connection::Httpable
|
5
|
-
|
6
|
-
include RSolr::Connection::Utils
|
7
|
-
|
8
|
-
attr_reader :opts, :uri, :proxy
|
9
|
-
|
10
|
-
# opts can have:
|
11
|
-
# :url => 'http://localhost:8080/solr'
|
12
|
-
def initialize opts={}
|
13
|
-
opts[:url] ||= 'http://127.0.0.1:8983/solr'
|
14
|
-
@opts = opts
|
15
|
-
@uri = URI.parse opts[:url]
|
16
|
-
@proxy = URI.parse opts[:proxy] if opts[:proxy]
|
17
|
-
end
|
18
|
-
|
19
|
-
# send a request to the connection
|
20
|
-
# request '/select', :q=>'*:*'
|
21
|
-
#
|
22
|
-
# request '/update', {:wt=>:xml}, '</commit>'
|
23
|
-
#
|
24
|
-
# force a post where the post body is the param query
|
25
|
-
# request '/update', "<optimize/>", :method=>:post
|
26
|
-
#
|
27
|
-
def request path, params={}, *extra
|
28
|
-
extra = extra.dup
|
29
|
-
opts = extra[-1].kind_of?(Hash) ? extra.pop : {}
|
30
|
-
data = extra[0]
|
31
|
-
|
32
|
-
context = create_http_context path, params, data, opts
|
33
|
-
|
34
|
-
error = nil
|
35
|
-
|
36
|
-
begin
|
37
|
-
|
38
|
-
# if data is being sent, this is a POST
|
39
|
-
if context[:data]
|
40
|
-
response = self.post context[:path], context[:data], context[:headers]
|
41
|
-
# use POST if :method => :post
|
42
|
-
elsif opts[:method] == :post
|
43
|
-
response = self.post context[:path], context[:query], context[:headers]
|
44
|
-
# GET
|
45
|
-
else
|
46
|
-
response = self.get context[:path]
|
47
|
-
end
|
48
|
-
|
49
|
-
# spray out our response into variables...
|
50
|
-
body, status_code, message = response
|
51
|
-
|
52
|
-
# merge the response into the http context
|
53
|
-
context.merge!(:body => body, :status_code => status_code, :message => message)
|
54
|
-
|
55
|
-
rescue
|
56
|
-
# throw RequestError?
|
57
|
-
context[:message] = $!.to_s
|
58
|
-
end
|
59
|
-
|
60
|
-
# if no :message but a non-200, throw a "SolrRequestError" ?
|
61
|
-
unless context[:status_code] == 200
|
62
|
-
error = context[:message] || "Non-200 Response Status Code"
|
63
|
-
raise RSolr::RequestError.new("#{error} -> #{context.inspect}")
|
64
|
-
end
|
65
|
-
|
66
|
-
context
|
67
|
-
end
|
68
|
-
|
69
|
-
# -> should this stuff be in a "ReqResContext" class? ->
|
70
|
-
|
71
|
-
# creates a Hash based "context"
|
72
|
-
# that contains all of the information sent to Solr
|
73
|
-
# The keys are:
|
74
|
-
# :host, :path, :params, :query, :data, :headers
|
75
|
-
def create_http_context path, params, data=nil, opts={}
|
76
|
-
context = {:host => base_url, :path => build_url(path), :params => params, :query => hash_to_query(params), :data => data}
|
77
|
-
if opts[:method] == :post
|
78
|
-
raise "Don't send POST data when using :method => :post" unless data.to_s.empty?
|
79
|
-
# force a POST, use the query string as the POST body
|
80
|
-
context.merge! :data => hash_to_query(params), :headers => {'Content-Type' => 'application/x-www-form-urlencoded'}
|
81
|
-
elsif data
|
82
|
-
# standard POST, using "data" as the POST body
|
83
|
-
context.merge! :headers => {'Content-Type' => 'text/xml; charset=utf-8'}
|
84
|
-
else
|
85
|
-
context.merge! :path => build_url(path, params)
|
86
|
-
end
|
87
|
-
context
|
88
|
-
end
|
89
|
-
|
90
|
-
# accepts a path/string and optional hash of query params
|
91
|
-
# returns a string that represents the full url
|
92
|
-
def build_url path, params={}
|
93
|
-
full_path = @uri.path + path
|
94
|
-
super full_path, params, @uri.query
|
95
|
-
end
|
96
|
-
|
97
|
-
def base_url
|
98
|
-
"#{@uri.scheme}://#{@uri.host}" + (@uri.port ? ":#{@uri.port}" : "")
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
|
-
#
|
4
|
-
# Connection for standard HTTP Solr server
|
5
|
-
#
|
6
|
-
class RSolr::Connection::NetHttp
|
7
|
-
|
8
|
-
include RSolr::Connection::Httpable
|
9
|
-
|
10
|
-
def connection
|
11
|
-
if @proxy
|
12
|
-
proxy_user, proxy_pass = @proxy.userinfo.split(/:/) if @proxy.userinfo
|
13
|
-
@connection ||= Net::HTTP.Proxy(@proxy.host, @proxy.port, proxy_user, proxy_pass).new(@uri.host, @uri.port)
|
14
|
-
else
|
15
|
-
@connection ||= Net::HTTP.new(@uri.host, @uri.port)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# maybe follow Rack and do [status, headers, body]
|
20
|
-
def get url
|
21
|
-
net_http_response = self.connection.get url
|
22
|
-
[net_http_response.code.to_i, net_http_response.message, net_http_response.body]
|
23
|
-
end
|
24
|
-
|
25
|
-
def post url, data, headers={}
|
26
|
-
net_http_response = self.connection.post url, data, headers
|
27
|
-
[net_http_response.code.to_i, net_http_response.message, net_http_response.body]
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# Helpful utility methods for building queries to a Solr server
|
2
|
-
# This includes helpers that the Direct connection can use -- not specific to http, for example
|
3
|
-
module RSolr::Connection::Utils
|
4
|
-
|
5
|
-
# Performs URI escaping so that you can construct proper
|
6
|
-
# query strings faster. Use this rather than the cgi.rb
|
7
|
-
# version since it's faster. (Stolen from Rack).
|
8
|
-
def escape(s)
|
9
|
-
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
10
|
-
#'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
11
|
-
'%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
|
12
|
-
}.tr(' ', '+')
|
13
|
-
end
|
14
|
-
|
15
|
-
# encodes the string as utf-8 in Ruby 1.9
|
16
|
-
# returns the unaltered string in Ruby 1.8
|
17
|
-
def encode_utf8 string
|
18
|
-
(string.respond_to?(:force_encoding) and string.respond_to?(:encoding)) ?
|
19
|
-
string.force_encoding(Encoding::UTF_8) : string
|
20
|
-
end
|
21
|
-
|
22
|
-
# Return the bytesize of String; uses String#size under Ruby 1.8 and
|
23
|
-
# String#bytesize under 1.9.
|
24
|
-
if ''.respond_to?(:bytesize)
|
25
|
-
def bytesize(string)
|
26
|
-
string.bytesize
|
27
|
-
end
|
28
|
-
else
|
29
|
-
def bytesize(string)
|
30
|
-
string.size
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# creates and returns a url as a string
|
35
|
-
# "url" is the base url
|
36
|
-
# "params" is an optional hash of GET style query params
|
37
|
-
# "string_query" is an extra query string that will be appended to the
|
38
|
-
# result of "url" and "params".
|
39
|
-
def build_url url='', params={}, string_query=''
|
40
|
-
queries = [string_query, hash_to_query(params)]
|
41
|
-
queries.delete_if{|i| i.to_s.empty?}
|
42
|
-
url += "?#{queries.join('&')}" unless queries.empty?
|
43
|
-
url
|
44
|
-
end
|
45
|
-
|
46
|
-
# converts a key value pair to an escaped string:
|
47
|
-
# Example:
|
48
|
-
# build_param(:id, 1) == "id=1"
|
49
|
-
def build_param(k,v)
|
50
|
-
"#{escape(k)}=#{escape(v)}"
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
# converts hash into URL query string, keys get an alpha sort
|
55
|
-
# if a value is an array, the array values get mapped to the same key:
|
56
|
-
# hash_to_query(:q=>'blah-query', :fq=>['f1', 'f1'], :facet=>true, 'facet.field'=>['location_facet', 'format_facet'])
|
57
|
-
# returns:
|
58
|
-
# ?q=blah-query&fq=f1&fq=f2&facet=true&facet.field=location_facet&facet.field=format.facet
|
59
|
-
#
|
60
|
-
# if a value is empty/nil etc., it is tossed out
|
61
|
-
#
|
62
|
-
def hash_to_query(params)
|
63
|
-
mapped = params.map do |k, v|
|
64
|
-
next if v.to_s.empty?
|
65
|
-
if v.class == Array
|
66
|
-
hash_to_query(v.map { |x| [k, x] })
|
67
|
-
else
|
68
|
-
build_param k, v
|
69
|
-
end
|
70
|
-
end
|
71
|
-
mapped.compact.join("&")
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
data/lib/rsolr/connection.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# A class that represents a "doc" xml element for a solr update
|
2
|
-
class RSolr::Message::Document
|
3
|
-
|
4
|
-
# "attrs" is a hash for setting the "doc" xml attributes
|
5
|
-
# "fields" is an array of Field objects
|
6
|
-
attr_accessor :attrs, :fields
|
7
|
-
|
8
|
-
# "doc_hash" must be a Hash/Mash object
|
9
|
-
# If a value in the "doc_hash" is an array,
|
10
|
-
# a field object is created for each value...
|
11
|
-
def initialize(doc_hash = {})
|
12
|
-
@fields = []
|
13
|
-
doc_hash.each_pair do |field,values|
|
14
|
-
# create a new field for each value (multi-valued)
|
15
|
-
# put non-array values into an array
|
16
|
-
values = [values] unless values.is_a?(Array)
|
17
|
-
values.each do |v|
|
18
|
-
next if v.to_s.empty?
|
19
|
-
@fields << RSolr::Message::Field.new({:name=>field}, v.to_s)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
@attrs={}
|
23
|
-
end
|
24
|
-
|
25
|
-
# returns an array of fields that match the "name" arg
|
26
|
-
def fields_by_name(name)
|
27
|
-
@fields.select{|f|f.name==name}
|
28
|
-
end
|
29
|
-
|
30
|
-
# returns the *first* field that matches the "name" arg
|
31
|
-
def field_by_name(name)
|
32
|
-
@fields.detect{|f|f.name==name}
|
33
|
-
end
|
34
|
-
|
35
|
-
#
|
36
|
-
# Add a field value to the document. Options map directly to
|
37
|
-
# XML attributes in the Solr <field> node.
|
38
|
-
# See http://wiki.apache.org/solr/UpdateXmlMessages#head-8315b8028923d028950ff750a57ee22cbf7977c6
|
39
|
-
#
|
40
|
-
# === Example:
|
41
|
-
#
|
42
|
-
# document.add_field('title', 'A Title', :boost => 2.0)
|
43
|
-
#
|
44
|
-
def add_field(name, value, options = {})
|
45
|
-
@fields << RSolr::Message::Field.new(options.merge({:name=>name}), value)
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
data/lib/rsolr/message/field.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# A class that represents a "doc"/"field" xml element for a solr update
|
2
|
-
class RSolr::Message::Field
|
3
|
-
|
4
|
-
# "attrs" is a hash for setting the "doc" xml attributes
|
5
|
-
# "value" is the text value for the node
|
6
|
-
attr_accessor :attrs, :value
|
7
|
-
|
8
|
-
# "attrs" must be a hash
|
9
|
-
# "value" should be something that responds to #_to_s
|
10
|
-
def initialize(attrs, value)
|
11
|
-
@attrs = attrs
|
12
|
-
@value = value
|
13
|
-
end
|
14
|
-
|
15
|
-
# the value of the "name" attribute
|
16
|
-
def name
|
17
|
-
@attrs[:name]
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
class RSolr::Message::Generator
|
2
|
-
|
3
|
-
def build &block
|
4
|
-
require 'builder'
|
5
|
-
b = ::Builder::XmlMarkup.new(:indent=>0, :margin=>0, :encoding => 'UTF-8')
|
6
|
-
b.instruct!
|
7
|
-
block_given? ? yield(b) : b
|
8
|
-
end
|
9
|
-
|
10
|
-
# generates "add" xml for updating solr
|
11
|
-
# "data" can be a hash or an array of hashes.
|
12
|
-
# - each hash should be a simple key=>value pair representing a solr doc.
|
13
|
-
# If a value is an array, multiple fields will be created.
|
14
|
-
#
|
15
|
-
# "add_attrs" can be a hash for setting the add xml element attributes.
|
16
|
-
#
|
17
|
-
# This method can also accept a block.
|
18
|
-
# The value yielded to the block is a Message::Document; for each solr doc in "data".
|
19
|
-
# You can set xml element attributes for each "doc" element or individual "field" elements.
|
20
|
-
#
|
21
|
-
# For example:
|
22
|
-
#
|
23
|
-
# solr.add({:id=>1, :nickname=>'Tim'}, {:boost=>5.0, :commitWithin=>1.0}) do |doc_msg|
|
24
|
-
# doc_msg.attrs[:boost] = 10.00 # boost the document
|
25
|
-
# nickname = doc_msg.field_by_name(:nickname)
|
26
|
-
# nickname.attrs[:boost] = 20 if nickname.value=='Tim' # boost a field
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# would result in an add element having the attributes boost="10.0"
|
30
|
-
# and a commitWithin="1.0".
|
31
|
-
# Each doc element would have a boost="10.0".
|
32
|
-
# The "nickname" field would have a boost="20.0"
|
33
|
-
# if the doc had a "nickname" field with the value of "Tim".
|
34
|
-
#
|
35
|
-
def add data, add_attrs={}, &block
|
36
|
-
data = [data] unless data.is_a?(Array)
|
37
|
-
build do |xml|
|
38
|
-
xml.add(add_attrs) do |add_node|
|
39
|
-
data.each do |doc|
|
40
|
-
doc = RSolr::Message::Document.new(doc) if doc.respond_to?(:each_pair)
|
41
|
-
yield doc if block_given?
|
42
|
-
add_node.doc(doc.attrs) do |doc_node|
|
43
|
-
doc.fields.each do |field_obj|
|
44
|
-
doc_node.field field_obj.value, field_obj.attrs
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# generates a <commit/> message
|
53
|
-
def commit(opts={})
|
54
|
-
build {|xml| xml.commit opts}
|
55
|
-
end
|
56
|
-
|
57
|
-
# generates a <optimize/> message
|
58
|
-
def optimize(opts={})
|
59
|
-
build {|xml| xml.optimize opts}
|
60
|
-
end
|
61
|
-
|
62
|
-
# generates a <rollback/> message
|
63
|
-
def rollback opts={}
|
64
|
-
build {|xml| xml.rollback opts}
|
65
|
-
end
|
66
|
-
|
67
|
-
# generates a <delete><id>ID</id></delete> message
|
68
|
-
# "ids" can be a single value or array of values
|
69
|
-
def delete_by_id(ids)
|
70
|
-
ids = [ids] unless ids.is_a?(Array)
|
71
|
-
build do |xml|
|
72
|
-
xml.delete do |delete_node|
|
73
|
-
ids.each { |id| delete_node.id(id) }
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# generates a <delete><query>ID</query></delete> message
|
79
|
-
# "queries" can be a single value or an array of values
|
80
|
-
def delete_by_query(queries)
|
81
|
-
queries = [queries] unless queries.is_a?(Array)
|
82
|
-
build do |xml|
|
83
|
-
xml.delete do |delete_node|
|
84
|
-
queries.each { |query| delete_node.query query }
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
data/lib/rsolr/message.rb
DELETED
data/spec/api/client_spec.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
describe RSolr::Client do
|
2
|
-
|
3
|
-
let(:client){ RSolr::Client.new('') }
|
4
|
-
|
5
|
-
context :method_missing do
|
6
|
-
|
7
|
-
it 'a non-existent method should be forwarded to #method_missing and then to #request' do
|
8
|
-
client.should_receive(:request).
|
9
|
-
with('/music', :q=>'Coltrane')
|
10
|
-
client.music :q=>'Coltrane'
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
context :update do
|
16
|
-
|
17
|
-
it 'should forward /update to #request("/update")' do
|
18
|
-
client.should_receive(:request)#.
|
19
|
-
# with('/update', {:wt=>:ruby}, "my xml message")
|
20
|
-
client.update "my xml message"
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'should forward #add calls to #update' do
|
24
|
-
client.should_receive(:update) {|value,params|
|
25
|
-
value.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><add><doc><field name=\"id\">1</field></doc></add>"
|
26
|
-
}
|
27
|
-
client.add(:id=>1)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'should forward #commit calls to #update' do
|
31
|
-
client.should_receive(:update).
|
32
|
-
with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><commit/>")
|
33
|
-
client.commit
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should forward #commit calls with options to #update' do
|
37
|
-
opts = {:waitFlush => false, :waitSearcher => false, :expungeDeletes => true}
|
38
|
-
# when client.commit is called, it eventually calls update
|
39
|
-
client.should_receive(:update).
|
40
|
-
with(opts)
|
41
|
-
# client.message is calls to create the xml
|
42
|
-
client.message.should_receive(:commit).
|
43
|
-
and_return(opts)
|
44
|
-
client.commit(opts)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should forward #optimize calls to #update' do
|
48
|
-
client.should_receive(:update).
|
49
|
-
with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><optimize/>")
|
50
|
-
client.optimize
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'should forward #optimize calls with options to #update' do
|
54
|
-
opts = {:maxSegments => 5, :waitFlush => false}
|
55
|
-
# when client.commit is called, it eventually calls update
|
56
|
-
client.should_receive(:update).
|
57
|
-
with(opts)
|
58
|
-
# client.message is calls to create the xml
|
59
|
-
client.message.should_receive(:optimize).
|
60
|
-
and_return(opts)
|
61
|
-
client.optimize(opts)
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'should forward #rollback calls to #update' do
|
65
|
-
client.should_receive(:update).
|
66
|
-
with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rollback/>")
|
67
|
-
client.rollback
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'should forward #delete_by_id calls to #update' do
|
71
|
-
client.should_receive(:update).
|
72
|
-
with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><id>1</id></delete>")
|
73
|
-
client.delete_by_id 1
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'should forward #delete_by_query calls to #update' do
|
77
|
-
client.should_receive(:update).
|
78
|
-
with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><query>blah</query></delete>")
|
79
|
-
client.delete_by_query 'blah'
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
context :request do
|
85
|
-
|
86
|
-
it 'should forward #request calls to the connection' do
|
87
|
-
client.connection.should_receive(:request).
|
88
|
-
with('/music', :q=>'Coltrane', :wt=>:ruby).
|
89
|
-
# empty params so that Client doesn't try to evalulate to Ruby;
|
90
|
-
# -- this happens if the :wt equal :ruby
|
91
|
-
and_return(:params=>{})
|
92
|
-
client.request '/music', :q=>'Coltrane'
|
93
|
-
end
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
context :adapt_response do
|
98
|
-
|
99
|
-
it 'should not try to evaluate ruby when the :qt is not :ruby' do
|
100
|
-
body = '{:time=>"NOW"}'
|
101
|
-
result = client.send(:adapt_response, {:body=>body, :params=>{}})
|
102
|
-
result.should be_a(String)
|
103
|
-
result.should == body
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'should evaluate ruby responses when the :wt is :ruby' do
|
107
|
-
body = '{:time=>"NOW"}'
|
108
|
-
result = client.send(:adapt_response, {:body=>body, :params=>{:wt=>:ruby}})
|
109
|
-
result.should be_a(Hash)
|
110
|
-
result.should == {:time=>"NOW"}
|
111
|
-
end
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
end
|
@@ -1,157 +0,0 @@
|
|
1
|
-
describe RSolr::Connection::Httpable do
|
2
|
-
|
3
|
-
# calls #let to set "net_http" as method accessor
|
4
|
-
class R
|
5
|
-
include RSolr::Connection::Httpable
|
6
|
-
end
|
7
|
-
|
8
|
-
module HttpableHelper
|
9
|
-
def self.included base
|
10
|
-
base.let(:httpable){R.new}
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context 'new' do
|
15
|
-
|
16
|
-
include HttpableHelper
|
17
|
-
|
18
|
-
it 'should define an intialize method that accepts a hash argument' do
|
19
|
-
lambda{R.new({})}.should_not raise_error
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should have an #opts attribute after creation' do
|
23
|
-
httpable.should respond_to(:opts)
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'should have an #uri attribute after creation' do
|
27
|
-
httpable.should respond_to(:uri)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'opts and uri' do
|
33
|
-
|
34
|
-
it 'should allow setting the opts' do
|
35
|
-
opts = {:url=>'blah'}
|
36
|
-
r = R.new(opts)
|
37
|
-
r.opts.should == opts
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should parser the url option into a URI object' do
|
41
|
-
opts = {:url => 'http://xyz:1010/solr'}
|
42
|
-
r = R.new(opts)
|
43
|
-
r.uri.should be_a(URI)
|
44
|
-
r.uri.host.should == 'xyz'
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
context :build_url do
|
50
|
-
|
51
|
-
include HttpableHelper
|
52
|
-
|
53
|
-
it 'should build a full path and create a query string' do
|
54
|
-
r = httpable
|
55
|
-
r.build_url("/select", :q=>1).should == '/solr/select?q=1'
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'should build a full path without a query string' do
|
59
|
-
r = httpable
|
60
|
-
r.build_url("/select").should == '/solr/select'
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
context :create_http_context do
|
66
|
-
|
67
|
-
include HttpableHelper
|
68
|
-
|
69
|
-
it "should build a simple GET context" do
|
70
|
-
r = httpable
|
71
|
-
result = r.create_http_context('/select', :q=>'a', :fq=>'b')
|
72
|
-
expected = {:path=>"/solr/select?q=a&fq=b", :params=>{:q=>"a", :fq=>"b"}, :data=>nil, :query=>"q=a&fq=b", :host=>"http://127.0.0.1:8983"}
|
73
|
-
|
74
|
-
result.keys.all? {|v| expected.keys.include?(v) }
|
75
|
-
result.values.all? {|v| expected.values.include?(v) }
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should build a POST context" do
|
79
|
-
r = httpable
|
80
|
-
result = r.create_http_context('/select', {:wt => :xml}, '<commit/>')
|
81
|
-
expected = {:path=>"/solr/select", :params=>{:wt=>:xml}, :headers=>{"Content-Type"=>"text/xml; charset=utf-8"}, :data=>"<commit/>", :query=>"wt=xml", :host=>"http://127.0.0.1:8983"}
|
82
|
-
result.should == expected
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should raise an exception when trying to use POST data AND :method => :post" do
|
86
|
-
r = httpable
|
87
|
-
lambda{
|
88
|
-
r.create_http_context('/select', {:wt => :xml}, '<commit/>', :method => :post)
|
89
|
-
}.should raise_error("Don't send POST data when using :method => :post")
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should form-encoded POST context" do
|
93
|
-
r = httpable
|
94
|
-
result = r.create_http_context('/select', {:q => 'some gigantic query string that is too big for GET (for example)'}, nil, :method => :post)
|
95
|
-
result.should == {:path=>"/solr/select", :params=>{:q=>"some gigantic query string that is too big for GET (for example)"}, :headers=>{"Content-Type"=>"application/x-www-form-urlencoded"}, :data=>"q=some+gigantic+query+string+that+is+too+big+for+GET+%28for+example%29", :query=>"q=some+gigantic+query+string+that+is+too+big+for+GET+%28for+example%29", :host=>"http://127.0.0.1:8983"}
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
context :request do
|
101
|
-
|
102
|
-
include HttpableHelper
|
103
|
-
|
104
|
-
it "should be able to build a request context, pass the url to #get and return a full context" do
|
105
|
-
httpable.should_receive(:create_http_context).
|
106
|
-
with("/admin/ping", {}, nil, {}).
|
107
|
-
and_return({:path => '/solr/admin/ping'})
|
108
|
-
httpable.should_receive(:get).
|
109
|
-
with('/solr/admin/ping').
|
110
|
-
and_return(["asdfasdf", 200, "OK"])
|
111
|
-
response = httpable.request '/admin/ping'
|
112
|
-
response.should == {:status_code=>200, :message=>"OK", :path=>"/solr/admin/ping", :body=>"asdfasdf"}
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'should send a get to itself with params' do
|
116
|
-
httpable.should_receive(:get).
|
117
|
-
with("/solr/blahasdf?id=1").
|
118
|
-
and_return(["", 200, "OK"])
|
119
|
-
r = httpable.request('/blahasdf', :id=>1)
|
120
|
-
r.should == {:status_code=>200, :path=>"/solr/blahasdf?id=1", :params=>{:id=>1}, :message=>"OK", :data=>nil, :query=>"id=1", :host=>"http://127.0.0.1:8983", :body=>""}
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'should raise an error if the status_code is not 200' do
|
124
|
-
httpable.should_receive(:get).
|
125
|
-
with("/solr/blah?id=1").
|
126
|
-
and_return( ["", 404, "Not Found"] )
|
127
|
-
lambda{
|
128
|
-
httpable.request('/blah', :id=>1).should == true
|
129
|
-
}.should raise_error(/Not Found/)
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'should send a post to itself if data is supplied' do
|
133
|
-
httpable.should_receive(:post).
|
134
|
-
with("/solr/blah", "<commit/>", {"Content-Type"=>"text/xml; charset=utf-8"}).
|
135
|
-
and_return(["", 200, "OK"])
|
136
|
-
httpable.request('/blah', {:id=>1}, "<commit/>")#.should == expected_response
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'should send a post to itself when :method=>:post is set even if no POST data is supplied' do
|
140
|
-
httpable.should_receive(:post).
|
141
|
-
with("/solr/blah", "q=testing", {"Content-Type"=>"application/x-www-form-urlencoded"}).
|
142
|
-
and_return(["", 200, "OK"])
|
143
|
-
response = httpable.request('/blah', {:q => "testing"}, :method => :post)#.should == expected_response
|
144
|
-
response[:body].should == ""
|
145
|
-
response[:path].should == "/solr/blah"
|
146
|
-
response[:message].should == "OK"
|
147
|
-
response[:status_code].should == 200
|
148
|
-
response[:params].should == {:q=>"testing"}
|
149
|
-
response[:headers].should == {"Content-Type"=>"application/x-www-form-urlencoded"}
|
150
|
-
response[:data].should == "q=testing"
|
151
|
-
response[:query].should == "q=testing"
|
152
|
-
response[:host].should == "http://127.0.0.1:8983"
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
end
|