require 'json' module RackCheck::Spec RSpec.describe "Rack env variables" do ENV_RU = %Q{ require 'json' run ->(env) { [200, {"Content-Type" => "application/json"}, [JSON.dump(env)]] } } def with_server(ru_file) yield start_server(ru_file) ensure stop_server end def start_server(ru_file) @server = ServerManager.new(RackCheck::Spec::server_context, ru_file) @endpoint = @server.run end def stop_server @server.stop end describe "CGI style variables" do before :all do start_server(ENV_RU) end after :all do stop_server end it "includes the request method" do result = JSON.load HTTP.get(@endpoint).to_s expect(result['REQUEST_METHOD']).to eq "GET" result = JSON.load HTTP.post(@endpoint).to_s expect(result['REQUEST_METHOD']).to eq "POST" end it "includes parts extracted from the url" do result = JSON.load HTTP.get(@endpoint + '/bladiebla?querystring').to_s expect(result['SCRIPT_NAME']).to eq "" expect(result['PATH_INFO']).to eq "/bladiebla" expect(result['QUERY_STRING']).to eq "querystring" end it "includes information about the server address" do result = JSON.load HTTP.get(@endpoint).to_s expect(result['SERVER_NAME']).to eq "localhost" expect(result['SERVER_PORT']).to eq "54123" end it "includes any client supplied headers" do result = JSON.load HTTP.headers(random: 'bla').get(@endpoint).to_s expect(result['HTTP_RANDOM']).to eq "bla" end end describe "special rack variables" do it "includes information about the server" do with_server(ENV_RU) do |endpoint| result = JSON.load HTTP.get(endpoint).to_s expect(result['rack.version'].first).to be >= 1 expect(result['rack.url_scheme']).to eq 'http' expect(result).to include('rack.multithread') expect(result).to include('rack.multiprocess') expect(result).to include('rack.run_once') end end describe "includes an input stream" do it "exposes an input stream that can be 'gets'ed until it returns nil" do with_server(%Q{ require 'json' run ->(env) { result = "" while !(next_value = env['rack.input'].gets).nil? result << next_value end [200, {"Content-Type" => "application/json"}, [result]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq(example) end end it "exposes an input stream that can be rewinded" do with_server(%Q{ require 'json' run ->(env) { result = "" while !(next_value = env['rack.input'].gets).nil? result << next_value end env['rack.input'].rewind while !(next_value = env['rack.input'].gets).nil? result << next_value end [200, {"Content-Type" => "application/json"}, [result]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq(example + example) end end describe "that exposes an input stream with a #read like IO#read" do it "reads until EOF when called without an argument" do with_server(%Q{ require 'json' run ->(env) { result = env['rack.input'].read [200, {"Content-Type" => "application/json"}, [result]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq(example) end end it "returns '' if no argument given and EOF written" do with_server(%Q{ require 'json' run ->(env) { env['rack.input'].read result = env['rack.input'].read [200, {"Content-Type" => "application/json"}, [result.class.name + result.to_s]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq('String') end end it "returns '' if no argument given and EOF written" do with_server(%Q{ require 'json' run ->(env) { env['rack.input'].read result = env['rack.input'].read(1024) [200, {"Content-Type" => "application/json"}, [result.class.name + result.to_s]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq('NilClass') end end it "can read up to an amount of bytes when length is given" do with_server(%Q{ require 'json' run ->(env) { buffer = "*********************************" env['rack.input'].read(9, buffer) [200, {"Content-Type" => "application/json"}, [buffer]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq('multiline') end end it "places results in a buffer if given" do with_server(%Q{ require 'json' run ->(env) { buffer = "*********************************" env['rack.input'].read(9, buffer) [200, {"Content-Type" => "application/json"}, [buffer]] } }) do |endpoint| example = "multiline\nbody" expect(HTTP.post(endpoint, body: example).to_s).to eq('multiline') end end end end describe "includes an error stream" do it "has a #puts that takes an object that responds to `to_s`" do with_server(%Q{ require 'json' run ->(env) { class S < BasicObject def to_s "result" end end env['rack.errors'].puts S.new [200, {"Content-Type" => "application/json"}, ["Ok"]] } }) do |endpoint| expect(HTTP.get(endpoint).to_s).to eq('Ok') end end it "has a #write that takes a String" do with_server(%Q{ require 'json' run ->(env) { env['rack.errors'].puts 'result' [200, {"Content-Type" => "application/json"}, ["Ok"]] } }) do |endpoint| expect(HTTP.get(endpoint).to_s).to eq('Ok') end end it "has a #flush that takes no arguments" do with_server(%Q{ require 'json' run ->(env) { env['rack.errors'].flush [200, {"Content-Type" => "application/json"}, ["Ok"]] } }) do |endpoint| expect(HTTP.get(endpoint).to_s).to eq('Ok') end end end def supports_hijack? if @supports_hijack.nil? result = '' with_server(ENV_RU) do |endpoint| result = JSON.load HTTP.get(endpoint).to_s end @supports_hijack = result['rack.hijack?'] end @supports_hijack end describe "might support rack hijack" do before :all do skip("Hijack not supported") if not supports_hijack? end it "exposes whether it supports rack hijack" do expect(@supports_hijack).to eq(true) end it "responds to #call which returns an io that is also rack.hijack_io" do with_server(%Q{ require 'json' run ->(env) { io = env['rack.hijack'].call equals = env['rack.hijack_io'] == io io.write("HTTP/1.1 200 OK\r\n") io.write("Connection: Closed\r\n") io.write("Content-Type: text/plain\r\n") io.write("\r\n") io.write("Equals: " + equals.to_s) io.close } }) do |endpoint| expect(HTTP.get(endpoint).to_s).to eq('Equals: true') end end end end end end