From ce3d4cab5320b03c17b18243670df6b4ff7a09d8 Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Tue, 24 Feb 2026 12:31:07 +0100 Subject: [PATCH 01/11] Upgrade rails to 7.2 and dependencies --- Gemfile | 8 +-- Gemfile.lock | 168 ++++++++++++++++++++++++++------------------------- 2 files changed, 89 insertions(+), 87 deletions(-) diff --git a/Gemfile b/Gemfile index 0df173b631..88b4fb771f 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'aws-sdk-rails', '~> 3' gem 'aws-sdk-s3', '~> 1' gem 'dotenv-rails', '~> 2.7' -gem 'rails', '~> 7.1.5' +gem 'rails', '~> 7.2.3' gem 'mail', '~> 2.8.1' @@ -59,7 +59,7 @@ gem 'yabeda-prometheus-mmap' gem 'yabeda-sidekiq' gem 'activemerchant', '~> 1.137' -gem 'audited', '~> 5.4.2' +gem 'audited', '~> 5.8.0' gem 'stripe', '~> 5.28.0' # we need the stripe gem because activemerchant can not generate Stripe's "customers" gem 'acts_as_list', '~> 0.9.17' @@ -85,7 +85,7 @@ gem 'secure_headers', '~> 6.3.0' gem 'redlock' gem 'acts-as-taggable-on', '~> 11.0' -gem 'baby_squeel', '~> 3.0', '>= 3.0.0' +gem 'baby_squeel', '~> 4.0.0' gem 'browser' gem 'diff-lcs', '~> 1.2' gem 'hiredis-client' @@ -248,7 +248,7 @@ group :oracle do oracle = -> { (ENV['ORACLE'] == '1') || ENV.fetch('DATABASE_URL', ENV['DB'])&.start_with?('oracle') } # ENV['NLS_LANG'] ||= 'AMERICAN_AMERICA.AL32UTF8' if oracle ENV['NLS_LANG'] ||= 'AMERICAN_AMERICA.UTF8' if oracle - gem 'activerecord-oracle_enhanced-adapter', '~> 7.1.0', install_if: oracle + gem 'activerecord-oracle_enhanced-adapter', '~> 7.2.0', install_if: oracle gem 'ruby-oci8', require: false, install_if: oracle end diff --git a/Gemfile.lock b/Gemfile.lock index efba18e773..af27af31d5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,59 +65,56 @@ GEM activesupport (>= 3.2.19) Ascii85 (1.1.0) RedCloth (4.3.3) - actioncable (7.1.5.2) - actionpack (= 7.1.5.2) - activesupport (= 7.1.5.2) + actioncable (7.2.3) + actionpack (= 7.2.3) + activesupport (= 7.2.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.5.2) - actionpack (= 7.1.5.2) - activejob (= 7.1.5.2) - activerecord (= 7.1.5.2) - activestorage (= 7.1.5.2) - activesupport (= 7.1.5.2) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.5.2) - actionpack (= 7.1.5.2) - actionview (= 7.1.5.2) - activejob (= 7.1.5.2) - activesupport (= 7.1.5.2) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (7.2.3) + actionpack (= 7.2.3) + activejob (= 7.2.3) + activerecord (= 7.2.3) + activestorage (= 7.2.3) + activesupport (= 7.2.3) + mail (>= 2.8.0) + actionmailer (7.2.3) + actionpack (= 7.2.3) + actionview (= 7.2.3) + activejob (= 7.2.3) + activesupport (= 7.2.3) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.5.2) - actionview (= 7.1.5.2) - activesupport (= 7.1.5.2) + actionpack (7.2.3) + actionview (= 7.2.3) + activesupport (= 7.2.3) + cgi nokogiri (>= 1.8.5) racc - rack (>= 2.2.4) + rack (>= 2.2.4, < 3.3) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.5.2) - actionpack (= 7.1.5.2) - activerecord (= 7.1.5.2) - activestorage (= 7.1.5.2) - activesupport (= 7.1.5.2) + useragent (~> 0.16) + actiontext (7.2.3) + actionpack (= 7.2.3) + activerecord (= 7.2.3) + activestorage (= 7.2.3) + activesupport (= 7.2.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.5.2) - activesupport (= 7.1.5.2) + actionview (7.2.3) + activesupport (= 7.2.3) builder (~> 3.1) + cgi erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_record_query_trace (1.8.2) activerecord (>= 6.0.0) - activejob (7.1.5.2) - activesupport (= 7.1.5.2) + activejob (7.2.3) + activesupport (= 7.2.3) globalid (>= 0.3.6) activejob-uniqueness (0.4.0) activejob (>= 4.2, < 8.1) @@ -128,39 +125,38 @@ GEM i18n (>= 0.6.9) nokogiri (~> 1.4) rexml (~> 3.3, >= 3.3.4) - activemodel (7.1.5.2) - activesupport (= 7.1.5.2) + activemodel (7.2.3) + activesupport (= 7.2.3) activemodel-serializers-xml (1.0.2) activemodel (> 5.x) activesupport (> 5.x) builder (~> 3.1) - activerecord (7.1.5.2) - activemodel (= 7.1.5.2) - activesupport (= 7.1.5.2) + activerecord (7.2.3) + activemodel (= 7.2.3) + activesupport (= 7.2.3) timeout (>= 0.4.0) - activerecord-oracle_enhanced-adapter (7.1.1) - activerecord (~> 7.1.0) + activerecord-oracle_enhanced-adapter (7.2.0) + activerecord (~> 7.2.0) ruby-oci8 ruby-plsql (>= 0.6.0) - activestorage (7.1.5.2) - actionpack (= 7.1.5.2) - activejob (= 7.1.5.2) - activerecord (= 7.1.5.2) - activesupport (= 7.1.5.2) + activestorage (7.2.3) + actionpack (= 7.2.3) + activejob (= 7.2.3) + activerecord (= 7.2.3) + activesupport (= 7.2.3) marcel (~> 1.0) - activesupport (7.1.5.2) + activesupport (7.2.3) base64 benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) logger (>= 1.4.2) minitest (>= 5.1) - mutex_m securerandom (>= 0.3) - tzinfo (~> 2.0) + tzinfo (~> 2.0, >= 2.0.5) acts-as-taggable-on (11.0.0) activerecord (>= 7.0, < 8.0) zeitwerk (>= 2.4, < 3.0) @@ -180,9 +176,9 @@ GEM anyway_config (2.7.2) ruby-next-core (~> 1.0) ast (2.4.3) - audited (5.4.3) - activerecord (>= 5.0, < 7.2) - request_store (~> 1.2) + audited (5.8.0) + activerecord (>= 5.2, < 8.2) + activesupport (>= 5.2, < 8.2) aws-eventstream (1.4.0) aws-partitions (1.1196.0) aws-record (2.7.0) @@ -223,8 +219,8 @@ GEM rack (~> 2) aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) - baby_squeel (3.0.0) - activerecord (>= 6.1.5, < 7.2) + baby_squeel (4.0.0) + activerecord (>= 7.1.5) ransack (~> 4.1) base64 (0.3.0) bcrypt (3.1.13) @@ -547,7 +543,6 @@ GEM multi_test (0.1.2) multi_xml (0.6.0) mustache (1.1.1) - mutex_m (0.3.0) mysql2 (0.5.6) n_plus_one_control (0.6.2) net-http-digest_auth (1.4.1) @@ -563,7 +558,7 @@ GEM net-smtp (0.5.0) net-protocol netrc (0.11.0) - nio4r (2.7.4) + nio4r (2.7.5) nkf (0.2.0) nokogiri (1.18.9) mini_portile2 (~> 2.8.2) @@ -659,20 +654,20 @@ GEM rackup (1.0.1) rack (< 3) webrick - rails (7.1.5.2) - actioncable (= 7.1.5.2) - actionmailbox (= 7.1.5.2) - actionmailer (= 7.1.5.2) - actionpack (= 7.1.5.2) - actiontext (= 7.1.5.2) - actionview (= 7.1.5.2) - activejob (= 7.1.5.2) - activemodel (= 7.1.5.2) - activerecord (= 7.1.5.2) - activestorage (= 7.1.5.2) - activesupport (= 7.1.5.2) + rails (7.2.3) + actioncable (= 7.2.3) + actionmailbox (= 7.2.3) + actionmailer (= 7.2.3) + actionpack (= 7.2.3) + actiontext (= 7.2.3) + actionview (= 7.2.3) + activejob (= 7.2.3) + activemodel (= 7.2.3) + activerecord (= 7.2.3) + activestorage (= 7.2.3) + activesupport (= 7.2.3) bundler (>= 1.15.0) - railties (= 7.1.5.2) + railties (= 7.2.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -696,21 +691,23 @@ GEM activemodel (>= 3.0) activesupport (>= 3.0) ruby_event_store (~> 0.9.0) - railties (7.1.5.2) - actionpack (= 7.1.5.2) - activesupport (= 7.1.5.2) - irb + railties (7.2.3) + actionpack (= 7.2.3) + activesupport (= 7.2.3) + cgi + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) raindrops (0.20.1) rake (13.2.1) rake-compiler-dock (1.9.1) - ransack (4.2.1) - activerecord (>= 6.1.5) - activesupport (>= 6.1.5) + ransack (4.4.1) + activerecord (>= 7.2) + activesupport (>= 7.2) i18n ratelimit (1.0.3) redis (>= 2.0.0) @@ -936,6 +933,9 @@ GEM tilt (2.0.11) timeout (0.4.3) tomlrb (2.0.3) + ts-datetime-delta (2.0.2) + thinking-sphinx (>= 1.3.8) + tsort (0.2.0) ttfunk (1.7.0) tty-color (0.6.0) tty-cursor (0.7.1) @@ -971,6 +971,7 @@ GEM rack unicorn uniform_notifier (1.17.0) + useragent (0.16.11) version_gem (1.1.3) webmock (3.24.0) addressable (>= 2.8.0) @@ -979,7 +980,8 @@ GEM webrick (1.8.2) webrobots (0.1.2) websocket (1.2.11) - websocket-driver (0.7.6) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) will_paginate (3.3.1) @@ -1017,17 +1019,17 @@ DEPENDENCIES activejob-uniqueness activemerchant (~> 1.137) activemodel-serializers-xml - activerecord-oracle_enhanced-adapter (~> 7.1.0) + activerecord-oracle_enhanced-adapter (~> 7.2.0) acts-as-taggable-on (~> 11.0) acts_as_list (~> 0.9.17) acts_as_tree (~> 2.9.1) addressable after_commit_queue (~> 1.1.0) analytics-ruby - audited (~> 5.4.2) + audited (~> 5.8.0) aws-sdk-rails (~> 3) aws-sdk-s3 (~> 1) - baby_squeel (~> 3.0, >= 3.0.0) + baby_squeel (~> 4.0.0) bcrypt (~> 3.1.7) bootsnap (~> 1.16) braintree (~> 4.25.0) @@ -1109,7 +1111,7 @@ DEPENDENCIES rack-no_animations (~> 1.0.3) rack-utf8_sanitizer rack-x_served_by (~> 0.1.1) - rails (~> 7.1.5) + rails (~> 7.2.3) rails-controller-testing (~> 1.0.4) rails-observers rails_event_store (~> 0.9.0) From 618f06b22b45184a1a7df3f79d1be35e118b158a Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Tue, 24 Feb 2026 12:40:55 +0100 Subject: [PATCH 02/11] Upgrade other dependencies --- Gemfile | 2 +- Gemfile.lock | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 88b4fb771f..4d18e40116 100644 --- a/Gemfile +++ b/Gemfile @@ -222,7 +222,7 @@ group :development, :test do gem 'active_record_query_trace' gem 'bootsnap', '~> 1.16' - gem 'bullet', '~> 7.1.6' + gem 'bullet', '~> 7.2.0' gem 'colorize' gem 'factory_bot_rails', '~> 6.2' diff --git a/Gemfile.lock b/Gemfile.lock index af27af31d5..858501fb8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -224,7 +224,7 @@ GEM ransack (~> 4.1) base64 (0.3.0) bcrypt (3.1.13) - benchmark (0.4.1) + benchmark (0.5.0) bigdecimal (3.3.1) binding_of_caller (1.0.1) debug_inspector (>= 1.2.0) @@ -237,7 +237,7 @@ GEM bugsnag (6.26.3) concurrent-ruby (~> 1.0) builder (3.3.0) - bullet (7.1.6) + bullet (7.2.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) byebug (12.0.0) @@ -267,8 +267,8 @@ GEM coffee-script-source (1.12.2) colorize (0.8.1) commonmarker (0.23.10) - concurrent-ruby (1.3.5) - connection_pool (2.5.4) + concurrent-ruby (1.3.6) + connection_pool (2.5.5) crack (1.0.0) bigdecimal rexml @@ -312,11 +312,11 @@ GEM cucumber-core (~> 10.1, >= 10.1.0) cucumber-cucumber-expressions (~> 14.0, >= 14.0.0) dalli (3.2.4) - database_cleaner (2.0.2) + database_cleaner (2.1.0) database_cleaner-active_record (>= 2, < 3) - database_cleaner-active_record (2.1.0) + database_cleaner-active_record (2.2.2) activerecord (>= 5.a) - database_cleaner-core (~> 2.0.0) + database_cleaner-core (~> 2.0) database_cleaner-core (2.0.1) date (3.4.1) debug_inspector (1.2.0) @@ -434,7 +434,7 @@ GEM http-form_data (2.3.0) http-parser (1.2.3) ffi-compiler (>= 1.0, < 2.0) - i18n (1.14.7) + i18n (1.14.8) concurrent-ruby (~> 1.0) injectedlogger (0.0.13) innertube (1.1.0) @@ -931,7 +931,7 @@ GEM riddle (~> 2.3) thor (1.4.0) tilt (2.0.11) - timeout (0.4.3) + timeout (0.6.0) tomlrb (2.0.3) ts-datetime-delta (2.0.2) thinking-sphinx (>= 1.3.8) @@ -970,7 +970,7 @@ GEM unicorn-rails (2.2.1) rack unicorn - uniform_notifier (1.17.0) + uniform_notifier (1.18.0) useragent (0.16.11) version_gem (1.1.3) webmock (3.24.0) @@ -1035,7 +1035,7 @@ DEPENDENCIES braintree (~> 4.25.0) browser bugsnag (~> 6.26) - bullet (~> 7.1.6) + bullet (~> 7.2.0) cancancan (~> 3.6.0) capybara (~> 3.40.0) childprocess From a9cbb000680f597e3f1ff6c71820d480dac185ce Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Tue, 24 Feb 2026 13:57:41 +0100 Subject: [PATCH 03/11] rails app:update --- bin/setup | 2 +- config/environments/development.rb | 11 +-- config/environments/production.rb | 8 +++ config/environments/test.rb | 12 ++-- config/initializers/assets.rb | 2 +- .../new_framework_defaults_7_2.rb | 70 +++++++++++++++++++ config/puma.rb | 37 +++++++--- public/robots.txt | 2 +- 8 files changed, 123 insertions(+), 21 deletions(-) create mode 100644 config/initializers/new_framework_defaults_7_2.rb diff --git a/bin/setup b/bin/setup index 51fa6249fd..151dccb767 100755 --- a/bin/setup +++ b/bin/setup @@ -1,8 +1,8 @@ #!/usr/bin/env ruby require "fileutils" -# path to your application root. APP_ROOT = File.expand_path("..", __dir__) +APP_NAME = "system" def system!(*args) system(*args, exception: true) diff --git a/config/environments/development.rb b/config/environments/development.rb index b52941c93b..4d9faf72ad 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -18,7 +18,7 @@ config.asset_host = config.three_scale.asset_host.presence - # Enable server timing + # Enable server timing. config.server_timing = true # Match custom domains on development @@ -36,12 +36,13 @@ # when we don't set this, the default from application config is used # config.cache_store = :memory_store - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" - } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" } # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = true + + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false config.action_mailer.perform_deliveries = true config.action_mailer.delivery_method = @@ -86,7 +87,7 @@ # WARNING: we can't enable it because it breaks some views that use `render_to_js_string` # config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = false # TODO: fix controllers and enable # Use an evented file watcher to asynchronously detect changes in source code, diff --git a/config/environments/production.rb b/config/environments/production.rb index 6616aa4887..374c0d25df 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -51,6 +51,9 @@ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + # Log to STDOUT by default # config.logger = ActiveSupport::Logger.new(STDOUT) # .tap { |logger| logger.formatter = ::Logger::Formatter.new } @@ -70,6 +73,8 @@ # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "system_production" + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. @@ -108,6 +113,9 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + # Only use :id for inspections in production. + config.active_record.attributes_for_inspect = [ :id ] + # Enable DNS rebinding protection and other `Host` header attacks. # config.hosts = [ # "example.com", # Allow requests from example.com diff --git a/config/environments/test.rb b/config/environments/test.rb index 9becd67bbe..201888e741 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -19,9 +19,7 @@ # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" - } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. config.consider_all_requests_local = false @@ -37,6 +35,8 @@ # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. @@ -44,6 +44,10 @@ # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # Unlike controllers, the mailer instance doesn't have any context about the + # incoming request so you'll need to provide the :host parameter yourself. + # config.action_mailer.default_url_options = { host: "www.example.com" } + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr @@ -60,7 +64,7 @@ # WARNING: we can't enable it because it breaks some views that use `render_to_js_string` # config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = false # TODO: fix controllers and enable config.active_support.test_order = :random diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 2eb2a03feb..9ade73458d 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -10,7 +10,7 @@ # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. -# Rails.application.config.assets.precompile += %w( admin.js admin.css ) +# Rails.application.config.assets.precompile += %w[ admin.js admin.css ] Rails.application.config.assets.paths << Rails.root.join("app/assets/builds") Rails.application.config.assets.paths << Rails.root.join('assets') diff --git a/config/initializers/new_framework_defaults_7_2.rb b/config/initializers/new_framework_defaults_7_2.rb new file mode 100644 index 0000000000..b549c4a258 --- /dev/null +++ b/config/initializers/new_framework_defaults_7_2.rb @@ -0,0 +1,70 @@ +# Be sure to restart your server when you modify this file. +# +# This file eases your Rails 7.2 framework defaults upgrade. +# +# Uncomment each configuration one by one to switch to the new default. +# Once your application is ready to run with all new defaults, you can remove +# this file and set the `config.load_defaults` to `7.2`. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. +# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html + +### +# Controls whether Active Job's `#perform_later` and similar methods automatically defer +# the job queuing to after the current Active Record transaction is committed. +# +# Example: +# Topic.transaction do +# topic = Topic.create(...) +# NewTopicNotificationJob.perform_later(topic) +# end +# +# In this example, if the configuration is set to `:never`, the job will +# be enqueued immediately, even though the `Topic` hasn't been committed yet. +# Because of this, if the job is picked up almost immediately, or if the +# transaction doesn't succeed for some reason, the job will fail to find this +# topic in the database. +# +# If `enqueue_after_transaction_commit` is set to `:default`, the queue adapter +# will define the behaviour. +# +# Note: Active Job backends can disable this feature. This is generally done by +# backends that use the same database as Active Record as a queue, hence they +# don't need this feature. +#++ +# Rails.application.config.active_job.enqueue_after_transaction_commit = :default + +### +# Adds image/webp to the list of content types Active Storage considers as an image +# Prevents automatic conversion to a fallback PNG, and assumes clients support WebP, as they support gif, jpeg, and png. +# This is possible due to broad browser support for WebP, but older browsers and email clients may still not support +# WebP. Requires imagemagick/libvips built with WebP support. +#++ +# Rails.application.config.active_storage.web_image_content_types = %w[image/png image/jpeg image/gif image/webp] + +### +# Enable validation of migration timestamps. When set, an ActiveRecord::InvalidMigrationTimestampError +# will be raised if the timestamp prefix for a migration is more than a day ahead of the timestamp +# associated with the current time. This is done to prevent forward-dating of migration files, which can +# impact migration generation and other migration commands. +# +# Applications with existing timestamped migrations that do not adhere to the +# expected format can disable validation by setting this config to `false`. +#++ +# Rails.application.config.active_record.validate_migration_timestamps = true + +### +# Controls whether the PostgresqlAdapter should decode dates automatically with manual queries. +# +# Example: +# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.select_value("select '2024-01-01'::date") #=> Date +# +# This query used to return a `String`. +#++ +# Rails.application.config.active_record.postgresql_adapter_decode_dates = true + +### +# Enables YJIT as of Ruby 3.3, to bring sizeable performance improvements. If you are +# deploying to a memory constrained environment you may want to set this to `false`. +#++ +# Rails.application.config.yjit = true diff --git a/config/puma.rb b/config/puma.rb index af7846b1ba..791e0e3591 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,10 +1,26 @@ -# Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers: a minimum and maximum. -# Any libraries that use thread pools should be configured to match -# the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum; this matches the default thread size of Active Record. +# This configuration file will be evaluated by Puma. The top-level methods that +# are invoked here are part of Puma's configuration DSL. For more information +# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. + +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. +# +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# to prioritize throughput over latency. +# +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. # -threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. +# +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 5) threads threads_count, threads_count # Specifies the `worker_timeout` threshold that Puma will use to wait before @@ -13,8 +29,7 @@ worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -# -port ENV.fetch("PORT") { 3000 } +port ENV.fetch("PORT", 3000) # Specifies the `environment` that Puma will run in. # @@ -57,5 +72,9 @@ # end # -# Allow puma to be restarted by `rails restart` command. +# Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart + +# Specify the PID file. Defaults to tmp/pids/server.pid in development. +# In other environments, only set the PID file if requested. +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/public/robots.txt b/public/robots.txt index 085187fa58..714e0b845a 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,4 +1,4 @@ -# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file # # To ban all spiders from the entire site uncomment the next two lines: # User-Agent: * From 28846fcadfb9271b3b5ef7ad5fbe974a3306185f Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Tue, 24 Mar 2026 18:11:28 +0100 Subject: [PATCH 04/11] Set the default threads count for Puma to 3 --- config/puma.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/puma.rb b/config/puma.rb index 791e0e3591..e0487e3566 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -20,7 +20,7 @@ # Any libraries that use a connection pool or another resource pool should # be configured to provide at least as many connections as the number of # threads. This includes Active Record's `pool` parameter in `database.yml`. -threads_count = ENV.fetch("RAILS_MAX_THREADS", 5) +threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) threads threads_count, threads_count # Specifies the `worker_timeout` threshold that Puma will use to wait before From fe8d71e8fd21a59fab720e5fcd739744500df93f Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Wed, 25 Feb 2026 16:31:25 +0100 Subject: [PATCH 05/11] Fix unit tests --- test/unit/account_test.rb | 15 ++++++++++++--- test/unit/application_keys_test.rb | 5 +++-- test/unit/logic/provider_upgrade_test.rb | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb index 05849840d7..109d71c0bb 100644 --- a/test/unit/account_test.rb +++ b/test/unit/account_test.rb @@ -775,7 +775,10 @@ class DestroyTest < ActiveSupport::TestCase ActiveMerchant::Billing::BogusGateway.any_instance.expects(:unstore).never ::Sidekiq::Testing.inline! do - provider.destroy! + # Prevent exception when deserializing ProviderDomainsChangedEvent with a non-existing (destroyed) provider + suppress(ActiveJob::DeserializationError) do + provider.destroy! + end end # TODO: master should not be emailed about events related to schduled_for_deletion providers @@ -788,7 +791,10 @@ class DestroyTest < ActiveSupport::TestCase provider.schedule_for_deletion! ::Sidekiq::Testing.inline! do - provider.destroy! + # Prevent exception when deserializing ProviderDomainsChangedEvent with a non-existing (destroyed) provider + suppress(ActiveJob::DeserializationError) do + provider.destroy! + end end # TODO: master should not be notified about deleted scheduled for deletion providers for any reason @@ -801,7 +807,10 @@ class DestroyTest < ActiveSupport::TestCase provider.schedule_for_deletion! ::Sidekiq::Testing.inline! do - provider.destroy! + # Prevent exception when deserializing ProviderDomainsChangedEvent with a non-existing (destroyed) provider + suppress(ActiveJob::DeserializationError) do + provider.destroy! + end end # TODO: master should not be notified about deleted scheduled for deletion providers for any reason diff --git a/test/unit/application_keys_test.rb b/test/unit/application_keys_test.rb index 64f412db29..9b447330d4 100644 --- a/test/unit/application_keys_test.rb +++ b/test/unit/application_keys_test.rb @@ -209,8 +209,9 @@ def test_regenerate_key end test 'is audited' do - app_key = FactoryBot.build(:application_key) - app_key.application.user_account.save! + # Create the application first to ensure all associated objects are persisted + application = FactoryBot.create(:cinstance) + app_key = FactoryBot.build(:application_key, application: application) assert_difference(Audited.audit_class.method(:count)) do ApplicationKey.with_synchronous_auditing do diff --git a/test/unit/logic/provider_upgrade_test.rb b/test/unit/logic/provider_upgrade_test.rb index 9f8e2ee315..d880c616fe 100644 --- a/test/unit/logic/provider_upgrade_test.rb +++ b/test/unit/logic/provider_upgrade_test.rb @@ -155,14 +155,14 @@ def test_hideable_switches test 'first update switch, then limits' do constraints = @provider.create_provider_constraints! - assert_difference(Audited.audit_class.method(:count), +2) do + assert_difference(-> { Audited.audit_class.where(auditable_type: 'ProviderConstraints').count }, +2) do ProviderConstraints.with_synchronous_auditing do assert constraints.auditing_enabled?, 'auditing should be enabled' @provider.force_upgrade_to_provider_plan!(@pro) end end - switch_audit, upgrade_audit = Audited.audit_class.order(:id).last(2) + switch_audit, upgrade_audit = Audited.audit_class.where(auditable_type: 'ProviderConstraints').order(:id).last(2) assert_equal 'Upgrading max_services because of switch is enabled.', switch_audit.comment assert_equal 'Upgrading limits to match plan pro3M', upgrade_audit.comment From 766612eee67faaffd4052fe7930ff63bf0c03676 Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Thu, 26 Feb 2026 12:30:01 +0100 Subject: [PATCH 06/11] Fix some deprecations and warnings --- app/lib/three_scale/xml/builder.rb | 3 +-- app/models/authentication_provider.rb | 2 +- app/models/invoice.rb | 2 +- test/unit/account_test.rb | 9 +++++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/lib/three_scale/xml/builder.rb b/app/lib/three_scale/xml/builder.rb index 3babadfc40..cd08fa6058 100644 --- a/app/lib/three_scale/xml/builder.rb +++ b/app/lib/three_scale/xml/builder.rb @@ -1,9 +1,8 @@ require 'builder' -require 'active_support/proxy_object' module ThreeScale module XML - class Builder < ActiveSupport::ProxyObject + class Builder < ::BasicObject delegate :is_a?, :respond_to?, :to_xml, :to => :@builder delegate :as_json, :to_s, :to_str, :to => :to_xml diff --git a/app/models/authentication_provider.rb b/app/models/authentication_provider.rb index da649d223f..9d3d741b41 100644 --- a/app/models/authentication_provider.rb +++ b/app/models/authentication_provider.rb @@ -10,7 +10,7 @@ class AuthenticationProvider < ApplicationRecord include SystemName - enum account_type: {developer: 'developer', provider: 'provider'} + enum :account_type, { developer: 'developer', provider: 'provider' } has_system_name uniqueness_scope: [:account_id] validates :kind, uniqueness: { scope: %i[account_id account_type], case_sensitive: true }, if: :developer? diff --git a/app/models/invoice.rb b/app/models/invoice.rb index b8c2874891..d45981d524 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -11,7 +11,7 @@ class Invoice < ApplicationRecord DECIMALS = 2 CHARGE_PRECISION = 2 - enum creation_type: {manual: 'manual', background: 'background'} + enum :creation_type, { manual: 'manual', background: 'background' } include AfterCommitQueue audited diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb index 109d71c0bb..df0823b725 100644 --- a/test/unit/account_test.rb +++ b/test/unit/account_test.rb @@ -106,7 +106,9 @@ def setup # regression test: https://github.com/3scale/system/pull/3406 test 'update with nil as param should not raise error' do buyer = FactoryBot.create(:simple_buyer) - buyer.update(nil) + assert_nothing_raised do + buyer.update(nil) + end end test 'should validate self_domain uniqueness' do @@ -154,7 +156,10 @@ def setup provider = FactoryBot.create(:simple_provider) @named_scoped_provider = provider - @named_scoped_provider.update(org_name: 'account is not readonly') + new_org_name = 'account is not readonly' + @named_scoped_provider.update(org_name: new_org_name) + + assert_equal new_org_name, @named_scoped_provider.reload.org_name end test 'deleted buyer account have working #to_xml' do From d6babb646fb2fa6ddb6d249f6cc27c4d1a00fd1f Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Thu, 26 Feb 2026 12:32:45 +0100 Subject: [PATCH 07/11] Fix formatting issues --- app/models/authentication_provider.rb | 5 +++-- app/models/invoice.rb | 1 + test/unit/logic/provider_upgrade_test.rb | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/models/authentication_provider.rb b/app/models/authentication_provider.rb index 9d3d741b41..23fab04503 100644 --- a/app/models/authentication_provider.rb +++ b/app/models/authentication_provider.rb @@ -22,8 +22,8 @@ class AuthenticationProvider < ApplicationRecord length: { maximum: 255 } validates :system_name, exclusion: [ - RedhatCustomerPortalSupport::RH_CUSTOMER_PORTAL_SYSTEM_NAME, - ServiceDiscovery::AuthenticationProviderSupport::SERVICE_DISCOVERY_SYSTEM_NAME + RedhatCustomerPortalSupport::RH_CUSTOMER_PORTAL_SYSTEM_NAME, + ServiceDiscovery::AuthenticationProviderSupport::SERVICE_DISCOVERY_SYSTEM_NAME ] before_validation :set_defaults, on: :create @@ -141,6 +141,7 @@ def self.branded_available? def verify_valid_kind_for_account_type my_class = self.class return if developer? || (provider? && my_class.available(my_class.account_types[:provider]).include?(my_class)) + errors.add(:kind, :not_found) false end diff --git a/app/models/invoice.rb b/app/models/invoice.rb index d45981d524..515196fd18 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -14,6 +14,7 @@ class Invoice < ApplicationRecord enum :creation_type, { manual: 'manual', background: 'background' } include AfterCommitQueue + audited has_associated_audits diff --git a/test/unit/logic/provider_upgrade_test.rb b/test/unit/logic/provider_upgrade_test.rb index d880c616fe..61ac2f6e18 100644 --- a/test/unit/logic/provider_upgrade_test.rb +++ b/test/unit/logic/provider_upgrade_test.rb @@ -8,15 +8,15 @@ def setup @power1M = FactoryBot.create(:published_plan, :system_name => 'power1M', :issuer => service) rule = @power1M.send :plan_rule rule.stubs(:switches).returns(%i[finance multiple_applications branding require_cc_on_signup - account_plans multiple_users groups] - ) + account_plans multiple_users groups] + ) rule.stubs(:limits).returns(PlanRule::Limit.new(max_services: 1, max_users: 1)) rule.stubs(:rank).returns(10) @pro = FactoryBot.create(:published_plan, :system_name => 'pro3M', :issuer => service) rule_pro = @pro.send :plan_rule rule_pro.stubs(:switches).returns(%i[finance multiple_applications branding require_cc_on_signup account_plans - multiple_users groups multiple_services service_plans] - ) + multiple_users groups multiple_services service_plans] + ) rule_pro.stubs(:limits).returns(PlanRule::Limit.new(max_services: 3, max_users: 5)) rule_pro.stubs(:rank).returns(19) @base = FactoryBot.create(:published_plan, :system_name => 'base', :issuer => service) From 09069e7d9be64293406ab43dcce3284c6261dfee Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Wed, 25 Mar 2026 17:03:31 +0100 Subject: [PATCH 08/11] Fix: private method 'warn' called for class ActiveSupport::Deprecation --- features/step_definitions/custom_web_steps.rb | 10 +++++----- features/step_definitions/finance/invoicing_steps.rb | 6 +++--- features/step_definitions/form_steps.rb | 2 +- features/step_definitions/pagination_steps.rb | 4 ++-- features/step_definitions/search_steps.rb | 2 +- features/step_definitions/service_steps.rb | 4 ++-- features/support/capybara_extensions.rb | 4 ++-- features/support/helpers/table_helpers.rb | 2 +- features/support/plan_helpers.rb | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/features/step_definitions/custom_web_steps.rb b/features/step_definitions/custom_web_steps.rb index 447b9d1263..3b2b7cc164 100644 --- a/features/step_definitions/custom_web_steps.rb +++ b/features/step_definitions/custom_web_steps.rb @@ -2,14 +2,14 @@ #DEPRECATED: replace with <> Then "(I )(they )should see (a )(the )link to {}" do |page_name| - ActiveSupport::Deprecation.warn 'replace with <>' + ActiveSupport.deprecator.warn 'replace with <>' path = path_to(page_name) assert page.all('a').any? { |node| matches_path?(node[:href], path) } end #DEPRECATED: replace with <> Then /^I should not see link to (.+)$/ do |page_name| - ActiveSupport::Deprecation.warn 'replace with <>' + ActiveSupport.deprecator.warn 'replace with <>' path = path_to(page_name) assert page.all('a').none? { |node| matches_path?(node[:href], path) } end @@ -21,7 +21,7 @@ def matches_path?(url, path) #DEPRECATED: replace with <> Then /^I should see (?:|the )link "([^"]*)" containing "([^"]*)" in the URL$/ do |label, params| - ActiveSupport::Deprecation.warn 'replace with <>' + ActiveSupport.deprecator.warn 'replace with <>' params = params.split href_contain_params = proc do |selector| params.each do |param| @@ -33,13 +33,13 @@ def matches_path?(url, path) #DEPRECATED: replace with "there {should} be a link to {string}" Then /^(?:I )?should see (the |)link "([^"]*)"$/ do |_, label| - ActiveSupport::Deprecation.warn 'replace with "there {should} be a link to {string}"' + ActiveSupport.deprecator.warn 'replace with "there {should} be a link to {string}"' assert page.has_css?('a', :text => label) end #DEPRECATED: replace with "there {should} be a link to {string}" Then /^I should not see (?:the )?link "([^"]*)"$/ do |label| - ActiveSupport::Deprecation.warn 'replace with "there {should} be a link to {string}"' + ActiveSupport.deprecator.warn 'replace with "there {should} be a link to {string}"' assert page.has_no_xpath? ".//a[text()='#{label}']" end diff --git a/features/step_definitions/finance/invoicing_steps.rb b/features/step_definitions/finance/invoicing_steps.rb index cd03c527f8..c46f0213fe 100644 --- a/features/step_definitions/finance/invoicing_steps.rb +++ b/features/step_definitions/finance/invoicing_steps.rb @@ -54,7 +54,7 @@ end Given "an invoice of {buyer} for {date} with items(:)" do |buyer, month, items| - ActiveSupport::Deprecation.warn '[Cucumber] Deprecated! Use the newer step.' + ActiveSupport.deprecator.warn '[Cucumber] Deprecated! Use the newer step.' invoice = create_invoice buyer, month items.hashes.each { |item| invoice.line_items.create!(item) } end @@ -109,7 +109,7 @@ end Then /^the buyer should have following line items for "([^"]*)"(?: in the (\d)(?:nd|st|rd|th))? invoice:$/ do |date, order, items| - ActiveSupport::Deprecation.warn '[Cucumber] Deprecated! Assert table instead.' + ActiveSupport.deprecator.warn '[Cucumber] Deprecated! Assert table instead.' step "the buyer logs in" visit admin_account_invoices_path @@ -133,7 +133,7 @@ # TODO: change to accept REGEXPs! (use page.body and assert) Then(/^I should see line items$/) do |items| - ActiveSupport::Deprecation.warn '[Cucumber] Deprecated! Assert table instead.' + ActiveSupport.deprecator.warn '[Cucumber] Deprecated! Assert table instead.' assert_line_items(items) end diff --git a/features/step_definitions/form_steps.rb b/features/step_definitions/form_steps.rb index 2687d191f8..9f73f7a524 100644 --- a/features/step_definitions/form_steps.rb +++ b/features/step_definitions/form_steps.rb @@ -91,7 +91,7 @@ end When "(I )(they )select {string} from {string}" do |value, field| - ActiveSupport::Deprecation.warn "[cucumber] Detected a form not using PF4 css" unless page.has_css?('.pf-c-form__label', text: field, wait: 0) + ActiveSupport.deprecator.warn "[cucumber] Detected a form not using PF4 css" unless page.has_css?('.pf-c-form__label', text: field, wait: 0) element = find_field(field) # 'input' for React forms, and 'select' for HTML if element.tag_name == 'select' diff --git a/features/step_definitions/pagination_steps.rb b/features/step_definitions/pagination_steps.rb index f5f7a9cf75..2552b8fc61 100644 --- a/features/step_definitions/pagination_steps.rb +++ b/features/step_definitions/pagination_steps.rb @@ -2,7 +2,7 @@ Then "(I )(they )should see {int} pages" do |count| if has_css?('.pagination', wait: 0) - ActiveSupport::Deprecation.warn 'Implement table toolbar instead' + ActiveSupport.deprecator.warn 'Implement table toolbar instead' links = within(".pagination") do all("a:not(.next_page), em.current") end @@ -17,7 +17,7 @@ When "they look at the {ordinal} page" do |page| if has_css?('.pagination', wait: 0) - ActiveSupport::Deprecation.warn 'Implement table toolbar instead' + ActiveSupport.deprecator.warn 'Implement table toolbar instead' within ".pagination" do click_link page end diff --git a/features/step_definitions/search_steps.rb b/features/step_definitions/search_steps.rb index 76dcc151d9..bdc05de98c 100644 --- a/features/step_definitions/search_steps.rb +++ b/features/step_definitions/search_steps.rb @@ -29,7 +29,7 @@ # DEPRECATED: remove and use "the table is filtered with:" When "I/they search for:" do |table| - ActiveSupport::Deprecation.warn 'remove and use "the table is filtered with:"' + ActiveSupport.deprecator.warn 'remove and use "the table is filtered with:"' within ".search" do parameterize_headers(table) diff --git a/features/step_definitions/service_steps.rb b/features/step_definitions/service_steps.rb index 67574393a2..e9b5a617fa 100644 --- a/features/step_definitions/service_steps.rb +++ b/features/step_definitions/service_steps.rb @@ -47,12 +47,12 @@ end Given "the service of {provider} has {string} {enabled}" do |account, toggle, enabled| - ActiveSupport::Deprecation.warn '[cucumber] stop using "the service of provider" use "product" instead' + ActiveSupport.deprecator.warn '[cucumber] stop using "the service of provider" use "product" instead' account.first_service!.update_attribute("#{underscore_spaces(toggle)}_enabled", enabled) end Given "the service of {provider} has {string} set to {string}" do |account, name, value| - ActiveSupport::Deprecation.warn '[cucumber] stop using "the service of provider" use "product" instead' + ActiveSupport.deprecator.warn '[cucumber] stop using "the service of provider" use "product" instead' account.first_service!.update_attribute(underscore_spaces(name), value) end diff --git a/features/support/capybara_extensions.rb b/features/support/capybara_extensions.rb index c55dbfcd04..e75502f3ac 100644 --- a/features/support/capybara_extensions.rb +++ b/features/support/capybara_extensions.rb @@ -19,7 +19,7 @@ def fill_in(field, with:, **options) .find('input.pf-c-form-control') .set with else - ActiveSupport::Deprecation.warn "[cucumber] field not implemented with Patternfly: #{field}" + ActiveSupport.deprecator.warn "[cucumber] field not implemented with Patternfly: #{field}" super end end @@ -40,7 +40,7 @@ def select(value = nil, from: nil, **options) end end else - ActiveSupport::Deprecation.warn "[cucumber] Select not implemented with Patternfly: #{from}" + ActiveSupport.deprecator.warn "[cucumber] Select not implemented with Patternfly: #{from}" super end end diff --git a/features/support/helpers/table_helpers.rb b/features/support/helpers/table_helpers.rb index d8aafb7eb1..5e768604a6 100644 --- a/features/support/helpers/table_helpers.rb +++ b/features/support/helpers/table_helpers.rb @@ -12,7 +12,7 @@ module TableHelpers # def extract_table(table, rows, cells = nil) table = find(*table) - ActiveSupport::Deprecation.warn '[Cucumber] Table not implemented with Patternfly' unless table[:class].include?('pf-c-table') + ActiveSupport.deprecator.warn '[Cucumber] Table not implemented with Patternfly' unless table[:class].include?('pf-c-table') table.all(*rows).map do |row| if cells.respond_to?(:call) cells.call(row) diff --git a/features/support/plan_helpers.rb b/features/support/plan_helpers.rb index e49c6d1f4c..e8a0a30c31 100644 --- a/features/support/plan_helpers.rb +++ b/features/support/plan_helpers.rb @@ -1,7 +1,7 @@ module PlanHelpers def create_plan(type, options) - ActiveSupport::Deprecation.warn '[create_plan] Stop using this method, use factories' + ActiveSupport.deprecator.warn '[create_plan] Stop using this method, use factories' options[:cost] ||= 0 issuer = options[:issuer] From fefcaf8cae08d4ee6e4e664268c248b0f1687c6b Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Thu, 26 Mar 2026 14:51:36 +0100 Subject: [PATCH 09/11] Use ActiveJob::QueueAdapters::TestAdapter for tests --- config/environments/test.rb | 2 ++ features/buyers/accounts/bulk_operations.feature | 1 + features/buyers/service_contracts/bulk_operations.feature | 1 + features/developer_portal/admin/account/invoices.feature | 1 + features/developer_portal/buyer_password_reset.feature | 4 ++++ features/old/buyers/invitations/for_admins.feature | 1 + features/old/cms/email_templates.feature | 1 + features/old/finance/reporting/buyer.feature | 1 + features/old/signup/providers.feature | 2 +- features/provider/admin/account/invitations.feature | 1 + .../provider/admin/applications/bulk_operations.feature | 1 + .../provider/admin/applications/show/change_plan.feature | 1 + features/provider/password/reset.feature | 4 ++++ features/support/email.rb | 8 ++++++-- features/support/sphinx.rb | 5 ++++- test/unit/tasks/multitenant/tenants_test.rb | 5 +++++ test/workers/backend_delete_application_worker_test.rb | 6 ++++-- 17 files changed, 39 insertions(+), 6 deletions(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 201888e741..b5633abd5e 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -69,6 +69,8 @@ config.active_support.test_order = :random + config.active_job.queue_adapter = :test + config.three_scale.payments.merge!(enabled: true, active_merchant_mode: :test, active_merchant_logging: false) config.three_scale.rolling_updates.raise_error_unknown_features = true diff --git a/features/buyers/accounts/bulk_operations.feature b/features/buyers/accounts/bulk_operations.feature index 12cf79da0b..ca04a4eb2f 100644 --- a/features/buyers/accounts/bulk_operations.feature +++ b/features/buyers/accounts/bulk_operations.feature @@ -79,6 +79,7 @@ Feature: Buyer accounts bulk operations And press "Send" Then "alice@example.com" should receive no emails + @emails Scenario: Send email in bulk Given they go to the buyer accounts page And "alice@example.com" should receive no emails diff --git a/features/buyers/service_contracts/bulk_operations.feature b/features/buyers/service_contracts/bulk_operations.feature index 27dc84d989..62944e0795 100644 --- a/features/buyers/service_contracts/bulk_operations.feature +++ b/features/buyers/service_contracts/bulk_operations.feature @@ -57,6 +57,7 @@ Feature: Audience > Accounts > Service subscriptions bulk operations And press "Send" Then "jane@example.com" should receive no emails + @emails Scenario: Send email in bulk Given "jane@example.com" should receive no emails And "bob@example.com" should receive no emails diff --git a/features/developer_portal/admin/account/invoices.feature b/features/developer_portal/admin/account/invoices.feature index 6381d3ec88..242bc461dd 100644 --- a/features/developer_portal/admin/account/invoices.feature +++ b/features/developer_portal/admin/account/invoices.feature @@ -1,3 +1,4 @@ +@emails Feature: Dev Portal Buyer Invoices In order not be confused As a buyer diff --git a/features/developer_portal/buyer_password_reset.feature b/features/developer_portal/buyer_password_reset.feature index 2973272dad..5f9b2754af 100644 --- a/features/developer_portal/buyer_password_reset.feature +++ b/features/developer_portal/buyer_password_reset.feature @@ -29,6 +29,7 @@ Feature: Buyer password reset And the current domain is foo.3scale.localhost And they go to the login page + @emails Scenario: Reset password of an existing user Given they follow "Forgot password?" And they fill in "Email" with "zed@3scale.localhost" @@ -46,6 +47,7 @@ Feature: Buyer password reset And they press "Sign in" Then they should be logged in as "zed" + @emails Scenario: Invalid email Given no user exists with an email of "bob@3scale.localhost" And they follow "Forgot password?" @@ -54,6 +56,7 @@ Feature: Buyer password reset Then they should see "A password reset link will be sent to bob@3scale.localhost if a user exists with this email" And "bob@3scale.localhost" should receive no emails + @emails Scenario: Wrong confirmation Given they follow "Forgot password?" And they fill in "Email" with "zed@3scale.localhost" @@ -65,6 +68,7 @@ Feature: Buyer password reset Then they should see the password confirmation error And the password of user "zed" should not be "new_password_123" + @emails Scenario: Blank passwords When they follow "Forgot password?" And they fill in "Email" with "zed@3scale.localhost" diff --git a/features/old/buyers/invitations/for_admins.feature b/features/old/buyers/invitations/for_admins.feature index 1533e54277..c443f11008 100644 --- a/features/old/buyers/invitations/for_admins.feature +++ b/features/old/buyers/invitations/for_admins.feature @@ -54,6 +54,7 @@ Feature: Buyer Account Invitations And confirm the dialog Then I should not see invitation for "alice@lolcats.com" + @emails Scenario: Resending invitations Given an invitation sent to "invited@lolcats.com" to join account "lol cats" And an invitation sent to "pending@lolcats.com" to join account "lol cats" diff --git a/features/old/cms/email_templates.feature b/features/old/cms/email_templates.feature index eb38a72586..0650cdb8ef 100644 --- a/features/old/cms/email_templates.feature +++ b/features/old/cms/email_templates.feature @@ -55,6 +55,7 @@ Feature: Email templates management And field "Bcc" should be "bcc@3scale.localhost" And field "Cc" should be "cc@3scale.localhost" + @emails Scenario: New signup email template Given admin of account "foo.3scale.localhost" has email "foo@3scale.localhost" And all the rolling updates features are off diff --git a/features/old/finance/reporting/buyer.feature b/features/old/finance/reporting/buyer.feature index 94db13d250..71fd9f57b1 100644 --- a/features/old/finance/reporting/buyer.feature +++ b/features/old/finance/reporting/buyer.feature @@ -1,3 +1,4 @@ +@emails Feature: Billing Reporting In order to be informed about my spendings As a buyer of a provider that has billing enabled diff --git a/features/old/signup/providers.feature b/features/old/signup/providers.feature index 4b53c78d0b..afa631e470 100644 --- a/features/old/signup/providers.feature +++ b/features/old/signup/providers.feature @@ -1,4 +1,4 @@ -@audit @javascript +@audit @javascript @emails Feature: Signup In order to use Red Hat 3scale API management infrastructure As a wanna-be API provider diff --git a/features/provider/admin/account/invitations.feature b/features/provider/admin/account/invitations.feature index 58b807251d..f66d16708b 100644 --- a/features/provider/admin/account/invitations.feature +++ b/features/provider/admin/account/invitations.feature @@ -76,6 +76,7 @@ Feature: Provider Account Settings User Invitations Then field "Send invitation to" has inline error "This invitation has already been sent." And no invitation should be sent to "alice@example.org" + @emails Scenario: Accepting an invitation with different email Given an invitation sent to "alice@example.org" to join account "foo.3scale.localhost" And the invitee follows the link to sign up to the provider in the invitation sent to "alice@example.org" diff --git a/features/provider/admin/applications/bulk_operations.feature b/features/provider/admin/applications/bulk_operations.feature index e23fe986e8..33d116db54 100644 --- a/features/provider/admin/applications/bulk_operations.feature +++ b/features/provider/admin/applications/bulk_operations.feature @@ -66,6 +66,7 @@ Feature: Audience > Applications > Bulk operations | Body | | Then the buyer has received no emails + @emails Scenario: Send email in bulk Given the buyer has received no emails And item "Bob's App" is selected diff --git a/features/provider/admin/applications/show/change_plan.feature b/features/provider/admin/applications/show/change_plan.feature index 6351adc472..ab41d9f90f 100644 --- a/features/provider/admin/applications/show/change_plan.feature +++ b/features/provider/admin/applications/show/change_plan.feature @@ -46,6 +46,7 @@ Feature: Application plan change card And press "Change" within the change plan card Then they should see a toast alert with text "Plan changed to 'Premium'" + @emails Scenario: Buyer is notified if their plan is changed Given they go to the application's admin page And they select "Premium" from "Change plan" within the change plan card diff --git a/features/provider/password/reset.feature b/features/provider/password/reset.feature index 4674f7bdb8..d07ef0506e 100644 --- a/features/provider/password/reset.feature +++ b/features/provider/password/reset.feature @@ -48,6 +48,7 @@ Feature: Provider password reset Then they should see "We sent an email with password reset instructions to: unknown@not.valid" Then the current page is the provider login page + @emails Scenario: Set a new password Given the user has requested a new password And follow the link found in the provider password reset email send to "pepe@example.com" @@ -58,6 +59,7 @@ Feature: Provider password reset And the current page is the provider login page And the user is now able to sign in with password "superSecret1234#" + @emails Scenario: New password form validation Given the user has requested a new password And follow the link found in the provider password reset email send to "pepe@example.com" @@ -73,6 +75,7 @@ Feature: Provider password reset Given they go to the provider password page with invalid password reset token Then they should see "The password reset token is invalid" + @emails Scenario: Password reset token expires after 1 day Given time flies to 12th June 2009 And the user has requested a new password @@ -80,6 +83,7 @@ Feature: Provider password reset And follow the link found in the provider password reset email send to "pepe@example.com" Then they should see "The password reset token is invalid" + @emails Scenario: Reuse a password reset token Given the user has requested a new password And follow the link found in the provider password reset email send to "pepe@example.com" diff --git a/features/support/email.rb b/features/support/email.rb index ccfe674fb2..aa4ebfbaea 100644 --- a/features/support/email.rb +++ b/features/support/email.rb @@ -14,7 +14,11 @@ def find_latest_email(options) World(EmailSupport) -Before do - Sidekiq::Job.clear_all +Before '@emails' do ActionMailer::Base.deliveries.clear + ActiveJob::Base.queue_adapter = :inline +end + +After '@emails' do + ActiveJob::Base.queue_adapter = Rails.configuration.active_job.queue_adapter end diff --git a/features/support/sphinx.rb b/features/support/sphinx.rb index 4bb41c9b00..5e9b713941 100644 --- a/features/support/sphinx.rb +++ b/features/support/sphinx.rb @@ -6,7 +6,8 @@ end Before '@search' do - Sidekiq::Job.clear_all + ActiveJob::Base.queue_adapter = :inline + ::ThinkingSphinx::Test.stop ::ThinkingSphinx::Test.clear ::ThinkingSphinx::Test.init @@ -19,4 +20,6 @@ After '@search' do ::ThinkingSphinx::Test.disable_search_jobs! ::ThinkingSphinx::Test.stop + + ActiveJob::Base.queue_adapter = Rails.configuration.active_job.queue_adapter end diff --git a/test/unit/tasks/multitenant/tenants_test.rb b/test/unit/tasks/multitenant/tenants_test.rb index 4ba29e3d8f..62e9180709 100644 --- a/test/unit/tasks/multitenant/tenants_test.rb +++ b/test/unit/tasks/multitenant/tenants_test.rb @@ -167,6 +167,9 @@ class StaleThrottledDeleteTest < ActiveSupport::TestCase setup do @provider1 = FactoryBot.create(:simple_provider, state: "scheduled_for_deletion", state_changed_at: 7.months.ago) @provider2 = FactoryBot.create(:simple_provider, state: "scheduled_for_deletion", state_changed_at: 5.months.ago) + + @original_queue_adapter = ActiveJob::Base.queue_adapter + ActiveJob::Base.queue_adapter = :sidekiq Sidekiq::Testing.disable! end @@ -174,7 +177,9 @@ class StaleThrottledDeleteTest < ActiveSupport::TestCase Sidekiq::ScheduledSet.new.each(&:delete) Sidekiq::Queue.new.each(&:delete) assert_empty Sidekiq::Workers.new.to_a + Sidekiq::Testing.fake! + ActiveJob::Base.queue_adapter = @original_queue_adapter end test "do not schedule more than target concurrency number of jobs" do diff --git a/test/workers/backend_delete_application_worker_test.rb b/test/workers/backend_delete_application_worker_test.rb index 56bffb2aee..2665df4573 100644 --- a/test/workers/backend_delete_application_worker_test.rb +++ b/test/workers/backend_delete_application_worker_test.rb @@ -3,6 +3,8 @@ require 'test_helper' class BackendDeleteApplicationWorkerTest < ActiveSupport::TestCase + include ActiveJob::TestHelper + test 'perform' do application = FactoryBot.create(:simple_cinstance, application_id: 'backend-app-id') service = application.service @@ -13,13 +15,13 @@ class BackendDeleteApplicationWorkerTest < ActiveSupport::TestCase ThreeScale::Core::Application.expects(:delete).with(service.backend_id, application.application_id).in_sequence(seq) event = Applications::ApplicationDeletedEvent.create_and_publish!(application) - Sidekiq::Testing.inline! { BackendDeleteApplicationWorker.perform_later(event.event_id) } + perform_enqueued_jobs { BackendDeleteApplicationWorker.perform_later(event.event_id) } end test 'perform reports error when the event does not exist' do System::ErrorReporting.expects(:report_error).once.with do |exception, options| exception.is_a?(ActiveRecord::RecordNotFound) && (parameters = options[:parameters]) && parameters[:event_id] == 'fake-id' end - Sidekiq::Testing.inline! { BackendDeleteApplicationWorker.perform_later('fake-id') } + perform_enqueued_jobs { BackendDeleteApplicationWorker.perform_later('fake-id') } end end From 55c2ed31b2a7bdc4ed1f2cf97797fd345620cead Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Thu, 30 Apr 2026 11:53:16 +0200 Subject: [PATCH 10/11] Replace assert_nothing_raised with another assertion --- test/unit/account_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb index df0823b725..5b0282b266 100644 --- a/test/unit/account_test.rb +++ b/test/unit/account_test.rb @@ -106,9 +106,9 @@ def setup # regression test: https://github.com/3scale/system/pull/3406 test 'update with nil as param should not raise error' do buyer = FactoryBot.create(:simple_buyer) - assert_nothing_raised do - buyer.update(nil) - end + + buyer.update(nil) + assert_empty buyer.saved_changes, 'no changes should be saved' end test 'should validate self_domain uniqueness' do From 134a1dbbac0f8f27eace9e73048b322c9ef28505 Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Mon, 18 May 2026 21:04:01 +0200 Subject: [PATCH 11/11] Revert error supressing --- test/unit/account_test.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb index 5b0282b266..73a76b1d65 100644 --- a/test/unit/account_test.rb +++ b/test/unit/account_test.rb @@ -796,10 +796,7 @@ class DestroyTest < ActiveSupport::TestCase provider.schedule_for_deletion! ::Sidekiq::Testing.inline! do - # Prevent exception when deserializing ProviderDomainsChangedEvent with a non-existing (destroyed) provider - suppress(ActiveJob::DeserializationError) do - provider.destroy! - end + provider.destroy! end # TODO: master should not be notified about deleted scheduled for deletion providers for any reason @@ -812,10 +809,7 @@ class DestroyTest < ActiveSupport::TestCase provider.schedule_for_deletion! ::Sidekiq::Testing.inline! do - # Prevent exception when deserializing ProviderDomainsChangedEvent with a non-existing (destroyed) provider - suppress(ActiveJob::DeserializationError) do - provider.destroy! - end + provider.destroy! end # TODO: master should not be notified about deleted scheduled for deletion providers for any reason