diff options
Diffstat (limited to 'spec/contracts')
23 files changed, 1326 insertions, 0 deletions
diff --git a/spec/contracts/.gitignore b/spec/contracts/.gitignore new file mode 100644 index 00000000000..cb89d4102d3 --- /dev/null +++ b/spec/contracts/.gitignore @@ -0,0 +1,2 @@ +logs/ +consumer/node_modules diff --git a/spec/contracts/README.md b/spec/contracts/README.md new file mode 100644 index 00000000000..d1f902064f1 --- /dev/null +++ b/spec/contracts/README.md @@ -0,0 +1,15 @@ +# Contract testing for GitLab + +This directory contains the contract test suites for GitLab, which use the [Pact](https://pact.io/) framework. + +The consumer tests are written using [`jest-pact`](https://github.com/pact-foundation/jest-pact) and the provider tests are written using [`pact-ruby`](https://github.com/pact-foundation/pact-ruby). + +## Write the tests + +- [Writing consumer tests](../../doc/development/testing_guide/contract/consumer_tests.md) +- [Writing provider tests](../../doc/development/testing_guide/contract/provider_tests.md) + +### Run the tests + +- [Running consumer tests](../../doc/development/testing_guide/contract/index.md#run-the-consumer-tests) +- [Running provider tests](../../doc/development/testing_guide/contract/index.md#run-the-provider-tests) diff --git a/spec/contracts/consumer/.eslintrc.yml b/spec/contracts/consumer/.eslintrc.yml new file mode 100644 index 00000000000..e4b380714d3 --- /dev/null +++ b/spec/contracts/consumer/.eslintrc.yml @@ -0,0 +1,7 @@ +--- +extends: + - 'plugin:@gitlab/jest' +settings: + import/core-modules: + - '@pact-foundation/pact' + - jest-pact diff --git a/spec/contracts/consumer/.node-version b/spec/contracts/consumer/.node-version new file mode 100644 index 00000000000..18711d290ea --- /dev/null +++ b/spec/contracts/consumer/.node-version @@ -0,0 +1 @@ +14.17.5 diff --git a/spec/contracts/consumer/babel.config.json b/spec/contracts/consumer/babel.config.json new file mode 100644 index 00000000000..1320b9a3272 --- /dev/null +++ b/spec/contracts/consumer/babel.config.json @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} diff --git a/spec/contracts/consumer/endpoints/project/merge_requests.js b/spec/contracts/consumer/endpoints/project/merge_requests.js new file mode 100644 index 00000000000..38773e5fb10 --- /dev/null +++ b/spec/contracts/consumer/endpoints/project/merge_requests.js @@ -0,0 +1,34 @@ +import { request } from 'axios'; + +export function getDiffsMetadata(endpoint) { + const { url } = endpoint; + + return request({ + method: 'GET', + baseURL: url, + url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json', + headers: { Accept: '*/*' }, + }).then((response) => response.data); +} + +export function getDiscussions(endpoint) { + const { url } = endpoint; + + return request({ + method: 'GET', + baseURL: url, + url: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json', + headers: { Accept: '*/*' }, + }).then((response) => response.data); +} + +export function getDiffsBatch(endpoint) { + const { url } = endpoint; + + return request({ + method: 'GET', + baseURL: url, + url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json?page=0', + headers: { Accept: '*/*' }, + }).then((response) => response.data); +} diff --git a/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js b/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js new file mode 100644 index 00000000000..b53e4bb335d --- /dev/null +++ b/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js @@ -0,0 +1,91 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { Matchers } from '@pact-foundation/pact'; + +const body = { + diff_files: Matchers.eachLike({ + content_sha: Matchers.string('b0c94059db75b2473d616d4b1fde1a77533355a3'), + submodule: Matchers.boolean(false), + edit_path: Matchers.string('/gitlab-qa-bot/...'), + ide_edit_path: Matchers.string('/gitlab-qa-bot/...'), + old_path_html: Matchers.string('Gemfile'), + new_path_html: Matchers.string('Gemfile'), + blob: { + id: Matchers.string('855071bb3928d140764885964f7be1bb3e582495'), + path: Matchers.string('Gemfile'), + name: Matchers.string('Gemfile'), + mode: Matchers.string('1234567'), + readable_text: Matchers.boolean(true), + icon: Matchers.string('doc-text'), + }, + can_modify_blob: Matchers.boolean(false), + file_identifier_hash: Matchers.string('67d82b8716a5b6c52c7abf0b2cd99c7594ed3587'), + file_hash: Matchers.string('67d82b8716a5b6c52c7abf0b2cd99c7594ed3587'), + file_path: Matchers.string('Gemfile'), + old_path: Matchers.string('Gemfile'), + new_path: Matchers.string('Gemfile'), + new_file: Matchers.boolean(false), + renamed_file: Matchers.boolean(false), + deleted_file: Matchers.boolean(false), + diff_refs: { + base_sha: Matchers.string('67d82b8716a5b6c52c7abf0b2cd99c7594ed3587'), + start_sha: Matchers.string('67d82b8716a5b6c52c7abf0b2cd99c7594ed3587'), + head_sha: Matchers.string('67d82b8716a5b6c52c7abf0b2cd99c7594ed3587'), + }, + mode_changed: Matchers.boolean(false), + a_mode: Matchers.string('123456'), + b_mode: Matchers.string('123456'), + viewer: { + name: Matchers.string('text'), + collapsed: Matchers.boolean(false), + }, + old_size: Matchers.integer(2288), + new_size: Matchers.integer(2288), + added_lines: Matchers.integer(1), + removed_lines: Matchers.integer(1), + load_collapsed_diff_url: Matchers.string('/gitlab-qa-bot/...'), + view_path: Matchers.string('/gitlab-qa-bot/...'), + context_lines_path: Matchers.string('/gitlab-qa-bot/...'), + highlighted_diff_lines: Matchers.eachLike({ + // The following values can also be null which is not supported + // line_code: Matchers.string('de3150c01c3a946a6168173c4116741379fe3579_1_1'), + // old_line: Matchers.integer(1), + // new_line: Matchers.integer(1), + text: Matchers.string('source'), + rich_text: Matchers.string('<span></span>'), + can_receive_suggestion: Matchers.boolean(true), + }), + is_fully_expanded: Matchers.boolean(false), + }), + pagination: { + total_pages: Matchers.integer(1), + }, +}; + +const DiffsBatch = { + body: Matchers.extractPayload(body), + + success: { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body, + }, + + request: { + uponReceiving: 'a request for diff lines', + withRequest: { + method: 'GET', + path: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json', + headers: { + Accept: '*/*', + }, + query: 'page=0', + }, + }, +}; + +export { DiffsBatch }; + +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js b/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js new file mode 100644 index 00000000000..39dbcf78ee7 --- /dev/null +++ b/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js @@ -0,0 +1,98 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { Matchers } from '@pact-foundation/pact'; + +const body = { + real_size: Matchers.string('1'), + size: Matchers.integer(1), + branch_name: Matchers.string('testing-branch-1'), + source_branch_exists: Matchers.boolean(true), + target_branch_name: Matchers.string('master'), + merge_request_diff: { + created_at: Matchers.iso8601DateTimeWithMillis('2022-02-17T11:47:08.804Z'), + commits_count: Matchers.integer(1), + latest: Matchers.boolean(true), + short_commit_sha: Matchers.string('aee1ffec'), + base_version_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773', + ), + head_version_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_head=true', + ), + version_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773', + ), + compare_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773&start_sha=aee1ffec2299c0cfb17c8821e931339b73a3759f', + ), + }, + latest_diff: Matchers.boolean(true), + latest_version_path: Matchers.string('/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs'), + added_lines: Matchers.integer(1), + removed_lines: Matchers.integer(1), + render_overflow_warning: Matchers.boolean(false), + email_patch_path: Matchers.string('/gitlab-qa-bot/contract-testing/-/merge_requests/1.patch'), + plain_diff_path: Matchers.string('/gitlab-qa-bot/contract-testing/-/merge_requests/1.diff'), + merge_request_diffs: Matchers.eachLike({ + commits_count: Matchers.integer(1), + latest: Matchers.boolean(true), + short_commit_sha: Matchers.string('aee1ffec'), + base_version_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773', + ), + head_version_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_head=true', + ), + version_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773', + ), + compare_path: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773&start_sha=aee1ffec2299c0cfb17c8821e931339b73a3759f', + ), + }), + definition_path_prefix: Matchers.string( + '/gitlab-qa-bot/contract-testing/-/blob/aee1ffec2299c0cfb17c8821e931339b73a3759f', + ), + diff_files: Matchers.eachLike({ + added_lines: Matchers.integer(1), + removed_lines: Matchers.integer(1), + new_path: Matchers.string('Gemfile'), + old_path: Matchers.string('Gemfile'), + new_file: Matchers.boolean(false), + deleted_file: Matchers.boolean(false), + submodule: Matchers.boolean(false), + file_identifier_hash: Matchers.string('67d82b8716a5b6c52c7abf0b2cd99c7594ed3587'), + file_hash: Matchers.string('de3150c01c3a946a6168173c4116741379fe3579'), + }), + has_conflicts: Matchers.boolean(false), + can_merge: Matchers.boolean(false), + project_path: Matchers.string('gitlab-qa-bot/contract-testing'), + project_name: Matchers.string('contract-testing'), +}; + +const DiffsMetadata = { + body: Matchers.extractPayload(body), + + success: { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body, + }, + + request: { + uponReceiving: 'a request for Diffs Metadata', + withRequest: { + method: 'GET', + path: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json', + headers: { + Accept: '*/*', + }, + }, + }, +}; + +export { DiffsMetadata }; + +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js b/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js new file mode 100644 index 00000000000..af0962a01cb --- /dev/null +++ b/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js @@ -0,0 +1,87 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { Matchers } from '@pact-foundation/pact'; + +const body = Matchers.eachLike({ + id: Matchers.string('fd73763cbcbf7b29eb8765d969a38f7d735e222a'), + reply_id: Matchers.string('fd73763cbcbf7b29eb8765d969a38f7d735e222a'), + project_id: Matchers.integer(6954442), + confidential: Matchers.boolean(false), + diff_discussion: Matchers.boolean(false), + expanded: Matchers.boolean(false), + for_commit: Matchers.boolean(false), + individual_note: Matchers.boolean(true), + resolvable: Matchers.boolean(false), + resolved_by_push: Matchers.boolean(false), + notes: Matchers.eachLike({ + id: Matchers.string('76489845'), + author: { + id: Matchers.integer(1675733), + username: Matchers.string('gitlab-qa-bot'), + name: Matchers.string('gitlab-qa-bot'), + state: Matchers.string('active'), + avatar_url: Matchers.string( + 'https://secure.gravatar.com/avatar/8355ad0f2761367fae6b9c4fe80994b9?s=80&d=identicon', + ), + show_status: Matchers.boolean(false), + path: Matchers.string('/gitlab-qa-bot'), + }, + created_at: Matchers.iso8601DateTimeWithMillis('2022-02-22T07:06:55.038Z'), + updated_at: Matchers.iso8601DateTimeWithMillis('2022-02-22T07:06:55.038Z'), + system: Matchers.boolean(false), + noteable_id: Matchers.integer(8333422), + noteable_type: Matchers.string('MergeRequest'), + resolvable: Matchers.boolean(false), + resolved: Matchers.boolean(true), + confidential: Matchers.boolean(false), + noteable_iid: Matchers.integer(1), + note: Matchers.string('This is a test comment'), + note_html: Matchers.string( + '<p data-sourcepos="1:1-1:22" dir="auto">This is a test comment</p>', + ), + current_user: { + can_edit: Matchers.boolean(true), + can_award_emoji: Matchers.boolean(true), + can_resolve: Matchers.boolean(false), + can_resolve_discussion: Matchers.boolean(false), + }, + is_noteable_author: Matchers.boolean(true), + discussion_id: Matchers.string('fd73763cbcbf7b29eb8765d969a38f7d735e222a'), + emoji_awardable: Matchers.boolean(true), + report_abuse_path: Matchers.string('/gitlab-qa-bot/...'), + noteable_note_url: Matchers.string('https://staging.gitlab.com/gitlab-qa-bot/...'), + cached_markdown_version: Matchers.integer(1900552), + human_access: Matchers.string('Maintainer'), + is_contributor: Matchers.boolean(false), + project_name: Matchers.string('contract-testing'), + path: Matchers.string('/gitlab-qa-bot/...'), + }), + resolved: Matchers.boolean(true), +}); + +const Discussions = { + body: Matchers.extractPayload(body), + + success: { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body, + }, + + request: { + uponReceiving: 'a request for discussions', + withRequest: { + method: 'GET', + path: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json', + headers: { + Accept: '*/*', + }, + }, + }, +}; + +export { Discussions }; + +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/package.json b/spec/contracts/consumer/package.json new file mode 100644 index 00000000000..6d3feaa6d4c --- /dev/null +++ b/spec/contracts/consumer/package.json @@ -0,0 +1,26 @@ +{ + "name": "consumer", + "version": "1.0.0", + "description": "consumer side contract testing", + "license": "MIT", + "repository": "https://gitlab.com/gitlab-org/gitlab.git", + "dependencies": { + "@pact-foundation/pact": "^9.17.2", + "axios": "^0.26.0", + "jest": "^27.5.1", + "jest-pact": "^0.9.1", + "prettier": "^2.5.1" + }, + "scripts": { + "test": "jest --runInBand" + }, + "jest": { + "transform": { + "^.+\\.[t|j]sx?$": "babel-jest" + } + }, + "devDependencies": { + "@babel/preset-env": "^7.18.2", + "babel-jest": "^28.1.1" + } +} diff --git a/spec/contracts/consumer/specs/project/merge_request/show.spec.js b/spec/contracts/consumer/specs/project/merge_request/show.spec.js new file mode 100644 index 00000000000..8c6e029cb12 --- /dev/null +++ b/spec/contracts/consumer/specs/project/merge_request/show.spec.js @@ -0,0 +1,112 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { pactWith } from 'jest-pact'; + +import { DiffsBatch } from '../../../fixtures/project/merge_request/diffs_batch.fixture'; +import { Discussions } from '../../../fixtures/project/merge_request/discussions.fixture'; +import { DiffsMetadata } from '../../../fixtures/project/merge_request/diffs_metadata.fixture'; +import { + getDiffsBatch, + getDiffsMetadata, + getDiscussions, +} from '../../../endpoints/project/merge_requests'; + +const CONSUMER_NAME = 'MergeRequest#show'; +const CONSUMER_LOG = '../logs/consumer.log'; +const CONTRACT_DIR = '../contracts/project/merge_request/show'; +const DIFFS_BATCH_PROVIDER_NAME = 'Merge Request Diffs Batch Endpoint'; +const DISCUSSIONS_PROVIDER_NAME = 'Merge Request Discussions Endpoint'; +const DIFFS_METADATA_PROVIDER_NAME = 'Merge Request Diffs Metadata Endpoint'; + +// API endpoint: /merge_requests/:id/diffs_batch.json +pactWith( + { + consumer: CONSUMER_NAME, + provider: DIFFS_BATCH_PROVIDER_NAME, + log: CONSUMER_LOG, + dir: CONTRACT_DIR, + }, + + (provider) => { + describe(DIFFS_BATCH_PROVIDER_NAME, () => { + beforeEach(() => { + const interaction = { + state: 'a merge request with diffs exists', + ...DiffsBatch.request, + willRespondWith: DiffsBatch.success, + }; + provider.addInteraction(interaction); + }); + + it('returns a successful body', () => { + return getDiffsBatch({ + url: provider.mockService.baseUrl, + }).then((diffsBatch) => { + expect(diffsBatch).toEqual(DiffsBatch.body); + }); + }); + }); + }, +); + +pactWith( + { + consumer: CONSUMER_NAME, + provider: DISCUSSIONS_PROVIDER_NAME, + log: CONSUMER_LOG, + dir: CONTRACT_DIR, + }, + + (provider) => { + describe(DISCUSSIONS_PROVIDER_NAME, () => { + beforeEach(() => { + const interaction = { + state: 'a merge request with discussions exists', + ...Discussions.request, + willRespondWith: Discussions.success, + }; + provider.addInteraction(interaction); + }); + + it('return a successful body', () => { + return getDiscussions({ + url: provider.mockService.baseUrl, + }).then((discussions) => { + expect(discussions).toEqual(Discussions.body); + }); + }); + }); + }, +); + +pactWith( + { + consumer: CONSUMER_NAME, + provider: DIFFS_METADATA_PROVIDER_NAME, + log: CONSUMER_LOG, + dir: CONTRACT_DIR, + }, + + (provider) => { + describe(DIFFS_METADATA_PROVIDER_NAME, () => { + beforeEach(() => { + const interaction = { + state: 'a merge request exists', + ...DiffsMetadata.request, + willRespondWith: DiffsMetadata.success, + }; + provider.addInteraction(interaction); + }); + + it('return a successful body', () => { + return getDiffsMetadata({ + url: provider.mockService.baseUrl, + }).then((diffsMetadata) => { + expect(diffsMetadata).toEqual(DiffsMetadata.body); + }); + }); + }); + }, +); + +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json new file mode 100644 index 00000000000..3fa13766766 --- /dev/null +++ b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json @@ -0,0 +1,229 @@ +{ + "consumer": { + "name": "MergeRequest#show" + }, + "provider": { + "name": "Merge Request Diffs Batch Endpoint" + }, + "interactions": [ + { + "description": "a request for diff lines", + "providerState": "a merge request with diffs exists", + "request": { + "method": "GET", + "path": "/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json", + "query": "page=0", + "headers": { + "Accept": "*/*" + } + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "body": { + "diff_files": [ + { + "content_sha": "b0c94059db75b2473d616d4b1fde1a77533355a3", + "submodule": false, + "edit_path": "/gitlab-qa-bot/...", + "ide_edit_path": "/gitlab-qa-bot/...", + "old_path_html": "Gemfile", + "new_path_html": "Gemfile", + "blob": { + "id": "855071bb3928d140764885964f7be1bb3e582495", + "path": "Gemfile", + "name": "Gemfile", + "mode": "1234567", + "readable_text": true, + "icon": "doc-text" + }, + "can_modify_blob": false, + "file_identifier_hash": "67d82b8716a5b6c52c7abf0b2cd99c7594ed3587", + "file_hash": "67d82b8716a5b6c52c7abf0b2cd99c7594ed3587", + "file_path": "Gemfile", + "old_path": "Gemfile", + "new_path": "Gemfile", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "diff_refs": { + "base_sha": "67d82b8716a5b6c52c7abf0b2cd99c7594ed3587", + "start_sha": "67d82b8716a5b6c52c7abf0b2cd99c7594ed3587", + "head_sha": "67d82b8716a5b6c52c7abf0b2cd99c7594ed3587" + }, + "mode_changed": false, + "a_mode": "123456", + "b_mode": "123456", + "viewer": { + "name": "text", + "collapsed": false + }, + "old_size": 2288, + "new_size": 2288, + "added_lines": 1, + "removed_lines": 1, + "load_collapsed_diff_url": "/gitlab-qa-bot/...", + "view_path": "/gitlab-qa-bot/...", + "context_lines_path": "/gitlab-qa-bot/...", + "highlighted_diff_lines": [ + { + "text": "source", + "rich_text": "<span></span>", + "can_receive_suggestion": true + } + ], + "is_fully_expanded": false + } + ], + "pagination": { + "total_pages": 1 + } + }, + "matchingRules": { + "$.body.diff_files": { + "min": 1 + }, + "$.body.diff_files[*].*": { + "match": "type" + }, + "$.body.diff_files[*].content_sha": { + "match": "type" + }, + "$.body.diff_files[*].submodule": { + "match": "type" + }, + "$.body.diff_files[*].edit_path": { + "match": "type" + }, + "$.body.diff_files[*].ide_edit_path": { + "match": "type" + }, + "$.body.diff_files[*].old_path_html": { + "match": "type" + }, + "$.body.diff_files[*].new_path_html": { + "match": "type" + }, + "$.body.diff_files[*].blob.id": { + "match": "type" + }, + "$.body.diff_files[*].blob.path": { + "match": "type" + }, + "$.body.diff_files[*].blob.name": { + "match": "type" + }, + "$.body.diff_files[*].blob.mode": { + "match": "type" + }, + "$.body.diff_files[*].blob.readable_text": { + "match": "type" + }, + "$.body.diff_files[*].blob.icon": { + "match": "type" + }, + "$.body.diff_files[*].can_modify_blob": { + "match": "type" + }, + "$.body.diff_files[*].file_identifier_hash": { + "match": "type" + }, + "$.body.diff_files[*].file_hash": { + "match": "type" + }, + "$.body.diff_files[*].file_path": { + "match": "type" + }, + "$.body.diff_files[*].old_path": { + "match": "type" + }, + "$.body.diff_files[*].new_path": { + "match": "type" + }, + "$.body.diff_files[*].new_file": { + "match": "type" + }, + "$.body.diff_files[*].renamed_file": { + "match": "type" + }, + "$.body.diff_files[*].deleted_file": { + "match": "type" + }, + "$.body.diff_files[*].diff_refs.base_sha": { + "match": "type" + }, + "$.body.diff_files[*].diff_refs.start_sha": { + "match": "type" + }, + "$.body.diff_files[*].diff_refs.head_sha": { + "match": "type" + }, + "$.body.diff_files[*].mode_changed": { + "match": "type" + }, + "$.body.diff_files[*].a_mode": { + "match": "type" + }, + "$.body.diff_files[*].b_mode": { + "match": "type" + }, + "$.body.diff_files[*].viewer.name": { + "match": "type" + }, + "$.body.diff_files[*].viewer.collapsed": { + "match": "type" + }, + "$.body.diff_files[*].old_size": { + "match": "type" + }, + "$.body.diff_files[*].new_size": { + "match": "type" + }, + "$.body.diff_files[*].added_lines": { + "match": "type" + }, + "$.body.diff_files[*].removed_lines": { + "match": "type" + }, + "$.body.diff_files[*].load_collapsed_diff_url": { + "match": "type" + }, + "$.body.diff_files[*].view_path": { + "match": "type" + }, + "$.body.diff_files[*].context_lines_path": { + "match": "type" + }, + "$.body.diff_files[*].highlighted_diff_lines": { + "min": 1 + }, + "$.body.diff_files[*].highlighted_diff_lines[*].*": { + "match": "type" + }, + "$.body.diff_files[*].highlighted_diff_lines[*].text": { + "match": "type" + }, + "$.body.diff_files[*].highlighted_diff_lines[*].rich_text": { + "match": "type" + }, + "$.body.diff_files[*].highlighted_diff_lines[*].can_receive_suggestion": { + "match": "type" + }, + "$.body.diff_files[*].is_fully_expanded": { + "match": "type" + }, + "$.body.pagination.total_pages": { + "match": "type" + } + } + } + } + ], + "metadata": { + "pactSpecification": { + "version": "2.0.0" + } + } +}
\ No newline at end of file diff --git a/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json new file mode 100644 index 00000000000..b98a0127e54 --- /dev/null +++ b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json @@ -0,0 +1,223 @@ +{ + "consumer": { + "name": "MergeRequest#show" + }, + "provider": { + "name": "Merge Request Diffs Metadata Endpoint" + }, + "interactions": [ + { + "description": "a request for Diffs Metadata", + "providerState": "a merge request exists", + "request": { + "method": "GET", + "path": "/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json", + "headers": { + "Accept": "*/*" + } + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "body": { + "real_size": "1", + "size": 1, + "branch_name": "testing-branch-1", + "source_branch_exists": true, + "target_branch_name": "master", + "merge_request_diff": { + "created_at": "2022-02-17T11:47:08.804Z", + "commits_count": 1, + "latest": true, + "short_commit_sha": "aee1ffec", + "base_version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773", + "head_version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_head=true", + "version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773", + "compare_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773&start_sha=aee1ffec2299c0cfb17c8821e931339b73a3759f" + }, + "latest_diff": true, + "latest_version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs", + "added_lines": 1, + "removed_lines": 1, + "render_overflow_warning": false, + "email_patch_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1.patch", + "plain_diff_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1.diff", + "merge_request_diffs": [ + { + "commits_count": 1, + "latest": true, + "short_commit_sha": "aee1ffec", + "base_version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773", + "head_version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_head=true", + "version_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773", + "compare_path": "/gitlab-qa-bot/contract-testing/-/merge_requests/1/diffs?diff_id=10581773&start_sha=aee1ffec2299c0cfb17c8821e931339b73a3759f" + } + ], + "definition_path_prefix": "/gitlab-qa-bot/contract-testing/-/blob/aee1ffec2299c0cfb17c8821e931339b73a3759f", + "diff_files": [ + { + "added_lines": 1, + "removed_lines": 1, + "new_path": "Gemfile", + "old_path": "Gemfile", + "new_file": false, + "deleted_file": false, + "submodule": false, + "file_identifier_hash": "67d82b8716a5b6c52c7abf0b2cd99c7594ed3587", + "file_hash": "de3150c01c3a946a6168173c4116741379fe3579" + } + ], + "has_conflicts": false, + "can_merge": false, + "project_path": "gitlab-qa-bot/contract-testing", + "project_name": "contract-testing" + }, + "matchingRules": { + "$.body.real_size": { + "match": "type" + }, + "$.body.size": { + "match": "type" + }, + "$.body.branch_name": { + "match": "type" + }, + "$.body.source_branch_exists": { + "match": "type" + }, + "$.body.target_branch_name": { + "match": "type" + }, + "$.body.merge_request_diff.created_at": { + "match": "regex", + "regex": "^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d(:?[0-5]\\d)?|Z)$" + }, + "$.body.merge_request_diff.commits_count": { + "match": "type" + }, + "$.body.merge_request_diff.latest": { + "match": "type" + }, + "$.body.merge_request_diff.short_commit_sha": { + "match": "type" + }, + "$.body.merge_request_diff.base_version_path": { + "match": "type" + }, + "$.body.merge_request_diff.head_version_path": { + "match": "type" + }, + "$.body.merge_request_diff.version_path": { + "match": "type" + }, + "$.body.merge_request_diff.compare_path": { + "match": "type" + }, + "$.body.latest_diff": { + "match": "type" + }, + "$.body.latest_version_path": { + "match": "type" + }, + "$.body.added_lines": { + "match": "type" + }, + "$.body.removed_lines": { + "match": "type" + }, + "$.body.render_overflow_warning": { + "match": "type" + }, + "$.body.email_patch_path": { + "match": "type" + }, + "$.body.plain_diff_path": { + "match": "type" + }, + "$.body.merge_request_diffs": { + "min": 1 + }, + "$.body.merge_request_diffs[*].*": { + "match": "type" + }, + "$.body.merge_request_diffs[*].commits_count": { + "match": "type" + }, + "$.body.merge_request_diffs[*].latest": { + "match": "type" + }, + "$.body.merge_request_diffs[*].short_commit_sha": { + "match": "type" + }, + "$.body.merge_request_diffs[*].base_version_path": { + "match": "type" + }, + "$.body.merge_request_diffs[*].head_version_path": { + "match": "type" + }, + "$.body.merge_request_diffs[*].version_path": { + "match": "type" + }, + "$.body.merge_request_diffs[*].compare_path": { + "match": "type" + }, + "$.body.definition_path_prefix": { + "match": "type" + }, + "$.body.diff_files": { + "min": 1 + }, + "$.body.diff_files[*].*": { + "match": "type" + }, + "$.body.diff_files[*].added_lines": { + "match": "type" + }, + "$.body.diff_files[*].removed_lines": { + "match": "type" + }, + "$.body.diff_files[*].new_path": { + "match": "type" + }, + "$.body.diff_files[*].old_path": { + "match": "type" + }, + "$.body.diff_files[*].new_file": { + "match": "type" + }, + "$.body.diff_files[*].deleted_file": { + "match": "type" + }, + "$.body.diff_files[*].submodule": { + "match": "type" + }, + "$.body.diff_files[*].file_identifier_hash": { + "match": "type" + }, + "$.body.diff_files[*].file_hash": { + "match": "type" + }, + "$.body.has_conflicts": { + "match": "type" + }, + "$.body.can_merge": { + "match": "type" + }, + "$.body.project_path": { + "match": "type" + }, + "$.body.project_name": { + "match": "type" + } + } + } + } + ], + "metadata": { + "pactSpecification": { + "version": "2.0.0" + } + } +}
\ No newline at end of file diff --git a/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json new file mode 100644 index 00000000000..ecaf9c123af --- /dev/null +++ b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json @@ -0,0 +1,236 @@ +{ + "consumer": { + "name": "MergeRequest#show" + }, + "provider": { + "name": "Merge Request Discussions Endpoint" + }, + "interactions": [ + { + "description": "a request for discussions", + "providerState": "a merge request with discussions exists", + "request": { + "method": "GET", + "path": "/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json", + "headers": { + "Accept": "*/*" + } + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "body": [ + { + "id": "fd73763cbcbf7b29eb8765d969a38f7d735e222a", + "reply_id": "fd73763cbcbf7b29eb8765d969a38f7d735e222a", + "project_id": 6954442, + "confidential": false, + "diff_discussion": false, + "expanded": false, + "for_commit": false, + "individual_note": true, + "resolvable": false, + "resolved_by_push": false, + "notes": [ + { + "id": "76489845", + "author": { + "id": 1675733, + "username": "gitlab-qa-bot", + "name": "gitlab-qa-bot", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/8355ad0f2761367fae6b9c4fe80994b9?s=80&d=identicon", + "show_status": false, + "path": "/gitlab-qa-bot" + }, + "created_at": "2022-02-22T07:06:55.038Z", + "updated_at": "2022-02-22T07:06:55.038Z", + "system": false, + "noteable_id": 8333422, + "noteable_type": "MergeRequest", + "resolvable": false, + "resolved": true, + "confidential": false, + "noteable_iid": 1, + "note": "This is a test comment", + "note_html": "<p data-sourcepos=\"1:1-1:22\" dir=\"auto\">This is a test comment</p>", + "current_user": { + "can_edit": true, + "can_award_emoji": true, + "can_resolve": false, + "can_resolve_discussion": false + }, + "is_noteable_author": true, + "discussion_id": "fd73763cbcbf7b29eb8765d969a38f7d735e222a", + "emoji_awardable": true, + "report_abuse_path": "/gitlab-qa-bot/...", + "noteable_note_url": "https://staging.gitlab.com/gitlab-qa-bot/...", + "cached_markdown_version": 1900552, + "human_access": "Maintainer", + "is_contributor": false, + "project_name": "contract-testing", + "path": "/gitlab-qa-bot/..." + } + ], + "resolved": true + } + ], + "matchingRules": { + "$.body": { + "min": 1 + }, + "$.body[*].*": { + "match": "type" + }, + "$.body[*].id": { + "match": "type" + }, + "$.body[*].reply_id": { + "match": "type" + }, + "$.body[*].project_id": { + "match": "type" + }, + "$.body[*].confidential": { + "match": "type" + }, + "$.body[*].diff_discussion": { + "match": "type" + }, + "$.body[*].expanded": { + "match": "type" + }, + "$.body[*].for_commit": { + "match": "type" + }, + "$.body[*].individual_note": { + "match": "type" + }, + "$.body[*].resolvable": { + "match": "type" + }, + "$.body[*].resolved_by_push": { + "match": "type" + }, + "$.body[*].notes": { + "min": 1 + }, + "$.body[*].notes[*].*": { + "match": "type" + }, + "$.body[*].notes[*].id": { + "match": "type" + }, + "$.body[*].notes[*].author.id": { + "match": "type" + }, + "$.body[*].notes[*].author.username": { + "match": "type" + }, + "$.body[*].notes[*].author.name": { + "match": "type" + }, + "$.body[*].notes[*].author.state": { + "match": "type" + }, + "$.body[*].notes[*].author.avatar_url": { + "match": "type" + }, + "$.body[*].notes[*].author.show_status": { + "match": "type" + }, + "$.body[*].notes[*].author.path": { + "match": "type" + }, + "$.body[*].notes[*].created_at": { + "match": "regex", + "regex": "^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d(:?[0-5]\\d)?|Z)$" + }, + "$.body[*].notes[*].updated_at": { + "match": "regex", + "regex": "^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d(:?[0-5]\\d)?|Z)$" + }, + "$.body[*].notes[*].system": { + "match": "type" + }, + "$.body[*].notes[*].noteable_id": { + "match": "type" + }, + "$.body[*].notes[*].noteable_type": { + "match": "type" + }, + "$.body[*].notes[*].resolvable": { + "match": "type" + }, + "$.body[*].notes[*].resolved": { + "match": "type" + }, + "$.body[*].notes[*].confidential": { + "match": "type" + }, + "$.body[*].notes[*].noteable_iid": { + "match": "type" + }, + "$.body[*].notes[*].note": { + "match": "type" + }, + "$.body[*].notes[*].note_html": { + "match": "type" + }, + "$.body[*].notes[*].current_user.can_edit": { + "match": "type" + }, + "$.body[*].notes[*].current_user.can_award_emoji": { + "match": "type" + }, + "$.body[*].notes[*].current_user.can_resolve": { + "match": "type" + }, + "$.body[*].notes[*].current_user.can_resolve_discussion": { + "match": "type" + }, + "$.body[*].notes[*].is_noteable_author": { + "match": "type" + }, + "$.body[*].notes[*].discussion_id": { + "match": "type" + }, + "$.body[*].notes[*].emoji_awardable": { + "match": "type" + }, + "$.body[*].notes[*].report_abuse_path": { + "match": "type" + }, + "$.body[*].notes[*].noteable_note_url": { + "match": "type" + }, + "$.body[*].notes[*].cached_markdown_version": { + "match": "type" + }, + "$.body[*].notes[*].human_access": { + "match": "type" + }, + "$.body[*].notes[*].is_contributor": { + "match": "type" + }, + "$.body[*].notes[*].project_name": { + "match": "type" + }, + "$.body[*].notes[*].path": { + "match": "type" + }, + "$.body[*].resolved": { + "match": "type" + } + } + } + } + ], + "metadata": { + "pactSpecification": { + "version": "2.0.0" + } + } +}
\ No newline at end of file diff --git a/spec/contracts/provider/environments/test.rb b/spec/contracts/provider/environments/test.rb new file mode 100644 index 00000000000..6efb19508d8 --- /dev/null +++ b/spec/contracts/provider/environments/test.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Provider + module Environments + class Test + def self.app + Rack::Builder.app do + map "/" do + run Gitlab::Application + end + end + end + end + end +end diff --git a/spec/contracts/provider/helpers/users_helper.rb b/spec/contracts/provider/helpers/users_helper.rb new file mode 100644 index 00000000000..1982bd9cfd2 --- /dev/null +++ b/spec/contracts/provider/helpers/users_helper.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Provider + module UsersHelper + CONTRACT_USER_NAME = "Contract Test User" + end +end diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/diffs_batch_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/diffs_batch_helper.rb new file mode 100644 index 00000000000..7d1fbe91e86 --- /dev/null +++ b/spec/contracts/provider/pact_helpers/project/merge_request/diffs_batch_helper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require_relative '../../../spec_helper' +require_relative '../../../states/project/merge_request/diffs_batch_state' + +module Provider + module DiffsBatchHelper + Pact.service_provider "Merge Request Diffs Batch Endpoint" do + app { Environments::Test.app } + + honours_pact_with 'MergeRequest#show' do + pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json' + end + end + end +end diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/diffs_metadata_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/diffs_metadata_helper.rb new file mode 100644 index 00000000000..5f0c58d18d4 --- /dev/null +++ b/spec/contracts/provider/pact_helpers/project/merge_request/diffs_metadata_helper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require_relative '../../../spec_helper' +require_relative '../../../states/project/merge_request/diffs_metadata_state' + +module Provider + module DiffsMetadataHelper + Pact.service_provider "Merge Request Diffs Metadata Endpoint" do + app { Environments::Test.app } + + honours_pact_with 'MergeRequest#show' do + pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json' + end + end + end +end diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/discussions_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/discussions_helper.rb new file mode 100644 index 00000000000..0f4244ba40a --- /dev/null +++ b/spec/contracts/provider/pact_helpers/project/merge_request/discussions_helper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require_relative '../../../spec_helper' +require_relative '../../../states/project/merge_request/discussions_state' + +module Provider + module DiscussionsHelper + Pact.service_provider "Merge Request Discussions Endpoint" do + app { Environments::Test.app } + + honours_pact_with 'MergeRequest#show' do + pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json' + end + end + end +end diff --git a/spec/contracts/provider/spec_helper.rb b/spec/contracts/provider/spec_helper.rb new file mode 100644 index 00000000000..6009d6524e1 --- /dev/null +++ b/spec/contracts/provider/spec_helper.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'zeitwerk' +require_relative 'helpers/users_helper' + +RSpec.configure do |config| + config.include Devise::Test::IntegrationHelpers + config.include FactoryBot::Syntax::Methods + + config.before do + user = create(:user, name: Provider::UsersHelper::CONTRACT_USER_NAME).tap do |user| + user.current_sign_in_at = Time.current + end + + sign_in user + end +end + +Pact.configure do |config| + config.include FactoryBot::Syntax::Methods +end + +module SpecHelper + require_relative '../../../config/bundler_setup' + Bundler.require(:default) + + root = File.expand_path('../', __dir__) + + loader = Zeitwerk::Loader.new + loader.push_dir(root) + + loader.ignore("#{root}/consumer") + loader.ignore("#{root}/contracts") + + loader.collapse("#{root}/provider/spec") + + loader.setup +end diff --git a/spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb b/spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb new file mode 100644 index 00000000000..ac20c17c187 --- /dev/null +++ b/spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +Pact.provider_states_for "MergeRequest#show" do + provider_state "a merge request with diffs exists" do + set_up do + user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME) + namespace = create(:namespace, name: 'gitlab-org') + project = create(:project, :custom_repo, name: 'gitlab-qa', namespace: namespace, files: {}) + + project.add_maintainer(user) + + merge_request = create(:merge_request_with_multiple_diffs, source_project: project) + merge_request_diff = create(:merge_request_diff, merge_request: merge_request) + + create(:merge_request_diff_file, :new_file, merge_request_diff: merge_request_diff) + end + end +end diff --git a/spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb b/spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb new file mode 100644 index 00000000000..8754232690c --- /dev/null +++ b/spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +Pact.provider_states_for "MergeRequest#show" do + provider_state "a merge request exists" do + set_up do + user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME) + namespace = create(:namespace, name: 'gitlab-org') + project = create(:project, :custom_repo, name: 'gitlab-qa', namespace: namespace, files: {}) + + project.add_maintainer(user) + + merge_request = create(:merge_request, source_project: project) + merge_request_diff = create(:merge_request_diff, merge_request: merge_request) + + create(:merge_request_diff_file, :new_file, merge_request_diff: merge_request_diff) + end + end +end diff --git a/spec/contracts/provider/states/project/merge_request/discussions_state.rb b/spec/contracts/provider/states/project/merge_request/discussions_state.rb new file mode 100644 index 00000000000..2d64f85eedf --- /dev/null +++ b/spec/contracts/provider/states/project/merge_request/discussions_state.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +Pact.provider_states_for "MergeRequest#show" do + provider_state "a merge request with discussions exists" do + set_up do + user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME) + namespace = create(:namespace, name: 'gitlab-org') + project = create(:project, name: 'gitlab-qa', namespace: namespace) + + project.add_maintainer(user) + + merge_request = create(:merge_request_with_diffs, source_project: project, author: user) + + create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: user) + end + end +end |