rubberband 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,101 @@
1
+ begin
2
+ require 'thrift'
3
+ rescue LoadError => error
4
+ raise "Please install the thrift gem (>= 0.5.0) to use the Thrift transport."
5
+ end
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "thrift"))
8
+ require 'rest'
9
+
10
+ module ElasticSearch
11
+ module Transport
12
+ class Thrift < Base
13
+
14
+ DEFAULTS = {
15
+ :timeout => 5,
16
+ :thrift_protocol => ::Thrift::BinaryProtocol,
17
+ :thrift_protocol_extra_params => [],
18
+ :thrift_transport => ::Thrift::Socket,
19
+ :thrift_transport_wrapper => ::Thrift::BufferedTransport,
20
+ :client_class => ElasticSearch::Thrift::Rest::Client
21
+ }.freeze
22
+
23
+ def initialize(server, options={})
24
+ super
25
+ @options = DEFAULTS.merge(@options)
26
+ end
27
+
28
+ def connect!
29
+ host, port = parse_server(@server)
30
+
31
+ @transport = @options[:thrift_transport].new(host, port.to_i, @options[:timeout])
32
+ @transport = @transport_wrapper.new(@transport) if @transport_wrapper
33
+ @transport.open
34
+
35
+ @client = @options[:client_class].new(@options[:thrift_protocol].new(@transport, *@options[:thrift_protocol_extra_params]))
36
+ rescue ::Thrift::TransportException, Errno::ECONNREFUSED
37
+ close
38
+ raise ConnectionFailed
39
+ end
40
+
41
+ def close
42
+ @transport.close rescue nil
43
+ end
44
+
45
+ private
46
+
47
+ def parse_server(server)
48
+ host, port = server.to_s.split(":")
49
+ raise ArgumentError, 'Servers must be in the form "host:port"' unless host and port
50
+ [host, port]
51
+ end
52
+
53
+ def stringify!(hash)
54
+ hash.keys.each do |k|
55
+ hash[k.to_s] = hash.delete(k).to_s
56
+ end
57
+ hash
58
+ end
59
+
60
+ def request(method, operation, params={}, body=nil, headers={})
61
+ begin
62
+ uri = generate_uri(operation)
63
+ #puts "request: #{@server} #{method} #{uri} #{params.inspect} #{body}"
64
+ request = ElasticSearch::Thrift::RestRequest.new
65
+ case method
66
+ when :get
67
+ request.method = ElasticSearch::Thrift::Method::GET
68
+ when :put
69
+ request.method = ElasticSearch::Thrift::Method::GET
70
+ when :post
71
+ request.method = ElasticSearch::Thrift::Method::POST
72
+ when :delete
73
+ request.method = ElasticSearch::Thrift::Method::DELETE
74
+ end
75
+
76
+ request.uri = uri
77
+ request.parameters = stringify!(params)
78
+ request.body = body
79
+ request.headers = stringify!(headers)
80
+ response = @client.execute(request)
81
+ handle_error(response) if response.status >= 500
82
+ response
83
+ rescue Exception => e
84
+ case e
85
+ when ::Thrift::TransportException
86
+ case e.type
87
+ when ::Thrift::TransportException::TIMED_OUT
88
+ raise TimeoutError
89
+ else
90
+ raise ConnectionFailed
91
+ end
92
+ #TODO Thrift::ApplicationException, Thrift::ProtocolException, IOError.. retryable or fatal?
93
+ else
94
+ raise e
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # Autogenerated by Thrift
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'elasticsearch_types'
8
+
9
+ module ElasticSearch
10
+ module Thrift
11
+ end
12
+ end
@@ -0,0 +1,124 @@
1
+ #
2
+ # Autogenerated by Thrift
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+
8
+ module ElasticSearch
9
+ module Thrift
10
+ module Method
11
+ GET = 0
12
+ PUT = 1
13
+ POST = 2
14
+ DELETE = 3
15
+ HEAD = 4
16
+ OPTIONS = 5
17
+ VALUE_MAP = {0 => "GET", 1 => "PUT", 2 => "POST", 3 => "DELETE", 4 => "HEAD", 5 => "OPTIONS"}
18
+ VALID_VALUES = Set.new([GET, PUT, POST, DELETE, HEAD, OPTIONS]).freeze
19
+ end
20
+
21
+ module Status
22
+ CONT = 100
23
+ SWITCHING_PROTOCOLS = 101
24
+ OK = 200
25
+ CREATED = 201
26
+ ACCEPTED = 202
27
+ NON_AUTHORITATIVE_INFORMATION = 203
28
+ NO_CONTENT = 204
29
+ RESET_CONTENT = 205
30
+ PARTIAL_CONTENT = 206
31
+ MULTI_STATUS = 207
32
+ MULTIPLE_CHOICES = 300
33
+ MOVED_PERMANENTLY = 301
34
+ FOUND = 302
35
+ SEE_OTHER = 303
36
+ NOT_MODIFIED = 304
37
+ USE_PROXY = 305
38
+ TEMPORARY_REDIRECT = 307
39
+ BAD_REQUEST = 400
40
+ UNAUTHORIZED = 401
41
+ PAYMENT_REQUIRED = 402
42
+ FORBIDDEN = 403
43
+ NOT_FOUND = 404
44
+ METHOD_NOT_ALLOWED = 405
45
+ NOT_ACCEPTABLE = 406
46
+ PROXY_AUTHENTICATION = 407
47
+ REQUEST_TIMEOUT = 408
48
+ CONFLICT = 409
49
+ GONE = 410
50
+ LENGTH_REQUIRED = 411
51
+ PRECONDITION_FAILED = 412
52
+ REQUEST_ENTITY_TOO_LARGE = 413
53
+ REQUEST_URI_TOO_LONG = 414
54
+ UNSUPPORTED_MEDIA_TYPE = 415
55
+ REQUESTED_RANGE_NOT_SATISFIED = 416
56
+ EXPECTATION_FAILED = 417
57
+ UNPROCESSABLE_ENTITY = 422
58
+ LOCKED = 423
59
+ FAILED_DEPENDENCY = 424
60
+ INTERNAL_SERVER_ERROR = 500
61
+ NOT_IMPLEMENTED = 501
62
+ BAD_GATEWAY = 502
63
+ SERVICE_UNAVAILABLE = 503
64
+ GATEWAY_TIMEOUT = 504
65
+ INSUFFICIENT_STORAGE = 506
66
+ VALUE_MAP = {100 => "CONT", 101 => "SWITCHING_PROTOCOLS", 200 => "OK", 201 => "CREATED", 202 => "ACCEPTED", 203 => "NON_AUTHORITATIVE_INFORMATION", 204 => "NO_CONTENT", 205 => "RESET_CONTENT", 206 => "PARTIAL_CONTENT", 207 => "MULTI_STATUS", 300 => "MULTIPLE_CHOICES", 301 => "MOVED_PERMANENTLY", 302 => "FOUND", 303 => "SEE_OTHER", 304 => "NOT_MODIFIED", 305 => "USE_PROXY", 307 => "TEMPORARY_REDIRECT", 400 => "BAD_REQUEST", 401 => "UNAUTHORIZED", 402 => "PAYMENT_REQUIRED", 403 => "FORBIDDEN", 404 => "NOT_FOUND", 405 => "METHOD_NOT_ALLOWED", 406 => "NOT_ACCEPTABLE", 407 => "PROXY_AUTHENTICATION", 408 => "REQUEST_TIMEOUT", 409 => "CONFLICT", 410 => "GONE", 411 => "LENGTH_REQUIRED", 412 => "PRECONDITION_FAILED", 413 => "REQUEST_ENTITY_TOO_LARGE", 414 => "REQUEST_URI_TOO_LONG", 415 => "UNSUPPORTED_MEDIA_TYPE", 416 => "REQUESTED_RANGE_NOT_SATISFIED", 417 => "EXPECTATION_FAILED", 422 => "UNPROCESSABLE_ENTITY", 423 => "LOCKED", 424 => "FAILED_DEPENDENCY", 500 => "INTERNAL_SERVER_ERROR", 501 => "NOT_IMPLEMENTED", 502 => "BAD_GATEWAY", 503 => "SERVICE_UNAVAILABLE", 504 => "GATEWAY_TIMEOUT", 506 => "INSUFFICIENT_STORAGE"}
67
+ VALID_VALUES = Set.new([CONT, SWITCHING_PROTOCOLS, OK, CREATED, ACCEPTED, NON_AUTHORITATIVE_INFORMATION, NO_CONTENT, RESET_CONTENT, PARTIAL_CONTENT, MULTI_STATUS, MULTIPLE_CHOICES, MOVED_PERMANENTLY, FOUND, SEE_OTHER, NOT_MODIFIED, USE_PROXY, TEMPORARY_REDIRECT, BAD_REQUEST, UNAUTHORIZED, PAYMENT_REQUIRED, FORBIDDEN, NOT_FOUND, METHOD_NOT_ALLOWED, NOT_ACCEPTABLE, PROXY_AUTHENTICATION, REQUEST_TIMEOUT, CONFLICT, GONE, LENGTH_REQUIRED, PRECONDITION_FAILED, REQUEST_ENTITY_TOO_LARGE, REQUEST_URI_TOO_LONG, UNSUPPORTED_MEDIA_TYPE, REQUESTED_RANGE_NOT_SATISFIED, EXPECTATION_FAILED, UNPROCESSABLE_ENTITY, LOCKED, FAILED_DEPENDENCY, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, INSUFFICIENT_STORAGE]).freeze
68
+ end
69
+
70
+ class RestRequest
71
+ include ::Thrift::Struct, ::Thrift::Struct_Union
72
+ METHOD = 1
73
+ URI = 2
74
+ PARAMETERS = 3
75
+ HEADERS = 4
76
+ BODY = 5
77
+
78
+ FIELDS = {
79
+ METHOD => {:type => ::Thrift::Types::I32, :name => 'method', :enum_class => ElasticSearch::Thrift::Method},
80
+ URI => {:type => ::Thrift::Types::STRING, :name => 'uri'},
81
+ PARAMETERS => {:type => ::Thrift::Types::MAP, :name => 'parameters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
82
+ HEADERS => {:type => ::Thrift::Types::MAP, :name => 'headers', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
83
+ BODY => {:type => ::Thrift::Types::STRING, :name => 'body', :binary => true, :optional => true}
84
+ }
85
+
86
+ def struct_fields; FIELDS; end
87
+
88
+ def validate
89
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field method is unset!') unless @method
90
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field uri is unset!') unless @uri
91
+ unless @method.nil? || ElasticSearch::Thrift::Method::VALID_VALUES.include?(@method)
92
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field method!')
93
+ end
94
+ end
95
+
96
+ ::Thrift::Struct.generate_accessors self
97
+ end
98
+
99
+ class RestResponse
100
+ include ::Thrift::Struct, ::Thrift::Struct_Union
101
+ STATUS = 1
102
+ HEADERS = 2
103
+ BODY = 3
104
+
105
+ FIELDS = {
106
+ STATUS => {:type => ::Thrift::Types::I32, :name => 'status', :enum_class => ElasticSearch::Thrift::Status},
107
+ HEADERS => {:type => ::Thrift::Types::MAP, :name => 'headers', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
108
+ BODY => {:type => ::Thrift::Types::STRING, :name => 'body', :binary => true, :optional => true}
109
+ }
110
+
111
+ def struct_fields; FIELDS; end
112
+
113
+ def validate
114
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field status is unset!') unless @status
115
+ unless @status.nil? || ElasticSearch::Thrift::Status::VALID_VALUES.include?(@status)
116
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field status!')
117
+ end
118
+ end
119
+
120
+ ::Thrift::Struct.generate_accessors self
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,83 @@
1
+ #
2
+ # Autogenerated by Thrift
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+ require 'elasticsearch_types'
9
+
10
+ module ElasticSearch
11
+ module Thrift
12
+ module Rest
13
+ class Client
14
+ include ::Thrift::Client
15
+
16
+ def execute(request)
17
+ send_execute(request)
18
+ return recv_execute()
19
+ end
20
+
21
+ def send_execute(request)
22
+ send_message('execute', Execute_args, :request => request)
23
+ end
24
+
25
+ def recv_execute()
26
+ result = receive_message(Execute_result)
27
+ return result.success unless result.success.nil?
28
+ raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'execute failed: unknown result')
29
+ end
30
+
31
+ end
32
+
33
+ class Processor
34
+ include ::Thrift::Processor
35
+
36
+ def process_execute(seqid, iprot, oprot)
37
+ args = read_args(iprot, Execute_args)
38
+ result = Execute_result.new()
39
+ result.success = @handler.execute(args.request)
40
+ write_result(result, oprot, 'execute', seqid)
41
+ end
42
+
43
+ end
44
+
45
+ # HELPER FUNCTIONS AND STRUCTURES
46
+
47
+ class Execute_args
48
+ include ::Thrift::Struct, ::Thrift::Struct_Union
49
+ REQUEST = 1
50
+
51
+ FIELDS = {
52
+ REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class => ElasticSearch::Thrift::RestRequest}
53
+ }
54
+
55
+ def struct_fields; FIELDS; end
56
+
57
+ def validate
58
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field request is unset!') unless @request
59
+ end
60
+
61
+ ::Thrift::Struct.generate_accessors self
62
+ end
63
+
64
+ class Execute_result
65
+ include ::Thrift::Struct, ::Thrift::Struct_Union
66
+ SUCCESS = 0
67
+
68
+ FIELDS = {
69
+ SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class => ElasticSearch::Thrift::RestResponse}
70
+ }
71
+
72
+ def struct_fields; FIELDS; end
73
+
74
+ def validate
75
+ end
76
+
77
+ ::Thrift::Struct.generate_accessors self
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1 @@
1
+ require 'elasticsearch'
@@ -0,0 +1,83 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rubberband}
8
+ s.version = "0.0.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["grantr"]
12
+ s.date = %q{2010-12-06}
13
+ s.description = %q{An ElasticSearch Client with ThriftClient-like failover handling.}
14
+ s.email = %q{grantr@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "TODO",
25
+ "VERSION",
26
+ "lib/elasticsearch.rb",
27
+ "lib/elasticsearch/client.rb",
28
+ "lib/elasticsearch/client/abstract_client.rb",
29
+ "lib/elasticsearch/client/admin_cluster.rb",
30
+ "lib/elasticsearch/client/admin_index.rb",
31
+ "lib/elasticsearch/client/auto_discovering_client.rb",
32
+ "lib/elasticsearch/client/default_scope.rb",
33
+ "lib/elasticsearch/client/hits.rb",
34
+ "lib/elasticsearch/client/index.rb",
35
+ "lib/elasticsearch/client/retrying_client.rb",
36
+ "lib/elasticsearch/encoding.rb",
37
+ "lib/elasticsearch/encoding/base.rb",
38
+ "lib/elasticsearch/encoding/json.rb",
39
+ "lib/elasticsearch/transport.rb",
40
+ "lib/elasticsearch/transport/base.rb",
41
+ "lib/elasticsearch/transport/base_protocol.rb",
42
+ "lib/elasticsearch/transport/http.rb",
43
+ "lib/elasticsearch/transport/thrift.rb",
44
+ "lib/elasticsearch/transport/thrift/elasticsearch_constants.rb",
45
+ "lib/elasticsearch/transport/thrift/elasticsearch_types.rb",
46
+ "lib/elasticsearch/transport/thrift/rest.rb",
47
+ "lib/rubberband.rb",
48
+ "rubberband.gemspec",
49
+ "test/elasticsearch_test.rb",
50
+ "test/hits_test.rb",
51
+ "test/test_helper.rb",
52
+ "vendor/elasticsearch/elasticsearch.thrift"
53
+ ]
54
+ s.homepage = %q{http://github.com/grantr/rubberband}
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.3.7}
57
+ s.summary = %q{An ElasticSearch client.}
58
+ s.test_files = [
59
+ "test/elasticsearch_test.rb",
60
+ "test/hits_test.rb",
61
+ "test/test_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
+ s.add_runtime_dependency(%q<patron>, [">= 0"])
70
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
71
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
72
+ else
73
+ s.add_dependency(%q<patron>, [">= 0"])
74
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
75
+ s.add_dependency(%q<shoulda>, [">= 0"])
76
+ end
77
+ else
78
+ s.add_dependency(%q<patron>, [">= 0"])
79
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
80
+ s.add_dependency(%q<shoulda>, [">= 0"])
81
+ end
82
+ end
83
+
@@ -2,6 +2,6 @@ require 'test_helper'
2
2
 
3
3
  class ElasticSearchTest < Test::Unit::TestCase
4
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"
5
+ #flunk "hey buddy, you should probably rename this file and start testing for real"
6
6
  end
7
7
  end
@@ -19,16 +19,83 @@ class HitsTest < Test::Unit::TestCase
19
19
  assert @hit.attributes.frozen?
20
20
  end
21
21
 
22
-
23
22
  end
24
23
 
25
24
  context "A Hits instance" do
26
25
  setup do
27
- @response1 = {"_source" => {"foo" => "bar"}, "_id" => "1"}
28
- @hit = ElasticSearch::Api::Hit.new(@response)
29
-
26
+ @response = {
27
+ "_shards"=>{"total"=>30, "successful"=>30, "failed"=>0},
28
+ "hits"=>{"total"=>2, "max_score"=>1.0, "hits"=>[
29
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"1", "_score"=>1.0, "_source"=>{"foo" => "bar"}},
30
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"2", "_score"=>1.0, "_source"=>{"foo" => "baz"}}
31
+ ]}}
32
+ @hits = ElasticSearch::Api::Hits.new(@response)
33
+ end
34
+
35
+ should "set response" do
36
+ assert_equal @response, @hits.response
37
+ end
38
+
39
+ should "set total_entries" do
40
+ assert_equal @response["hits"]["hits"].size, @hits.total_entries
41
+ end
42
+
43
+ should "instantiate hits in order" do
44
+ @response["hits"]["hits"].each_with_index do |hit, i|
45
+ assert_equal ElasticSearch::Api::Hit.new(hit), @hits.hits[i]
46
+ end
30
47
  end
31
48
 
32
- should "exist"
49
+ should "freeze hits" do
50
+ assert @hits.hits.all? { |h| h.frozen? }
51
+ end
52
+
53
+ should "freeze hits array when frozen" do
54
+ @hits.freeze
55
+ assert @hits.hits.frozen?
56
+ end
57
+
58
+ should "respond to to_a" do
59
+ assert_equal @hits.hits, @hits.to_a
60
+ end
61
+
62
+ should "respond to array methods" do
63
+ assert @hits.respond_to?(:collect)
64
+ assert_equal @response["hits"]["hits"].collect { |h| h["_id"] }, @hits.collect { |h| h.id }
65
+ end
66
+ end
67
+
68
+ context "a paginated hits instance" do
69
+ setup do
70
+ @response = {
71
+ "_shards"=>{"total"=>30, "successful"=>30, "failed"=>0},
72
+ "hits"=>{"total"=>6, "max_score"=>1.0, "hits"=>[
73
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"3", "_score"=>1.0, "_source"=>{"foo" => "bar"}},
74
+ {"_index"=>"test_index", "_type"=>"test_type", "_id"=>"4", "_score"=>1.0, "_source"=>{"foo" => "baz"}}
75
+ ]}}
76
+ @per_page = 2
77
+ @page = 2
78
+ @hits = ElasticSearch::Api::Hits.new(@response, {:page => @page, :per_page => @per_page})
79
+ end
80
+
81
+ should "respond to total_pages" do
82
+ assert_equal (@response["hits"]["total"] / @per_page.to_f).ceil, @hits.total_pages
83
+ end
84
+
85
+ should "respond to next_page" do
86
+ assert_equal @page + 1, @hits.next_page
87
+ end
88
+
89
+ should "respond to previous_page" do
90
+ assert_equal @page - 1, @hits.previous_page
91
+ end
92
+
93
+ should "respond to current_page" do
94
+ assert_equal @page, @hits.current_page
95
+ end
96
+
97
+ should "respond to per page" do
98
+ assert_equal @per_page, @hits.per_page
99
+ end
33
100
  end
34
101
  end