LoginSignup
12
13

More than 5 years have passed since last update.

sham_rack使ってみた

Last updated at Posted at 2015-01-14

sham_rackとは

README.md
ShamRack plumbs HTTP requests into Rack.
(ShamRackはHTTPリクエストをRackの中へ送り込みます。)

HTTPリクエストをRackに放り込んで、登録した処理を行う。
Rackミドルウェアのように見える。

何ができるか

HTTPリクエストをリクエストホストに大して投げる前にフックして、あたかも処理されたようにレスポンスを返すことができる。
つまり、StubやMockのようなことができる。

注意点

2015/01/16追記。

あるホストをsham_rackに追加すると、そのホストに対する全てリクエストがsham_rackに食われてしまう(ように見える)。

sham_rackではNet::HTTPにShamRack::NetHTTPをextendしているため、
Net:HTTPを使ったライブラリのリクエストはsham_rackに流れてしまう。
これを回避するためには、TCPSocketやExconの様なsocketを使った通信を行う他ない。
(勉強中なので他のやり方があったら是非教えてください)

使い方

ShamRack.atでリクエストホストを第一引数に、期待する処理をブロックで渡す。
ブロックはRackミドルウェアのcallメソッド内の処理を書くのとほぼ同じ。
ブロック内ではリクエストの情報をRackのEnvとして受け取れる。
ブロックで渡した処理はアプリとしてShamRackに登録される。

HTTPリクエストのStub

例えば、http://www.google.co.jp/ にGETしたら"Hello, world!"が返ってくるようにStubする。

get_http_google_top.rb
require 'sham_rack'

ShamRack.at("www.google.co.jp") do |env|
  if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == "/"
    ["200 OK", { "Content-type" => "text/plain" }, ["Hello, world!"]]
  end
end

response = Net::HTTP.new("www.google.co.jp", 80).get("/")
response.code  #=> "200"
response.body  #=> "Hello, world!"

HTTPSリクエストのStub

HTTPSの場合は、ShamRack.atの第二引数に443番ポートを指定する。

get_https_google_top.rb
require 'sham_rack'

ShamRack.at("www.google.co.jp", 443) do |env|
  if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == "/"
    ["200 OK", { "Content-type" => "text/plain" }, ["Hello, world!"]]
  end
end

https = Net::HTTP.new("www.google.co.jp", 443)
https.use_ssl = true
response = https.get("/")
response.code  #=> "200"
response.body  #=> "Hello, world!"

複数のリクエスト先のStub

複数書くだけ。

get_google_top.rb
ShamRack.at("www.google.co.jp") do |env|
  if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == "/"
    ["200 OK", { "Content-type" => "text/plain" }, ["Hello, world!"]]
  end
end

ShamRack.at("www.google.co.jp", 443) do |env|
  if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == "/"
    ["200 OK", { "Content-type" => "text/plain" }, ["Hello, world!"]]
  end
end

他のStubの書き方

2015/01/16追記。

sham_rackのREADME.mdにも書いてあるが、以下のようにstubすると、同一ホストで登録していないパスへのアクセスが404になる。
これはdefault_responseとしてsham_rackに定義されている。

sham_rack_stub.rb
@stub_app = ShamRack.at("www.google.co.jp", 443).stub
@stub_app.register_resource("/", "Hello, world!", "text/plain")

https = Net::HTTP.new("www.google.co.jp", 443)
https.use_ssl = true
response = https.get("/")
response.code  #=> "200"
response.body  #=> "Hello, world!"

response = https.get("/")
response.code  #=> "404"
response.body  #=> "Not found"

Stubを止める場合

アプリをアンマウントする。登録したアプリ全てがアンマウントされる。

get_http_google_top_and_stub_top.rb

ShamRack.at("www.google.co.jp") do |env|
  if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == "/"
    ["200 OK", { "Content-type" => "text/plain" }, ["Hello, world!"]]
  end
end

puts "----- google (stub) -----"
uri = URI.parse("http://www.google.co.jp/")
res = http(uri).get(uri.path)
p res.code  #=> "200"
p res.body  #=> "Hello, world!"

ShamRack.unmount_all

puts "----- google -----"
uri = URI.parse("http://www.google.co.jp/")
res = http(uri).get(uri.path)
p res.code  #=> "200"
p res.body  #=> "<!doctype html><html itemscope=\"\" itemtype=..."

ShamRackにRackミドルウェアも追加する場合

2015/01/16追記。

use_middleware.rb
class MyMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == "/"
      @app.call(env)
    else
      [404, { "Content-type" => "text/plain" }, ["Not Found"]]
    end
  end
end

rackapp = Proc.new do
  ["200 OK", { "Content-type" => "text/plain" }, ["Hello, world!"]]
end
app = MyMiddleware.new(rackapp)


ShamRack.at("www.google.co.jp") do |env|
  app.call(env)
end

README.mdに書いてある通り、以下のような書き方もできる。

ShamRack.at("www.google.co.jp").rackup do |env|
  use MyMiddleware
  run rackapp
end

感想

  • Rack層でstubができるのですごく便利!
  • テストやMock開発に役立ちそう
12
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13