diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-15 03:08:49 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-15 03:08:49 +0300 |
commit | 9de5cc2d1f25957d51268cd5b4c9c77a4ba4f695 (patch) | |
tree | 2b731956adb9c79408601c8f0d6157a84cbacc22 /spec/contracts | |
parent | cde60c9291a22ff0921f703568c4daef4a65ead7 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/contracts')
8 files changed, 384 insertions, 0 deletions
diff --git a/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js b/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js new file mode 100644 index 00000000000..f51ed9c2c74 --- /dev/null +++ b/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js @@ -0,0 +1,99 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { Matchers } from '@pact-foundation/pact'; +import { + JOB_STATUSES, + PIPELINE_GROUPS, + PIPELINE_STATUSES, + PIPELINE_TEXTS, + URL, + URL_PATH, +} from '../../../helpers/common_regex_patterns'; + +const body = { + data: { + project: { + id: Matchers.string('gid://gitlab/Project/278964'), + pipeline: { + id: Matchers.string('gid://gitlab/Ci::Pipeline/577266584'), + iid: Matchers.string('1175084'), + status: Matchers.term({ + matcher: JOB_STATUSES, + generate: 'RUNNING', + }), + retryable: Matchers.boolean(false), + cancelable: Matchers.boolean(true), + userPermissions: { + destroyPipeline: Matchers.boolean(false), + updatePipeline: Matchers.boolean(true), + }, + detailedStatus: { + id: Matchers.string('running-577266584-577266584'), + detailsPath: Matchers.term({ + matcher: URL_PATH, + generate: '/gitlab-org/gitlab/-/pipelines/577266584', + }), + icon: Matchers.term({ + matcher: PIPELINE_STATUSES, + generate: 'status_running', + }), + group: Matchers.term({ + matcher: PIPELINE_GROUPS, + generate: 'running', + }), + text: Matchers.term({ + matcher: PIPELINE_TEXTS, + generate: 'running', + }), + }, + createdAt: Matchers.iso8601DateTime('2022-06-30T16:58:59Z'), + user: { + id: Matchers.string('gid://gitlab/User/194645'), + name: Matchers.string('John Doe'), + username: Matchers.string('jdoe'), + webPath: Matchers.term({ + matcher: URL_PATH, + generate: '/gitlab-bot', + }), + webUrl: Matchers.term({ + matcher: URL, + generate: 'https://gitlab.com/gitlab-bot', + }), + email: null, + avatarUrl: Matchers.term({ + matcher: URL, + generate: + 'https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon', + }), + status: null, + }, + }, + }, + }, +}; + +const PipelineHeaderData = { + body: Matchers.extractPayload(body), + + success: { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body, + }, + + request: { + method: 'POST', + path: '/api/graphql', + }, + + variables: { + fullPath: 'gitlab-org/gitlab-qa', + iid: 1, + }, +}; + +export { PipelineHeaderData }; + +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/consumer/helpers/common_regex_patterns.js b/spec/contracts/consumer/helpers/common_regex_patterns.js index 1b7094bc082..664a71ab8a9 100644 --- a/spec/contracts/consumer/helpers/common_regex_patterns.js +++ b/spec/contracts/consumer/helpers/common_regex_patterns.js @@ -16,5 +16,9 @@ export const PIPELINE_STATUSES = export const PIPELINE_TEXTS = '^(canceled|created|delayed|failed|manual|passed|pending|preparing|running|skipped|waiting)$'; +// Jobs +export const JOB_STATUSES = + '^(CANCELED|CREATED|FAILED|MANUAL|PENDING|PREPARING|RUNNING|SCHEDULED|SKIPPED|SUCCESS|WAITING_FOR_RESOURCE)$'; + // Users export const USER_STATES = '^(active|blocked)$'; diff --git a/spec/contracts/consumer/helpers/graphql_query_extractor.js b/spec/contracts/consumer/helpers/graphql_query_extractor.js new file mode 100644 index 00000000000..884fa2cf528 --- /dev/null +++ b/spec/contracts/consumer/helpers/graphql_query_extractor.js @@ -0,0 +1,8 @@ +import { readFile } from 'fs/promises'; +import path from 'path'; + +export async function extractGraphQLQuery(fileLocation) { + const file = path.resolve(__dirname, '..', '..', '..', '..', fileLocation); + + return readFile(file, { encoding: 'UTF-8' }); +} diff --git a/spec/contracts/consumer/resources/graphql/pipelines.js b/spec/contracts/consumer/resources/graphql/pipelines.js new file mode 100644 index 00000000000..4f7ce58891c --- /dev/null +++ b/spec/contracts/consumer/resources/graphql/pipelines.js @@ -0,0 +1,25 @@ +import axios from 'axios'; + +import { extractGraphQLQuery } from '../../helpers/graphql_query_extractor'; + +export async function getPipelineHeaderDataRequest(endpoint) { + const { url } = endpoint; + const query = await extractGraphQLQuery( + 'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql', + ); + const graphqlQuery = { + query, + variables: { + fullPath: 'gitlab-org/gitlab-qa', + iid: 1, + }, + }; + + return axios({ + baseURL: url, + url: '/api/graphql', + method: 'POST', + headers: { Accept: '*/*' }, + data: graphqlQuery, + }); +} diff --git a/spec/contracts/consumer/specs/project/pipeline/show.spec.js b/spec/contracts/consumer/specs/project/pipeline/show.spec.js new file mode 100644 index 00000000000..0f1cc1c3108 --- /dev/null +++ b/spec/contracts/consumer/specs/project/pipeline/show.spec.js @@ -0,0 +1,53 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { pactWith } from 'jest-pact'; +import { GraphQLInteraction } from '@pact-foundation/pact'; + +import { extractGraphQLQuery } from '../../../helpers/graphql_query_extractor'; + +import { PipelineHeaderData } from '../../../fixtures/project/pipeline/get_pipeline_header_data.fixture'; +import { getPipelineHeaderDataRequest } from '../../../resources/graphql/pipelines'; + +const CONSUMER_NAME = 'Pipelines#show'; +const CONSUMER_LOG = '../logs/consumer.log'; +const CONTRACT_DIR = '../contracts/project/pipeline/show'; +const PROVIDER_NAME = 'GET pipeline header data'; + +// GraphQL query: getPipelineHeaderData +pactWith( + { + consumer: CONSUMER_NAME, + provider: PROVIDER_NAME, + log: CONSUMER_LOG, + dir: CONTRACT_DIR, + }, + + (provider) => { + describe(PROVIDER_NAME, () => { + beforeEach(async () => { + const query = await extractGraphQLQuery( + 'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql', + ); + const graphqlQuery = new GraphQLInteraction() + .given('a pipeline for a project exists') + .uponReceiving('a request for the pipeline header data') + .withQuery(query) + .withRequest(PipelineHeaderData.request) + .withVariables(PipelineHeaderData.variables) + .willRespondWith(PipelineHeaderData.success); + + provider.addInteraction(graphqlQuery); + }); + + it('returns a successful body', async () => { + const pipelineHeaderData = await getPipelineHeaderDataRequest({ + url: provider.mockService.baseUrl, + }); + + expect(pipelineHeaderData.data).toEqual(PipelineHeaderData.body); + }); + }); + }, +); + +/* eslint-enable @gitlab/require-i18n-strings */ diff --git a/spec/contracts/contracts/project/pipeline/show/pipelines#show-get_pipeline_header_data.json b/spec/contracts/contracts/project/pipeline/show/pipelines#show-get_pipeline_header_data.json new file mode 100644 index 00000000000..2d775dc0f61 --- /dev/null +++ b/spec/contracts/contracts/project/pipeline/show/pipelines#show-get_pipeline_header_data.json @@ -0,0 +1,152 @@ +{ + "consumer": { + "name": "Pipelines#show" + }, + "provider": { + "name": "GET pipeline header data" + }, + "interactions": [ + { + "description": "a request for the pipeline header data", + "providerState": "a pipeline for a project exists", + "request": { + "method": "POST", + "path": "/api/graphql", + "headers": { + "content-type": "application/json" + }, + "body": { + "query": "query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {\n project(fullPath: $fullPath) {\n id\n pipeline(iid: $iid) {\n id\n iid\n status\n retryable\n cancelable\n userPermissions {\n destroyPipeline\n updatePipeline\n }\n detailedStatus {\n id\n detailsPath\n icon\n group\n text\n }\n createdAt\n user {\n id\n name\n username\n webPath\n webUrl\n email\n avatarUrl\n status {\n message\n emoji\n }\n }\n }\n }\n}\n", + "variables": { + "fullPath": "gitlab-org/gitlab-qa", + "iid": 1 + } + }, + "matchingRules": { + "$.body.query": { + "match": "regex", + "regex": "query\\s*getPipelineHeaderData\\(\\$fullPath:\\s*ID!,\\s*\\$iid:\\s*ID!\\)\\s*\\{\\s*project\\(fullPath:\\s*\\$fullPath\\)\\s*\\{\\s*id\\s*pipeline\\(iid:\\s*\\$iid\\)\\s*\\{\\s*id\\s*iid\\s*status\\s*retryable\\s*cancelable\\s*userPermissions\\s*\\{\\s*destroyPipeline\\s*updatePipeline\\s*\\}\\s*detailedStatus\\s*\\{\\s*id\\s*detailsPath\\s*icon\\s*group\\s*text\\s*\\}\\s*createdAt\\s*user\\s*\\{\\s*id\\s*name\\s*username\\s*webPath\\s*webUrl\\s*email\\s*avatarUrl\\s*status\\s*\\{\\s*message\\s*emoji\\s*\\}\\s*\\}\\s*\\}\\s*\\}\\s*\\}\\s*" + } + } + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "body": { + "data": { + "project": { + "id": "gid://gitlab/Project/278964", + "pipeline": { + "id": "gid://gitlab/Ci::Pipeline/577266584", + "iid": "1175084", + "status": "RUNNING", + "retryable": false, + "cancelable": true, + "userPermissions": { + "destroyPipeline": false, + "updatePipeline": true + }, + "detailedStatus": { + "id": "running-577266584-577266584", + "detailsPath": "/gitlab-org/gitlab/-/pipelines/577266584", + "icon": "status_running", + "group": "running", + "text": "running" + }, + "createdAt": "2022-06-30T16:58:59Z", + "user": { + "id": "gid://gitlab/User/194645", + "name": "John Doe", + "username": "jdoe", + "webPath": "/gitlab-bot", + "webUrl": "https://gitlab.com/gitlab-bot", + "email": null, + "avatarUrl": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon", + "status": null + } + } + } + } + }, + "matchingRules": { + "$.body.data.project.id": { + "match": "type" + }, + "$.body.data.project.pipeline.id": { + "match": "type" + }, + "$.body.data.project.pipeline.iid": { + "match": "type" + }, + "$.body.data.project.pipeline.status": { + "match": "regex", + "regex": "^(CANCELED|CREATED|FAILED|MANUAL|PENDING|PREPARING|RUNNING|SCHEDULED|SKIPPED|SUCCESS|WAITING_FOR_RESOURCE)$" + }, + "$.body.data.project.pipeline.retryable": { + "match": "type" + }, + "$.body.data.project.pipeline.cancelable": { + "match": "type" + }, + "$.body.data.project.pipeline.userPermissions.destroyPipeline": { + "match": "type" + }, + "$.body.data.project.pipeline.userPermissions.updatePipeline": { + "match": "type" + }, + "$.body.data.project.pipeline.detailedStatus.id": { + "match": "type" + }, + "$.body.data.project.pipeline.detailedStatus.detailsPath": { + "match": "regex", + "regex": "^\\/[a-zA-Z0-9#-=?_]+$" + }, + "$.body.data.project.pipeline.detailedStatus.icon": { + "match": "regex", + "regex": "^status_(canceled|created|failed|manual|pending|preparing|running|scheduled|skipped|success|warning)$" + }, + "$.body.data.project.pipeline.detailedStatus.group": { + "match": "regex", + "regex": "^(canceled|created|failed|manual|pending|preparing|running|scheduled|skipped|success|success_warning|waiting-for-resource)$" + }, + "$.body.data.project.pipeline.detailedStatus.text": { + "match": "regex", + "regex": "^(canceled|created|delayed|failed|manual|passed|pending|preparing|running|skipped|waiting)$" + }, + "$.body.data.project.pipeline.createdAt": { + "match": "regex", + "regex": "^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z)$" + }, + "$.body.data.project.pipeline.user.id": { + "match": "type" + }, + "$.body.data.project.pipeline.user.name": { + "match": "type" + }, + "$.body.data.project.pipeline.user.username": { + "match": "type" + }, + "$.body.data.project.pipeline.user.webPath": { + "match": "regex", + "regex": "^\\/[a-zA-Z0-9#-=?_]+$" + }, + "$.body.data.project.pipeline.user.webUrl": { + "match": "regex", + "regex": "^(http|https):\\/\\/[a-z0-9]+([-.]{1}[a-z0-9]+)*.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$" + }, + "$.body.data.project.pipeline.user.avatarUrl": { + "match": "regex", + "regex": "^(http|https):\\/\\/[a-z0-9]+([-.]{1}[a-z0-9]+)*.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$" + } + } + } + } + ], + "metadata": { + "pactSpecification": { + "version": "2.0.0" + } + } +}
\ No newline at end of file diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/get_pipeline_header_data_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/get_pipeline_header_data_helper.rb new file mode 100644 index 00000000000..abb2781f987 --- /dev/null +++ b/spec/contracts/provider/pact_helpers/project/pipeline/get_pipeline_header_data_helper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require_relative '../../../spec_helper' +require_relative '../../../states/project/pipeline/pipeline_state' + +module Provider + module GetPipelinesHeaderDataHelper + Pact.service_provider "GET pipeline header data" do + app { Environments::Test.app } + + honours_pact_with 'Pipelines#show' do + pact_uri '../contracts/project/pipeline/show/pipelines#show-get_project_pipeline_header_data.json' + end + end + end +end diff --git a/spec/contracts/provider/states/project/pipeline/pipeline_state.rb b/spec/contracts/provider/states/project/pipeline/pipeline_state.rb new file mode 100644 index 00000000000..d1a4cd34bdd --- /dev/null +++ b/spec/contracts/provider/states/project/pipeline/pipeline_state.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +Pact.provider_states_for "Pipelines#show" do + provider_state "a pipeline for a project exists" do + set_up do + user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME) + namespace = create(:namespace, name: 'gitlab-org') + project = create(:project, :repository, name: 'gitlab-qa', namespace: namespace, creator: user) + scheduled_job = create(:ci_build, :scheduled) + manual_job = create(:ci_build, :manual) + + project.add_maintainer(user) + + create( + :ci_pipeline, + :with_job, + :success, + iid: 1, + project: project, + user: user, + duration: 10, + finished_at: '2022-06-01T02:47:31.432Z', + builds: [scheduled_job, manual_job] + ) + end + end +end |