http_monkey 0.0.1

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.
@@ -0,0 +1,64 @@
1
+ require "net/http"
2
+ require "rack"
3
+ require "httpi"
4
+
5
+ require "http_monkey/version"
6
+ require "http_monkey/entry_point"
7
+ require "http_monkey/configuration"
8
+ require "http_monkey/configuration/behaviours"
9
+ require "http_monkey/configuration/middlewares"
10
+ require "http_monkey/client"
11
+ require "http_monkey/client/http_request"
12
+ require "http_monkey/client/environment"
13
+ require "http_monkey/client/environment_builder"
14
+ require "http_monkey/middlewares"
15
+
16
+ module HttpMonkey
17
+
18
+ def self.at(url)
19
+ default_client.at(url)
20
+ end
21
+
22
+ def self.configure(&block)
23
+ default_client.configure(&block)
24
+ end
25
+
26
+ def self.build(&block)
27
+ HttpMonkey::Client.new.configure(&block)
28
+ end
29
+
30
+ protected
31
+
32
+ def self.default_client
33
+ @@default_client ||= build do
34
+ net_adapter :net_http
35
+ behaviours do
36
+ # Follow redirects
37
+ on([301, 302, 303, 307]) do |client, request, response|
38
+ if (location = response.headers["location"])
39
+ request.url = location
40
+ client.http_request(:get, request)
41
+ else
42
+ raise "HTTP status #{response.code} not supported (or location not found)"
43
+ end
44
+ end
45
+ # By default, always return response
46
+ on_unknown do |client, request, response|
47
+ response
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ HTTPI.log = false
56
+
57
+ # This monkey patch is to avoid a bug from httpi (1.1.1) on ruby 1.8.7
58
+ # that raises "undefined method `use_ssl=' for Net::HTTP"
59
+ if RUBY_VERSION =~ /1\.8/
60
+ class Net::HTTPSession
61
+ def use_ssl=(flag)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,28 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::Client::Environment do
4
+
5
+ subject { HttpMonkey::Client::Environment }
6
+
7
+ describe "#accessor" do
8
+ it "gets like Hash" do
9
+ env = subject.new(:test => "value")
10
+ env[:test].must_equal("value")
11
+ end
12
+ it "sets like Hash" do
13
+ env = subject.new(:test => "value")
14
+ env[:test] = "owned"
15
+ env[:test].must_equal("owned")
16
+ end
17
+ end
18
+
19
+ it "#http_headers" do
20
+ env = subject.new("HTTP_CONTENT_TYPE" => "text/html",
21
+ "HTTP_X_CUSTOM" => "custom")
22
+
23
+ env.http_headers.must_be_instance_of(Hash)
24
+ env.http_headers["Content-Type"].must_equal("text/html")
25
+ env.http_headers["X-Custom"].must_equal("custom")
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::Client do
4
+
5
+ subject do
6
+ HttpMonkey::Client.new
7
+ end
8
+
9
+ it "#at" do
10
+ subject.at("http://server.com").must_be_instance_of(HttpMonkey::EntryPoint)
11
+ end
12
+
13
+ describe "default values" do
14
+ it "#net_adapter" do
15
+ subject.net_adapter.must_equal(:net_http)
16
+ end
17
+ end
18
+
19
+ describe "#configure" do
20
+ it "#net_adapter" do
21
+ subject.configure do
22
+ net_adapter(:curb)
23
+ end
24
+ subject.net_adapter.must_equal(:curb)
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,34 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::Configuration::Behaviours do
4
+
5
+ subject { HttpMonkey::Configuration::Behaviours.new }
6
+
7
+ describe "#on" do
8
+ it "support Integer code" do
9
+ subject.on(1) { "test int" }
10
+
11
+ subject.find(1).call.must_equal("test int")
12
+ subject.find(2).must_be_nil
13
+ end
14
+ it "support Range code" do
15
+ subject.on(90...100) { "test range" }
16
+
17
+ subject.find(90).call.must_equal("test range")
18
+ subject.find(99).call.must_equal("test range")
19
+ subject.find(100).must_be_nil
20
+ end
21
+ it "support Array code (or anything that respond_to include?)" do
22
+ subject.on([2,3]) { "test array" }
23
+
24
+ subject.find(2).call.must_equal("test array")
25
+ subject.find(3).call.must_equal("test array")
26
+ subject.find(1).must_be_nil
27
+ end
28
+ end
29
+
30
+ it "#on_unknown" do
31
+ subject.on_unknown { "ok" }
32
+ subject.unknown_behaviour.call.must_equal("ok")
33
+ end
34
+ end
@@ -0,0 +1,73 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::Configuration::Middlewares do
4
+
5
+ subject { HttpMonkey::Configuration::Middlewares.new }
6
+
7
+ class MiddleBase
8
+ def initialize(app, args = {}, &block)
9
+ @app = app
10
+ @args = args
11
+ @block = block
12
+ end
13
+ def call(env)
14
+ env[:args] = @args
15
+ env[:block] = @block
16
+ env[:app] ||= []
17
+ env[:app] << "before #{self.class.to_s}"
18
+ result = @app.call(env)
19
+ env[:app] << "after #{self.class.to_s}"
20
+ result
21
+ end
22
+ end
23
+
24
+ class Middle1 < MiddleBase; end
25
+ class Middle2 < MiddleBase; end
26
+
27
+ let(:app) do
28
+ Proc.new do |env|
29
+ env[:app] << "app"
30
+ "OK"
31
+ end
32
+ end
33
+
34
+ let(:env) do
35
+ {:app => []}
36
+ end
37
+
38
+ describe "#use" do
39
+ it "delegate args" do
40
+ subject.use Middle1, :arg1 =>'arg1', :arg2 => "arg2"
41
+ subject.execute(app, env)
42
+ env[:args].must_equal({:arg1 =>'arg1', :arg2 => "arg2"})
43
+ end
44
+ it "delegate block" do
45
+ subject.use Middle1 do
46
+ "Middle1 block"
47
+ end
48
+ subject.execute(app, env)
49
+ env[:block].call.must_equal("Middle1 block")
50
+ end
51
+ end
52
+
53
+ describe "#execute" do
54
+ it "without chain" do
55
+ result = subject.execute(app, env)
56
+ result.must_equal("OK")
57
+ end
58
+ it "chain of one" do
59
+ subject.use Middle1
60
+ subject.execute(app, env)
61
+
62
+ env[:app].must_equal(["before Middle1", "app", "after Middle1"])
63
+ end
64
+ it "chain of many (maintain order)" do
65
+ subject.use Middle1
66
+ subject.use Middle2
67
+ subject.execute(app, env)
68
+
69
+ env[:app].must_equal(["before Middle1", "before Middle2", "app", "after Middle2", "after Middle1"])
70
+ end
71
+ end
72
+
73
+ end
@@ -0,0 +1,64 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::Configuration do
4
+
5
+ subject do
6
+ HttpMonkey::Configuration.new
7
+ end
8
+
9
+ describe "#clone" do
10
+ it "#behaviours" do
11
+ clone = subject.clone
12
+ subject.behaviours.wont_be_same_as(clone.behaviours)
13
+ end
14
+ it "#middlewares" do
15
+ clone = subject.clone
16
+ subject.middlewares.wont_be_same_as(clone.middlewares)
17
+ end
18
+ end
19
+
20
+ describe "#net_adapter" do
21
+ it "returns value" do
22
+ subject.net_adapter.must_equal(:net_http)
23
+ end
24
+ it "sets value" do
25
+ subject.net_adapter(:curb)
26
+ subject.net_adapter.must_equal(:curb)
27
+ end
28
+ end
29
+
30
+ describe "#behaviours" do
31
+ it "respond_to" do
32
+ subject.must_respond_to(:behaviours)
33
+ end
34
+ it "returns value" do
35
+ subject.behaviours.must_be_instance_of(HttpMonkey::Configuration::Behaviours)
36
+ end
37
+ it "sets value using block" do
38
+ flag = "out block"
39
+ subject.behaviours do
40
+ self.must_be_instance_of(HttpMonkey::Configuration::Behaviours)
41
+ flag = "inside block"
42
+ end
43
+ flag.must_equal("inside block")
44
+ end
45
+ end
46
+
47
+ describe "#middlewares" do
48
+ it "respond_to" do
49
+ subject.must_respond_to(:middlewares)
50
+ end
51
+ it "returns value" do
52
+ subject.middlewares.must_be_instance_of(HttpMonkey::Configuration::Middlewares)
53
+ end
54
+ it "sets value using block" do
55
+ flag = "out block"
56
+ subject.middlewares do
57
+ self.must_be_instance_of(HttpMonkey::Configuration::Middlewares)
58
+ flag = "inside block"
59
+ end
60
+ flag.must_equal("inside block")
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,135 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::EntryPoint do
4
+
5
+ TEST_URL = "https://www.google.com.br"
6
+
7
+ before do
8
+ @mock_client = stub("client")
9
+ end
10
+
11
+ subject do
12
+ HttpMonkey::EntryPoint.new(@mock_client, TEST_URL)
13
+ end
14
+
15
+ def expects_request_on(client, method, body, &block)
16
+ client.expects(:http_request).with do |method, request|
17
+ if block.respond_to?(:call)
18
+ block_assertion = block.call(method, request)
19
+ else
20
+ block_assertion = true
21
+ end
22
+
23
+ request_url = request.url.select(:scheme, :host).join("://")
24
+
25
+ body_assertion = false
26
+ if body.nil?
27
+ body_assertion = request.body.must_be_nil
28
+ elsif body.is_a?(String)
29
+ body_assertion = request.body.must_equal(body)
30
+ elsif body.is_a?(Regexp)
31
+ body_assertion = request.body.must_match(body)
32
+ end
33
+
34
+ block_assertion && \
35
+ method.must_equal(method) && \
36
+ request_url.must_equal(TEST_URL) && \
37
+ request.must_be_instance_of(HTTPI::Request) && \
38
+ body_assertion
39
+ end
40
+ end
41
+
42
+ it "#get" do
43
+ expects_request_on(@mock_client, :get, nil)
44
+ subject.get
45
+ end
46
+
47
+ it "#get with parameters" do
48
+ expects_request_on(@mock_client, :get, nil) do |method, request|
49
+ request.url.query.must_match(/(p1=param1&p2=param2)|(p2=param2&p1=param1)/)
50
+ end
51
+
52
+ subject.get(:p1 => "param1", :p2 => "param2")
53
+ end
54
+
55
+ it "#post with parameters" do
56
+ expects_request_on(@mock_client, :post, /(b1=param1&b2=param2)|(b2=param2&b1=param1)/)
57
+ subject.post(:b1 => "param1", :b2 => "param2")
58
+ end
59
+
60
+ it "#put with parameters" do
61
+ expects_request_on(@mock_client, :put, /(p1=param1&p2=param2)|(p2=param2&p1=param1)/)
62
+ subject.put(:p1 => "param1", :p2 => "param2")
63
+ end
64
+
65
+ it "#delete" do
66
+ expects_request_on(@mock_client, :delete, nil)
67
+ subject.delete
68
+ end
69
+
70
+ it "HTTP requests should accept configuration block" do
71
+ block = lambda { raise "Not to be raised" }
72
+ @mock_client.expects(:clone).returns(@mock_client)
73
+ @mock_client.expects(:configure).returns(@mock_client)
74
+ expects_request_on(@mock_client, :get, nil)
75
+
76
+ subject.get(&block)
77
+ end
78
+
79
+ describe "FluentInterface -_-" do
80
+
81
+ it "#with_header" do
82
+ expects_request_on(@mock_client, :get, nil) do |method, request|
83
+ request.headers.must_equal({"Content-Type" => "text/html", "X-Custom" => "sample"})
84
+ end
85
+ subject.with_header("Content-Type" => "text/html").
86
+ with_header("X-Custom" => "sample").
87
+ get
88
+ end
89
+
90
+ it "#with_headers" do
91
+ expects_request_on(@mock_client, :get, nil) do |method, request|
92
+ request.headers.must_equal({"Content-Type" => "text/html", "X-Custom" => "sample"})
93
+ end
94
+ subject.with_headers("Content-Type" => "text/html",
95
+ "X-Custom" => "sample").get
96
+ end
97
+
98
+ it "#set_cookie" do
99
+ expects_request_on(@mock_client, :get, nil) do |method, request|
100
+ request.headers["Cookie"].must_equal("name=value;name2=value2")
101
+ end
102
+ subject.set_cookie("name=value;name2=value2").get
103
+ end
104
+
105
+ it "#basic_auth" do
106
+ expects_request_on(@mock_client, :get, nil) do |method, request|
107
+ request.auth.type.must_equal(:basic) && \
108
+ request.auth.credentials.must_equal(["mad", "max"])
109
+ end
110
+ subject.basic_auth("mad", "max").get
111
+ end
112
+
113
+ it "#digest_auth" do
114
+ expects_request_on(@mock_client, :get, nil) do |method, request|
115
+ request.auth.type.must_equal(:digest) && \
116
+ request.auth.credentials.must_equal(["mad", "max"])
117
+ end
118
+ subject.digest_auth("mad", "max").get
119
+ end
120
+
121
+ it "#yield_request" do
122
+ expects_request_on(@mock_client, :get, nil) do |method, request|
123
+ request.proxy.to_s.must_equal("http://proxy.com") && \
124
+ request.open_timeout.must_equal(30) && \
125
+ request.read_timeout.must_equal(15)
126
+ end
127
+ subject.yield_request do |req|
128
+ req.proxy = "http://proxy.com"
129
+ req.open_timeout = 30
130
+ req.read_timeout = 15
131
+ end.get
132
+ end
133
+ end
134
+
135
+ end
@@ -0,0 +1,26 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey do
4
+
5
+ subject { HttpMonkey }
6
+
7
+ it "#at" do
8
+ subject.at("http://google.com.br").must_be_instance_of(HttpMonkey::EntryPoint)
9
+ end
10
+
11
+ it "#configure" do
12
+ flag = "out block"
13
+ subject.configure do
14
+ self.must_be_instance_of(HttpMonkey::Configuration)
15
+ flag = "inside block"
16
+ end
17
+ flag.must_equal("inside block")
18
+ end
19
+
20
+ describe "#build" do
21
+ it "wont be same client" do
22
+ subject.build.wont_be_same_as(HttpMonkey.default_client)
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,32 @@
1
+ require "test_helper"
2
+
3
+ describe HttpMonkey::Middlewares::DefaultHeaders do
4
+
5
+ before do
6
+ @mock_app = stub("app", :call => "stubbed")
7
+ end
8
+
9
+ let(:fake_env) { Hash.new }
10
+ subject { HttpMonkey::Middlewares::DefaultHeaders }
11
+
12
+ it "always call app" do
13
+ @mock_app.expects(:call).with(fake_env)
14
+ subject.new(@mock_app).call(fake_env)
15
+ end
16
+
17
+ it "sets header" do
18
+ middle = subject.new(@mock_app, {"X-Custom" => "value"})
19
+ middle.call(fake_env)
20
+
21
+ fake_env["HTTP_X_CUSTOM"].must_equal("value")
22
+ end
23
+
24
+ it "not overwrite header" do
25
+ fake_env["HTTP_X_CUSTOM"] = "request"
26
+ middle = subject.new(@mock_app, {"X-Custom" => "value"})
27
+ middle.call(fake_env)
28
+
29
+ fake_env["HTTP_X_CUSTOM"].must_equal("request")
30
+ end
31
+
32
+ end
@@ -0,0 +1,73 @@
1
+ require "test_helper"
2
+
3
+ # Inspiration from https://github.com/djanowski/mock-server
4
+ class IntegrationServer
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def start(host = "localhost", port = 4000)
11
+ Thread.new do
12
+ silence_output do # comment this if you want information
13
+ Rack::Server.start(
14
+ :app => @app,
15
+ :server => 'webrick',
16
+ :environment => :none,
17
+ :daemonize => false,
18
+ :Host => host,
19
+ :Port => port
20
+ )
21
+ end
22
+ end
23
+ wait_for_service(host, port)
24
+ true
25
+ end
26
+
27
+ protected
28
+
29
+ # quick and dirty
30
+ def silence_output
31
+ $stdout = File.new('/dev/null', 'w')
32
+ $stderr = File.new('/dev/null', 'w')
33
+ yield
34
+ ensure
35
+ $stdout = STDOUT
36
+ $stderr = STDERR
37
+ end
38
+
39
+ def listening?(host, port)
40
+ begin
41
+ socket = TCPSocket.new(host, port)
42
+ socket.close unless socket.nil?
43
+ true
44
+ rescue Errno::ECONNREFUSED,
45
+ Errno::EBADF, # Windows
46
+ Errno::EADDRNOTAVAIL # Windows
47
+ false
48
+ end
49
+ end
50
+
51
+ def wait_for_service(host, port, timeout = 5)
52
+ start_time = Time.now
53
+
54
+ until listening?(host, port)
55
+ if timeout && (Time.now > (start_time + timeout))
56
+ raise SocketError.new("Socket did not open within #{timeout} seconds")
57
+ end
58
+ end
59
+
60
+ true
61
+ end
62
+
63
+ end
64
+
65
+ class IntegrationServer::InspectEnv
66
+ def initialize(app)
67
+ @app = app
68
+ end
69
+ def call(env)
70
+ puts "-> #{env.inspect}"
71
+ @app.call(env)
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ require "integration/server"
2
+
3
+ VerbsApp = Rack::Builder.new do
4
+ #use IntegrationServer::InspectEnv # i can see clear now the rain is gone ...
5
+ map "/" do
6
+ run lambda { |env|
7
+ env['rack.input'] = env['rack.input'].read if env['rack.input'].respond_to?(:read)
8
+ body = YAML.dump(env)
9
+ [200, {"Content-Type" => "text/plain", "Content-Length" => body.size.to_s}, [body]]
10
+ }
11
+ end
12
+ end
13
+
14
+ IntegrationServer.new(VerbsApp).start
15
+
16
+ describe "Integration Specs - Verbs" do
17
+
18
+ describe "#get" do
19
+ it "no parameter" do
20
+ response = HttpMonkey.at("http://localhost:4000").get
21
+ server_env = YAML.load(response.body)
22
+
23
+ server_env["REQUEST_METHOD"].must_equal("GET")
24
+ server_env["QUERY_STRING"].must_be_empty
25
+ end
26
+ it "with parameters" do
27
+ response = HttpMonkey.at("http://localhost:4000").get(:q => "query")
28
+ server_env = YAML.load(response.body)
29
+
30
+ server_env["REQUEST_METHOD"].must_equal("GET")
31
+ server_env["QUERY_STRING"].must_equal("q=query")
32
+ end
33
+ end
34
+
35
+ it "#post" do
36
+ response = HttpMonkey.at("http://localhost:4000").post(:var => "post_var")
37
+ server_env = YAML.load(response.body)
38
+
39
+ server_env["REQUEST_METHOD"].must_equal("POST")
40
+ server_env["rack.input"].must_equal("var=post_var")
41
+ end
42
+
43
+ it "#put" do
44
+ response = HttpMonkey.at("http://localhost:4000").put(:var => "put_var")
45
+ server_env = YAML.load(response.body)
46
+
47
+ server_env["REQUEST_METHOD"].must_equal("PUT")
48
+ server_env["rack.input"].must_equal("var=put_var")
49
+ end
50
+
51
+ it "#delete" do
52
+ response = HttpMonkey.at("http://localhost:4000").delete
53
+ server_env = YAML.load(response.body)
54
+
55
+ server_env["REQUEST_METHOD"].must_equal("DELETE")
56
+ end
57
+
58
+ end
@@ -0,0 +1,9 @@
1
+ require "http_monkey"
2
+
3
+ require "minitest/autorun"
4
+ require "minitest/reporters"
5
+
6
+ require "mocha"
7
+
8
+ MiniTest::Unit.runner = MiniTest::SuiteRunner.new
9
+ MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new