halcyon 0.4.0 → 0.5.0
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.
- data/AUTHORS +1 -0
- data/LICENSE +20 -0
- data/README +107 -0
- data/Rakefile +8 -6
- data/bin/halcyon +3 -204
- data/lib/halcyon.rb +55 -42
- data/lib/halcyon/application.rb +247 -0
- data/lib/halcyon/application/router.rb +86 -0
- data/lib/halcyon/client.rb +187 -35
- data/lib/halcyon/client/ssl.rb +38 -0
- data/lib/halcyon/controller.rb +154 -0
- data/lib/halcyon/exceptions.rb +67 -59
- data/lib/halcyon/logging.rb +31 -0
- data/lib/halcyon/logging/analogger.rb +31 -0
- data/lib/halcyon/logging/helpers.rb +37 -0
- data/lib/halcyon/logging/log4r.rb +25 -0
- data/lib/halcyon/logging/logger.rb +20 -0
- data/lib/halcyon/logging/logging.rb +19 -0
- data/lib/halcyon/runner.rb +141 -0
- data/lib/halcyon/runner/commands.rb +141 -0
- data/lib/halcyon/runner/helpers.rb +9 -0
- data/lib/halcyon/runner/helpers/command_helper.rb +71 -0
- data/spec/halcyon/application_spec.rb +70 -0
- data/spec/halcyon/client_spec.rb +63 -0
- data/spec/halcyon/controller_spec.rb +68 -0
- data/spec/halcyon/halcyon_spec.rb +63 -0
- data/spec/halcyon/logging_spec.rb +31 -0
- data/spec/halcyon/router_spec.rb +37 -12
- data/spec/halcyon/runner_spec.rb +54 -0
- data/spec/spec_helper.rb +75 -9
- data/support/generators/halcyon/USAGE +0 -0
- data/support/generators/halcyon/halcyon_generator.rb +52 -0
- data/support/generators/halcyon/templates/README +26 -0
- data/support/generators/halcyon/templates/Rakefile +32 -0
- data/support/generators/halcyon/templates/app/application.rb +43 -0
- data/support/generators/halcyon/templates/config/config.yml +36 -0
- data/support/generators/halcyon/templates/config/init/environment.rb +11 -0
- data/support/generators/halcyon/templates/config/init/hooks.rb +39 -0
- data/support/generators/halcyon/templates/config/init/requires.rb +10 -0
- data/support/generators/halcyon/templates/config/init/routes.rb +50 -0
- data/support/generators/halcyon/templates/lib/client.rb +77 -0
- data/support/generators/halcyon/templates/runner.ru +8 -0
- data/support/generators/halcyon_flat/USAGE +0 -0
- data/support/generators/halcyon_flat/halcyon_flat_generator.rb +52 -0
- data/support/generators/halcyon_flat/templates/README +26 -0
- data/support/generators/halcyon_flat/templates/Rakefile +32 -0
- data/support/generators/halcyon_flat/templates/app.rb +49 -0
- data/support/generators/halcyon_flat/templates/lib/client.rb +17 -0
- data/support/generators/halcyon_flat/templates/runner.ru +8 -0
- metadata +73 -20
- data/lib/halcyon/client/base.rb +0 -261
- data/lib/halcyon/client/exceptions.rb +0 -41
- data/lib/halcyon/client/router.rb +0 -106
- data/lib/halcyon/server.rb +0 -62
- data/lib/halcyon/server/auth/basic.rb +0 -107
- data/lib/halcyon/server/base.rb +0 -774
- data/lib/halcyon/server/exceptions.rb +0 -41
- data/lib/halcyon/server/router.rb +0 -103
- data/spec/halcyon/error_spec.rb +0 -55
- data/spec/halcyon/server_spec.rb +0 -105
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
include Log4r
|
3
|
+
module Halcyon
|
4
|
+
module Logging
|
5
|
+
class Log4r < Log4r::Logger
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def setup(config)
|
10
|
+
logger = self.new(config[:label] || Halcyon.app)
|
11
|
+
if config[:file]
|
12
|
+
logger.outputters = Log4r::FileOutputter.new(:filename => config[:file])
|
13
|
+
else
|
14
|
+
logger.outputters = Log4r::Outputter.stdout
|
15
|
+
end
|
16
|
+
logger.level = Object.const_get((config[:level] || 'debug').upcase.to_sym)
|
17
|
+
logger.outputters[0].formatter = Log4r::PatternFormatter.new(:pattern => "%5l [%d] (#{$$}) #{Halcyon.app} :: %m\n", :date_pattern => "%Y-%m-%d %H:%M:%S")
|
18
|
+
logger
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Halcyon
|
3
|
+
module Logging
|
4
|
+
class Logger < ::Logger
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def setup(config)
|
9
|
+
logger = config[:logger] || self.new(config[:file] || STDOUT)
|
10
|
+
logger.formatter = proc{|s,t,p,m|"%5s [%s] (%s) %s :: %s\n" % [s, t.strftime("%Y-%m-%d %H:%M:%S"), $$, p, m]}
|
11
|
+
logger.progname = Halcyon.app
|
12
|
+
logger.level = Logger.const_get((config[:level] || 'info').upcase)
|
13
|
+
logger
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'logging'
|
2
|
+
module Halcyon
|
3
|
+
module Logging
|
4
|
+
class Logging < Logging::Logger
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def setup(config)
|
9
|
+
logger = config[:logger] || ::Logging.logger(config[:file] || STDOUT)
|
10
|
+
logger.level = config[:level].downcase.to_sym
|
11
|
+
logger.instance_variable_get("@appenders")[0].instance_variable_set("@layout", ::Logging::Layouts::Pattern.new(:pattern => "%5l [%d] (%p) #{Halcyon.app} :: %m\n", :date_pattern => "%Y-%m-%d %H:%M:%S"))
|
12
|
+
logger
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Halcyon
|
2
|
+
|
3
|
+
# Handles initializing and running the application, including:
|
4
|
+
# * setting up the logger
|
5
|
+
# * loading initializers
|
6
|
+
# * loading controllers
|
7
|
+
#
|
8
|
+
# The Runner is a full-fledged Rack application, and accepts calls to #call.
|
9
|
+
#
|
10
|
+
# Also handles running commands form the command line.
|
11
|
+
#
|
12
|
+
# Examples
|
13
|
+
# # start serving the current app (in .)
|
14
|
+
# Halcyon::Runner.run!(['start', '-p', '4647'])
|
15
|
+
#
|
16
|
+
# # load the config file and initialize the app
|
17
|
+
# Halcyon::Runner.load_config Halcyon.root/'config'/'config.yml'
|
18
|
+
# Halcyon::Runner.new
|
19
|
+
class Runner
|
20
|
+
|
21
|
+
autoload :Commands, 'halcyon/runner/commands'
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Runs commands from the CLI.
|
26
|
+
# +argv+ the arguments to pass to the commands
|
27
|
+
#
|
28
|
+
# Returns nothing
|
29
|
+
def run!(argv=ARGV)
|
30
|
+
Commands.send(argv.shift, argv)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the path to the configuration file specified, defaulting
|
34
|
+
# to the path for the <tt>config.yml</tt> file.
|
35
|
+
# +file+ the name of the config file path (without the <tt>.yml</tt>
|
36
|
+
# extension)
|
37
|
+
def config_path(file = "config")
|
38
|
+
Halcyon.paths[:config]/"#{file}.yml"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# Initializes the application and application resources.
|
44
|
+
def initialize
|
45
|
+
Halcyon::Runner.load_paths if Halcyon.paths.nil?
|
46
|
+
|
47
|
+
# Load the configuration if none is set already
|
48
|
+
if Halcyon.config.nil?
|
49
|
+
if File.exist?(Halcyon::Runner.config_path)
|
50
|
+
Halcyon.config = Halcyon::Runner.load_config
|
51
|
+
else
|
52
|
+
Halcon.config = Halcyon::Application::DEFAULT_OPTIONS
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set application name
|
57
|
+
Halcyon.app = Halcyon.config[:app] || Halcyon.root.split('/').last.camel_case
|
58
|
+
|
59
|
+
# Setup logger
|
60
|
+
if Halcyon.config[:logger]
|
61
|
+
Halcyon.config[:logging] = (Halcyon.config[:logging] || Halcyon::Application::DEFAULT_OPTIONS[:logging]).merge({
|
62
|
+
:type => Halcyon.config[:logger].class.to_s,
|
63
|
+
:logger => Halcyon.config[:logger]
|
64
|
+
})
|
65
|
+
end
|
66
|
+
Halcyon::Logging.set((Halcyon.config[:logging][:type] rescue nil))
|
67
|
+
Halcyon.logger = Halcyon::Logger.setup(Halcyon.config[:logging])
|
68
|
+
|
69
|
+
# Run initializers
|
70
|
+
Dir.glob(Halcyon.paths[:init]/'{requires,hooks,routes,environment,*}.rb').each do |initializer|
|
71
|
+
self.logger.debug "Init: #{File.basename(initializer).chomp('.rb').camel_case}" if
|
72
|
+
require initializer.chomp('.rb')
|
73
|
+
end
|
74
|
+
|
75
|
+
# Setup autoloads for Controllers found in Halcyon.root/'app'
|
76
|
+
Dir.glob(Halcyon.paths[:controller]/'{application,*}.rb').each do |controller|
|
77
|
+
self.logger.debug "Load: #{File.basename(controller).chomp('.rb').camel_case} Controller" if
|
78
|
+
require controller.chomp('.rb')
|
79
|
+
end
|
80
|
+
|
81
|
+
@app = Halcyon::Application.new
|
82
|
+
end
|
83
|
+
|
84
|
+
# Calls the application, which gets proxied to the dispatcher.
|
85
|
+
# +env+ the request environment details
|
86
|
+
#
|
87
|
+
# Returns [Fixnum:status, {String:header => String:value}, [String:body]]
|
88
|
+
def call(env)
|
89
|
+
@app.call(env)
|
90
|
+
end
|
91
|
+
|
92
|
+
class << self
|
93
|
+
|
94
|
+
# Loads the configuration file specified into <tt>Halcyon.config</tt>.
|
95
|
+
# +file+ the configuration file to load
|
96
|
+
#
|
97
|
+
# Examples
|
98
|
+
# Halcyon::Runner.load_config Halcyon.root/'config'/'config.yml'
|
99
|
+
# Halcyon.config #=> {:allow_from => :all, :logging => {...}, ...}.to_mash
|
100
|
+
#
|
101
|
+
# Returns {Symbol:key => String:value}.to_mash
|
102
|
+
def load_config(file=Halcyon::Runner.config_path)
|
103
|
+
if File.exist?(file)
|
104
|
+
require 'yaml'
|
105
|
+
|
106
|
+
# load the config file
|
107
|
+
begin
|
108
|
+
config = YAML.load_file(file).to_mash
|
109
|
+
rescue Errno::EACCES
|
110
|
+
raise LoadError.new("Can't access #{file}, try 'sudo #{$0}'")
|
111
|
+
end
|
112
|
+
else
|
113
|
+
warn "#{file} not found, ensure the path to this file is correct. Ignoring."
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Set the paths for resources to be located.
|
119
|
+
#
|
120
|
+
# Used internally for setting the load paths if not manually overridden
|
121
|
+
# and needed to be set before normal application initialization.
|
122
|
+
#
|
123
|
+
# TODO: Move this to the planned <tt>Halcyon::Config</tt> object.
|
124
|
+
#
|
125
|
+
# Returns nothing.
|
126
|
+
def load_paths
|
127
|
+
# Set the default application paths, not overwriting manually set paths
|
128
|
+
Halcyon.paths = {
|
129
|
+
:controller => Halcyon.root/'app',
|
130
|
+
:model => Halcyon.root/'app'/'models',
|
131
|
+
:lib => Halcyon.root/'lib',
|
132
|
+
:config => Halcyon.root/'config',
|
133
|
+
:init => Halcyon.root/'config'/'{init,initialize}',
|
134
|
+
:log => Halcyon.root/'log'
|
135
|
+
}.to_mash.merge(Halcyon.paths || {})
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Halcyon
|
4
|
+
class Runner
|
5
|
+
|
6
|
+
autoload :Helpers, 'halcyon/runner/helpers'
|
7
|
+
|
8
|
+
class Commands
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Run the Halcyon application
|
12
|
+
def start(argv)
|
13
|
+
options = {
|
14
|
+
:port => 4647,
|
15
|
+
:server => (Gem.searcher.find('thin').nil? ? 'mongrel' : 'thin')
|
16
|
+
}
|
17
|
+
|
18
|
+
OptionParser.new do |opts|
|
19
|
+
opts.banner = "Usage: halcyon start [options]"
|
20
|
+
|
21
|
+
opts.separator ""
|
22
|
+
opts.separator "Start options:"
|
23
|
+
opts.on("-s", "--server SERVER", "") { |server| options[:server] = server }
|
24
|
+
|
25
|
+
begin
|
26
|
+
opts.parse! argv
|
27
|
+
rescue OptionParser::InvalidOption => e
|
28
|
+
# the other options can be used elsewhere, like in RubiGen
|
29
|
+
argv = e.recover(argv)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if options[:server] == 'thin'
|
34
|
+
# Thin is installed
|
35
|
+
command = "thin start -R runner.ru #{argv.join(' ')}"
|
36
|
+
else
|
37
|
+
# Thin is not installed
|
38
|
+
command = "rackup runner.ru -s #{options[:server]} #{argv.join(' ')}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# run command
|
42
|
+
exec command
|
43
|
+
end
|
44
|
+
|
45
|
+
# Start the Halcyon server up in interactive mode
|
46
|
+
def console(argv)
|
47
|
+
# Notify user of environment
|
48
|
+
puts "(Starting Halcyon app in console...)"
|
49
|
+
|
50
|
+
# Add ./lib to load path
|
51
|
+
$:.unshift(Halcyon.root/'lib')
|
52
|
+
|
53
|
+
# prepare environment for IRB
|
54
|
+
ARGV.clear
|
55
|
+
require 'rack/mock'
|
56
|
+
require 'logger'
|
57
|
+
require 'irb'
|
58
|
+
require 'irb/completion'
|
59
|
+
if File.exists? '.irbrc'
|
60
|
+
ENV['IRBRC'] = '.irbrc'
|
61
|
+
end
|
62
|
+
|
63
|
+
# Set up the application
|
64
|
+
Object.instance_eval do
|
65
|
+
$log = ''
|
66
|
+
Halcyon::Runner.load_paths if Halcyon.paths.nil?
|
67
|
+
(Halcyon.config = Halcyon::Runner.load_config) || require(Halcyon.root/'app')
|
68
|
+
Halcyon.config[:logger] = Logger.new(StringIO.new($log))
|
69
|
+
$app = Halcyon::Runner.new
|
70
|
+
$response = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
# Setup helper methods
|
74
|
+
Object.send(:include, Halcyon::Runner::Helpers::CommandHelper)
|
75
|
+
|
76
|
+
# Let users know what methods and values are available
|
77
|
+
puts "Call #usage for usage details."
|
78
|
+
|
79
|
+
# Start IRB session
|
80
|
+
IRB.start
|
81
|
+
|
82
|
+
exit
|
83
|
+
end
|
84
|
+
alias_method :interactive, :console
|
85
|
+
alias_method :irb, :console
|
86
|
+
alias_method :"-i", :console
|
87
|
+
|
88
|
+
# Generate a new Halcyon application
|
89
|
+
def init(argv)
|
90
|
+
app_name = argv.last
|
91
|
+
|
92
|
+
options = {
|
93
|
+
:generator => 'halcyon',
|
94
|
+
:git => false
|
95
|
+
}
|
96
|
+
|
97
|
+
OptionParser.new do |opts|
|
98
|
+
opts.banner = "Usage: halcyon init [options]"
|
99
|
+
|
100
|
+
opts.separator ""
|
101
|
+
opts.separator "Generator options:"
|
102
|
+
opts.on("-f", "--flat", "") { options[:generator] = 'halcyon_flat' }
|
103
|
+
|
104
|
+
opts.separator ""
|
105
|
+
opts.separator "Additional options:"
|
106
|
+
opts.on("-g", "--git", "Initialize a Git repository when finished generating") { options[:git] = true }
|
107
|
+
opts.on("-G", "--git-commit", "Initialize a Git repo and commit") { options[:git] = options[:git_commit] = true }
|
108
|
+
|
109
|
+
begin
|
110
|
+
opts.parse! argv
|
111
|
+
rescue OptionParser::InvalidOption => e
|
112
|
+
# the other options can be used elsewhere, like in RubiGen
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
require 'rubigen'
|
117
|
+
require 'rubigen/scripts/generate'
|
118
|
+
RubiGen::Base.use_application_sources!
|
119
|
+
RubiGen::Base.sources << RubiGen::PathSource.new(:custom, File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', "support/generators")))
|
120
|
+
RubiGen::Scripts::Generate.new.run(argv, :generator => options[:generator])
|
121
|
+
|
122
|
+
# Create a Git repository in the new app dir
|
123
|
+
if options[:git]
|
124
|
+
system("cd #{app_name} && git init -q && cd #{Dir.pwd}")
|
125
|
+
puts "Initialized Git repository in #{app_name}/"
|
126
|
+
File.open(File.join("#{app_name}",'.gitignore'),"w") {|f| f << "log/*.log" }
|
127
|
+
File.open(File.join("#{app_name}",'log','.gitignore'),"w") {|f| f << "" }
|
128
|
+
end
|
129
|
+
|
130
|
+
# commit to the git repo
|
131
|
+
if options[:git_commit]
|
132
|
+
system("cd #{app_name} && git add . && git commit -m 'Initial import.' -q && cd #{Dir.pwd}")
|
133
|
+
puts "Committed empty application in #{app_name}/"
|
134
|
+
puts "Run `git commit --amend` to change the commit message."
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Halcyon
|
2
|
+
class Runner
|
3
|
+
class Helpers
|
4
|
+
module CommandHelper
|
5
|
+
|
6
|
+
def usage
|
7
|
+
msg = <<-"end;"
|
8
|
+
|
9
|
+
These methods will provide you with most of the
|
10
|
+
functionality you will need to test your app.
|
11
|
+
|
12
|
+
#app The loaded application
|
13
|
+
#log The contents of the log (Ex: puts log)
|
14
|
+
#tail The tail end of the log (Ex: tail)
|
15
|
+
#clear Clears the log (Ex: clear)
|
16
|
+
#get Sends a GET request to the app
|
17
|
+
Ex: get '/controller/action'
|
18
|
+
#post Sends a POST request to #app
|
19
|
+
Ex: post '/controller/action', :key => value
|
20
|
+
#put See #post
|
21
|
+
#delete See #get
|
22
|
+
#response Response of the last request
|
23
|
+
|
24
|
+
end;
|
25
|
+
puts msg.gsub(/^[ ]{12}/, '')
|
26
|
+
end
|
27
|
+
|
28
|
+
def app
|
29
|
+
$app
|
30
|
+
end
|
31
|
+
|
32
|
+
def log
|
33
|
+
$log
|
34
|
+
end
|
35
|
+
|
36
|
+
def tail
|
37
|
+
puts $log.split("\n").reverse[0..5].reverse.join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
def clear
|
41
|
+
$log = ''
|
42
|
+
end
|
43
|
+
|
44
|
+
def get(path)
|
45
|
+
$response = Rack::MockRequest.new($app).get(path)
|
46
|
+
JSON.parse($response.body)
|
47
|
+
end
|
48
|
+
|
49
|
+
def post(path, params = {})
|
50
|
+
$response = Rack::MockRequest.new($app).post(path, :input => params.to_params)
|
51
|
+
JSON.parse($response.body)
|
52
|
+
end
|
53
|
+
|
54
|
+
def put(path, params = {})
|
55
|
+
$response = Rack::MockRequest.new($app).put(path, :input => params.to_params)
|
56
|
+
JSON.parse($response.body)
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete(path)
|
60
|
+
$response = Rack::MockRequest.new($app).delete(path)
|
61
|
+
JSON.parse($response.body)
|
62
|
+
end
|
63
|
+
|
64
|
+
def response
|
65
|
+
$response
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
describe "Halcyon::Application" do
|
2
|
+
|
3
|
+
before do
|
4
|
+
@log = ''
|
5
|
+
@logger = Logger.new(StringIO.new(@log))
|
6
|
+
@config = $config.dup
|
7
|
+
@config[:logger] = @logger
|
8
|
+
@config[:app] = 'Specs'
|
9
|
+
Halcyon.config = @config
|
10
|
+
@app = Halcyon::Runner.new
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should run startup hook if defined" do
|
14
|
+
# $started is set by the startup hook
|
15
|
+
$started.should.be.true?
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should dispatch methods according to their respective routes" do
|
19
|
+
Rack::MockRequest.new(@app).get("/hello/Matt")
|
20
|
+
@log.should =~ / INFO \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] \(\d+\) Specs :: \[200\] \/hello\/Matt \(.+\)\n/
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should handle requests and respond with JSON" do
|
24
|
+
body = JSON.parse(Rack::MockRequest.new(@app).get("/").body)
|
25
|
+
body['status'].should == 200
|
26
|
+
body['body'].should == "Found"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should handle requests with param values in the URL" do
|
30
|
+
body = JSON.parse(Rack::MockRequest.new(@app).get("/hello/Matt?test=value").body)
|
31
|
+
body['status'].should == 200
|
32
|
+
body['body'].should == "Hello Matt"
|
33
|
+
@log.split("\n").last.should =~ /"test"=>"value"/
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not dispatch private methods" do
|
37
|
+
body = JSON.parse(Rack::MockRequest.new(@app).get("/specs/undispatchable_private_method").body)
|
38
|
+
body['status'].should == 404
|
39
|
+
body['body'].should == "Not Found"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should route unmatchable requests to the default route and return JSON with appropriate status" do
|
43
|
+
body = JSON.parse(Rack::MockRequest.new(@app).get("/garbage/request/url").body)
|
44
|
+
body['status'].should == 404
|
45
|
+
body['body'].should == "Not Found"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should log activity" do
|
49
|
+
Halcyon.logger.is_a?(Logger).should.be.true?
|
50
|
+
Rack::MockRequest.new(@app).get("/lolcats/r/cute")
|
51
|
+
@log.should =~ / INFO \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] \(\d+\) Specs :: \[404\] \/lolcats\/r\/cute \(.+\)\n/
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should allow all requests by default" do
|
55
|
+
Halcyon.config[:allow_from].should == :all
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should handle exceptions gracefully" do
|
59
|
+
body = JSON.parse(Rack::MockRequest.new(@app).get("/specs/cause_exception").body)
|
60
|
+
body['status'].should == 500
|
61
|
+
body['body'].should == "Internal Server Error"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not confuse a NoMethodFound error in an action as a missing route" do
|
65
|
+
body = JSON.parse(Rack::MockRequest.new(@app).get("/specs/call_nonexistent_method").body)
|
66
|
+
body['status'].should.not == 404
|
67
|
+
body['body'].should == "Internal Server Error"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|