Skip to content

Improve schema matcher to display errors

Peter Leitzen requested to merge pl-json-schema-matcher into master

What does this MR do and why?

This MR improves schema matcher to display errors. See before/after below.

This MR also fixes JSON schema public_api/v4/merge_request.json.

Prior this commit this schema expected an optional property named properties.

This commit:

  • remove nested properties
  • references milestone schema for property milestone
  • references user basic schema for property assignees

Refs !79409 (diffs, comment 829327771)

Follow-ups

#351777 (closed) and https://gitlab.com/gitlab-org/gitlab/-/issues/351904 track how to prevent future cases like these.

Screenshots or screen recordings

Before

Failures:

  1) API::MergeRequests GET /projects/:id/merge_requests/:merge_request_iid matches json schema
     Failure/Error: expect(response).to match_response_schema('public_api/v4/merge_request')
       expected #<ActionDispatch::TestResponse:0x000056540647bc28 @mon_data=#<Monitor:0x000056540647ba98>, @mon_data_...w.example.com/api/v4/projects/1/merge_requests/1?private_token=yLENozMxcDy_BtwohpsT" for 127.0.0.1>> to match response schema "public_api/v4/merge_request"
     # ./spec/requests/api/merge_requests_spec.rb:1193:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:408:in `block (3 levels) in <top (required)>'
     # ./spec/support/sidekiq_middleware.rb:9:in `with_sidekiq_server_middleware'
     # ./spec/spec_helper.rb:399:in `block (2 levels) in <top (required)>'
     # ./spec/spec_helper.rb:395:in `block (3 levels) in <top (required)>'
     # ./lib/gitlab/application_context.rb:31:in `with_raw_context'
     # ./spec/spec_helper.rb:395:in `block (2 levels) in <top (required)>'
     # ./spec/support/system_exit_detected.rb:7:in `block (2 levels) in <main>'
     # ./spec/support/database/prevent_cross_joins.rb:106:in `block (3 levels) in <main>'
     # ./spec/support/database/prevent_cross_joins.rb:60:in `with_cross_joins_prevented'
     # ./spec/support/database/prevent_cross_joins.rb:106:in `block (2 levels) in <main>'

Finished in 1 minute 1.58 seconds (files took 1 minute 0.97 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/requests/api/merge_requests_spec.rb:1188 # API::MergeRequests GET /projects/:id/merge_requests/:merge_request_iid matches json schema

After

  1) API::MergeRequests GET /projects/:id/merge_requests/:merge_request_iid matches json schema
     Failure/Error: expect(response).to match_response_schema('public_api/v4/merge_request')

       expected JSON response to match schema #<Pathname:/home/peter/devel/gitlab/gdk-ee/gitlab/ee/spec/fixtures/api/schemas/public_api/v4/merge_request.json>.

       JSON input:   {
           "id": 5,
           "iid": 1,
           "project_id": 5,
           "title": "Test",
           "description": null,
           "state": "opened",
           "created_at": "2022-02-04T14:16:46.056Z",
           "updated_at": "2022-02-04T14:16:53.018Z",
           "merged_by": null,
           "merge_user": null,
           "merged_at": null,
           "closed_by": null,
           "closed_at": null,
           "target_branch": "feature",
           "source_branch": "master",
           "user_notes_count": 0,
           "upvotes": 0,
           "downvotes": 0,
           "author": {
             "id": 13,
             "username": "user1",
             "name": "Sidney Jones2",
             "state": "active",
             "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
             "web_url": "http://localhost/user1"
           },
           "assignees": [
             {
               "id": 13,
               "username": "user1",
               "name": "Sidney Jones2",
               "state": "active",
               "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
               "web_url": "http://localhost/user1"
             }
           ],
           "assignee": {
             "id": 13,
             "username": "user1",
             "name": "Sidney Jones2",
             "state": "active",
             "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
             "web_url": "http://localhost/user1"
           },
           "reviewers": [

           ],
           "source_project_id": 5,
           "target_project_id": 5,
           "labels": [

           ],
           "draft": false,
           "work_in_progress": false,
           "milestone": {
             "id": 5,
             "iid": 1,
             "project_id": 5,
             "title": "0.9",
             "description": null,
             "state": "active",
             "created_at": "2022-02-04T14:16:52.461Z",
             "updated_at": "2022-02-04T14:16:52.461Z",
             "due_date": null,
             "start_date": null,
             "expired": null,
             "web_url": "http://localhost/user1/project1/-/milestones/1"
           },
           "merge_when_pipeline_succeeds": false,
           "merge_status": "can_be_merged",
           "sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0",
           "merge_commit_sha": null,
           "squash_commit_sha": null,
           "discussion_locked": null,
           "should_remove_source_branch": null,
           "force_remove_source_branch": null,
           "reference": "!1",
           "references": {
             "short": "!1",
             "relative": "!1",
             "full": "user1/project1!1"
           },
           "web_url": "http://localhost/user1/project1/-/merge_requests/1",
           "time_stats": {
             "time_estimate": 0,
             "total_time_spent": 0,
             "human_time_estimate": null,
             "human_total_time_spent": null
           },
           "squash": false,
           "task_completion_status": {
             "count": 0,
             "completed_count": 0
           },
           "has_conflicts": false,
           "blocking_discussions_resolved": true,
           "approvals_before_merge": null,
           "subscribed": true,
           "changes_count": "20",
           "latest_build_started_at": null,
           "latest_build_finished_at": null,
           "first_deployed_to_production_at": null,
           "pipeline": null,
           "head_pipeline": {
             "id": 5,
             "iid": 1,
             "project_id": 5,
             "sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0",
             "ref": "master",
             "status": "success",
             "source": "push",
             "created_at": "2022-02-04T14:16:52.917Z",
             "updated_at": "2022-02-04T14:16:52.917Z",
             "web_url": "http://localhost/user1/project1/-/pipelines/5",
             "before_sha": "0000000000000000000000000000000000000000",
             "tag": false,
             "yaml_errors": null,
             "user": null,
             "started_at": null,
             "finished_at": null,
             "committed_at": null,
             "duration": null,
             "queued_duration": null,
             "coverage": null,
             "detailed_status": {
               "icon": "status_success",
               "text": "passed",
               "label": "passed",
               "group": "success",
               "tooltip": "passed",
               "has_details": true,
               "details_path": "/user1/project1/-/pipelines/5",
               "illustration": null,
               "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png"
             }
           },
           "diff_refs": {
             "base_sha": "ae73cb07c9eeaf35924a10f713b364d32b2dd34f",
             "head_sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0",
             "start_sha": "0b4bc9a49b562e85de7cc9e834518ea6828729b9"
           },
           "merge_error": null,
           "first_contribution": false,
           "user": {
             "can_merge": true
           }
         }

       Schema errors:

       Property: /assignees/0
         Actual value:   {
           "id": 13,
           "username": "user1",
           "name": "Sidney Jones2",
           "state": "active",
           "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
           "web_url": "http://localhost/user1"
         }
         Error: property '/assignees/0' is missing required keys: iid, project_id, title, description, created_at, updated_at, target_branch, source_branch, upvotes, downvotes, author, assignee, source_project_id, target_project_id, labels, work_in_progress, milestone, merge_when_pipeline_succeeds, merge_status, sha, merge_commit_sha, user_notes_count, should_remove_source_branch, force_remove_source_branch, squash

       Property: /milestone/due_date
         Actual value:   null
         Error: property '/milestone/due_date' is not of type: string

       Property: /milestone/start_date
         Actual value:   null
         Error: property '/milestone/start_date' is not of type: string

       Property: /milestone/expired
         Actual value:   null
         Error: property '/milestone/expired' is invalid: error_type=schema

       Property: /milestone/web_url
         Actual value:   "http://localhost/user1/project1/-/milestones/1"
         Error: property '/milestone/web_url' is invalid: error_type=schema
     # ./spec/requests/api/merge_requests_spec.rb:1193:in `block (3 levels) in <main>'
     # ./spec/spec_helper.rb:408:in `block (3 levels) in <main>'
     # ./spec/support/sidekiq_middleware.rb:9:in `with_sidekiq_server_middleware'
     # ./spec/spec_helper.rb:399:in `block (2 levels) in <main>'
     # ./spec/spec_helper.rb:395:in `block (3 levels) in <main>'
     # ./lib/gitlab/application_context.rb:31:in `with_raw_context'
     # ./spec/spec_helper.rb:395:in `block (2 levels) in <main>'
     # ./spec/support/system_exit_detected.rb:7:in `block (2 levels) in <main>'
     # ./spec/support/database/prevent_cross_joins.rb:106:in `block (3 levels) in <main>'
     # ./spec/support/database/prevent_cross_joins.rb:60:in `with_cross_joins_prevented'
     # ./spec/support/database/prevent_cross_joins.rb:106:in `block (2 levels) in <main>'
     # -e:1:in `<main>'

Finished in 22.38 seconds (files took 5.56 seconds to load)
1 example, 1 failure

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Peter Leitzen

Merge request reports