rails-health-checker 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +55 -18
- metadata +25 -69
- data/CHANGELOG.md +0 -37
- data/COMMANDS.md +0 -118
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -222
- data/LICENSE +0 -21
- data/Rakefile +0 -6
- data/SECURITY.md +0 -41
- data/TESTING.md +0 -64
- data/TEST_RESULTS.md +0 -51
- data/example_usage.rb +0 -23
- data/lib/rails_health_checker/checker.rb +0 -88
- data/lib/rails_health_checker/dashboard_middleware.rb +0 -503
- data/lib/rails_health_checker/gem_analyzer.rb +0 -39
- data/lib/rails_health_checker/health_middleware.rb +0 -53
- data/lib/rails_health_checker/job_analyzer.rb +0 -108
- data/lib/rails_health_checker/railtie.rb +0 -11
- data/lib/rails_health_checker/report_generator.rb +0 -499
- data/lib/rails_health_checker/system_analyzer.rb +0 -182
- data/lib/rails_health_checker/tasks.rb +0 -63
- data/lib/rails_health_checker/version.rb +0 -3
- data/lib/rails_health_checker.rb +0 -17
- data/rails_health_checker.gemspec +0 -33
- data/simple_test.rb +0 -52
- data/test_gem.rb +0 -100
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
module RailsHealthChecker
|
|
2
|
-
class SystemAnalyzer
|
|
3
|
-
def analyze
|
|
4
|
-
{
|
|
5
|
-
rails_info: rails_system_info,
|
|
6
|
-
required_libs: check_required_libraries,
|
|
7
|
-
optional_libs: check_optional_libraries,
|
|
8
|
-
server_requirements: check_server_requirements,
|
|
9
|
-
cable_info: check_action_cable,
|
|
10
|
-
environment_info: environment_details
|
|
11
|
-
}
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def rails_system_info
|
|
17
|
-
{
|
|
18
|
-
version: Rails.version,
|
|
19
|
-
environment: Rails.env,
|
|
20
|
-
root: Rails.root.to_s,
|
|
21
|
-
config_loaded: Rails.application.config.loaded?,
|
|
22
|
-
eager_load: Rails.application.config.eager_load,
|
|
23
|
-
cache_classes: Rails.application.config.cache_classes
|
|
24
|
-
}
|
|
25
|
-
rescue => e
|
|
26
|
-
{ error: e.message }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def check_required_libraries
|
|
30
|
-
required = {
|
|
31
|
-
'bundler' => { required: true, available: defined?(Bundler), purpose: 'Dependency management' },
|
|
32
|
-
'rack' => { required: true, available: defined?(Rack), purpose: 'Web server interface' },
|
|
33
|
-
'activerecord' => { required: true, available: defined?(ActiveRecord), purpose: 'Database ORM' },
|
|
34
|
-
'actionpack' => { required: true, available: defined?(ActionPack), purpose: 'Web framework core' },
|
|
35
|
-
'activesupport' => { required: true, available: defined?(ActiveSupport), purpose: 'Core extensions' }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
required.each do |name, info|
|
|
39
|
-
info[:status] = info[:available] ? 'loaded' : 'missing'
|
|
40
|
-
info[:version] = get_gem_version(name) if info[:available]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
required
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def check_optional_libraries
|
|
47
|
-
optional = {
|
|
48
|
-
'sidekiq' => { available: defined?(Sidekiq), purpose: 'Background job processing' },
|
|
49
|
-
'resque' => { available: defined?(Resque), purpose: 'Background job processing' },
|
|
50
|
-
'redis' => { available: defined?(Redis), purpose: 'In-memory data store' },
|
|
51
|
-
'puma' => { available: defined?(Puma), purpose: 'Web server' },
|
|
52
|
-
'unicorn' => { available: defined?(Unicorn), purpose: 'Web server' },
|
|
53
|
-
'passenger' => { available: defined?(PhusionPassenger), purpose: 'Web server' },
|
|
54
|
-
'devise' => { available: defined?(Devise), purpose: 'Authentication' },
|
|
55
|
-
'cancancan' => { available: defined?(CanCan), purpose: 'Authorization' },
|
|
56
|
-
'turbo-rails' => { available: defined?(Turbo), purpose: 'SPA-like experience' },
|
|
57
|
-
'stimulus-rails' => { available: defined?(Stimulus), purpose: 'JavaScript framework' },
|
|
58
|
-
'bootsnap' => { available: defined?(Bootsnap), purpose: 'Boot optimization' },
|
|
59
|
-
'sprockets' => { available: defined?(Sprockets), purpose: 'Asset pipeline' }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
optional.each do |name, info|
|
|
63
|
-
info[:status] = info[:available] ? 'loaded' : 'not_loaded'
|
|
64
|
-
info[:version] = get_gem_version(name) if info[:available]
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
optional
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def check_server_requirements
|
|
71
|
-
{
|
|
72
|
-
web_server: detect_web_server,
|
|
73
|
-
database: detect_database_adapter,
|
|
74
|
-
cache_store: detect_cache_store,
|
|
75
|
-
session_store: detect_session_store,
|
|
76
|
-
asset_host: (Rails.application.config.asset_host rescue nil)
|
|
77
|
-
}
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def check_action_cable
|
|
81
|
-
return { available: false } unless defined?(ActionCable)
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
available: true,
|
|
85
|
-
adapter: (ActionCable.server.config.cable[:adapter] rescue 'unknown'),
|
|
86
|
-
url: (ActionCable.server.config.cable[:url] rescue nil),
|
|
87
|
-
allowed_request_origins: (ActionCable.server.config.allowed_request_origins rescue []),
|
|
88
|
-
status: action_cable_status
|
|
89
|
-
}
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def environment_details
|
|
93
|
-
{
|
|
94
|
-
ruby_version: RUBY_VERSION,
|
|
95
|
-
ruby_platform: RUBY_PLATFORM,
|
|
96
|
-
rails_env: Rails.env,
|
|
97
|
-
rack_env: ENV['RACK_ENV'],
|
|
98
|
-
database_url: ENV['DATABASE_URL'] ? 'configured' : 'not_set',
|
|
99
|
-
redis_url: ENV['REDIS_URL'] ? 'configured' : 'not_set',
|
|
100
|
-
secret_key_base: ENV['SECRET_KEY_BASE'] ? 'configured' : 'not_set'
|
|
101
|
-
}
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def get_gem_version(gem_name)
|
|
105
|
-
Gem.loaded_specs[gem_name]&.version&.to_s || 'unknown'
|
|
106
|
-
rescue
|
|
107
|
-
'unknown'
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def detect_web_server
|
|
111
|
-
return 'puma' if defined?(Puma)
|
|
112
|
-
return 'unicorn' if defined?(Unicorn)
|
|
113
|
-
return 'passenger' if defined?(PhusionPassenger)
|
|
114
|
-
return 'thin' if defined?(Thin)
|
|
115
|
-
return 'webrick' if defined?(WEBrick)
|
|
116
|
-
'unknown'
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def detect_database_adapter
|
|
120
|
-
ActiveRecord::Base.connection.adapter_name
|
|
121
|
-
rescue
|
|
122
|
-
'unknown'
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def detect_cache_store
|
|
126
|
-
cache_class = Rails.cache.class.name
|
|
127
|
-
{
|
|
128
|
-
type: cache_class,
|
|
129
|
-
explanation: get_cache_explanation(cache_class),
|
|
130
|
-
recommendation: get_cache_recommendation(cache_class)
|
|
131
|
-
}
|
|
132
|
-
rescue
|
|
133
|
-
{
|
|
134
|
-
type: 'unknown',
|
|
135
|
-
explanation: 'Unable to detect cache store',
|
|
136
|
-
recommendation: 'Check Rails cache configuration'
|
|
137
|
-
}
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def detect_session_store
|
|
141
|
-
Rails.application.config.session_store.name
|
|
142
|
-
rescue
|
|
143
|
-
'unknown'
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def action_cable_status
|
|
147
|
-
return 'healthy' if ActionCable.server.config.cable[:adapter] != 'test'
|
|
148
|
-
'not_configured'
|
|
149
|
-
rescue
|
|
150
|
-
'error'
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def get_cache_explanation(cache_class)
|
|
154
|
-
explanations = {
|
|
155
|
-
'ActiveSupport::Cache::NullStore' => 'No caching (common in development)',
|
|
156
|
-
'ActiveSupport::Cache::MemoryStore' => 'In-memory caching (single process)',
|
|
157
|
-
'ActiveSupport::Cache::FileStore' => 'File-based caching (disk storage)',
|
|
158
|
-
'ActiveSupport::Cache::RedisStore' => 'Redis-based caching (recommended for production)',
|
|
159
|
-
'ActiveSupport::Cache::MemCacheStore' => 'Memcached-based caching (production ready)',
|
|
160
|
-
'ActiveSupport::Cache::RedisCacheStore' => 'Redis caching with Rails 5.2+ features'
|
|
161
|
-
}
|
|
162
|
-
explanations[cache_class] || 'Custom or unknown cache store'
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def get_cache_recommendation(cache_class)
|
|
166
|
-
case cache_class
|
|
167
|
-
when 'ActiveSupport::Cache::NullStore'
|
|
168
|
-
Rails.env.production? ? 'Configure Redis or Memcached for production' : 'OK for development'
|
|
169
|
-
when 'ActiveSupport::Cache::MemoryStore'
|
|
170
|
-
'Consider Redis/Memcached for multi-server deployments'
|
|
171
|
-
when 'ActiveSupport::Cache::FileStore'
|
|
172
|
-
'Consider Redis/Memcached for better performance'
|
|
173
|
-
when 'ActiveSupport::Cache::RedisStore', 'ActiveSupport::Cache::RedisCacheStore'
|
|
174
|
-
'Excellent choice for production'
|
|
175
|
-
when 'ActiveSupport::Cache::MemCacheStore'
|
|
176
|
-
'Good choice for production'
|
|
177
|
-
else
|
|
178
|
-
'Verify cache store configuration'
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
namespace :health do
|
|
2
|
-
desc "Run comprehensive health check"
|
|
3
|
-
task check: :environment do
|
|
4
|
-
RailsHealthChecker.check
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
desc "Check gem dependencies"
|
|
8
|
-
task gems: :environment do
|
|
9
|
-
analyzer = RailsHealthChecker::GemAnalyzer.new
|
|
10
|
-
results = analyzer.analyze
|
|
11
|
-
|
|
12
|
-
puts "=== Gem Health Report ==="
|
|
13
|
-
puts "Total gems: #{results[:total]}"
|
|
14
|
-
puts "Outdated gems: #{results[:outdated]}"
|
|
15
|
-
puts "Vulnerable gems: #{results[:vulnerable]}"
|
|
16
|
-
puts "========================="
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
desc "Check database connectivity"
|
|
20
|
-
task database: :environment do
|
|
21
|
-
begin
|
|
22
|
-
ActiveRecord::Base.connection.active?
|
|
23
|
-
puts "✓ Database connection: healthy"
|
|
24
|
-
rescue => e
|
|
25
|
-
puts "✗ Database connection: failed (#{e.message})"
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
desc "Check background jobs health"
|
|
30
|
-
task jobs: :environment do
|
|
31
|
-
analyzer = RailsHealthChecker::JobAnalyzer.new
|
|
32
|
-
results = analyzer.analyze
|
|
33
|
-
|
|
34
|
-
puts "=== Background Jobs Health ==="
|
|
35
|
-
puts "Overall Status: #{results[:status]}"
|
|
36
|
-
|
|
37
|
-
if results[:sidekiq][:available]
|
|
38
|
-
sidekiq = results[:sidekiq]
|
|
39
|
-
puts "\nSidekiq:"
|
|
40
|
-
puts " Status: #{sidekiq[:status]}"
|
|
41
|
-
puts " Enqueued: #{sidekiq[:enqueued]}" unless sidekiq[:error]
|
|
42
|
-
puts " Failed: #{sidekiq[:failed]}" unless sidekiq[:error]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
if results[:resque][:available]
|
|
46
|
-
resque = results[:resque]
|
|
47
|
-
puts "\nResque:"
|
|
48
|
-
puts " Status: #{resque[:status]}"
|
|
49
|
-
puts " Pending: #{resque[:pending]}" unless resque[:error]
|
|
50
|
-
puts " Failed: #{resque[:failed]}" unless resque[:error]
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
puts "============================="
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
desc "Generate detailed health report file"
|
|
57
|
-
task report: :environment do
|
|
58
|
-
results = RailsHealthChecker::Checker.new.run
|
|
59
|
-
report_generator = RailsHealthChecker::ReportGenerator.new(results)
|
|
60
|
-
filename = report_generator.save_to_file
|
|
61
|
-
puts "📄 Health report updated: #{filename}"
|
|
62
|
-
end
|
|
63
|
-
end
|
data/lib/rails_health_checker.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
require_relative "rails_health_checker/version"
|
|
2
|
-
require_relative "rails_health_checker/checker"
|
|
3
|
-
require_relative "rails_health_checker/gem_analyzer"
|
|
4
|
-
require_relative "rails_health_checker/job_analyzer"
|
|
5
|
-
require_relative "rails_health_checker/system_analyzer"
|
|
6
|
-
require_relative "rails_health_checker/health_middleware"
|
|
7
|
-
require_relative "rails_health_checker/dashboard_middleware"
|
|
8
|
-
require_relative "rails_health_checker/report_generator"
|
|
9
|
-
require_relative "rails_health_checker/railtie" if defined?(Rails)
|
|
10
|
-
|
|
11
|
-
module RailsHealthChecker
|
|
12
|
-
class Error < StandardError; end
|
|
13
|
-
|
|
14
|
-
def self.check
|
|
15
|
-
Checker.new.run
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
require_relative "lib/rails_health_checker/version"
|
|
2
|
-
|
|
3
|
-
Gem::Specification.new do |spec|
|
|
4
|
-
spec.name = "rails-health-checker"
|
|
5
|
-
spec.version = RailsHealthChecker::VERSION
|
|
6
|
-
spec.authors = ["Arshdeep Singh"]
|
|
7
|
-
spec.email = ["arsh199820@gmail.com"]
|
|
8
|
-
|
|
9
|
-
spec.summary = "Comprehensive health checker for Rails applications and dependencies"
|
|
10
|
-
spec.description = "A Ruby gem that provides comprehensive health checking for Rails applications, including database connectivity, gem dependencies, security vulnerabilities, and system health monitoring with a web dashboard."
|
|
11
|
-
spec.homepage = "https://rails-health-checker.netlify.app"
|
|
12
|
-
spec.license = "MIT"
|
|
13
|
-
spec.required_ruby_version = ">= 2.6.0"
|
|
14
|
-
|
|
15
|
-
spec.metadata["homepage_uri"] = "https://rails-health-checker.netlify.app"
|
|
16
|
-
spec.metadata["source_code_uri"] = "https://github.com/ArshdeepGrover/rails-health-checker"
|
|
17
|
-
spec.metadata["changelog_uri"] = "https://github.com/ArshdeepGrover/rails-health-checker/blob/main/CHANGELOG.md"
|
|
18
|
-
spec.metadata["documentation_uri"] = "https://rails-health-checker.netlify.app"
|
|
19
|
-
spec.metadata["bug_tracker_uri"] = "https://github.com/ArshdeepGrover/rails-health-checker/issues"
|
|
20
|
-
|
|
21
|
-
spec.files = Dir.chdir(__dir__) do
|
|
22
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
23
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
spec.bindir = "exe"
|
|
27
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
28
|
-
spec.require_paths = ["lib"]
|
|
29
|
-
|
|
30
|
-
spec.add_dependency "rails", ">= 6.0"
|
|
31
|
-
spec.add_dependency "bundler", ">= 2.0"
|
|
32
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
|
33
|
-
end
|
data/simple_test.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require_relative 'lib/rails_health_checker/version'
|
|
4
|
-
require_relative 'lib/rails_health_checker/gem_analyzer'
|
|
5
|
-
|
|
6
|
-
puts "=== Simple Gem Test ==="
|
|
7
|
-
puts "Version: #{RailsHealthChecker::VERSION}"
|
|
8
|
-
|
|
9
|
-
# Test gem analyzer with mocked Bundler
|
|
10
|
-
module Bundler
|
|
11
|
-
def self.load
|
|
12
|
-
MockBundler.new
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class MockBundler
|
|
17
|
-
def specs
|
|
18
|
-
[
|
|
19
|
-
MockGem.new('rails', '7.0.0'),
|
|
20
|
-
MockGem.new('rspec', '3.12.0')
|
|
21
|
-
]
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
class MockGem
|
|
26
|
-
attr_reader :name, :version
|
|
27
|
-
|
|
28
|
-
def initialize(name, version)
|
|
29
|
-
@name = name
|
|
30
|
-
@version = MockVersion.new(version)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def gem_dir
|
|
34
|
-
"/path/to/#{name}"
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
class MockVersion
|
|
39
|
-
def initialize(version)
|
|
40
|
-
@version = version
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def to_s
|
|
44
|
-
@version
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
analyzer = RailsHealthChecker::GemAnalyzer.new
|
|
49
|
-
results = analyzer.analyze
|
|
50
|
-
|
|
51
|
-
puts "✓ Gem analysis: #{results[:total]} gems, #{results[:outdated]} outdated"
|
|
52
|
-
puts "✅ Basic functionality works!"
|
data/test_gem.rb
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
# Simple test script to verify gem functionality
|
|
4
|
-
require_relative 'lib/rails_health_checker'
|
|
5
|
-
|
|
6
|
-
# Mock Rails and ActiveRecord for testing
|
|
7
|
-
module Rails
|
|
8
|
-
def self.version
|
|
9
|
-
"7.0.0"
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
module ActiveRecord
|
|
14
|
-
class Base
|
|
15
|
-
def self.connection
|
|
16
|
-
MockConnection.new
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class MockConnection
|
|
22
|
-
def active?
|
|
23
|
-
true
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class Time
|
|
28
|
-
def self.current
|
|
29
|
-
Time.now
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Mock Bundler
|
|
34
|
-
module Bundler
|
|
35
|
-
def self.load
|
|
36
|
-
MockBundler.new
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
class MockBundler
|
|
41
|
-
def specs
|
|
42
|
-
[
|
|
43
|
-
MockGem.new('rails', '7.0.0'),
|
|
44
|
-
MockGem.new('rspec', '3.12.0')
|
|
45
|
-
]
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
class MockGem
|
|
50
|
-
attr_reader :name, :version
|
|
51
|
-
|
|
52
|
-
def initialize(name, version)
|
|
53
|
-
@name = name
|
|
54
|
-
@version = MockVersion.new(version)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def gem_dir
|
|
58
|
-
"/path/to/#{name}"
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
class MockVersion
|
|
63
|
-
def initialize(version)
|
|
64
|
-
@version = version
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def to_s
|
|
68
|
-
@version
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Test the gem
|
|
73
|
-
puts "Testing RailsHealthChecker gem..."
|
|
74
|
-
|
|
75
|
-
begin
|
|
76
|
-
# Test version
|
|
77
|
-
puts "✓ Version: #{RailsHealthChecker::VERSION}"
|
|
78
|
-
|
|
79
|
-
# Test checker
|
|
80
|
-
checker = RailsHealthChecker::Checker.new
|
|
81
|
-
results = checker.run
|
|
82
|
-
puts "✓ Health check completed"
|
|
83
|
-
|
|
84
|
-
# Test gem analyzer
|
|
85
|
-
analyzer = RailsHealthChecker::GemAnalyzer.new
|
|
86
|
-
gem_results = analyzer.analyze
|
|
87
|
-
puts "✓ Gem analysis completed: #{gem_results[:total]} gems found"
|
|
88
|
-
|
|
89
|
-
# Test middleware
|
|
90
|
-
middleware = RailsHealthChecker::HealthMiddleware.new(nil)
|
|
91
|
-
env = { 'PATH_INFO' => '/health' }
|
|
92
|
-
response = middleware.call(env)
|
|
93
|
-
puts "✓ Health endpoint returns: #{response[0]} status"
|
|
94
|
-
|
|
95
|
-
puts "\n✅ All tests passed!"
|
|
96
|
-
|
|
97
|
-
rescue => e
|
|
98
|
-
puts "❌ Test failed: #{e.message}"
|
|
99
|
-
puts e.backtrace.first(3)
|
|
100
|
-
end
|