manticore 0.1.0-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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +3 -0
- data/APACHE-LICENSE-2.0.txt +202 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +28 -0
- data/README.md +120 -0
- data/Rakefile +8 -0
- data/lib/jar/commons-logging-1.1.3.jar +0 -0
- data/lib/jar/httpclient-4.3.2.jar +0 -0
- data/lib/jar/httpcore-4.3.1.jar +0 -0
- data/lib/manticore/async_response.rb +80 -0
- data/lib/manticore/client.rb +391 -0
- data/lib/manticore/facade.rb +40 -0
- data/lib/manticore/response.rb +76 -0
- data/lib/manticore/version.rb +3 -0
- data/lib/manticore.rb +27 -0
- data/manticore.gemspec +25 -0
- data/spec/manticore/client_spec.rb +178 -0
- data/spec/manticore/facade_spec.rb +41 -0
- data/spec/manticore/response_spec.rb +29 -0
- data/spec/spec_helper.rb +74 -0
- metadata +111 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Manticore::Client do
|
|
4
|
+
let(:client) { Manticore::Client.new }
|
|
5
|
+
|
|
6
|
+
it "should fetch a URL and return a response" do
|
|
7
|
+
client.get(local_server).should be_a Manticore::Response
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should resolve redirections" do
|
|
11
|
+
response = client.get(local_server, headers: {"X-Redirect" => "/foobar"})
|
|
12
|
+
response.code.should == 200
|
|
13
|
+
response.final_url.should == URI(local_server("/foobar"))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should accept custom headers" do
|
|
17
|
+
response = client.get(local_server, headers: {"X-Custom-Header" => "Blaznotts"})
|
|
18
|
+
json = JSON.load(response.body)
|
|
19
|
+
json["headers"]["X-Custom-Header"].should == "Blaznotts"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "should enable compression" do
|
|
23
|
+
response = client.get(local_server)
|
|
24
|
+
json = JSON.load(response.body)
|
|
25
|
+
json["headers"].should have_key "Accept-Encoding"
|
|
26
|
+
json["headers"]["Accept-Encoding"].should match("gzip")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "when compression is disabled" do
|
|
30
|
+
let(:client) {
|
|
31
|
+
Manticore::Client.new do |client, request_config|
|
|
32
|
+
client.disable_content_compression
|
|
33
|
+
end
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
it "should disable compression" do
|
|
37
|
+
response = client.get(local_server)
|
|
38
|
+
json = JSON.load(response.body)
|
|
39
|
+
json["headers"]["Accept-Encoding"].should be_nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#get" do
|
|
44
|
+
it "should work" do
|
|
45
|
+
response = client.get(local_server)
|
|
46
|
+
JSON.load(response.body)["method"].should == "GET"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "#post" do
|
|
51
|
+
it "should work" do
|
|
52
|
+
response = client.post(local_server)
|
|
53
|
+
JSON.load(response.body)["method"].should == "POST"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should send a body" do
|
|
57
|
+
response = client.post(local_server, body: "This is a post body")
|
|
58
|
+
JSON.load(response.body)["body"].should == "This is a post body"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should send params" do
|
|
62
|
+
response = client.post(local_server, params: {key: "value"})
|
|
63
|
+
JSON.load(response.body)["body"].should == "key=value"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "#put" do
|
|
68
|
+
it "should work" do
|
|
69
|
+
response = client.put(local_server)
|
|
70
|
+
JSON.load(response.body)["method"].should == "PUT"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should send a body" do
|
|
74
|
+
response = client.put(local_server, body: "This is a put body")
|
|
75
|
+
JSON.load(response.body)["body"].should == "This is a put body"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should send params" do
|
|
79
|
+
response = client.put(local_server, params: {key: "value"})
|
|
80
|
+
JSON.load(response.body)["body"].should == "key=value"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "#head" do
|
|
85
|
+
it "should work" do
|
|
86
|
+
response = client.head(local_server)
|
|
87
|
+
JSON.load(response.body).should be_nil
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe "#options" do
|
|
92
|
+
it "should work" do
|
|
93
|
+
response = client.options(local_server)
|
|
94
|
+
JSON.load(response.body)["method"].should == "OPTIONS"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "#patch" do
|
|
99
|
+
it "should work" do
|
|
100
|
+
response = client.patch(local_server)
|
|
101
|
+
JSON.load(response.body)["method"].should == "PATCH"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should send a body" do
|
|
105
|
+
response = client.patch(local_server, body: "This is a patch body")
|
|
106
|
+
JSON.load(response.body)["body"].should == "This is a patch body"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should send params" do
|
|
110
|
+
response = client.patch(local_server, params: {key: "value"})
|
|
111
|
+
JSON.load(response.body)["body"].should == "key=value"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
describe "async methods" do
|
|
116
|
+
it "should not make a request until execute is called" do
|
|
117
|
+
anchor = Time.now.to_f
|
|
118
|
+
client.async_get("http://localhost:55441/?sleep=0.5")
|
|
119
|
+
(Time.now.to_f - anchor).should < 0.4
|
|
120
|
+
|
|
121
|
+
anchor = Time.now.to_f
|
|
122
|
+
client.execute!
|
|
123
|
+
(Time.now.to_f - anchor).should > 0.4
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "should return the response object, which may then have handlers attached" do
|
|
127
|
+
response = client.async_get("http://localhost:55441/")
|
|
128
|
+
success = false
|
|
129
|
+
response.on_success do
|
|
130
|
+
success = true
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
client.execute!
|
|
134
|
+
success.should == true
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "can chain handlers" do
|
|
138
|
+
client.async_get("http://localhost:55441/").on_success {|r| r.code }
|
|
139
|
+
client.execute!.should == [200]
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe "#execute!" do
|
|
144
|
+
it "should perform multiple concurrent requests" do
|
|
145
|
+
@times = []
|
|
146
|
+
[55441, 55442].each do |port|
|
|
147
|
+
client.async_get("http://localhost:#{port}/?sleep=1") do |request|
|
|
148
|
+
request.on_success do |response, request|
|
|
149
|
+
@times << Time.now.to_f
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
client.execute!
|
|
155
|
+
@times[0].should be_within(0.5).of(@times[1])
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "should return the results of the handler blocks" do
|
|
159
|
+
[55441, 55442].each do |port|
|
|
160
|
+
client.async_get("http://localhost:#{port}/") do |request|
|
|
161
|
+
request.on_success {|response, request| "Result" }
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
client.execute!.should == ["Result", "Result"]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe "#clear_pending" do
|
|
170
|
+
it "should remove pending requests" do
|
|
171
|
+
ran = false
|
|
172
|
+
client.async_get("http://google.com").on_success {|r| ran = true }
|
|
173
|
+
client.clear_pending
|
|
174
|
+
client.execute!.should be_empty
|
|
175
|
+
ran.should be_false
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Manticore::Facade do
|
|
4
|
+
context "when extended into an arbitrary class" do
|
|
5
|
+
let(:extended_class) {
|
|
6
|
+
Class.new do
|
|
7
|
+
include Manticore::Facade
|
|
8
|
+
include_http_client
|
|
9
|
+
end
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let(:extended_shared_class) {
|
|
13
|
+
Class.new do
|
|
14
|
+
include Manticore::Facade
|
|
15
|
+
include_http_client shared_pool: true
|
|
16
|
+
end
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
it "should get a response" do
|
|
20
|
+
result = JSON.parse extended_class.get(local_server).body
|
|
21
|
+
result["method"].should == "GET"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should not use the shared client by default" do
|
|
25
|
+
extended_class.instance_variable_get("@manticore_facade").object_id.should_not ==
|
|
26
|
+
Manticore.instance_variable_get("@manticore_facade").object_id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should be able to use the shared client" do
|
|
30
|
+
extended_shared_class.instance_variable_get("@manticore_facade").object_id.should ==
|
|
31
|
+
Manticore.instance_variable_get("@manticore_facade").object_id
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "from the default Manticore module" do
|
|
36
|
+
it "should get a response" do
|
|
37
|
+
result = JSON.parse Manticore.get(local_server).body
|
|
38
|
+
result["method"].should == "GET"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Manticore::Response do
|
|
4
|
+
let(:client) { Manticore::Client.new }
|
|
5
|
+
subject { client.get( local_server ) }
|
|
6
|
+
|
|
7
|
+
its(:headers) { should be_a Hash }
|
|
8
|
+
its(:body) { should be_a String }
|
|
9
|
+
its(:length) { should be_a Fixnum }
|
|
10
|
+
|
|
11
|
+
it "should read the body" do
|
|
12
|
+
subject.body.should match "Manticore"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context "when the client is invoked with a block" do
|
|
16
|
+
it "should allow reading the body from a block" do
|
|
17
|
+
response = client.get(local_server) do |response|
|
|
18
|
+
response.body.should match 'Manticore'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
response.body.should match "Manticore"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should not read the body implicitly if called with a block" do
|
|
25
|
+
response = client.get(local_server) {}
|
|
26
|
+
expect { response.body }.to raise_exception(Manticore::StreamClosedException)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
require 'manticore'
|
|
4
|
+
require 'zlib'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'rack'
|
|
7
|
+
|
|
8
|
+
PORT = 55441
|
|
9
|
+
|
|
10
|
+
def local_server(path = "/", port = PORT)
|
|
11
|
+
URI.join("http://localhost:#{port}", path).to_s
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def read_nonblock(socket)
|
|
15
|
+
buffer = ""
|
|
16
|
+
loop {
|
|
17
|
+
begin
|
|
18
|
+
buffer << socket.read_nonblock(4096)
|
|
19
|
+
rescue Errno::EAGAIN
|
|
20
|
+
# Resource temporarily unavailable - read would block
|
|
21
|
+
break
|
|
22
|
+
end
|
|
23
|
+
}
|
|
24
|
+
buffer
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def start_server(port = PORT)
|
|
28
|
+
@servers ||= {}
|
|
29
|
+
@servers[port] = Thread.new {
|
|
30
|
+
Net::HTTP::Server.run(port: port) do |request, stream|
|
|
31
|
+
|
|
32
|
+
query = Rack::Utils.parse_query(request[:uri][:query].to_s)
|
|
33
|
+
if query["sleep"]
|
|
34
|
+
sleep(query["sleep"].to_f)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if cl = request[:headers]["Content-Length"]
|
|
38
|
+
request[:body] = read_nonblock stream.socket
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if request[:headers]["X-Redirect"] && request[:uri][:path] != request[:headers]["X-Redirect"]
|
|
42
|
+
[301, {"Location" => local_server( request[:headers]["X-Redirect"] )}, [""]]
|
|
43
|
+
else
|
|
44
|
+
if request[:headers]["Accept-Encoding"] && request[:headers]["Accept-Encoding"].match("gzip")
|
|
45
|
+
out = StringIO.new('', "w")
|
|
46
|
+
io = Zlib::GzipWriter.new(out, 2)
|
|
47
|
+
io.write JSON.dump(request)
|
|
48
|
+
io.close
|
|
49
|
+
payload = out.string
|
|
50
|
+
[200, {'Content-Type' => "text/plain", 'Content-Encoding' => "gzip", "Content-Length" => payload.length}, [payload]]
|
|
51
|
+
else
|
|
52
|
+
payload = JSON.dump(request)
|
|
53
|
+
[200, {'Content-Type' => "text/plain", "Content-Length" => payload.length}, [payload]]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def stop_servers
|
|
61
|
+
@servers.values.each(&:kill) if @servers
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
RSpec.configure do |c|
|
|
65
|
+
require 'net/http/server'
|
|
66
|
+
|
|
67
|
+
c.before(:suite) {
|
|
68
|
+
@server = {}
|
|
69
|
+
start_server 55441
|
|
70
|
+
start_server 55442
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
c.after(:suite) { stop_servers }
|
|
74
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: manticore
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: java
|
|
6
|
+
authors:
|
|
7
|
+
- Chris Heald
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-02-17 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: addressable
|
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.3'
|
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ~>
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: '2.3'
|
|
25
|
+
prerelease: false
|
|
26
|
+
type: :runtime
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.3'
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ~>
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '1.3'
|
|
39
|
+
prerelease: false
|
|
40
|
+
type: :development
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - '>='
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
prerelease: false
|
|
54
|
+
type: :development
|
|
55
|
+
description: Manticore is an HTTP client built on the Apache HttpCore components
|
|
56
|
+
email:
|
|
57
|
+
- cheald@mashable.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- .gitignore
|
|
63
|
+
- .travis.yml
|
|
64
|
+
- APACHE-LICENSE-2.0.txt
|
|
65
|
+
- Gemfile
|
|
66
|
+
- LICENSE.txt
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- lib/jar/commons-logging-1.1.3.jar
|
|
70
|
+
- lib/jar/httpclient-4.3.2.jar
|
|
71
|
+
- lib/jar/httpcore-4.3.1.jar
|
|
72
|
+
- lib/manticore.rb
|
|
73
|
+
- lib/manticore/async_response.rb
|
|
74
|
+
- lib/manticore/client.rb
|
|
75
|
+
- lib/manticore/facade.rb
|
|
76
|
+
- lib/manticore/response.rb
|
|
77
|
+
- lib/manticore/version.rb
|
|
78
|
+
- manticore.gemspec
|
|
79
|
+
- spec/manticore/client_spec.rb
|
|
80
|
+
- spec/manticore/facade_spec.rb
|
|
81
|
+
- spec/manticore/response_spec.rb
|
|
82
|
+
- spec/spec_helper.rb
|
|
83
|
+
homepage: https://github.com/cheald/manticore
|
|
84
|
+
licenses:
|
|
85
|
+
- MIT
|
|
86
|
+
metadata: {}
|
|
87
|
+
post_install_message:
|
|
88
|
+
rdoc_options: []
|
|
89
|
+
require_paths:
|
|
90
|
+
- lib
|
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - '>='
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
|
+
requirements:
|
|
98
|
+
- - '>='
|
|
99
|
+
- !ruby/object:Gem::Version
|
|
100
|
+
version: '0'
|
|
101
|
+
requirements: []
|
|
102
|
+
rubyforge_project:
|
|
103
|
+
rubygems_version: 2.2.1
|
|
104
|
+
signing_key:
|
|
105
|
+
specification_version: 4
|
|
106
|
+
summary: Manticore is an HTTP client built on the Apache HttpCore components
|
|
107
|
+
test_files:
|
|
108
|
+
- spec/manticore/client_spec.rb
|
|
109
|
+
- spec/manticore/facade_spec.rb
|
|
110
|
+
- spec/manticore/response_spec.rb
|
|
111
|
+
- spec/spec_helper.rb
|