From 3c23a18b62230bd3a4dc82d753b59ae17a4bcb95 Mon Sep 17 00:00:00 2001 From: Martin Emde Date: Tue, 3 Dec 2024 11:27:44 -0800 Subject: [PATCH] assert_equal_hash performs assert_equal, but improves diffs on fail Convert all multi-line hash comparisons to assert_equal_hash --- .../api/v1/oidc/api_key_roles_test.rb | 53 +++---- .../integration/api/v1/oidc/id_tokens_test.rb | 9 +- ...ygem_trusted_publishers_controller_test.rb | 18 ++- .../oidc/trusted_publisher_controller_test.rb | 13 +- test/jobs/upload_info_file_job_test.rb | 9 +- test/jobs/upload_names_file_job_test.rb | 9 +- test/jobs/upload_versions_file_job_test.rb | 9 +- .../trusted_publisher/github_action_test.rb | 16 +-- test/models/sendgrid_event_test.rb | 8 +- test/models/web_hook_test.rb | 18 ++- test/system/avo/manual_changes_test.rb | 6 +- test/system/avo/rubygems_test.rb | 8 +- test/system/avo/users_test.rb | 14 +- test/system/avo/versions_test.rb | 2 +- test/system/avo/web_hooks_test.rb | 2 +- test/system/oidc_test.rb | 59 ++++---- ...set_links_to_version_metadata_task_test.rb | 45 +++--- test/test_helper.rb | 23 ++++ test/unit/avo/actions/base_action_test.rb | 129 +++++++++--------- .../unit/gemcutter/request_ip_address_test.rb | 2 +- 20 files changed, 239 insertions(+), 213 deletions(-) diff --git a/test/integration/api/v1/oidc/api_key_roles_test.rb b/test/integration/api/v1/oidc/api_key_roles_test.rb index 242b03ce242..b2f9a08e2b5 100644 --- a/test/integration/api/v1/oidc/api_key_roles_test.rb +++ b/test/integration/api/v1/oidc/api_key_roles_test.rb @@ -56,9 +56,8 @@ class Api::V1::OIDC::ApiKeyRolesTest < ActionDispatch::IntegrationTest headers: { "HTTP_AUTHORIZATION" => @user_api_key } assert_response :success - assert_equal( - { - "id" => @role.id, + assert_equal_hash( + { "id" => @role.id, "token" => @role.token, "oidc_provider_id" => @role.oidc_provider_id, "user_id" => @user.id, @@ -75,8 +74,8 @@ class Api::V1::OIDC::ApiKeyRolesTest < ActionDispatch::IntegrationTest ] }, "created_at" => @role.created_at.as_json, "updated_at" => @role.updated_at.as_json, - "deleted_at" => nil - }, response.parsed_body + "deleted_at" => nil }, + response.parsed_body ) end end @@ -252,12 +251,13 @@ def jwt(claims = @claims, key: @pkey) resp = response.parsed_body assert_match(/^rubygems_/, resp["rubygems_api_key"]) - assert_equal({ - "rubygems_api_key" => resp["rubygems_api_key"], + assert_equal_hash( + { "rubygems_api_key" => resp["rubygems_api_key"], "name" => "#{@role.name}-79685b65-945d-450a-a3d8-a36bcf72c23d", "scopes" => ["push_rubygem"], - "expires_at" => 30.minutes.from_now - }, resp) + "expires_at" => 30.minutes.from_now }, + resp + ) hashed_key = @user.api_keys.sole.hashed_key assert_equal hashed_key, Digest::SHA256.hexdigest(resp["rubygems_api_key"]) @@ -281,13 +281,14 @@ def jwt(claims = @claims, key: @pkey) resp = response.parsed_body assert_match(/^rubygems_/, resp["rubygems_api_key"]) - assert_equal({ - "rubygems_api_key" => resp["rubygems_api_key"], + assert_equal_hash( + { "rubygems_api_key" => resp["rubygems_api_key"], "name" => "#{@role.name}-79685b65-945d-450a-a3d8-a36bcf72c23d", "scopes" => ["push_rubygem"], "expires_at" => 30.minutes.from_now, - "gem" => Rubygem.find_by!(name: gem_name).as_json - }, resp) + "gem" => Rubygem.find_by!(name: gem_name).as_json }, + resp + ) hashed_key = @user.api_keys.sole.hashed_key assert_equal hashed_key, Digest::SHA256.hexdigest(resp["rubygems_api_key"]) @@ -344,12 +345,13 @@ def jwt(claims = @claims, key: @pkey) resp = response.parsed_body assert_match(/^rubygems_/, resp["rubygems_api_key"]) - assert_equal({ - "rubygems_api_key" => resp["rubygems_api_key"], + assert_equal_hash( + { "rubygems_api_key" => resp["rubygems_api_key"], "name" => "#{@role.name}-79685b65-945d-450a-a3d8-a36bcf72c23d", "scopes" => ["push_rubygem"], - "expires_at" => 30.minutes.from_now - }, resp) + "expires_at" => 30.minutes.from_now }, + resp + ) hashed_key = @user.api_keys.sole.hashed_key assert_equal hashed_key, Digest::SHA256.hexdigest(resp["rubygems_api_key"]) @@ -358,16 +360,14 @@ def jwt(claims = @claims, key: @pkey) assert_equal hashed_key, oidc_id_token.api_key.hashed_key assert_equal @role.provider, oidc_id_token.provider - assert_equal( - { - "claims" => @claims, + assert_equal_hash( + { "claims" => @claims, "header" => { "alg" => "RS256", "kid" => @pkey.to_jwk[:kid], "typ" => "JWT" - } - }, - oidc_id_token.jwt + } }, + oidc_id_token.jwt ) post assume_role_api_v1_oidc_api_key_role_path(@role.token), @@ -377,9 +377,10 @@ def jwt(claims = @claims, key: @pkey) headers: {} assert_response :unprocessable_content - assert_equal({ - "errors" => { "jwt.claims.jti" => ["must be unique"] } - }, response.parsed_body) + assert_equal_hash( + { "errors" => { "jwt.claims.jti" => ["must be unique"] } }, + response.parsed_body + ) end end end diff --git a/test/integration/api/v1/oidc/id_tokens_test.rb b/test/integration/api/v1/oidc/id_tokens_test.rb index 60bd7154cc4..7e9dd1aca81 100644 --- a/test/integration/api/v1/oidc/id_tokens_test.rb +++ b/test/integration/api/v1/oidc/id_tokens_test.rb @@ -38,14 +38,13 @@ class Api::V1::OIDC::IdTokensTest < ActionDispatch::IntegrationTest headers: { "HTTP_AUTHORIZATION" => @user_api_key } assert_response :success - assert_equal( - { - "api_key_role_token" => @id_token.api_key_role.token, + assert_equal_hash( + { "api_key_role_token" => @id_token.api_key_role.token, "jwt" => { "claims" => @id_token.jwt["claims"], "header" => @id_token.jwt["header"] - } - }, response.parsed_body + } }, + response.parsed_body ) end end diff --git a/test/integration/api/v1/oidc/rubygem_trusted_publishers_controller_test.rb b/test/integration/api/v1/oidc/rubygem_trusted_publishers_controller_test.rb index 64af8414c8c..7eff8bc4adc 100644 --- a/test/integration/api/v1/oidc/rubygem_trusted_publishers_controller_test.rb +++ b/test/integration/api/v1/oidc/rubygem_trusted_publishers_controller_test.rb @@ -107,7 +107,7 @@ class Api::V1::OIDC::RubygemTrustedPublishersControllerTest < ActionDispatch::In repository_name = @trusted_publisher.trusted_publisher.repository_name assert_response :success - assert_equal( + assert_equal_hash( { "id" => @trusted_publisher.id, "trusted_publisher_type" => "OIDC::TrustedPublisher::GitHubAction", "trusted_publisher" => { @@ -117,7 +117,8 @@ class Api::V1::OIDC::RubygemTrustedPublishersControllerTest < ActionDispatch::In "repository_owner_id" => "123456", "workflow_filename" => "push_gem.yml", "environment" => nil - } }, @response.parsed_body + } }, + @response.parsed_body ) end end @@ -142,7 +143,7 @@ class Api::V1::OIDC::RubygemTrustedPublishersControllerTest < ActionDispatch::In trusted_publisher = OIDC::RubygemTrustedPublisher.find(response.parsed_body["id"]) assert_equal @rubygem, trusted_publisher.rubygem - assert_equal( + assert_equal_hash( { "id" => response.parsed_body["id"], "trusted_publisher_type" => "OIDC::TrustedPublisher::GitHubAction", "trusted_publisher" => { @@ -152,7 +153,8 @@ class Api::V1::OIDC::RubygemTrustedPublishersControllerTest < ActionDispatch::In "repository_owner_id" => "123456", "workflow_filename" => "push_gem.yml", "environment" => nil - } }, response.parsed_body + } }, + response.parsed_body ) end @@ -180,9 +182,11 @@ class Api::V1::OIDC::RubygemTrustedPublishersControllerTest < ActionDispatch::In headers: { "HTTP_AUTHORIZATION" => "12345" } assert_response :unprocessable_content - assert_equal({ "trusted_publisher.repository_name" => ["can't be blank"], - "trusted_publisher.workflow_filename" => ["can't be blank"] }, - response.parsed_body["errors"]) + assert_equal_hash( + { "trusted_publisher.repository_name" => ["can't be blank"], + "trusted_publisher.workflow_filename" => ["can't be blank"] }, + response.parsed_body["errors"] + ) end end diff --git a/test/integration/api/v1/oidc/trusted_publisher_controller_test.rb b/test/integration/api/v1/oidc/trusted_publisher_controller_test.rb index 98286492fd6..5d704d43818 100644 --- a/test/integration/api/v1/oidc/trusted_publisher_controller_test.rb +++ b/test/integration/api/v1/oidc/trusted_publisher_controller_test.rb @@ -241,12 +241,13 @@ def jwt(claims = @claims, key: @pkey) resp = response.parsed_body assert_match(/^rubygems_/, resp["rubygems_api_key"]) - assert_equal({ - "rubygems_api_key" => resp["rubygems_api_key"], - "name" => "GitHub Actions segiddins/oidc-test @ .github/workflows/token.yml 2023-03-28T16:22:17Z", - "scopes" => ["push_rubygem"], - "expires_at" => 15.minutes.from_now - }, resp) + assert_equal_hash( + { "rubygems_api_key" => resp["rubygems_api_key"], + "name" => "GitHub Actions segiddins/oidc-test @ .github/workflows/token.yml 2023-03-28T16:22:17Z", + "scopes" => ["push_rubygem"], + "expires_at" => 15.minutes.from_now }, + resp + ) api_key = trusted_publisher.api_keys.sole diff --git a/test/jobs/upload_info_file_job_test.rb b/test/jobs/upload_info_file_job_test.rb index f6780421052..61d5860f7e5 100644 --- a/test/jobs/upload_info_file_job_test.rb +++ b/test/jobs/upload_info_file_job_test.rb @@ -17,9 +17,8 @@ class UploadInfoFileJobTest < ActiveJob::TestCase assert_equal content, RubygemFs.compact_index.get("info/#{version.rubygem.name}") - assert_equal( - { - metadata: { + assert_equal_hash( + { metadata: { "surrogate-control" => "max-age=3600, stale-while-revalidate=1800", "surrogate-key" => "info/* info/#{version.rubygem.name} gem/#{version.rubygem.name} s3-compact-index s3-info/* s3-info/#{version.rubygem.name}", @@ -30,8 +29,8 @@ class UploadInfoFileJobTest < ActiveJob::TestCase content_type: "text/plain; charset=utf-8", checksum_sha256: Digest::SHA256.base64digest(content), content_md5: Digest::MD5.base64digest(content), - key: "info/#{version.rubygem.name}" - }, RubygemFs.compact_index.head("info/#{version.rubygem.name}") + key: "info/#{version.rubygem.name}" }, + RubygemFs.compact_index.head("info/#{version.rubygem.name}") ) assert_enqueued_with(job: FastlyPurgeJob, args: [{ key: "s3-info/#{version.rubygem.name}", soft: true }]) diff --git a/test/jobs/upload_names_file_job_test.rb b/test/jobs/upload_names_file_job_test.rb index 09437026bcb..ef792fcb449 100644 --- a/test/jobs/upload_names_file_job_test.rb +++ b/test/jobs/upload_names_file_job_test.rb @@ -17,9 +17,8 @@ class UploadNamesFileJobTest < ActiveJob::TestCase assert_equal content, RubygemFs.compact_index.get("names") - assert_equal( - { - metadata: { + assert_equal_hash( + { metadata: { "surrogate-control" => "max-age=3600, stale-while-revalidate=1800", "surrogate-key" => "names s3-compact-index s3-names", @@ -30,8 +29,8 @@ class UploadNamesFileJobTest < ActiveJob::TestCase content_type: "text/plain; charset=utf-8", checksum_sha256: Digest::SHA256.base64digest(content), content_md5: Digest::MD5.base64digest(content), - key: "names" - }, RubygemFs.compact_index.head("names") + key: "names" }, + RubygemFs.compact_index.head("names") ) assert_enqueued_with(job: FastlyPurgeJob, args: [{ key: "s3-names", soft: true }]) diff --git a/test/jobs/upload_versions_file_job_test.rb b/test/jobs/upload_versions_file_job_test.rb index 6aaf266f283..539e3a74896 100644 --- a/test/jobs/upload_versions_file_job_test.rb +++ b/test/jobs/upload_versions_file_job_test.rb @@ -18,9 +18,8 @@ class UploadVersionsFileJobTest < ActiveJob::TestCase assert_equal content, RubygemFs.compact_index.get("versions") - assert_equal( - { - metadata: { + assert_equal_hash( + { metadata: { "surrogate-control" => "max-age=3600, stale-while-revalidate=1800", "surrogate-key" => "versions s3-compact-index s3-versions", "sha256" => Digest::SHA256.base64digest(content), @@ -30,8 +29,8 @@ class UploadVersionsFileJobTest < ActiveJob::TestCase content_type: "text/plain; charset=utf-8", checksum_sha256: Digest::SHA256.base64digest(content), content_md5: Digest::MD5.base64digest(content), - key: "versions" - }, RubygemFs.compact_index.head("versions") + key: "versions" }, + RubygemFs.compact_index.head("versions") ) assert_enqueued_with(job: FastlyPurgeJob, args: [{ key: "s3-versions", soft: true }]) diff --git a/test/models/oidc/trusted_publisher/github_action_test.rb b/test/models/oidc/trusted_publisher/github_action_test.rb index bae69432ff9..cb6cc961bd8 100644 --- a/test/models/oidc/trusted_publisher/github_action_test.rb +++ b/test/models/oidc/trusted_publisher/github_action_test.rb @@ -79,11 +79,10 @@ class OIDC::TrustedPublisher::GitHubActionTest < ActiveSupport::TestCase test "#to_access_policy" do publisher = create(:oidc_trusted_publisher_github_action, repository_name: "rubygem1") - assert_equal( + assert_equal_hash( { statements: [ - { - effect: "allow", + { effect: "allow", principal: { oidc: "https://token.actions.githubusercontent.com" }, @@ -92,10 +91,8 @@ class OIDC::TrustedPublisher::GitHubActionTest < ActiveSupport::TestCase { operator: "string_equals", claim: "repository_owner_id", value: "123456" }, { operator: "string_equals", claim: "aud", value: Gemcutter::HOST }, { operator: "string_equals", claim: "job_workflow_ref", value: "example/rubygem1/.github/workflows/push_gem.yml@ref" } - ] - }, - { - effect: "allow", + ] }, + { effect: "allow", principal: { oidc: "https://token.actions.githubusercontent.com" }, @@ -104,8 +101,7 @@ class OIDC::TrustedPublisher::GitHubActionTest < ActiveSupport::TestCase { operator: "string_equals", claim: "repository_owner_id", value: "123456" }, { operator: "string_equals", claim: "aud", value: Gemcutter::HOST }, { operator: "string_equals", claim: "job_workflow_ref", value: "example/rubygem1/.github/workflows/push_gem.yml@sha" } - ] - } + ] } ] }.deep_stringify_keys, publisher.to_access_policy({ ref: "ref", sha: "sha" }).as_json @@ -113,7 +109,7 @@ class OIDC::TrustedPublisher::GitHubActionTest < ActiveSupport::TestCase publisher.update!(environment: "test") - assert_equal( + assert_equal_hash( { statements: [ { diff --git a/test/models/sendgrid_event_test.rb b/test/models/sendgrid_event_test.rb index 3acbf590856..aa4f2585b49 100644 --- a/test/models/sendgrid_event_test.rb +++ b/test/models/sendgrid_event_test.rb @@ -78,13 +78,11 @@ class SendgridEventTest < ActiveSupport::TestCase assert_equal("bounce", event.event_type) assert_equal(occurred_at, event.occurred_at) assert_predicate event, :pending? - assert_equal( - { - "email" => "user@example.com", + assert_equal_hash( + { "email" => "user@example.com", "sg_event_id" => "t61hI0Xpmk8XSR1YX4s0Kg==", "event" => "bounce", - "timestamp" => occurred_at.to_i - }, + "timestamp" => occurred_at.to_i }, event.payload ) end diff --git a/test/models/web_hook_test.rb b/test/models/web_hook_test.rb index 048eced3c6b..74defd8e84e 100644 --- a/test/models/web_hook_test.rb +++ b/test/models/web_hook_test.rb @@ -97,11 +97,10 @@ def stub_hook_relay_request(url, webhook_id, authorization, max_attempts = 3) end should "show limited attributes for to_json" do - assert_equal( - { - "url" => @url, - "failure_count" => @webhook.failure_count - }, JSON.load(@webhook.to_json) + assert_equal_hash( + { "url" => @url, + "failure_count" => @webhook.failure_count }, + JSON.load(@webhook.to_json) ) end @@ -115,11 +114,10 @@ def stub_hook_relay_request(url, webhook_id, authorization, max_attempts = 3) end should "show limited attributes for to_yaml" do - assert_equal( - { - "url" => @url, - "failure_count" => @webhook.failure_count - }, YAML.safe_load(@webhook.to_yaml) + assert_equal_hash( + { "url" => @url, + "failure_count" => @webhook.failure_count }, + YAML.safe_load(@webhook.to_yaml) ) end diff --git a/test/system/avo/manual_changes_test.rb b/test/system/avo/manual_changes_test.rb index 8d47468e5ea..91ad03c67e4 100644 --- a/test/system/avo/manual_changes_test.rb +++ b/test/system/avo/manual_changes_test.rb @@ -35,7 +35,7 @@ class Avo::ManualChangesSystemTest < ApplicationSystemTestCase assert_equal log_ticket, audit.auditable assert_equal "LogTicket", audit.auditable_type assert_equal "Manual create of LogTicket", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/LogTicket/#{log_ticket.id}" => { @@ -80,7 +80,7 @@ class Avo::ManualChangesSystemTest < ApplicationSystemTestCase assert_equal log_ticket, audit.auditable assert_equal "LogTicket", audit.auditable_type assert_equal "Manual update of LogTicket", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/LogTicket/#{log_ticket.id}" => { @@ -129,7 +129,7 @@ class Avo::ManualChangesSystemTest < ApplicationSystemTestCase assert_equal log_ticket.id, audit.auditable_id assert_equal "LogTicket", audit.auditable_type assert_equal "Manual destroy of LogTicket", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/LogTicket/#{log_ticket.id}" => { diff --git a/test/system/avo/rubygems_test.rb b/test/system/avo/rubygems_test.rb index e9d9dda8c00..df2099044a5 100644 --- a/test/system/avo/rubygems_test.rb +++ b/test/system/avo/rubygems_test.rb @@ -40,7 +40,7 @@ class Avo::RubygemsSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "Rubygem", audit.auditable_type assert_equal "Release reserved namespace", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/Rubygem/#{rubygem.id}" => { @@ -106,7 +106,7 @@ class Avo::RubygemsSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "Rubygem", audit.auditable_type assert_equal "Yank Rubygem", audit.action - assert_equal( + assert_equal_hash( { "fields" => { "version" => version.id.to_s }, "arguments" => {}, @@ -187,7 +187,7 @@ class Avo::RubygemsSystemTest < ApplicationSystemTestCase assert_equal "Rubygem", audit.auditable_type assert_equal "Yank Rubygem", audit.action - assert_equal( + assert_equal_hash( { "fields" => { "version" => "All" }, "arguments" => {}, @@ -274,7 +274,7 @@ class Avo::RubygemsSystemTest < ApplicationSystemTestCase assert_equal "Rubygem", audit.auditable_type assert_equal "Add owner", audit.action - assert_equal( + assert_equal_hash( { "fields" => { "owner" => { "id" => new_owner.id, "handle" => new_owner.handle } }, "arguments" => {}, diff --git a/test/system/avo/users_test.rb b/test/system/avo/users_test.rb index 19a99118c28..97d4c1c4dab 100644 --- a/test/system/avo/users_test.rb +++ b/test/system/avo/users_test.rb @@ -48,7 +48,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "User", audit.auditable_type assert_equal "Reset User 2FA", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/User/#{user.id}" => { @@ -123,7 +123,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "User", audit.auditable_type assert_equal "Block User", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/User/#{user.id}" => { @@ -208,7 +208,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "User", audit.auditable_type assert_equal "Reset Api Key", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/User/#{user.id}" => { @@ -294,7 +294,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase end rubygem_updated_at_changes = rubygem_audit["gid://gemcutter/Rubygem/#{rubygem.id}"]["changes"]["updated_at"] - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/Deletion/#{deletion.id}" => { @@ -398,7 +398,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase password_changed_event = user.events.where(tag: Events::UserEvent::PASSWORD_CHANGED).sole version_yanked_event = rubygem.events.where(tag: Events::RubygemEvent::VERSION_YANKED).sole - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/Deletion/#{deletion.id}" => { @@ -519,7 +519,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "User", audit.auditable_type assert_equal "Change User Email", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/User/#{user.id}" => { @@ -593,7 +593,7 @@ class Avo::UsersSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "User", audit.auditable_type assert_equal "Create User", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/User/#{user.id}" => { diff --git a/test/system/avo/versions_test.rb b/test/system/avo/versions_test.rb index 75a868ad56f..11b506c1b45 100644 --- a/test/system/avo/versions_test.rb +++ b/test/system/avo/versions_test.rb @@ -53,7 +53,7 @@ class Avo::VersionsSystemTest < ApplicationSystemTestCase rubygem_updated_at_changes = rubygem_audit["gid://gemcutter/Rubygem/#{rubygem.id}"]["changes"]["updated_at"] version_unyank_event = rubygem.events.where(tag: Events::RubygemEvent::VERSION_UNYANKED).sole - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/Version/#{version.id}" => diff --git a/test/system/avo/web_hooks_test.rb b/test/system/avo/web_hooks_test.rb index bbc2c22ca7b..1c28ffeb016 100644 --- a/test/system/avo/web_hooks_test.rb +++ b/test/system/avo/web_hooks_test.rb @@ -31,7 +31,7 @@ class Avo::WebHooksSystemTest < ApplicationSystemTestCase page.assert_text audit.id assert_equal "WebHook", audit.auditable_type assert_equal "Delete Webhook", audit.action - assert_equal( + assert_equal_hash( { "records" => { "gid://gemcutter/WebHook/#{web_hook.id}" => { diff --git a/test/system/oidc_test.rb b/test/system/oidc_test.rb index a6e19618a8a..62524a77d78 100644 --- a/test/system/oidc_test.rb +++ b/test/system/oidc_test.rb @@ -142,14 +142,14 @@ def verify_session # rubocop:disable Minitest/TestMethodName } } - assert_equal(expected, role.as_json.slice(*expected.keys)) + assert_equal_hash(expected, role.as_json.slice(*expected.keys)) click_button "Edit API Key Role" page.scroll_to :bottom click_button "Update Api key role" page.assert_selector "h1", text: "API Key Role Push #{rubygem.name}" - assert_equal(expected, role.reload.as_json.slice(*expected.keys)) + assert_equal_hash(expected, role.reload.as_json.slice(*expected.keys)) click_button "Edit API Key Role" @@ -176,7 +176,7 @@ def verify_session # rubocop:disable Minitest/TestMethodName click_button "Update Api key role" page.assert_text "Access policy statements[1] conditions[1] claim unknown for the provider" - assert_equal(expected, role.reload.as_json.slice(*expected.keys)) + assert_equal_hash(expected, role.reload.as_json.slice(*expected.keys)) page.find_field("Claim", with: "fudge").fill_in with: "event_name" @@ -188,31 +188,34 @@ def verify_session # rubocop:disable Minitest/TestMethodName click_button "Update Api key role" page.assert_selector "h1", text: "API Key Role Push gems" - assert_equal(expected.merge( - "name" => "Push gems", - "api_key_permissions" => { - "scopes" => %w[push_rubygem yank_rubygem], "valid_for" => 1800, "gems" => nil - }, - "access_policy" => { - "statements" => [ - { - "effect" => "allow", - "principal" => { "oidc" => "https://token.actions.githubusercontent.com" }, - "conditions" => [ - { "operator" => "string_equals", "claim" => "aud", "value" => "localhost" } - ] - }, - { - "effect" => "allow", - "principal" => { "oidc" => "https://token.actions.githubusercontent.com" }, - "conditions" => [ - { "operator" => "string_matches", "claim" => "sub", "value" => "repo:example/repo:ref:refs/tags/.*" }, - { "operator" => "string_equals", "claim" => "event_name", "value" => "" } - ] - } - ] - } - ), role.reload.as_json.slice(*expected.keys)) + + expected.merge!( + "name" => "Push gems", + "api_key_permissions" => { + "scopes" => %w[push_rubygem yank_rubygem], "valid_for" => 1800, "gems" => nil + }, + "access_policy" => { + "statements" => [ + { + "effect" => "allow", + "principal" => { "oidc" => "https://token.actions.githubusercontent.com" }, + "conditions" => [ + { "operator" => "string_equals", "claim" => "aud", "value" => "localhost" } + ] + }, + { + "effect" => "allow", + "principal" => { "oidc" => "https://token.actions.githubusercontent.com" }, + "conditions" => [ + { "operator" => "string_matches", "claim" => "sub", "value" => "repo:example/repo:ref:refs/tags/.*" }, + { "operator" => "string_equals", "claim" => "event_name", "value" => "" } + ] + } + ] + } + ) + + assert_equal_hash(expected, role.reload.as_json.slice(*expected.keys)) end test "creating rubygem trusted publishers" do diff --git a/test/tasks/maintenance/backfill_linkset_links_to_version_metadata_task_test.rb b/test/tasks/maintenance/backfill_linkset_links_to_version_metadata_task_test.rb index 258ed6d2b38..7fe84688650 100644 --- a/test/tasks/maintenance/backfill_linkset_links_to_version_metadata_task_test.rb +++ b/test/tasks/maintenance/backfill_linkset_links_to_version_metadata_task_test.rb @@ -42,12 +42,13 @@ class Maintenance::BackfillLinksetLinksToVersionMetadataTaskTest < ActiveSupport should "only update the home uri" do Maintenance::BackfillLinksetLinksToVersionMetadataTask.process(@version) - assert_equal({ - "source_code_uri" => "https://example.com/source", - "documentation_uri" => "https://example.com/docs", - "foo" => "bar", - "homepage_uri" => "https://example.com/home" - }, @version.reload.metadata) + assert_equal_hash( + { "source_code_uri" => "https://example.com/source", + "documentation_uri" => "https://example.com/docs", + "foo" => "bar", + "homepage_uri" => "https://example.com/home" }, + @version.reload.metadata + ) end should "not update the home uri when present in metadata" do @@ -56,12 +57,13 @@ class Maintenance::BackfillLinksetLinksToVersionMetadataTaskTest < ActiveSupport Maintenance::BackfillLinksetLinksToVersionMetadataTask.process(@version) - assert_equal({ - "source_code_uri" => "https://example.com/source", - "documentation_uri" => "https://example.com/docs", - "foo" => "bar", - "homepage_uri" => "https://example.com/home/custom" - }, @version.reload.metadata) + assert_equal_hash( + { "source_code_uri" => "https://example.com/source", + "documentation_uri" => "https://example.com/docs", + "foo" => "bar", + "homepage_uri" => "https://example.com/home/custom" }, + @version.reload.metadata + ) end end @@ -76,15 +78,16 @@ class Maintenance::BackfillLinksetLinksToVersionMetadataTaskTest < ActiveSupport should "update the version metadata" do Maintenance::BackfillLinksetLinksToVersionMetadataTask.process(@version) - assert_equal({ - "wiki_uri" => "https://example.com/wiki", - "foo" => "bar", - "homepage_uri" => "https://example.com/home", - "bug_tracker_uri" => "http://example.com", - "source_code_uri" => "http://example.com", - "mailing_list_uri" => "http://example.com", - "documentation_uri" => "http://example.com" - }, @version.reload.metadata) + assert_equal_hash( + { "wiki_uri" => "https://example.com/wiki", + "foo" => "bar", + "homepage_uri" => "https://example.com/home", + "bug_tracker_uri" => "http://example.com", + "source_code_uri" => "http://example.com", + "mailing_list_uri" => "http://example.com", + "documentation_uri" => "http://example.com" }, + @version.reload.metadata + ) end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index b5c11b97833..a1da1d4b86f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -144,6 +144,29 @@ def assert_event(tag, expected_additional, actual) assert_equal actual.additional_type.new(user_agent_info:, **expected_additional), actual.additional end + # Hashes with different orders will still be equal according to assert_equal. + # However, when they are not equal, the output diff will print them in their + # original order which makes it hard to see what is actually different. + # + # Improve diff output by sorting any nested hashes within enumerables, + # leaving array order untouched. + def assert_equal_hash(expected, actual, context = "expected") + assert_equal deep_sort_hashes(expected), deep_sort_hashes(actual), "Expected equal elements in #{context}" + end + + # sort the hash keys and recursively sort nested hashes within enumberables + def deep_sort_hashes(obj) + if obj.is_a?(Hash) + obj.map do |k, v| + [k, deep_sort_hashes(v)] + end.sort!.to_h + elsif obj.respond_to?(:map) + obj.map { |v| deep_sort_hashes(v) } + else + obj + end + end + def headless_chrome_driver Capybara.current_driver = :selenium_chrome_headless Capybara.default_max_wait_time = 2 diff --git a/test/unit/avo/actions/base_action_test.rb b/test/unit/avo/actions/base_action_test.rb index ff803c1da39..6e656f0aaaf 100644 --- a/test/unit/avo/actions/base_action_test.rb +++ b/test/unit/avo/actions/base_action_test.rb @@ -83,26 +83,27 @@ def each as_json = audit.as_json.except("created_at", "updated_at") as_json.dig("audited_changes", "records").values.sole["changes"].except!("created_at", "updated_at") - assert_equal({ - "id" => audit.id, - "auditable_type" => "WebHook", - "auditable_id" => webhook.id, - "admin_github_user_id" => admin.id, - "audited_changes" => { - "records" => { - webhook.to_global_id.uri.to_s => { - "changes" => { "id" => [webhook.id, nil], "failure_count" => [0, nil], "user_id" => [webhook.user.id, nil], "url" => [webhook.url, nil], - "successes_since_last_failure" => [0, nil], "failures_since_last_success" => [0, nil] }, - "unchanged" => { "rubygem_id" => nil, "disabled_reason" => nil, "disabled_at" => nil, "last_success" => nil, "last_failure" => nil } - } + assert_equal_hash( + { "id" => audit.id, + "auditable_type" => "WebHook", + "auditable_id" => webhook.id, + "admin_github_user_id" => admin.id, + "audited_changes" => { + "records" => { + webhook.to_global_id.uri.to_s => { + "changes" => { "id" => [webhook.id, nil], "failure_count" => [0, nil], "user_id" => [webhook.user.id, nil], "url" => [webhook.url, nil], + "successes_since_last_failure" => [0, nil], "failures_since_last_success" => [0, nil] }, + "unchanged" => { "rubygem_id" => nil, "disabled_reason" => nil, "disabled_at" => nil, "last_success" => nil, "last_failure" => nil } + } + }, + "fields" => {}, + "arguments" => {}, + "models" => [webhook.to_global_id.uri.to_s] }, - "fields" => {}, - "arguments" => {}, - "models" => [webhook.to_global_id.uri.to_s] - }, - "comment" => "Sufficiently detailed", - "action" => "Destroyer action" - }, as_json) + "comment" => "Sufficiently detailed", + "action" => "Destroyer action" }, + as_json + ) end test "tracks no changes" do @@ -127,20 +128,21 @@ def each audit = Audit.sole as_json = audit.as_json.except("created_at", "updated_at") - assert_equal({ - "id" => audit.id, - "auditable_type" => "User", - "auditable_id" => user.id, - "admin_github_user_id" => admin.id, - "audited_changes" => { - "records" => {}, - "fields" => {}, - "arguments" => {}, - "models" => [user.to_global_id.uri.to_s] - }, - "comment" => "Sufficiently detailed", - "action" => "Empty action" - }, as_json) + assert_equal_hash( + { "id" => audit.id, + "auditable_type" => "User", + "auditable_id" => user.id, + "admin_github_user_id" => admin.id, + "audited_changes" => { + "records" => {}, + "fields" => {}, + "arguments" => {}, + "models" => [user.to_global_id.uri.to_s] + }, + "comment" => "Sufficiently detailed", + "action" => "Empty action" }, + as_json + ) end test "tracks insertions" do @@ -167,36 +169,37 @@ def each as_json = audit.as_json.except("created_at", "updated_at") as_json.dig("audited_changes", "records").values.sole["changes"].except!("created_at", "updated_at") - assert_equal({ - "id" => audit.id, - "auditable_type" => "User", - "auditable_id" => user.id, - "admin_github_user_id" => admin.id, - "audited_changes" => { - "records" => { - webhook.to_global_id.uri.to_s => { - "changes" => { - "id" => [nil, webhook.id], - "user_id" => [nil, user.id], - "url" => [nil, webhook.url], - "failure_count" => [nil, 0], - "rubygem_id" => [nil, nil], - "disabled_reason" => [nil, nil], - "disabled_at" => [nil, nil], - "last_success" => [nil, nil], - "last_failure" => [nil, nil], - "successes_since_last_failure" => [nil, 0], - "failures_since_last_success" => [nil, 0] - }, - "unchanged" => {} - } + assert_equal_hash( + { "id" => audit.id, + "auditable_type" => "User", + "auditable_id" => user.id, + "admin_github_user_id" => admin.id, + "audited_changes" => { + "records" => { + webhook.to_global_id.uri.to_s => { + "changes" => { + "id" => [nil, webhook.id], + "user_id" => [nil, user.id], + "url" => [nil, webhook.url], + "failure_count" => [nil, 0], + "rubygem_id" => [nil, nil], + "disabled_reason" => [nil, nil], + "disabled_at" => [nil, nil], + "last_success" => [nil, nil], + "last_failure" => [nil, nil], + "successes_since_last_failure" => [nil, 0], + "failures_since_last_success" => [nil, 0] + }, + "unchanged" => {} + } + }, + "fields" => {}, + "arguments" => {}, + "models" => [user.to_global_id.uri.to_s] }, - "fields" => {}, - "arguments" => {}, - "models" => [user.to_global_id.uri.to_s] - }, - "comment" => "Sufficiently detailed", - "action" => "Web hook create action" - }, as_json) + "comment" => "Sufficiently detailed", + "action" => "Web hook create action" }, + as_json + ) end end diff --git a/test/unit/gemcutter/request_ip_address_test.rb b/test/unit/gemcutter/request_ip_address_test.rb index 9a7600823f4..197578de624 100644 --- a/test/unit/gemcutter/request_ip_address_test.rb +++ b/test/unit/gemcutter/request_ip_address_test.rb @@ -75,7 +75,7 @@ class Gemcutter::RequestIpAddressTest < ActiveSupport::TestCase geoip_info = @request.ip_address.geoip_info refute_nil geoip_info - assert_equal( + assert_equal_hash( { "continent_code" => "NA", "country_code" => "US", "country_code3" => "USA", "country_name" => "United States of America", "region" => "NY", "city" => "Buffalo" },