Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ jobs:
strategy:
matrix:
appraisal: [
'rails50_rack22',
'rails52_rack22',
'rails60_rack22',
'rails61_rack22',
'rails70_rack22',
'rails71_rack22',
Expand Down
3 changes: 0 additions & 3 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ version_spec = ->(prefix, desc) { "~> #{desc.split(prefix).last.insert(1, ".")}.
# Rails version -> rack versions in format
# rails#{MAJOR}#{MINOR} => %w[ rack#{MAJOR}#{MINOR} ]
{
"rails50" => %w[rack22],
"rails52" => %w[rack22],
"rails60" => %w[rack22],
"rails61" => %w[rack22],
"rails70" => %w[rack22],
"rails71" => %w[rack22],
Expand Down
1 change: 1 addition & 0 deletions History.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Support Javax Servlet API 4.0 (JEE 8)
- Adds basic compatibility with JRuby 10.0
- Drop support for JRuby 9.3
- Drop support for Rails < 6.1
- Drop unnecessary `jruby.compat.version` and `RackConfig.getCompatVersion()` API
- Drop JMS support
- Drop deprecated `RackLogger` string (level) constants
Expand Down
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ For more information on Rack, visit http://rack.github.io/.

| JRuby-Rack Series | Status | Rack | JRuby | Java | Rails | Target Servlet API | Notes |
|------------------------------------------------------------|------------|-----------|------------|------|-----------|---------------------|--------------------------------------------|
| 2.0 (_planned_) | Dev | 2.2 | 9.4 → 10.0 | 8+ | 5.0 → 8.0 | 5.0+ (Jakarta EE 9) | Pre 5.0 servlet APIs non functional. |
| 1.3 (master, _unreleased_) | Dev | 2.2 | 9.4 → 10.0 | 8+ | 5.0 → 8.0 | 4.0 (Java EE 8) | Servlet 2.5 → 3.1 likely to work fine. |
| 2.0 (_planned_) | Dev | 2.2 | 9.4 → 10.0 | 8+ | 6.1 → 8.0 | 5.0+ (Jakarta EE 9) | Pre 5.0 servlet APIs non functional. |
| 1.3 (master, _unreleased_) | Dev | 2.2 | 9.4 → 10.0 | 8+ | 6.1 → 8.0 | 4.0 (Java EE 8) | Servlet 2.5 → 3.1 likely to work fine. |
| [1.2](https://github.com/jruby/jruby-rack/tree/1.2-stable) | Maintained | 2.2 | 9.3 → 9.4 | 8+ | 5.0 → 7.2 | 3.0 (Java EE 6) | Servlet 3.1 → 4.0 OK with some containers. |
| [1.1](https://github.com/jruby/jruby-rack/tree/1.1-stable) | EOL | 1.x → 2.2 | 1.6 → 9.4 | 6+ | 2.1 → 5.2 | 2.5 (Java EE 5) | Servlet 3.0 → 4.0 OK with some containers. |
| 1.0 | EOL | 0.9 → 1.x | 1.1 → 1.9 | 5+ | 2.1 → 3.x | 2.5 (Java EE 5) | |
Expand Down Expand Up @@ -335,6 +335,20 @@ package and push the .jar every time a commit changes a source file).
* `./mvnw release:perform` (possibly with `-DuseReleaseProfile=false` due to Javadoc doclint failures for now)
* `rake clean gem SKIP_SPECS=true` and push the gem

## Adding testing for new Rails versions

* Add the new version to `.github/workflows/maven.yml` under the `matrix` section
* Add a new configuration to the `Appraisals` file, then
```bundle exec appraisal generate```
* Generate a new stub Rails application for the new version
```shell
VERSION=rails72
cd src/spec/stub
rm -rf $VERSION && BUNDLE_GEMFILE=~/Projects/community/jruby-rack/gemfiles/${VERSION}_rack22.gemfile bundle exec rails new $VERSION --minimal --skip-git --skip-docker --skip-active-model --skip-active-record --skip-test --skip-system-test --skip-dev-gems --skip-bundle --skip-keeps --skip-asset-pipeline --skip-ci --skip-brakeman --skip-rubocop
```
* Manual changes to make to support testing
* In `config/production.rb` comment out the default `config.logger` value so jruby-rack applies its own `RailsLogger`.

## Support

Please use [github][3] to file bugs, patches and/or pull requests.
Expand Down
15 changes: 0 additions & 15 deletions gemfiles/rails50_rack22.gemfile

This file was deleted.

15 changes: 0 additions & 15 deletions gemfiles/rails52_rack22.gemfile

This file was deleted.

15 changes: 0 additions & 15 deletions gemfiles/rails60_rack22.gemfile

This file was deleted.

159 changes: 95 additions & 64 deletions src/spec/ruby/jruby/rack/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,77 +82,73 @@

end

it "should have defined Rails stub tests" do
expect(File.foreach(__FILE__).select { |line| line.include?("describe") }).to include(/^ describe.*lib: :#{CURRENT_LIB}/),
"Expected rails stub tests to be defined for #{CURRENT_LIB} inside integration_spec.rb"
expect(File.exist?(File.join(STUB_DIR, CURRENT_LIB.to_s))).to be(true),
"Expected rails stub dir for #{CURRENT_LIB.to_s} to exist at #{File.join(STUB_DIR, CURRENT_LIB.to_s).inspect}"
end if CURRENT_LIB.to_s.include?('rails')

shared_examples_for 'a rails app', :shared => true do

base_path = "file://#{STUB_DIR}/#{CURRENT_LIB.to_s}"

let(:servlet_context) do
new_servlet_context(base_path).tap { |servlet_context| prepare_servlet_context(servlet_context) }
new_servlet_context(base_path).tap { |servlet_context| prepare_servlet_context(servlet_context, base_path) }
end

it "initializes pooling when min/max set" do
servlet_context.addInitParameter('jruby.min.runtimes', '1')
servlet_context.addInitParameter('jruby.max.runtimes', '2')

listener = org.jruby.rack.rails.RailsServletContextListener.new
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
context "runtime" do

rack_factory = servlet_context.getAttribute("rack.factory")
expect(rack_factory).to be_a(RackApplicationFactory)
expect(rack_factory).to be_a(PoolingRackApplicationFactory)
expect(rack_factory.delegate).to be_a(RailsRackApplicationFactory)
it "initializes pooling when min/max set" do
servlet_context.addInitParameter('jruby.min.runtimes', '1')
servlet_context.addInitParameter('jruby.max.runtimes', '2')

expect(servlet_context.getAttribute("rack.context")).to be_a(RackContext)
expect(servlet_context.getAttribute("rack.context")).to be_a(ServletRackContext)
listener = org.jruby.rack.rails.RailsServletContextListener.new
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)

expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
end
rack_factory = servlet_context.getAttribute("rack.factory")
expect(rack_factory).to be_a(RackApplicationFactory)
expect(rack_factory).to be_a(PoolingRackApplicationFactory)
expect(rack_factory.delegate).to be_a(RailsRackApplicationFactory)

it "initializes shared (thread-safe) by default" do
listener = org.jruby.rack.rails.RailsServletContextListener.new
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
expect(servlet_context.getAttribute("rack.context")).to be_a(RackContext)
expect(servlet_context.getAttribute("rack.context")).to be_a(ServletRackContext)

rack_factory = servlet_context.getAttribute("rack.factory")
expect(rack_factory).to be_a(RackApplicationFactory)
expect(rack_factory).to be_a(SharedRackApplicationFactory)
expect(rack_factory.delegate).to be_a(RailsRackApplicationFactory)

expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
end

it "initializes shared (thread-safe) whem max runtimes is 1" do
servlet_context.addInitParameter('jruby.max.runtimes', '1')
expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
end

listener = org.jruby.rack.rails.RailsServletContextListener.new
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
it "initializes shared (thread-safe) by default" do
listener = org.jruby.rack.rails.RailsServletContextListener.new
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)

rack_factory = servlet_context.getAttribute("rack.factory")
expect(rack_factory).to be_a(RackApplicationFactory)
expect(rack_factory).to be_a(SharedRackApplicationFactory)
expect(rack_factory.delegate).to be_a(RailsRackApplicationFactory)
end
rack_factory = servlet_context.getAttribute("rack.factory")
expect(rack_factory).to be_a(RackApplicationFactory)
expect(rack_factory).to be_a(SharedRackApplicationFactory)
expect(rack_factory.delegate).to be_a(RailsRackApplicationFactory)

end
expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
end

describe 'rails 7.2', lib: :rails72 do
it "initializes shared (thread-safe) whem max runtimes is 1" do
servlet_context.addInitParameter('jruby.max.runtimes', '1')

before(:all) do
name = :rails72 # copy_gemfile :
raise "Environment variable BUNDLE_GEMFILE seems to not contain #{name.to_s}" unless ENV['BUNDLE_GEMFILE']&.include?(name.to_s)
FileUtils.cp ENV['BUNDLE_GEMFILE'], File.join(STUB_DIR, "#{name}/Gemfile")
FileUtils.cp "#{ENV['BUNDLE_GEMFILE']}.lock", File.join(STUB_DIR, "#{name}/Gemfile.lock")
Dir.chdir File.join(STUB_DIR, name.to_s)
end
listener = org.jruby.rack.rails.RailsServletContextListener.new
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)

def base_path
"#{STUB_DIR}/rails72"
rack_factory = servlet_context.getAttribute("rack.factory")
expect(rack_factory).to be_a(RackApplicationFactory)
expect(rack_factory).to be_a(SharedRackApplicationFactory)
expect(rack_factory.delegate).to be_a(RailsRackApplicationFactory)
end
end

it_should_behave_like 'a rails app'

context "initialized" do

before(:all) { copy_gemfile }

before(:all) do
initialize_rails('production', "file://#{base_path}") do |servlet_context, _|
prepare_servlet_context(servlet_context)
prepare_servlet_context(servlet_context, base_path)
end
end
after(:all) { restore_rails }
Expand All @@ -168,21 +164,30 @@ def base_path
should_eval_as_not_nil "defined?(Rails)"
should_eval_as_not_nil "Rails.logger"

# Rails 7.x wraps the default in a ActiveSupport::BroadcastLogger
should_eval_as_eql_to "Rails.logger.is_a? ActiveSupport::BroadcastLogger", true
should_eval_as_eql_to "Rails.logger.broadcasts.size", 1
should_eval_as_eql_to "Rails.logger.broadcasts.first.is_a? JRuby::Rack::Logger", true
# NOTE: TaggedLogging is a module that extends the logger instance:
should_eval_as_eql_to "Rails.logger.broadcasts.first.is_a? ActiveSupport::TaggedLogging", true

# production.rb: config.log_level = 'info'
should_eval_as_eql_to "Rails.logger.level", Logger::INFO
should_eval_as_eql_to "Rails.logger.broadcasts.first.level", Logger::INFO

unwrap_logger = "logger = Rails.logger.broadcasts.first;"
# Rails 7.1+ wraps the default in a ActiveSupport::BroadcastLogger
if Rails::VERSION::STRING < '7.1'
should_eval_as_eql_to "Rails.logger.is_a? JRuby::Rack::Logger", true
should_eval_as_eql_to "Rails.logger.is_a? ActiveSupport::TaggedLogging", true
unwrap_logger = "logger = Rails.logger;"
else
should_eval_as_not_nil "defined?(ActiveSupport::BroadcastLogger)"
should_eval_as_eql_to "Rails.logger.is_a? ActiveSupport::BroadcastLogger", true
should_eval_as_eql_to "Rails.logger.broadcasts.size", 1
should_eval_as_eql_to "Rails.logger.broadcasts.first.is_a? JRuby::Rack::Logger", true
# NOTE: TaggedLogging is a module that extends the logger instance:
should_eval_as_eql_to "Rails.logger.broadcasts.first.is_a? ActiveSupport::TaggedLogging", true

should_eval_as_eql_to "Rails.logger.broadcasts.first.level", Logger::INFO

unwrap_logger = "logger = Rails.logger.broadcasts.first;"
end

# sanity check logger-silence works:
should_eval_as_not_nil "#{unwrap_logger} defined?(logger.silence)"
should_eval_as_eql_to "#{unwrap_logger} logger.silence { logger.warn('from-integration-spec') }", true

should_eval_as_eql_to "#{unwrap_logger} logger.real_logger.is_a?(org.jruby.rack.logging.ServletContextLogger)", true
end

Expand All @@ -191,9 +196,33 @@ def base_path
should_eval_as_eql_to "Rails.public_path.to_s", "#{base_path}/public"
end

it "disables rack's chunked support (by default)" do
@runtime = @rack_factory.getApplication.getRuntime
expect_to_have_monkey_patched_chunked
end
end
end

describe 'rails 6.1', lib: :rails61 do
it_should_behave_like 'a rails app'
end

describe 'rails 7.0', lib: :rails70 do
it_should_behave_like 'a rails app'
end

describe 'rails 7.1', lib: :rails71 do
it_should_behave_like 'a rails app'
end

describe 'rails 7.2', lib: :rails72 do
it_should_behave_like 'a rails app'
end

describe 'rails 8.0', lib: :rails80 do
it_should_behave_like 'a rails app'
end

def expect_to_have_monkey_patched_chunked
@runtime.evalScriptlet "require 'rack/chunked'"
script = %{
Expand Down Expand Up @@ -232,17 +261,19 @@ def new_servlet_context(base_path = nil)
servlet_context
end

def prepare_servlet_context(servlet_context)
def prepare_servlet_context(servlet_context, base_path)
servlet_context.addInitParameter('rails.root', base_path)
servlet_context.addInitParameter('jruby.rack.layout_class', 'FileSystemLayout')
end

GEMFILES_DIR = File.expand_path('../../../gemfiles', STUB_DIR)

def copy_gemfile(name)
# e.g. 'rails30'
FileUtils.cp File.join(GEMFILES_DIR, "#{name}.gemfile"), File.join(STUB_DIR, "#{name}/WEB-INF/Gemfile")
FileUtils.cp File.join(GEMFILES_DIR, "#{name}.gemfile.lock"), File.join(STUB_DIR, "#{name}/WEB-INF/Gemfile.lock")
def copy_gemfile
name = CURRENT_LIB.to_s
raise "Environment variable BUNDLE_GEMFILE seems to not contain #{name}" unless ENV['BUNDLE_GEMFILE']&.include?(name)
FileUtils.cp ENV['BUNDLE_GEMFILE'], File.join(STUB_DIR, "#{name}/Gemfile")
FileUtils.cp "#{ENV['BUNDLE_GEMFILE']}.lock", File.join(STUB_DIR, "#{name}/Gemfile.lock")
Dir.chdir File.join(STUB_DIR, name)
end

ENV_COPY = ENV.to_h
Expand Down
19 changes: 19 additions & 0 deletions src/spec/stub/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
*/tmp
*/*.war

# Rails stub files we don't want
rails*/Rakefile
rails*/Gemfile
rails*/Gemfile.lock
rails*/bin
rails*/README.md
rails*/config.ru
rails*/.ruby-version
rails*/package.json

# Rails generates assets in samples that we don't really want
rails*/**/*.ico
rails*/**/*.png
rails*/**/*.svg
rails*/**/*.html
rails*/**/*.erb
rails*/**/*.js
rails*/**/*.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ApplicationController < ActionController::Base
end
2 changes: 2 additions & 0 deletions src/spec/stub/rails61/app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module ApplicationHelper
end
38 changes: 38 additions & 0 deletions src/spec/stub/rails61/config/application.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require_relative "boot"

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
# require "active_job/railtie"
# require "active_record/railtie"
# require "active_storage/engine"
require "action_controller/railtie"
# require "action_mailer/railtie"
# require "action_mailbox/engine"
# require "action_text/engine"
require "action_view/railtie"
# require "action_cable/engine"
# require "sprockets/railtie"
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Rails61
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.1

# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")

# Don't generate system test files.
config.generators.system_tests = nil
end
end
Loading