Skip to content

Commit 1f4bf67

Browse files
authored
Merge pull request #323 from chadlwilson/1.2-reinstate-rails-stub-tests
[1.2] Reinstate Rails integration test stubs for Rails 5.0 -> 7.2
2 parents 1de971a + 690b569 commit 1f4bf67

File tree

161 files changed

+2951
-41
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+2951
-41
lines changed

.github/workflows/maven.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ jobs:
8686
cache: maven
8787

8888
- name: Setup JRuby
89-
uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
89+
uses: ruby/setup-ruby@829114fc20da43a41d27359103ec7a63020954d4 # v1.255.0
9090
with:
9191
ruby-version: jruby-${{ matrix.jruby_version }}
9292
bundler-cache: 'false' # Need to install later so we can vary from Gemfile.lock as required for JRuby version compatibility

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,20 @@ package and push the .jar every time a commit changes a source file).
348348
* mvn release:perform (possibly with -DuseReleaseProfile=false due to Javadoc doclint failures for now)
349349
* rake clean gem SKIP_SPECS=true and push the gem
350350

351+
## Adding testing for new Rails versions
352+
353+
* Add the new version to `.github/workflows/maven.yml` under the `matrix` section
354+
* Add a new configuration to the `Appraisals` file, then
355+
```bundle exec appraisal generate```
356+
* Generate a new stub Rails application for the new version
357+
```shell
358+
VERSION=rails72
359+
cd src/spec/stub
360+
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
361+
```
362+
* Manual changes to make to support testing
363+
* In `config/production.rb` comment out the default `config.logger` value so jruby-rack applies its own `RailsLogger`.
364+
351365
## Support
352366

353367
Please use [github][4] to file bugs, patches and/or pull requests.

src/spec/ruby/jruby/rack/integration_spec.rb

Lines changed: 141 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
before(:all) { require 'fileutils' }
1616

17-
#after(:all) { JRuby::Rack.context = nil }
18-
1917
describe 'rack (lambda)' do
2018

2119
before do
@@ -86,40 +84,141 @@
8684

8785
end
8886

87+
it "should have defined Rails stub tests" do
88+
expect(File.foreach(__FILE__).select { |line| line.include?("describe") }).to include(/^ describe.*lib: :#{CURRENT_LIB}/),
89+
"Expected rails stub tests to be defined for #{CURRENT_LIB} inside integration_spec.rb"
90+
expect(File.exist?(File.join(STUB_DIR, CURRENT_LIB.to_s))).to be(true),
91+
"Expected rails stub dir for #{CURRENT_LIB.to_s} to exist at #{File.join(STUB_DIR, CURRENT_LIB.to_s).inspect}"
92+
end if CURRENT_LIB.to_s.include?('rails')
93+
8994
shared_examples_for 'a rails app', :shared => true do
9095

91-
let(:servlet_context) { new_servlet_context(base_path) }
96+
base_path = "file://#{STUB_DIR}/#{CURRENT_LIB.to_s}"
9297

93-
it "initializes (pooling by default)" do
94-
listener = org.jruby.rack.rails.RailsServletContextListener.new
95-
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
98+
let(:servlet_context) do
99+
new_servlet_context(base_path).tap { |servlet_context| prepare_servlet_context(servlet_context, base_path) }
100+
end
96101

97-
rack_factory = servlet_context.getAttribute("rack.factory")
98-
expect(rack_factory).to be_a(RackApplicationFactory)
99-
expect(rack_factory).to be_a(PoolingRackApplicationFactory)
100-
expect(rack_factory).to respond_to(:realFactory)
101-
expect(rack_factory.realFactory).to be_a(RailsRackApplicationFactory)
102+
context "runtime" do
103+
104+
it "initializes (pooling by default)" do
105+
listener = org.jruby.rack.rails.RailsServletContextListener.new
106+
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
107+
108+
rack_factory = servlet_context.getAttribute("rack.factory")
109+
expect(rack_factory).to be_a(RackApplicationFactory)
110+
expect(rack_factory).to be_a(PoolingRackApplicationFactory)
111+
expect(rack_factory).to respond_to(:realFactory)
112+
expect(rack_factory.realFactory).to be_a(RailsRackApplicationFactory)
113+
114+
expect(servlet_context.getAttribute("rack.context")).to be_a(RackContext)
115+
expect(servlet_context.getAttribute("rack.context")).to be_a(ServletRackContext)
102116

103-
expect(servlet_context.getAttribute("rack.context")).to be_a(RackContext)
104-
expect(servlet_context.getAttribute("rack.context")).to be_a(ServletRackContext)
117+
expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
118+
end
119+
120+
it "initializes threadsafe!" do
121+
servlet_context.addInitParameter('jruby.max.runtimes', '1')
122+
123+
listener = org.jruby.rack.rails.RailsServletContextListener.new
124+
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
125+
126+
rack_factory = servlet_context.getAttribute("rack.factory")
127+
expect(rack_factory).to be_a(RackApplicationFactory)
128+
expect(rack_factory).to be_a(SharedRackApplicationFactory)
129+
expect(rack_factory.realFactory).to be_a(RailsRackApplicationFactory)
105130

106-
expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
131+
expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
132+
end
107133
end
108134

109-
it "initializes threadsafe!" do
110-
servlet_context.addInitParameter('jruby.max.runtimes', '1')
135+
context "initialized" do
111136

112-
listener = org.jruby.rack.rails.RailsServletContextListener.new
113-
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
137+
before(:all) { copy_gemfile }
114138

115-
rack_factory = servlet_context.getAttribute("rack.factory")
116-
expect(rack_factory).to be_a(RackApplicationFactory)
117-
expect(rack_factory).to be_a(SharedRackApplicationFactory)
118-
expect(rack_factory.realFactory).to be_a(RailsRackApplicationFactory)
139+
before(:all) do
140+
initialize_rails('production', "file://#{base_path}") do |servlet_context, _|
141+
prepare_servlet_context(servlet_context, base_path)
142+
end
143+
end
144+
after(:all) { restore_rails }
145+
146+
it "loaded rack ~> 2.2.0" do
147+
@runtime = @rack_factory.getApplication.getRuntime
148+
should_eval_as_not_nil "defined?(Rack.release)"
149+
should_eval_as_eql_to "Rack.release.to_s[0, 3]", '2.2'
150+
end
151+
152+
it "booted with a servlet logger" do
153+
@runtime = @rack_factory.getApplication.getRuntime
154+
should_eval_as_not_nil "defined?(Rails)"
155+
should_eval_as_not_nil "Rails.logger"
156+
157+
# production.rb: config.log_level = 'info'
158+
should_eval_as_eql_to "Rails.logger.level", Logger::INFO
159+
160+
# Rails 7.1+ wraps the default in a ActiveSupport::BroadcastLogger
161+
if Rails::VERSION::STRING < '7.1'
162+
should_eval_as_eql_to "Rails.logger.is_a? JRuby::Rack::Logger", true
163+
should_eval_as_eql_to "Rails.logger.is_a? ActiveSupport::TaggedLogging", true
164+
unwrap_logger = "logger = Rails.logger;"
165+
else
166+
should_eval_as_not_nil "defined?(ActiveSupport::BroadcastLogger)"
167+
should_eval_as_eql_to "Rails.logger.is_a? ActiveSupport::BroadcastLogger", true
168+
should_eval_as_eql_to "Rails.logger.broadcasts.size", 1
169+
should_eval_as_eql_to "Rails.logger.broadcasts.first.is_a? JRuby::Rack::Logger", true
170+
# NOTE: TaggedLogging is a module that extends the logger instance:
171+
should_eval_as_eql_to "Rails.logger.broadcasts.first.is_a? ActiveSupport::TaggedLogging", true
172+
173+
should_eval_as_eql_to "Rails.logger.broadcasts.first.level", Logger::INFO
174+
175+
unwrap_logger = "logger = Rails.logger.broadcasts.first;"
176+
end
177+
178+
# sanity check logger-silence works:
179+
should_eval_as_eql_to "#{unwrap_logger} logger.silence { logger.warn('from-integration-spec') }", true
180+
181+
should_eval_as_eql_to "#{unwrap_logger} logger.real_logger.is_a?(Java::OrgJrubyRackServlet::DefaultServletRackContext)", true
182+
end
183+
184+
it "sets up public_path" do
185+
@runtime = @rack_factory.getApplication.getRuntime
186+
should_eval_as_eql_to "Rails.public_path.to_s", "#{base_path}/public"
187+
end
119188

120-
expect(rack_factory.getApplication).to be_a(DefaultRackApplication)
189+
it "disables rack's chunked support (by default)" do
190+
@runtime = @rack_factory.getApplication.getRuntime
191+
expect_to_have_monkey_patched_chunked
192+
end
121193
end
194+
end
195+
196+
describe 'rails 5.0', lib: :rails50 do
197+
it_should_behave_like 'a rails app'
198+
end
199+
200+
describe 'rails 5.2', lib: :rails52 do
201+
it_should_behave_like 'a rails app'
202+
end
122203

204+
describe 'rails 6.0', lib: :rails60 do
205+
it_should_behave_like 'a rails app'
206+
end
207+
208+
describe 'rails 6.1', lib: :rails61 do
209+
it_should_behave_like 'a rails app'
210+
end
211+
212+
describe 'rails 7.0', lib: :rails70 do
213+
it_should_behave_like 'a rails app'
214+
end
215+
216+
describe 'rails 7.1', lib: :rails71 do
217+
it_should_behave_like 'a rails app'
218+
end
219+
220+
describe 'rails 7.2', lib: :rails72 do
221+
it_should_behave_like 'a rails app'
123222
end
124223

125224
def expect_to_have_monkey_patched_chunked
@@ -135,8 +234,6 @@ def expect_to_have_monkey_patched_chunked
135234
should_eval_as_eql_to script, "1\nsecond"
136235
end
137236

138-
ENV_COPY = ENV.to_h
139-
140237
def initialize_rails(env = nil, servlet_context = @servlet_context)
141238
if !servlet_context || servlet_context.is_a?(String)
142239
base = servlet_context.is_a?(String) ? servlet_context : nil
@@ -149,41 +246,45 @@ def initialize_rails(env = nil, servlet_context = @servlet_context)
149246
servlet_context.addInitParameter("jruby.runtime.env", the_env)
150247

151248
yield(servlet_context, listener) if block_given?
249+
152250
listener.contextInitialized javax.servlet.ServletContextEvent.new(servlet_context)
153251
@rack_context = servlet_context.getAttribute("rack.context")
154252
@rack_factory = servlet_context.getAttribute("rack.factory")
155-
@servlet_context ||= servlet_context
156-
end
157-
158-
def restore_rails
159-
#ENV['RACK_ENV'] = ENV_COPY['RACK_ENV'] if ENV.key?('RACK_ENV')
160-
#ENV['RAILS_ENV'] = ENV_COPY['RAILS_ENV'] if ENV.key?('RAILS_ENV')
253+
@servlet_context = servlet_context
161254
end
162255

163256
def new_servlet_context(base_path = nil)
164257
servlet_context = org.jruby.rack.mock.RackLoggingMockServletContext.new base_path
165-
servlet_context.logger = raise_logger
166-
prepare_servlet_context servlet_context
258+
servlet_context.logger = raise_logger('WARN').tap { |logger| logger.setEnabled(false) }
167259
servlet_context
168260
end
169261

170-
def prepare_servlet_context(servlet_context)
262+
def prepare_servlet_context(servlet_context, base_path)
171263
set_compat_version servlet_context
264+
servlet_context.addInitParameter('rails.root', base_path)
265+
servlet_context.addInitParameter('jruby.rack.layout_class', 'FileSystemLayout')
172266
end
173267

174268
def set_compat_version(servlet_context = @servlet_context); require 'jruby'
175269
compat_version = JRuby.runtime.getInstanceConfig.getCompatVersion # RUBY1_9
176270
servlet_context.addInitParameter("jruby.compat.version", compat_version.to_s)
177271
end
178272

179-
private
180-
181273
GEMFILES_DIR = File.expand_path('../../../gemfiles', STUB_DIR)
182274

183-
def copy_gemfile(name)
184-
# e.g. 'rails30'
185-
FileUtils.cp File.join(GEMFILES_DIR, "#{name}.gemfile"), File.join(STUB_DIR, "#{name}/WEB-INF/Gemfile")
186-
FileUtils.cp File.join(GEMFILES_DIR, "#{name}.gemfile.lock"), File.join(STUB_DIR, "#{name}/WEB-INF/Gemfile.lock")
275+
def copy_gemfile
276+
name = CURRENT_LIB.to_s
277+
raise "Environment variable BUNDLE_GEMFILE seems to not contain #{name}" unless ENV['BUNDLE_GEMFILE']&.include?(name)
278+
FileUtils.cp ENV['BUNDLE_GEMFILE'], File.join(STUB_DIR, "#{name}/Gemfile")
279+
FileUtils.cp "#{ENV['BUNDLE_GEMFILE']}.lock", File.join(STUB_DIR, "#{name}/Gemfile.lock")
280+
Dir.chdir File.join(STUB_DIR, name)
281+
end
282+
283+
ENV_COPY = ENV.to_h
284+
285+
def restore_rails
286+
ENV['RACK_ENV'] = ENV_COPY['RACK_ENV'] if ENV.key?('RACK_ENV')
287+
ENV['RAILS_ENV'] = ENV_COPY['RAILS_ENV'] if ENV.key?('RAILS_ENV')
187288
end
188289

189290
end

src/spec/stub/.gitignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
11
*/tmp
22
*/*.war
3+
4+
# Rails stub files we don't want
5+
rails*/Rakefile
6+
rails*/Gemfile
7+
rails*/Gemfile.lock
8+
rails*/bin
9+
rails*/README.md
10+
rails*/config.ru
11+
rails*/.ruby-version
12+
rails*/package.json
13+
14+
# Rails generates assets in samples that we don't really want
15+
rails*/**/*.ico
16+
rails*/**/*.png
17+
rails*/**/*.svg
18+
rails*/**/*.html
19+
rails*/**/*.erb
20+
rails*/**/*.js
21+
rails*/**/*.css
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class ApplicationController < ActionController::Base
2+
protect_from_forgery with: :exception
3+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module ApplicationHelper
2+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class ApplicationJob < ActiveJob::Base
2+
end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
require_relative 'boot'
2+
3+
require "rails"
4+
# Pick the frameworks you want:
5+
require "active_model/railtie"
6+
require "active_job/railtie"
7+
# require "active_record/railtie"
8+
require "action_controller/railtie"
9+
# require "action_mailer/railtie"
10+
require "action_view/railtie"
11+
# require "action_cable/engine"
12+
# require "sprockets/railtie"
13+
# require "rails/test_unit/railtie"
14+
15+
# Require the gems listed in Gemfile, including any gems
16+
# you've limited to :test, :development, or :production.
17+
Bundler.require(*Rails.groups)
18+
19+
module Rails50
20+
class Application < Rails::Application
21+
# Settings in config/environments/* take precedence over those specified here.
22+
# Application configuration should go into files in config/initializers
23+
# -- all .rb files in that directory are automatically loaded.
24+
end
25+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2+
3+
require 'bundler/setup' # Set up gems listed in the Gemfile.
4+
5+
# workaround for https://github.com/ruby-concurrency/concurrent-ruby/issues/1077 since https://github.com/rails/rails/pull/54264 wont be backported earlier than 7.1.
6+
require "logger"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Load the Rails application.
2+
require_relative 'application'
3+
4+
# Initialize the Rails application.
5+
Rails.application.initialize!

0 commit comments

Comments
 (0)