mirror of
https://gitea.invidious.io/iv-org/shard-kemal.git
synced 2024-08-15 00:53:36 +00:00
Decouple specs from global state to isolated tests
This commit is contained in:
parent
29b18c927c
commit
2e42b3f48c
19 changed files with 336 additions and 304 deletions
|
@ -1,81 +1,62 @@
|
||||||
require "./spec_helper"
|
require "./spec_helper"
|
||||||
|
|
||||||
describe "Context" do
|
describe "Context" do
|
||||||
context "headers" do
|
|
||||||
it "sets content type" do
|
it "sets content type" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
env.response.content_type = "application/json"
|
env.response.content_type = "application/json"
|
||||||
"Hello"
|
"Hello"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.headers["Content-Type"].should eq("application/json")
|
client_response.headers["Content-Type"].should eq("application/json")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "parses headers" do
|
it "parses headers" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
name = env.request.headers["name"]
|
name = env.request.headers["name"]
|
||||||
"Hello #{name}"
|
"Hello #{name}"
|
||||||
end
|
end
|
||||||
headers = HTTP::Headers.new
|
headers = HTTP::Headers.new
|
||||||
headers["name"] = "kemal"
|
headers["name"] = "kemal"
|
||||||
request = HTTP::Request.new("GET", "/", headers)
|
request = HTTP::Request.new("GET", "/", headers)
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should eq "Hello kemal"
|
client_response.body.should eq "Hello kemal"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets response headers" do
|
it "sets response headers" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
env.response.headers.add "Accept-Language", "tr"
|
env.response.headers.add "Accept-Language", "tr"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.headers["Accept-Language"].should eq "tr"
|
client_response.headers["Accept-Language"].should eq "tr"
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context "storage" do
|
it "can store variables" do
|
||||||
it "can store primitive types" do
|
app = Kemal::Base.new
|
||||||
before_get "/" do |env|
|
app.before_get "/" do |env|
|
||||||
env.set "before_get", "Kemal"
|
|
||||||
env.set "before_get_int", 123
|
|
||||||
env.set "before_get_float", 3.5
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/" do |env|
|
|
||||||
{
|
|
||||||
before_get: env.get("before_get"),
|
|
||||||
before_get_int: env.get("before_get_int"),
|
|
||||||
before_get_float: env.get("before_get_float"),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
|
||||||
io = IO::Memory.new
|
|
||||||
response = HTTP::Server::Response.new(io)
|
|
||||||
context = HTTP::Server::Context.new(request, response)
|
|
||||||
Kemal::FilterHandler::INSTANCE.call(context)
|
|
||||||
Kemal::RouteHandler::INSTANCE.call(context)
|
|
||||||
|
|
||||||
context.get("before_get").should eq "Kemal"
|
|
||||||
context.get("before_get_int").should eq 123
|
|
||||||
context.get("before_get_float").should eq 3.5
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can store custom types" do
|
|
||||||
before_get "/" do |env|
|
|
||||||
t = TestContextStorageType.new
|
t = TestContextStorageType.new
|
||||||
t.id = 32
|
t.id = 32
|
||||||
a = AnotherContextStorageType.new
|
a = AnotherContextStorageType.new
|
||||||
|
env.set "key", "value"
|
||||||
|
env.set "before_get", "Kemal"
|
||||||
|
env.set "before_get_int", 123
|
||||||
env.set "before_get_context_test", t
|
env.set "before_get_context_test", t
|
||||||
env.set "another_context_test", a
|
env.set "another_context_test", a
|
||||||
|
env.set "before_get_float", 3.5
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/" do |env|
|
app.get "/" do |env|
|
||||||
|
env.set "key", "value"
|
||||||
{
|
{
|
||||||
|
key: env.get("key"),
|
||||||
|
before_get: env.get("before_get"),
|
||||||
|
before_get_int: env.get("before_get_int"),
|
||||||
|
before_get_float: env.get("before_get_float"),
|
||||||
before_get_context_test: env.get("before_get_context_test"),
|
before_get_context_test: env.get("before_get_context_test"),
|
||||||
another_context_test: env.get("another_context_test"),
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -83,20 +64,9 @@ describe "Context" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::FilterHandler::INSTANCE.call(context)
|
context.app = app
|
||||||
Kemal::RouteHandler::INSTANCE.call(context)
|
app.filter_handler.call(context)
|
||||||
|
app.route_handler.call(context)
|
||||||
context.get("before_get_context_test").as(TestContextStorageType).id.should eq 32
|
|
||||||
context.get("another_context_test").as(AnotherContextStorageType).name.should eq "kemal-context"
|
|
||||||
end
|
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
|
||||||
io = IO::Memory.new
|
|
||||||
response = HTTP::Server::Response.new(io)
|
|
||||||
context = HTTP::Server::Context.new(request, response)
|
|
||||||
context.app = Kemal.application
|
|
||||||
Kemal.application.filter_handler.call(context)
|
|
||||||
Kemal.application.route_handler.call(context)
|
|
||||||
context.store["key"].should eq "value"
|
context.store["key"].should eq "value"
|
||||||
context.store["before_get"].should eq "Kemal"
|
context.store["before_get"].should eq "Kemal"
|
||||||
context.store["before_get_int"].should eq 123
|
context.store["before_get_int"].should eq 123
|
||||||
|
|
58
spec/dsl_helper.cr
Normal file
58
spec/dsl_helper.cr
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
require "./spec_helper"
|
||||||
|
require "../src/kemal/dsl"
|
||||||
|
|
||||||
|
include Kemal
|
||||||
|
|
||||||
|
class CustomLogHandler < Kemal::BaseLogHandler
|
||||||
|
def call(env)
|
||||||
|
call_next env
|
||||||
|
end
|
||||||
|
|
||||||
|
def write(message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestContextStorageType
|
||||||
|
property id
|
||||||
|
@id = 1
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
@id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class AnotherContextStorageType
|
||||||
|
property name
|
||||||
|
@name = "kemal-context"
|
||||||
|
end
|
||||||
|
|
||||||
|
add_context_storage_type(TestContextStorageType)
|
||||||
|
add_context_storage_type(AnotherContextStorageType)
|
||||||
|
|
||||||
|
def create_request_and_return_io(handler, request)
|
||||||
|
io = IO::Memory.new
|
||||||
|
response = HTTP::Server::Response.new(io)
|
||||||
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = Kemal.application
|
||||||
|
handler.call(context)
|
||||||
|
response.close
|
||||||
|
io.rewind
|
||||||
|
io
|
||||||
|
end
|
||||||
|
|
||||||
|
def call_request_on_app(request)
|
||||||
|
call_request_on_app(Kemal.application, request)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_main_handler
|
||||||
|
build_main_handler(Kemal.application)
|
||||||
|
end
|
||||||
|
|
||||||
|
Spec.before_each do
|
||||||
|
config = Kemal.config
|
||||||
|
config.env = "development"
|
||||||
|
end
|
||||||
|
|
||||||
|
Spec.after_each do
|
||||||
|
Kemal.application.clear
|
||||||
|
end
|
|
@ -1,18 +1,13 @@
|
||||||
require "./spec_helper"
|
require "./dsl_helper"
|
||||||
|
|
||||||
private INSTANCE = Kemal::ExceptionHandler.new
|
|
||||||
|
|
||||||
describe "Kemal::ExceptionHandler" do
|
describe "Kemal::ExceptionHandler" do
|
||||||
it "renders 404 on route not found" do
|
it "renders 404 on route not found" do
|
||||||
get "/" do
|
|
||||||
"Hello"
|
|
||||||
end
|
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/asd")
|
request = HTTP::Request.new("GET", "/asd")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
INSTANCE.call(context)
|
subject = Kemal::ExceptionHandler.new(Kemal::Base.new)
|
||||||
|
subject.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -20,19 +15,21 @@ describe "Kemal::ExceptionHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders custom error" do
|
it "renders custom error" do
|
||||||
error 403 do
|
|
||||||
"403 error"
|
|
||||||
end
|
|
||||||
get "/" do |env|
|
|
||||||
env.response.status_code = 403
|
|
||||||
end
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
app = Kemal::Base.new
|
||||||
INSTANCE.next = Kemal::RouteHandler.new
|
app.error 403 do
|
||||||
INSTANCE.call(context)
|
"403 error"
|
||||||
|
end
|
||||||
|
app.get "/" do |env|
|
||||||
|
env.response.status_code = 403
|
||||||
|
end
|
||||||
|
context.app = app
|
||||||
|
subject = Kemal::ExceptionHandler.new(app)
|
||||||
|
subject.next = Kemal::RouteHandler.new
|
||||||
|
subject.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -42,19 +39,21 @@ describe "Kemal::ExceptionHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders custom 500 error" do
|
it "renders custom 500 error" do
|
||||||
error 500 do
|
|
||||||
"Something happened"
|
|
||||||
end
|
|
||||||
get "/" do |env|
|
|
||||||
env.response.status_code = 500
|
|
||||||
end
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
app = Kemal::Base.new
|
||||||
INSTANCE.next = Kemal::RouteHandler.new
|
app.error 500 do |env|
|
||||||
INSTANCE.call(context)
|
"Something happened"
|
||||||
|
end
|
||||||
|
app.get "/" do |env|
|
||||||
|
env.response.status_code = 500
|
||||||
|
end
|
||||||
|
context.app = app
|
||||||
|
subject = Kemal::ExceptionHandler.new(app)
|
||||||
|
subject.next = Kemal::RouteHandler.new
|
||||||
|
subject.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -64,20 +63,22 @@ describe "Kemal::ExceptionHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "keeps the specified error Content-Type" do
|
it "keeps the specified error Content-Type" do
|
||||||
error 500 do
|
|
||||||
"Something happened"
|
|
||||||
end
|
|
||||||
get "/" do |env|
|
|
||||||
env.response.content_type = "application/json"
|
|
||||||
env.response.status_code = 500
|
|
||||||
end
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
app = Kemal::Base.new
|
||||||
INSTANCE.next = Kemal::RouteHandler.new
|
app.error 500 do |env|
|
||||||
INSTANCE.call(context)
|
"Something happened"
|
||||||
|
end
|
||||||
|
app.get "/" do |env|
|
||||||
|
env.response.content_type = "application/json"
|
||||||
|
env.response.status_code = 500
|
||||||
|
end
|
||||||
|
context.app = app
|
||||||
|
subject = Kemal::ExceptionHandler.new(app)
|
||||||
|
subject.next = Kemal::RouteHandler.new
|
||||||
|
subject.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -87,20 +88,22 @@ describe "Kemal::ExceptionHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders custom error with env and error" do
|
it "renders custom error with env and error" do
|
||||||
error 500 do |_, err|
|
|
||||||
err.message
|
|
||||||
end
|
|
||||||
get "/" do |env|
|
|
||||||
env.response.content_type = "application/json"
|
|
||||||
env.response.status_code = 500
|
|
||||||
end
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
app = Kemal::Base.new
|
||||||
INSTANCE.next = Kemal::RouteHandler.new
|
app.error 500 do |env, err|
|
||||||
INSTANCE.call(context)
|
err.message
|
||||||
|
end
|
||||||
|
app.get "/" do |env|
|
||||||
|
env.response.content_type = "application/json"
|
||||||
|
env.response.status_code = 500
|
||||||
|
end
|
||||||
|
context.app = app
|
||||||
|
subject = Kemal::ExceptionHandler.new(Kemal::Base.new)
|
||||||
|
subject.next = Kemal::RouteHandler.new
|
||||||
|
subject.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
|
|
@ -78,81 +78,88 @@ describe "Handler" do
|
||||||
filter_middleware._add_route_filter("GET", "/", :before) do |env|
|
filter_middleware._add_route_filter("GET", "/", :before) do |env|
|
||||||
env.response << " so"
|
env.response << " so"
|
||||||
end
|
end
|
||||||
Kemal.application.add_filter_handler filter_middleware
|
app = Kemal::Base.new
|
||||||
|
app.add_filter_handler filter_middleware
|
||||||
|
|
||||||
add_handler CustomTestHandler.new
|
app.add_handler CustomTestHandler.new
|
||||||
|
|
||||||
get "/" do
|
app.get "/" do |env|
|
||||||
" Great"
|
" Great"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.status_code.should eq(200)
|
client_response.status_code.should eq(200)
|
||||||
client_response.body.should eq("Kemal is so Great")
|
client_response.body.should eq("Kemal is so Great")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "runs specified only_routes in middleware" do
|
it "runs specified only_routes in middleware" do
|
||||||
get "/only" do
|
app = Kemal::Base.new
|
||||||
|
app.get "/only" do |env|
|
||||||
"Get"
|
"Get"
|
||||||
end
|
end
|
||||||
add_handler OnlyHandler.new
|
app.add_handler OnlyHandler.new
|
||||||
request = HTTP::Request.new("GET", "/only")
|
request = HTTP::Request.new("GET", "/only")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should eq "OnlyGet"
|
client_response.body.should eq "OnlyGet"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't run specified exclude_routes in middleware" do
|
it "doesn't run specified exclude_routes in middleware" do
|
||||||
get "/" do
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
"Get"
|
"Get"
|
||||||
end
|
end
|
||||||
get "/exclude" do
|
app.get "/exclude" do
|
||||||
"Exclude"
|
"Exclude"
|
||||||
end
|
end
|
||||||
add_handler ExcludeHandler.new
|
app.add_handler ExcludeHandler.new
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should eq "ExcludeGet"
|
client_response.body.should eq "ExcludeGet"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "runs specified only_routes with method in middleware" do
|
it "runs specified only_routes with method in middleware" do
|
||||||
post "/only" do
|
app = Kemal::Base.new
|
||||||
|
app.post "/only" do
|
||||||
"Post"
|
"Post"
|
||||||
end
|
end
|
||||||
get "/only" do
|
app.get "/only" do
|
||||||
"Get"
|
"Get"
|
||||||
end
|
end
|
||||||
add_handler PostOnlyHandler.new
|
app.add_handler PostOnlyHandler.new
|
||||||
request = HTTP::Request.new("POST", "/only")
|
request = HTTP::Request.new("POST", "/only")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should eq "OnlyPost"
|
client_response.body.should eq "OnlyPost"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't run specified exclude_routes with method in middleware" do
|
it "doesn't run specified exclude_routes with method in middleware" do
|
||||||
post "/exclude" do
|
app = Kemal::Base.new
|
||||||
|
app.post "/exclude" do
|
||||||
"Post"
|
"Post"
|
||||||
end
|
end
|
||||||
post "/only" do
|
app.post "/only" do
|
||||||
"Post"
|
"Post"
|
||||||
end
|
end
|
||||||
add_handler PostOnlyHandler.new
|
app.add_handler PostOnlyHandler.new
|
||||||
add_handler PostExcludeHandler.new
|
app.add_handler PostExcludeHandler.new
|
||||||
request = HTTP::Request.new("POST", "/only")
|
request = HTTP::Request.new("POST", "/only")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should eq "OnlyExcludePost"
|
client_response.body.should eq "OnlyExcludePost"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds a handler at given position" do
|
it "adds a handler at given position" do
|
||||||
post_handler = PostOnlyHandler.new
|
post_handler = PostOnlyHandler.new
|
||||||
add_handler post_handler, 1
|
app = Kemal::Base.new
|
||||||
Kemal.application.setup
|
app.add_handler post_handler, 1
|
||||||
Kemal.application.handlers[1].should eq post_handler
|
app.setup
|
||||||
|
app.handlers[1].should eq post_handler
|
||||||
end
|
end
|
||||||
|
|
||||||
it "assigns custom handlers" do
|
it "assigns custom handlers" do
|
||||||
post_only_handler = PostOnlyHandler.new
|
post_only_handler = PostOnlyHandler.new
|
||||||
post_exclude_handler = PostExcludeHandler.new
|
post_exclude_handler = PostExcludeHandler.new
|
||||||
Kemal.application.handlers = [post_only_handler, post_exclude_handler]
|
app = Kemal::Base.new
|
||||||
Kemal.application.handlers.should eq [post_only_handler, post_exclude_handler]
|
app.handlers = [post_only_handler, post_exclude_handler]
|
||||||
|
app.handlers.should eq [post_only_handler, post_exclude_handler]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is able to use %w in macros" do
|
it "is able to use %w in macros" do
|
||||||
|
|
|
@ -10,9 +10,10 @@ describe "Macros" do
|
||||||
|
|
||||||
describe "#add_handler" do
|
describe "#add_handler" do
|
||||||
it "adds a custom handler" do
|
it "adds a custom handler" do
|
||||||
add_handler CustomTestHandler.new
|
app = Kemal::Application.new
|
||||||
Kemal.application.setup
|
app.add_handler CustomTestHandler.new
|
||||||
Kemal.application.handlers.size.should eq 8
|
app.setup
|
||||||
|
app.handlers.size.should eq 8
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -23,7 +24,6 @@ describe "Macros" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets a custom logger" do
|
it "sets a custom logger" do
|
||||||
config = Kemal.config
|
|
||||||
logger CustomLogHandler.new
|
logger CustomLogHandler.new
|
||||||
Kemal.application.logger.should be_a(CustomLogHandler)
|
Kemal.application.logger.should be_a(CustomLogHandler)
|
||||||
end
|
end
|
||||||
|
@ -31,32 +31,34 @@ describe "Macros" do
|
||||||
|
|
||||||
describe "#halt" do
|
describe "#halt" do
|
||||||
it "can break block with halt macro" do
|
it "can break block with halt macro" do
|
||||||
get "/non-breaking" do
|
app = Kemal::Base.new
|
||||||
|
app.get "/non-breaking" do |env|
|
||||||
"hello"
|
"hello"
|
||||||
"world"
|
"world"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/non-breaking")
|
request = HTTP::Request.new("GET", "/non-breaking")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.status_code.should eq(200)
|
client_response.status_code.should eq(200)
|
||||||
client_response.body.should eq("world")
|
client_response.body.should eq("world")
|
||||||
|
|
||||||
get "/breaking" do |env|
|
app.get "/breaking" do |env|
|
||||||
halt env, 404, "hello"
|
halt env, 404, "hello"
|
||||||
"world"
|
"world"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/breaking")
|
request = HTTP::Request.new("GET", "/breaking")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.status_code.should eq(404)
|
client_response.status_code.should eq(404)
|
||||||
client_response.body.should eq("hello")
|
client_response.body.should eq("hello")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can break block with halt macro using default values" do
|
it "can break block with halt macro using default values" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
halt env
|
halt env
|
||||||
"world"
|
"world"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.status_code.should eq(200)
|
client_response.status_code.should eq(200)
|
||||||
client_response.body.should eq("")
|
client_response.body.should eq("")
|
||||||
end
|
end
|
||||||
|
@ -64,7 +66,8 @@ describe "Macros" do
|
||||||
|
|
||||||
describe "#headers" do
|
describe "#headers" do
|
||||||
it "can add headers" do
|
it "can add headers" do
|
||||||
get "/headers" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/headers" do |env|
|
||||||
env.response.headers.add "Content-Type", "image/png"
|
env.response.headers.add "Content-Type", "image/png"
|
||||||
headers env, {
|
headers env, {
|
||||||
"Access-Control-Allow-Origin" => "*",
|
"Access-Control-Allow-Origin" => "*",
|
||||||
|
@ -72,7 +75,7 @@ describe "Macros" do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/headers")
|
request = HTTP::Request.new("GET", "/headers")
|
||||||
response = call_request_on_app(request)
|
response = call_request_on_app(app, request)
|
||||||
response.headers["Access-Control-Allow-Origin"].should eq("*")
|
response.headers["Access-Control-Allow-Origin"].should eq("*")
|
||||||
response.headers["Content-Type"].should eq("text/plain")
|
response.headers["Content-Type"].should eq("text/plain")
|
||||||
end
|
end
|
||||||
|
@ -80,36 +83,39 @@ describe "Macros" do
|
||||||
|
|
||||||
describe "#send_file" do
|
describe "#send_file" do
|
||||||
it "sends file with given path and default mime-type" do
|
it "sends file with given path and default mime-type" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
send_file env, "./spec/asset/hello.ecr"
|
send_file env, "./spec/asset/hello.ecr"
|
||||||
end
|
end
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
response = call_request_on_app(request)
|
response = call_request_on_app(app, request)
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.headers["Content-Type"].should eq("application/octet-stream")
|
response.headers["Content-Type"].should eq("application/octet-stream")
|
||||||
response.headers["Content-Length"].should eq("18")
|
response.headers["Content-Length"].should eq("18")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sends file with given path and given mime-type" do
|
it "sends file with given path and given mime-type" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
send_file env, "./spec/asset/hello.ecr", "image/jpeg"
|
send_file env, "./spec/asset/hello.ecr", "image/jpeg"
|
||||||
end
|
end
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
response = call_request_on_app(request)
|
response = call_request_on_app(app, request)
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.headers["Content-Type"].should eq("image/jpeg")
|
response.headers["Content-Type"].should eq("image/jpeg")
|
||||||
response.headers["Content-Length"].should eq("18")
|
response.headers["Content-Length"].should eq("18")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sends file with binary stream" do
|
it "sends file with binary stream" do
|
||||||
get "/" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/" do |env|
|
||||||
send_file env, "Serdar".to_slice
|
send_file env, "Serdar".to_slice
|
||||||
end
|
end
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
response = call_request_on_app(request)
|
response = call_request_on_app(app, request)
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.headers["Content-Type"].should eq("application/octet-stream")
|
response.headers["Content-Type"].should eq("application/octet-stream")
|
||||||
response.headers["Content-Length"].should eq("6")
|
response.headers["Content-Length"].should eq("6")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require "./spec_helper"
|
require "./dsl_helper"
|
||||||
|
|
||||||
describe "ParamParser" do
|
describe "ParamParser" do
|
||||||
it "parses query params" do
|
it "parses query params" do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require "./spec_helper"
|
require "./dsl_helper"
|
||||||
|
|
||||||
describe "Kemal::RouteHandler" do
|
describe "Kemal::RouteHandler" do
|
||||||
it "routes" do
|
it "routes" do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require "./spec_helper"
|
require "./dsl_helper"
|
||||||
|
|
||||||
describe "Route" do
|
describe "Route" do
|
||||||
describe "match?" do
|
describe "match?" do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require "./spec_helper"
|
require "./dsl_helper"
|
||||||
|
|
||||||
private def run(code)
|
private def run(code)
|
||||||
code = <<-CR
|
code = <<-CR
|
||||||
|
|
|
@ -1,89 +1,24 @@
|
||||||
require "spec"
|
require "spec"
|
||||||
require "../src/**"
|
require "../src/kemal"
|
||||||
require "../src/kemal/base"
|
|
||||||
require "../src/kemal/dsl"
|
|
||||||
|
|
||||||
include Kemal
|
def call_request_on_app(app, request)
|
||||||
|
|
||||||
class CustomLogHandler < Kemal::BaseLogHandler
|
|
||||||
def call(env)
|
|
||||||
call_next env
|
|
||||||
end
|
|
||||||
|
|
||||||
def write(message)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class TestContextStorageType
|
|
||||||
property id
|
|
||||||
@id = 1
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
@id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class AnotherContextStorageType
|
|
||||||
property name
|
|
||||||
@name = "kemal-context"
|
|
||||||
end
|
|
||||||
|
|
||||||
add_context_storage_type(TestContextStorageType)
|
|
||||||
add_context_storage_type(AnotherContextStorageType)
|
|
||||||
|
|
||||||
def create_request_and_return_io_and_context(handler, request)
|
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
main_handler = build_main_handler(app)
|
||||||
handler.call(context)
|
|
||||||
response.close
|
|
||||||
io.rewind
|
|
||||||
{io, context}
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_ws_request_and_return_io_and_context(handler, request)
|
|
||||||
io = IO::Memory.new
|
|
||||||
response = HTTP::Server::Response.new(io)
|
|
||||||
context = HTTP::Server::Context.new(request, response)
|
|
||||||
context.app = Kemal.application
|
|
||||||
begin
|
|
||||||
handler.call context
|
|
||||||
rescue IO::Error
|
|
||||||
# Raises because the IO::Memory is empty
|
|
||||||
end
|
|
||||||
io.rewind
|
|
||||||
{io, context}
|
|
||||||
end
|
|
||||||
|
|
||||||
def call_request_on_app(request)
|
|
||||||
io = IO::Memory.new
|
|
||||||
response = HTTP::Server::Response.new(io)
|
|
||||||
context = HTTP::Server::Context.new(request, response)
|
|
||||||
main_handler = build_main_handler
|
|
||||||
main_handler.call context
|
main_handler.call context
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
HTTP::Client::Response.from_io(io, decompress: false)
|
HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_main_handler
|
def build_main_handler(app)
|
||||||
Kemal.application.setup
|
app.setup
|
||||||
main_handler = Kemal.application.handlers.first
|
main_handler = app.handlers.first
|
||||||
current_handler = main_handler
|
current_handler = main_handler
|
||||||
Kemal.application.handlers.each_with_index do |handler, index|
|
app.handlers.each_with_index do |handler, index|
|
||||||
current_handler.next = handler
|
current_handler.next = handler
|
||||||
current_handler = handler
|
current_handler = handler
|
||||||
end
|
end
|
||||||
main_handler
|
main_handler
|
||||||
end
|
end
|
||||||
|
|
||||||
Spec.before_each do
|
|
||||||
config = Kemal.config
|
|
||||||
config.env = "development"
|
|
||||||
config.logging = false
|
|
||||||
end
|
|
||||||
|
|
||||||
Spec.after_each do
|
|
||||||
Kemal.application.clear
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
require "./spec_helper"
|
require "./spec_helper"
|
||||||
|
|
||||||
private def handle(request, fallthrough = true)
|
private def handle(request, config = default_config, fallthrough = true)
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
handler = Kemal::StaticFileHandler.new config, fallthrough
|
||||||
handler = Kemal::StaticFileHandler.new "#{__DIR__}/static", fallthrough
|
|
||||||
handler.call context
|
handler.call context
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
HTTP::Client::Response.from_io(io)
|
HTTP::Client::Response.from_io(io)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def default_config
|
||||||
|
Kemal::Config.new.tap do |config|
|
||||||
|
config.public_folder = "#{__DIR__}/static"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe Kemal::StaticFileHandler do
|
describe Kemal::StaticFileHandler do
|
||||||
file = File.open "#{__DIR__}/static/dir/test.txt"
|
file = File.open "#{__DIR__}/static/dir/test.txt"
|
||||||
file_size = file.size
|
file_size = file.size
|
||||||
|
@ -37,38 +42,43 @@ describe Kemal::StaticFileHandler do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not list directory's entries" do
|
it "should not list directory's entries" do
|
||||||
serve_static({"gzip" => true, "dir_listing" => false})
|
config = default_config
|
||||||
response = handle HTTP::Request.new("GET", "/dir/")
|
config.serve_static = {"gzip" => true, "dir_listing" => false}
|
||||||
|
response = handle HTTP::Request.new("GET", "/dir/"), config
|
||||||
response.status_code.should eq(404)
|
response.status_code.should eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should list directory's entries when config is set" do
|
it "should list directory's entries when config is set" do
|
||||||
serve_static({"gzip" => true, "dir_listing" => true})
|
config = default_config
|
||||||
response = handle HTTP::Request.new("GET", "/dir/")
|
config.serve_static = {"gzip" => true, "dir_listing" => true}
|
||||||
|
response = handle HTTP::Request.new("GET", "/dir/"), config
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.body.should match(/test.txt/)
|
response.body.should match(/test.txt/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should gzip a file if config is true, headers accept gzip and file is > 880 bytes" do
|
it "should gzip a file if config is true, headers accept gzip and file is > 880 bytes" do
|
||||||
serve_static({"gzip" => true, "dir_listing" => true})
|
config = default_config
|
||||||
|
config.serve_static = {"gzip" => true, "dir_listing" => true}
|
||||||
headers = HTTP::Headers{"Accept-Encoding" => "gzip, deflate, sdch, br"}
|
headers = HTTP::Headers{"Accept-Encoding" => "gzip, deflate, sdch, br"}
|
||||||
response = handle HTTP::Request.new("GET", "/dir/bigger.txt", headers)
|
response = handle HTTP::Request.new("GET", "/dir/bigger.txt", headers), config
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.headers["Content-Encoding"].should eq "gzip"
|
response.headers["Content-Encoding"].should eq "gzip"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not gzip a file if config is true, headers accept gzip and file is < 880 bytes" do
|
it "should not gzip a file if config is true, headers accept gzip and file is < 880 bytes" do
|
||||||
serve_static({"gzip" => true, "dir_listing" => true})
|
config = default_config
|
||||||
|
config.serve_static = {"gzip" => true, "dir_listing" => true}
|
||||||
headers = HTTP::Headers{"Accept-Encoding" => "gzip, deflate, sdch, br"}
|
headers = HTTP::Headers{"Accept-Encoding" => "gzip, deflate, sdch, br"}
|
||||||
response = handle HTTP::Request.new("GET", "/dir/test.txt", headers)
|
response = handle HTTP::Request.new("GET", "/dir/test.txt", headers), config
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.headers["Content-Encoding"]?.should be_nil
|
response.headers["Content-Encoding"]?.should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not gzip a file if config is false, headers accept gzip and file is > 880 bytes" do
|
it "should not gzip a file if config is false, headers accept gzip and file is > 880 bytes" do
|
||||||
serve_static({"gzip" => false, "dir_listing" => true})
|
config = default_config
|
||||||
|
config.serve_static = {"gzip" => false, "dir_listing" => true}
|
||||||
headers = HTTP::Headers{"Accept-Encoding" => "gzip, deflate, sdch, br"}
|
headers = HTTP::Headers{"Accept-Encoding" => "gzip, deflate, sdch, br"}
|
||||||
response = handle HTTP::Request.new("GET", "/dir/bigger.txt", headers)
|
response = handle HTTP::Request.new("GET", "/dir/bigger.txt", headers), config
|
||||||
response.status_code.should eq(200)
|
response.status_code.should eq(200)
|
||||||
response.headers["Content-Encoding"]?.should be_nil
|
response.headers["Content-Encoding"]?.should be_nil
|
||||||
end
|
end
|
||||||
|
@ -97,7 +107,7 @@ describe Kemal::StaticFileHandler do
|
||||||
%w(POST PUT DELETE).each do |method|
|
%w(POST PUT DELETE).each do |method|
|
||||||
response = handle HTTP::Request.new(method, "/dir/test.txt")
|
response = handle HTTP::Request.new(method, "/dir/test.txt")
|
||||||
response.status_code.should eq(404)
|
response.status_code.should eq(404)
|
||||||
response = handle HTTP::Request.new(method, "/dir/test.txt"), false
|
response = handle HTTP::Request.new(method, "/dir/test.txt"), fallthrough: false
|
||||||
response.status_code.should eq(405)
|
response.status_code.should eq(405)
|
||||||
response.headers["Allow"].should eq("GET, HEAD")
|
response.headers["Allow"].should eq("GET, HEAD")
|
||||||
end
|
end
|
||||||
|
@ -133,22 +143,21 @@ describe Kemal::StaticFileHandler do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should handle setting custom headers" do
|
it "should handle setting custom headers" do
|
||||||
headers = Proc(HTTP::Server::Response, String, File::Info, Void).new do |response, path, stat|
|
config = default_config
|
||||||
|
config.static_headers = Proc(HTTP::Server::Response, String, File::Info, Void).new do |response, path, stat|
|
||||||
if path =~ /\.html$/
|
if path =~ /\.html$/
|
||||||
response.headers.add("Access-Control-Allow-Origin", "*")
|
response.headers.add("Access-Control-Allow-Origin", "*")
|
||||||
end
|
end
|
||||||
response.headers.add("Content-Size", stat.size.to_s)
|
response.headers.add("Content-Size", stat.size.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
static_headers(&headers)
|
response = handle HTTP::Request.new("GET", "/dir/test.txt"), config
|
||||||
|
|
||||||
response = handle HTTP::Request.new("GET", "/dir/test.txt")
|
|
||||||
response.headers.has_key?("Access-Control-Allow-Origin").should be_false
|
response.headers.has_key?("Access-Control-Allow-Origin").should be_false
|
||||||
response.headers["Content-Size"].should eq(
|
response.headers["Content-Size"].should eq(
|
||||||
File.info("#{__DIR__}/static/dir/test.txt").size.to_s
|
File.info("#{__DIR__}/static/dir/test.txt").size.to_s
|
||||||
)
|
)
|
||||||
|
|
||||||
response = handle HTTP::Request.new("GET", "/dir/index.html")
|
response = handle HTTP::Request.new("GET", "/dir/index.html"), config
|
||||||
response.headers["Access-Control-Allow-Origin"].should eq("*")
|
response.headers["Access-Control-Allow-Origin"].should eq("*")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require "./spec_helper"
|
require "./dsl_helper"
|
||||||
|
|
||||||
macro render_with_base_and_layout(filename)
|
macro render_with_base_and_layout(filename)
|
||||||
render "spec/asset/#{{{filename}}}", "spec/asset/layout.ecr"
|
render "spec/asset/#{{{filename}}}", "spec/asset/layout.ecr"
|
||||||
|
@ -6,56 +6,61 @@ end
|
||||||
|
|
||||||
describe "Views" do
|
describe "Views" do
|
||||||
it "renders file" do
|
it "renders file" do
|
||||||
get "/view/:name" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/view/:name" do |env|
|
||||||
name = env.params.url["name"]
|
name = env.params.url["name"]
|
||||||
render "spec/asset/hello.ecr"
|
render "spec/asset/hello.ecr"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/view/world")
|
request = HTTP::Request.new("GET", "/view/world")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should contain("Hello world")
|
client_response.body.should contain("Hello world")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders file with dynamic variables" do
|
it "renders file with dynamic variables" do
|
||||||
get "/view/:name" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/view/:name" do |env|
|
||||||
name = env.params.url["name"]
|
name = env.params.url["name"]
|
||||||
render_with_base_and_layout "hello.ecr"
|
render_with_base_and_layout "hello.ecr"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/view/world")
|
request = HTTP::Request.new("GET", "/view/world")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should contain("Hello world")
|
client_response.body.should contain("Hello world")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders layout" do
|
it "renders layout" do
|
||||||
get "/view/:name" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/view/:name" do |env|
|
||||||
name = env.params.url["name"]
|
name = env.params.url["name"]
|
||||||
render "spec/asset/hello.ecr", "spec/asset/layout.ecr"
|
render "spec/asset/hello.ecr", "spec/asset/layout.ecr"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/view/world")
|
request = HTTP::Request.new("GET", "/view/world")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should contain("<html>Hello world")
|
client_response.body.should contain("<html>Hello world")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders layout with variables" do
|
it "renders layout with variables" do
|
||||||
get "/view/:name" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/view/:name" do |env|
|
||||||
name = env.params.url["name"]
|
name = env.params.url["name"]
|
||||||
var1 = "serdar"
|
var1 = "serdar"
|
||||||
var2 = "kemal"
|
var2 = "kemal"
|
||||||
render "spec/asset/hello_with_content_for.ecr", "spec/asset/layout_with_yield_and_vars.ecr"
|
render "spec/asset/hello_with_content_for.ecr", "spec/asset/layout_with_yield_and_vars.ecr"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/view/world")
|
request = HTTP::Request.new("GET", "/view/world")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should contain("Hello world")
|
client_response.body.should contain("Hello world")
|
||||||
client_response.body.should contain("serdar")
|
client_response.body.should contain("serdar")
|
||||||
client_response.body.should contain("kemal")
|
client_response.body.should contain("kemal")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders layout with content_for" do
|
it "renders layout with content_for" do
|
||||||
get "/view/:name" do |env|
|
app = Kemal::Base.new
|
||||||
|
app.get "/view/:name" do |env|
|
||||||
name = env.params.url["name"]
|
name = env.params.url["name"]
|
||||||
render "spec/asset/hello_with_content_for.ecr", "spec/asset/layout_with_yield.ecr"
|
render "spec/asset/hello_with_content_for.ecr", "spec/asset/layout_with_yield.ecr"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("GET", "/view/world")
|
request = HTTP::Request.new("GET", "/view/world")
|
||||||
client_response = call_request_on_app(request)
|
client_response = call_request_on_app(app, request)
|
||||||
client_response.body.should contain("Hello world")
|
client_response.body.should contain("Hello world")
|
||||||
client_response.body.should contain("<h1>Hello from otherside</h1>")
|
client_response.body.should contain("<h1>Hello from otherside</h1>")
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,24 @@
|
||||||
require "./spec_helper"
|
require "./spec_helper"
|
||||||
|
|
||||||
|
private def create_ws_request_and_return_io(handler, request, app)
|
||||||
|
io = IO::Memory.new
|
||||||
|
response = HTTP::Server::Response.new(io)
|
||||||
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = app
|
||||||
|
begin
|
||||||
|
handler.call context
|
||||||
|
rescue IO::Error
|
||||||
|
# Raises because the IO::Memory is empty
|
||||||
|
end
|
||||||
|
io
|
||||||
|
end
|
||||||
|
|
||||||
describe "Kemal::WebSocketHandler" do
|
describe "Kemal::WebSocketHandler" do
|
||||||
it "doesn't match on wrong route" do
|
it "doesn't match on wrong route" do
|
||||||
|
app = Kemal::Base.new
|
||||||
handler = Kemal::WebSocketHandler.new
|
handler = Kemal::WebSocketHandler.new
|
||||||
handler.next = Kemal::RouteHandler.new
|
handler.next = Kemal::RouteHandler.new
|
||||||
ws "/" { }
|
app.ws "/" { }
|
||||||
headers = HTTP::Headers{
|
headers = HTTP::Headers{
|
||||||
"Upgrade" => "websocket",
|
"Upgrade" => "websocket",
|
||||||
"Connection" => "Upgrade",
|
"Connection" => "Upgrade",
|
||||||
|
@ -14,7 +28,7 @@ describe "Kemal::WebSocketHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
context.app = app
|
||||||
|
|
||||||
expect_raises(Kemal::Exceptions::RouteNotFound) do
|
expect_raises(Kemal::Exceptions::RouteNotFound) do
|
||||||
handler.call context
|
handler.call context
|
||||||
|
@ -22,9 +36,10 @@ describe "Kemal::WebSocketHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches on given route" do
|
it "matches on given route" do
|
||||||
|
app = Kemal::Base.new
|
||||||
handler = Kemal::WebSocketHandler.new
|
handler = Kemal::WebSocketHandler.new
|
||||||
ws "/" { |socket, context| socket.send("Match") }
|
app.ws "/" { |socket, context| socket.send("Match") }
|
||||||
ws "/no_match" { |socket, context| socket.send "No Match" }
|
app.ws "/no_match" { |socket, context| socket.send "No Match" }
|
||||||
headers = HTTP::Headers{
|
headers = HTTP::Headers{
|
||||||
"Upgrade" => "websocket",
|
"Upgrade" => "websocket",
|
||||||
"Connection" => "Upgrade",
|
"Connection" => "Upgrade",
|
||||||
|
@ -33,13 +48,14 @@ describe "Kemal::WebSocketHandler" do
|
||||||
}
|
}
|
||||||
request = HTTP::Request.new("GET", "/", headers)
|
request = HTTP::Request.new("GET", "/", headers)
|
||||||
|
|
||||||
io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0]
|
io_with_context = create_ws_request_and_return_io(handler, request, app)
|
||||||
io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n\x81\u0005Match")
|
io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-Websocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n\x81\u0005Match")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fetches named url parameters" do
|
it "fetches named url parameters" do
|
||||||
|
app = Kemal::Base.new
|
||||||
handler = Kemal::WebSocketHandler.new
|
handler = Kemal::WebSocketHandler.new
|
||||||
ws "/:id" { |s, c| c.params.url["id"] }
|
app.ws "/:id" { |s, c| c.params.url["id"] }
|
||||||
headers = HTTP::Headers{
|
headers = HTTP::Headers{
|
||||||
"Upgrade" => "websocket",
|
"Upgrade" => "websocket",
|
||||||
"Connection" => "Upgrade",
|
"Connection" => "Upgrade",
|
||||||
|
@ -47,20 +63,21 @@ describe "Kemal::WebSocketHandler" do
|
||||||
"Sec-WebSocket-Version" => "13",
|
"Sec-WebSocket-Version" => "13",
|
||||||
}
|
}
|
||||||
request = HTTP::Request.new("GET", "/1234", headers)
|
request = HTTP::Request.new("GET", "/1234", headers)
|
||||||
io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0]
|
io_with_context = create_ws_request_and_return_io(handler, request, app)
|
||||||
io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
|
io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-Websocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches correct verb" do
|
it "matches correct verb" do
|
||||||
|
app = Kemal::Base.new
|
||||||
handler = Kemal::WebSocketHandler.new
|
handler = Kemal::WebSocketHandler.new
|
||||||
handler.next = Kemal::RouteHandler.new
|
handler.next = Kemal::RouteHandler.new
|
||||||
ws "/" { }
|
app.ws "/" { }
|
||||||
get "/" { "get" }
|
app.get "/" { "get" }
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
context.app = Kemal.application
|
context.app = app
|
||||||
handler.call(context)
|
handler.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
|
|
|
@ -99,4 +99,8 @@ class Kemal::Base
|
||||||
raise "Kemal is already stopped."
|
raise "Kemal is already stopped."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def log(message)
|
||||||
|
logger.write "#{message}\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Kemal::Base
|
||||||
|
|
||||||
private def setup_error_handler
|
private def setup_error_handler
|
||||||
if @config.always_rescue?
|
if @config.always_rescue?
|
||||||
error_handler = @error_handler ||= Kemal::ExceptionHandler.new
|
error_handler = @error_handler ||= Kemal::ExceptionHandler.new(self)
|
||||||
@handlers.insert(@handler_position, error_handler)
|
@handlers.insert(@handler_position, error_handler)
|
||||||
@handler_position += 1
|
@handler_position += 1
|
||||||
end
|
end
|
||||||
|
@ -79,7 +79,7 @@ class Kemal::Base
|
||||||
|
|
||||||
private def setup_static_file_handler
|
private def setup_static_file_handler
|
||||||
if @config.serve_static.is_a?(Hash)
|
if @config.serve_static.is_a?(Hash)
|
||||||
@handlers.insert(@handler_position, Kemal::StaticFileHandler.new(@config.public_folder))
|
@handlers.insert(@handler_position, Kemal::StaticFileHandler.new(@config))
|
||||||
@handler_position += 1
|
@handler_position += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,6 +57,10 @@ module Kemal
|
||||||
def extra_options(&@extra_options : OptionParser ->)
|
def extra_options(&@extra_options : OptionParser ->)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def serve_static?(key)
|
||||||
|
(h = @serve_static).is_a?(Hash) && h[key]? == true
|
||||||
|
end
|
||||||
|
|
||||||
# Create a config with default values
|
# Create a config with default values
|
||||||
def self.default
|
def self.default
|
||||||
new
|
new
|
||||||
|
|
|
@ -3,6 +3,13 @@ module Kemal
|
||||||
class ExceptionHandler
|
class ExceptionHandler
|
||||||
include HTTP::Handler
|
include HTTP::Handler
|
||||||
|
|
||||||
|
getter app : Kemal::Base
|
||||||
|
|
||||||
|
def initialize(@app)
|
||||||
|
end
|
||||||
|
|
||||||
|
delegate log, to: app
|
||||||
|
|
||||||
def call(context : HTTP::Server::Context)
|
def call(context : HTTP::Server::Context)
|
||||||
begin
|
begin
|
||||||
call_next(context)
|
call_next(context)
|
||||||
|
@ -14,7 +21,7 @@ module Kemal
|
||||||
log("Exception: #{ex.inspect_with_backtrace}")
|
log("Exception: #{ex.inspect_with_backtrace}")
|
||||||
return call_exception_with_status_code(context, ex, 500) if context.app.error_handlers.has_key?(500)
|
return call_exception_with_status_code(context, ex, 500) if context.app.error_handlers.has_key?(500)
|
||||||
verbosity = context.app.config.env == "production" ? false : true
|
verbosity = context.app.config.env == "production" ? false : true
|
||||||
return render_500(context, ex.inspect_with_backtrace, verbosity)
|
return app.render_500(context, ex.inspect_with_backtrace, verbosity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
module Kemal::FileHelpers
|
module Kemal::FileHelpers
|
||||||
def log(message)
|
extend self
|
||||||
logger.write "#{message}\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Send a file with given path and base the mime-type on the file extension
|
# Send a file with given path and base the mime-type on the file extension
|
||||||
# or default `application/octet-stream` mime_type.
|
# or default `application/octet-stream` mime_type.
|
||||||
#
|
#
|
||||||
|
@ -15,8 +12,7 @@ module Kemal::FileHelpers
|
||||||
# ```
|
# ```
|
||||||
# send_file env, "./path/to/file", "image/jpeg"
|
# send_file env, "./path/to/file", "image/jpeg"
|
||||||
# ```
|
# ```
|
||||||
def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil)
|
def send_file(env : HTTP::Server::Context, path : String, config : Kemal::Config, mime_type : String? = nil)
|
||||||
config = env.app.config
|
|
||||||
file_path = File.expand_path(path, Dir.current)
|
file_path = File.expand_path(path, Dir.current)
|
||||||
mime_type ||= Kemal::Utils.mime_type(file_path)
|
mime_type ||= Kemal::Utils.mime_type(file_path)
|
||||||
env.response.content_type = mime_type
|
env.response.content_type = mime_type
|
||||||
|
@ -28,17 +24,18 @@ module Kemal::FileHelpers
|
||||||
filestat = File.stat(file_path)
|
filestat = File.stat(file_path)
|
||||||
|
|
||||||
config.static_headers.try(&.call(env.response, file_path, filestat))
|
config.static_headers.try(&.call(env.response, file_path, filestat))
|
||||||
|
gzip = config.serve_static?("gzip")
|
||||||
|
|
||||||
File.open(file_path) do |file|
|
File.open(file_path) do |file|
|
||||||
if env.request.method == "GET" && env.request.headers.has_key?("Range")
|
if env.request.method == "GET" && env.request.headers.has_key?("Range")
|
||||||
next multipart(file, env)
|
next multipart(file, env)
|
||||||
end
|
end
|
||||||
if request_headers.includes_word?("Accept-Encoding", "gzip") && config.serve_static?("gzip") && filesize > minsize && Kemal::Utils.zip_types(file_path)
|
if request_headers.includes_word?("Accept-Encoding", "gzip") && gzip && filesize > minsize && Kemal::Utils.zip_types(file_path)
|
||||||
env.response.headers["Content-Encoding"] = "gzip"
|
env.response.headers["Content-Encoding"] = "gzip"
|
||||||
Gzip::Writer.open(env.response) do |deflate|
|
Gzip::Writer.open(env.response) do |deflate|
|
||||||
IO.copy(file, deflate)
|
IO.copy(file, deflate)
|
||||||
end
|
end
|
||||||
elsif request_headers.includes_word?("Accept-Encoding", "deflate") && config.serve_static?("gzip") && filesize > minsize && Kemal::Utils.zip_types(file_path)
|
elsif request_headers.includes_word?("Accept-Encoding", "deflate") && gzip && filesize > minsize && Kemal::Utils.zip_types(file_path)
|
||||||
env.response.headers["Content-Encoding"] = "deflate"
|
env.response.headers["Content-Encoding"] = "deflate"
|
||||||
Flate::Writer.open(env.response) do |deflate|
|
Flate::Writer.open(env.response) do |deflate|
|
||||||
IO.copy(file, deflate)
|
IO.copy(file, deflate)
|
||||||
|
@ -51,6 +48,10 @@ module Kemal::FileHelpers
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def send_file(env, path : String, mime_type : String? = nil)
|
||||||
|
send_file(env, path, env.app.config, mime_type)
|
||||||
|
end
|
||||||
|
|
||||||
private def multipart(file, env : HTTP::Server::Context)
|
private def multipart(file, env : HTTP::Server::Context)
|
||||||
# See http://httpwg.org/specs/rfc7233.html
|
# See http://httpwg.org/specs/rfc7233.html
|
||||||
fileb = file.size
|
fileb = file.size
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
module Kemal
|
module Kemal
|
||||||
class StaticFileHandler < HTTP::StaticFileHandler
|
class StaticFileHandler < HTTP::StaticFileHandler
|
||||||
|
getter config : Kemal::Config
|
||||||
|
|
||||||
|
def initialize(@config, fallthrough = true)
|
||||||
|
super(@config.public_folder, fallthrough)
|
||||||
|
end
|
||||||
|
|
||||||
def call(context : HTTP::Server::Context)
|
def call(context : HTTP::Server::Context)
|
||||||
return call_next(context) if context.request.path.not_nil! == "/"
|
return call_next(context) if context.request.path.not_nil! == "/"
|
||||||
|
|
||||||
|
@ -19,7 +25,6 @@ module Kemal
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
config = Kemal.config.serve_static
|
|
||||||
original_path = context.request.path.not_nil!
|
original_path = context.request.path.not_nil!
|
||||||
request_path = URI.unescape(original_path)
|
request_path = URI.unescape(original_path)
|
||||||
|
|
||||||
|
@ -48,7 +53,7 @@ module Kemal
|
||||||
end
|
end
|
||||||
|
|
||||||
if Dir.exists?(file_path)
|
if Dir.exists?(file_path)
|
||||||
if config.is_a?(Hash) && config["dir_listing"] == true
|
if @config.serve_static?("dir_listing")
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
directory_listing(context.response, request_path, file_path)
|
directory_listing(context.response, request_path, file_path)
|
||||||
else
|
else
|
||||||
|
@ -62,7 +67,8 @@ module Kemal
|
||||||
context.response.status_code = 304
|
context.response.status_code = 304
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
send_file(context, file_path)
|
|
||||||
|
FileHelpers.send_file(context, file_path, config)
|
||||||
else
|
else
|
||||||
call_next(context)
|
call_next(context)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue