Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/contracts')
-rw-r--r--spec/contracts/.gitignore2
-rw-r--r--spec/contracts/README.md15
-rw-r--r--spec/contracts/consumer/.eslintrc.yml7
-rw-r--r--spec/contracts/consumer/.node-version1
-rw-r--r--spec/contracts/consumer/babel.config.json3
-rw-r--r--spec/contracts/consumer/endpoints/project/merge_requests.js34
-rw-r--r--spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js91
-rw-r--r--spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js98
-rw-r--r--spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js87
-rw-r--r--spec/contracts/consumer/package.json26
-rw-r--r--spec/contracts/consumer/specs/project/merge_request/show.spec.js112
-rw-r--r--spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json229
-rw-r--r--spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json223
-rw-r--r--spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json236
-rw-r--r--spec/contracts/provider/environments/test.rb15
-rw-r--r--spec/contracts/provider/helpers/users_helper.rb7
-rw-r--r--spec/contracts/provider/pact_helpers/project/merge_request/diffs_batch_helper.rb16
-rw-r--r--spec/contracts/provider/pact_helpers/project/merge_request/diffs_metadata_helper.rb16
-rw-r--r--spec/contracts/provider/pact_helpers/project/merge_request/discussions_helper.rb16
-rw-r--r--spec/contracts/provider/spec_helper.rb39
-rw-r--r--spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb18
-rw-r--r--spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb18
-rw-r--r--spec/contracts/provider/states/project/merge_request/discussions_state.rb17
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