summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/boot.rb11
-rw-r--r--test/functional/workflows_controller_test.rb39
2 files changed, 50 insertions, 0 deletions
diff --git a/config/boot.rb b/config/boot.rb
index 7479b5aff..72ea699a5 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -1,5 +1,16 @@
# frozen_string_literal: true
+# Rack 3.1.14 or later limits query parameters to 4096 by default, which
+# prevents saving workflows with many statuses.
+# Setting RACK_QUERY_PARSER_PARAMS_LIMIT to 65536 allows handling up to
+# approximately 100 statuses.
+#
+# See also:
+# - https://www.redmine.org/issues/42875
+# - https://github.com/rack/rack/blob/v3.1.16/README.md#configuration
+# - https://github.com/rack/rack/blob/v3.1.16/lib/rack/query_parser.rb#L57
+ENV['RACK_QUERY_PARSER_PARAMS_LIMIT'] ||= '65536'
+
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
diff --git a/test/functional/workflows_controller_test.rb b/test/functional/workflows_controller_test.rb
index b30559d80..dcdc8d5bb 100644
--- a/test/functional/workflows_controller_test.rb
+++ b/test/functional/workflows_controller_test.rb
@@ -211,6 +211,45 @@ class WorkflowsControllerTest < Redmine::ControllerTest
assert w.assignee
end
+ def test_post_edit_with_large_number_of_statuses
+ # This test ensures that workflows with many statuses can be saved.
+ # Without setting `ENV['RACK_QUERY_PARSER_PARAMS_LIMIT']`, this raises
+ # ActionController::BadRequest exception due to exceeding the default
+ # query parameter limit of 4096.
+ WorkflowTransition.delete_all
+
+ num_statuses = 40
+ transitions_data = {}
+
+ # Allowed statuses for a new issue (status_id = 0)
+ transitions_data['0'] = {}
+ (1..num_statuses).each do |status_id|
+ transitions_data['0'][status_id.to_s] = {'always' => '1'}
+ end
+
+ # Status transitions between statuses
+ (1..num_statuses).each do |status_id_from| # rubocop:disable RuboCopStyle/CombinableLoops
+ transitions_data[status_id_from.to_s] = {}
+ (1..num_statuses).each do |status_id_to|
+ # skip self-transitions
+ next if status_id_from == status_id_to
+
+ transitions_data[status_id_from.to_s][status_id_to.to_s] = {
+ 'always' => '1', 'author' => '1', 'assignee' => '1'
+ }
+ end
+ end
+
+ assert_nothing_raised do
+ patch :update, :params => {
+ :role_id => 2,
+ :tracker_id => 1,
+ :transitions => transitions_data
+ }
+ end
+ assert_response :found
+ end
+
def test_get_permissions
get :permissions