From 9245460cdd200e7d97257c6f873ed40fbb11732f Mon Sep 17 00:00:00 2001 From: Philipp Thun Date: Fri, 24 Jan 2025 11:06:54 +0100 Subject: [PATCH] ActiveModel compatibility between Rails 7 and 8 The internal representation of the validation context has changed between Rails 7 and 8. As we don't use validation contexts, it only has to be ensured that a newly introduced class exists. --- lib/cloud_controller/db.rb | 8 ++ spec/unit/jobs/deserialization_spec.rb | 131 ++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/lib/cloud_controller/db.rb b/lib/cloud_controller/db.rb index 6a2083a6a94..cd9b9a40ba0 100644 --- a/lib/cloud_controller/db.rb +++ b/lib/cloud_controller/db.rb @@ -255,3 +255,11 @@ def self.logger end end end + +if Rails::VERSION::MAJOR < 8 + module ActiveModel + # rubocop:disable Lint/EmptyClass + class ValidationContext; end + # rubocop:enable Lint/EmptyClass + end +end diff --git a/spec/unit/jobs/deserialization_spec.rb b/spec/unit/jobs/deserialization_spec.rb index 5e3185b2ab6..4090492944c 100644 --- a/spec/unit/jobs/deserialization_spec.rb +++ b/spec/unit/jobs/deserialization_spec.rb @@ -118,7 +118,7 @@ module Jobs subject(:job) { SpaceApplyManifestActionJob.new(space, app_guid_message_hash, apply_manifest_action, user_audit_info) } - let(:serialized_job) do + let(:serialized_job_rails_7) do <<~EOS --- !ruby/object:VCAP::CloudController::Jobs::LoggingContextJob handler: !ruby/object:VCAP::CloudController::Jobs::TimeoutJob @@ -230,21 +230,142 @@ module Jobs EOS end + let(:serialized_job_rails_8) do + <<~EOS + --- !ruby/object:VCAP::CloudController::Jobs::LoggingContextJob + handler: !ruby/object:VCAP::CloudController::Jobs::TimeoutJob + handler: !ruby/object:VCAP::CloudController::Jobs::SpaceApplyManifestActionJob + space: !ruby/object:VCAP::CloudController::Space + values: + :id: #{space.id} + :guid: space-guid + :created_at: #{space.created_at.strftime('%F %H:%M:%S.%9N Z')} + :updated_at: #{space.updated_at.strftime('%F %H:%M:%S.%9N Z')} + :name: space-name + :organization_id: #{org.id} + :space_quota_definition_id:#{' '} + :allow_ssh: true + :isolation_segment_guid:#{' '} + app_guid_message_hash: + app-guid: &1 !ruby/object:VCAP::CloudController::AppManifestMessage + requested_keys: + - :name + - :instances + - :routes + - :buildpack + - :stack + extra_keys: [] + buildpack: ruby + instances: 4 + name: app-name + routes: + - :route: app.bommel + stack: cflinuxfs4 + original_yaml: + :name: app-name + :instances: 4 + :routes: + - :route: app.bommel + :buildpack: ruby + :stack: cflinuxfs4 + context_for_validation: !ruby/object:ActiveModel::ValidationContext + context:#{' '} + errors: !ruby/object:ActiveModel::Errors + base: *1 + errors: [] + manifest_process_scale_messages: + - &2 !ruby/object:VCAP::CloudController::ManifestProcessScaleMessage + requested_keys: + - :instances + - :type + extra_keys: [] + instances: 4 + type: web + context_for_validation: !ruby/object:ActiveModel::ValidationContext + context:#{' '} + errors: !ruby/object:ActiveModel::Errors + base: *2 + errors: [] + manifest_process_update_messages: [] + app_update_message: &3 !ruby/object:VCAP::CloudController::AppUpdateMessage + requested_keys: + - :lifecycle + extra_keys: [] + lifecycle: + :data: + :buildpacks: + - ruby + :stack: cflinuxfs4 + context_for_validation: !ruby/object:ActiveModel::ValidationContext + context:#{' '} + errors: !ruby/object:ActiveModel::Errors + base: *3 + errors: [] + manifest_buildpack_message: &4 !ruby/object:VCAP::CloudController::ManifestBuildpackMessage + requested_keys: + - :buildpack + extra_keys: [] + buildpack: ruby + context_for_validation: !ruby/object:ActiveModel::ValidationContext + context:#{' '} + errors: !ruby/object:ActiveModel::Errors + base: *4 + errors: [] + manifest_routes_update_message: &5 !ruby/object:VCAP::CloudController::ManifestRoutesUpdateMessage + requested_keys: + - :routes + extra_keys: [] + routes: + - :route: app.bommel + context_for_validation: !ruby/object:ActiveModel::ValidationContext + context:#{' '} + errors: !ruby/object:ActiveModel::Errors + base: *5 + errors: [] + manifest_route_mappings: + - :route: !ruby/object:VCAP::CloudController::ManifestRoute + attrs: + :scheme: unspecified + :user:#{' '} + :password:#{' '} + :host: app.bommel + :port:#{' '} + :path: '' + :query:#{' '} + :fragment:#{' '} + :full_route: app.bommel + :options: {} + :protocol:#{' '} + apply_manifest_action: !ruby/object:VCAP::CloudController::AppApplyManifest + user_audit_info: &6 !ruby/object:VCAP::CloudController::UserAuditInfo + user_email: user@bommel.com + user_name: user-name + user_guid: user-guid + user_audit_info: *6 + timeout: 14400 + request_id:#{' '} + EOS + end + it 'equals dumped job yaml' do VCAP::CloudController::Jobs::Enqueuer.new(job).enqueue jobs_in_db = Sequel::Model.db.fetch('SELECT handler FROM delayed_jobs').all expect(jobs_in_db.size).to eq(1) # We are not interested in minor differences like ordering of nodes. Therefore comparing it as hash. - permitted_classes = [ActiveModel::Errors, Time, Symbol, UserAuditInfo, AppApplyManifest, ManifestRoute, ManifestRoutesUpdateMessage, ManifestBuildpackMessage, - AppUpdateMessage, ManifestProcessScaleMessage, AppManifestMessage, Space, SpaceApplyManifestActionJob, TimeoutJob, LoggingContextJob] + permitted_classes = [ActiveModel::Errors, ActiveModel::ValidationContext, Time, Symbol, UserAuditInfo, AppApplyManifest, ManifestRoute, ManifestRoutesUpdateMessage, + ManifestBuildpackMessage, AppUpdateMessage, ManifestProcessScaleMessage, AppManifestMessage, Space, SpaceApplyManifestActionJob, TimeoutJob, + LoggingContextJob] db_job = YAML.safe_load(jobs_in_db[0][:handler], permitted_classes: permitted_classes, aliases: true).as_json - dumped_job = YAML.safe_load(serialized_job, permitted_classes: permitted_classes, aliases: true).as_json + dumped_job = YAML.safe_load(Rails::VERSION::MAJOR >= 8 ? serialized_job_rails_8 : serialized_job_rails_7, permitted_classes: permitted_classes, aliases: true).as_json expect(db_job).to eq(dumped_job) end it 'can be deserialized' do - object = YAML.load_dj(serialized_job) + object = YAML.load_dj(serialized_job_rails_7) + expect(object).not_to be_nil + + object = YAML.load_dj(serialized_job_rails_8) expect(object).not_to be_nil end end