Skip to content

Commit

Permalink
Support for mocked client requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Jun 23, 2024
1 parent 1591f3f commit f67783f
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
23 changes: 23 additions & 0 deletions lib/async/http/mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true
#
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

require_relative 'mock/endpoint'
70 changes: 70 additions & 0 deletions lib/async/http/mock/endpoint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frozen_string_literal: true
#
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

require_relative '../protocol'

require 'async/queue'

module Async
module HTTP
module Mock
# This is an endpoint which bridges a client with a local server.
class Endpoint
def initialize(protocol = Protocol::HTTP2, scheme = "http", authority = "localhost", queue: Queue.new)
@protocol = protocol
@scheme = scheme
@authority = authority

@queue = queue
end

attr :protocol
attr :scheme
attr :authority

# Processing incoming connections
# @yield [::HTTP::Protocol::Request] the requests as they come in.
def run(parent: Task.current, &block)
while peer = @queue.dequeue
server = @protocol.server(peer)

parent.async do
server.each(&block)
end
end
end

def connect
local, remote = ::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)

@queue.enqueue(remote)

return local
end

def wrap(endpoint)
self.class.new(@protocol, endpoint.scheme, endpoint.authority, queue: @queue)
end
end
end
end
end
74 changes: 74 additions & 0 deletions test/async/http/mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

require 'async/http/mock'
require 'async/http/endpoint'
require 'async/http/client'

require 'sus/fixtures/async/reactor_context'

describe Async::HTTP::Mock do
include Sus::Fixtures::Async::ReactorContext

let(:endpoint) {Async::HTTP::Mock::Endpoint.new}

it "can respond to requests" do
server = Async do
endpoint.run do |request|
::Protocol::HTTP::Response[200, [], ["Hello World"]]
end
end

client = Async::HTTP::Client.new(endpoint)

response = client.get("/index")

expect(response).to be(:success?)
expect(response.read).to be == "Hello World"
end

with 'mocked client' do
it "can mock a client" do
server = Async do
endpoint.run do |request|
::Protocol::HTTP::Response[200, [], ["Authority: #{request.authority}"]]
end
end

mock(Async::HTTP::Client) do |mock|
replacement_endpoint = self.endpoint

mock.wrap(:new) do |original, original_endpoint, **options|
original.call(replacement_endpoint.wrap(original_endpoint), **options)
end
end

google_endpoint = Async::HTTP::Endpoint.parse("https://www.google.com")
client = Async::HTTP::Client.new(google_endpoint)

response = client.get("/search?q=hello")

expect(response).to be(:success?)
expect(response.read).to be == "Authority: www.google.com"
ensure
response&.close
end
end
end

0 comments on commit f67783f

Please sign in to comment.