diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-15 21:09:29 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-15 21:09:29 +0300 |
commit | 0e5ce539275e32cfd7592362e03673807fca9cc7 (patch) | |
tree | 9d2c10afd7965a6dec4a48a36f9d0c886f55247c /spec | |
parent | 977720d7565377672df302ecb82b1e7a221cfba6 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/frontend/fixtures/pipeline_header.rb | 26 | ||||
-rw-r--r-- | spec/frontend/pipelines/mock_data.js | 8 | ||||
-rw-r--r-- | spec/frontend/pipelines/pipeline_details_header_spec.js | 14 | ||||
-rw-r--r-- | spec/frontend/search/sort/components/app_spec.js | 23 | ||||
-rw-r--r-- | spec/lib/atlassian/jira_connect/client_spec.rb | 7 | ||||
-rw-r--r-- | spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/error_tracking/project_error_tracking_setting_spec.rb | 2 | ||||
-rw-r--r-- | spec/requests/api/admin/dictionary_spec.rb | 59 | ||||
-rw-r--r-- | spec/requests/api/integrations_spec.rb | 1 | ||||
-rw-r--r-- | spec/scripts/api/create_merge_request_note_spec.rb | 37 | ||||
-rw-r--r-- | spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb | 279 |
11 files changed, 441 insertions, 17 deletions
diff --git a/spec/frontend/fixtures/pipeline_header.rb b/spec/frontend/fixtures/pipeline_header.rb index 89f548caf72..3fdc45b1194 100644 --- a/spec/frontend/fixtures/pipeline_header.rb +++ b/spec/frontend/fixtures/pipeline_header.rb @@ -64,6 +64,32 @@ RSpec.describe "GraphQL Pipeline Header", '(JavaScript fixtures)', type: :reques end end + context 'with running pipeline and duration' do + let_it_be(:pipeline) do + create( + :ci_pipeline, + project: project, + sha: commit.id, + ref: 'master', + user: user, + status: :running, + duration: 7210, + created_at: 2.hours.ago, + started_at: 1.hour.ago + ) + end + + let_it_be(:build) { create(:ci_build, :running, pipeline: pipeline, ref: 'master') } + + it "graphql/pipelines/pipeline_header_running_with_duration.json" do + query = get_graphql_query_as_string(query_path) + + post_graphql(query, current_user: user, variables: { fullPath: project.full_path, iid: pipeline.iid }) + + expect_graphql_errors_to_be_empty + end + end + context 'with failed pipeline' do let_it_be(:pipeline) do create( diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js index 8bbe0ef78c0..62c0d6e2d91 100644 --- a/spec/frontend/pipelines/mock_data.js +++ b/spec/frontend/pipelines/mock_data.js @@ -1,5 +1,6 @@ import pipelineHeaderSuccess from 'test_fixtures/graphql/pipelines/pipeline_header_success.json'; import pipelineHeaderRunning from 'test_fixtures/graphql/pipelines/pipeline_header_running.json'; +import pipelineHeaderRunningWithDuration from 'test_fixtures/graphql/pipelines/pipeline_header_running_with_duration.json'; import pipelineHeaderFailed from 'test_fixtures/graphql/pipelines/pipeline_header_failed.json'; const PIPELINE_RUNNING = 'RUNNING'; @@ -9,7 +10,12 @@ const PIPELINE_FAILED = 'FAILED'; const threeWeeksAgo = new Date(); threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21); -export { pipelineHeaderSuccess, pipelineHeaderRunning, pipelineHeaderFailed }; +export { + pipelineHeaderSuccess, + pipelineHeaderRunning, + pipelineHeaderRunningWithDuration, + pipelineHeaderFailed, +}; export const pipelineRetryMutationResponseSuccess = { data: { pipelineRetry: { errors: [] } }, diff --git a/spec/frontend/pipelines/pipeline_details_header_spec.js b/spec/frontend/pipelines/pipeline_details_header_spec.js index 2fef4924cc7..deaf5c6f72f 100644 --- a/spec/frontend/pipelines/pipeline_details_header_spec.js +++ b/spec/frontend/pipelines/pipeline_details_header_spec.js @@ -16,6 +16,7 @@ import getPipelineDetailsQuery from '~/pipelines/graphql/queries/get_pipeline_he import { pipelineHeaderSuccess, pipelineHeaderRunning, + pipelineHeaderRunningWithDuration, pipelineHeaderFailed, pipelineRetryMutationResponseSuccess, pipelineCancelMutationResponseSuccess, @@ -33,6 +34,7 @@ describe('Pipeline details header', () => { const successHandler = jest.fn().mockResolvedValue(pipelineHeaderSuccess); const runningHandler = jest.fn().mockResolvedValue(pipelineHeaderRunning); + const runningHandlerWithDuration = jest.fn().mockResolvedValue(pipelineHeaderRunningWithDuration); const failedHandler = jest.fn().mockResolvedValue(pipelineHeaderFailed); const retryMutationHandlerSuccess = jest @@ -273,6 +275,18 @@ describe('Pipeline details header', () => { }); }); + describe('running pipeline with duration', () => { + beforeEach(async () => { + createComponent([[getPipelineDetailsQuery, runningHandlerWithDuration]]); + + await waitForPromises(); + }); + + it('does not display pipeline duration text', () => { + expect(findPipelineDuration().exists()).toBe(false); + }); + }); + describe('actions', () => { describe('retry action', () => { beforeEach(async () => { diff --git a/spec/frontend/search/sort/components/app_spec.js b/spec/frontend/search/sort/components/app_spec.js index 322ce1b16ef..09c295e3ea9 100644 --- a/spec/frontend/search/sort/components/app_spec.js +++ b/spec/frontend/search/sort/components/app_spec.js @@ -1,4 +1,4 @@ -import { GlButtonGroup, GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlButtonGroup, GlButton, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; @@ -35,13 +35,16 @@ describe('GlobalSearchSort', () => { ...defaultProps, ...props, }, + stubs: { + GlCollapsibleListbox, + }, }); }; const findSortButtonGroup = () => wrapper.findComponent(GlButtonGroup); - const findSortDropdown = () => wrapper.findComponent(GlDropdown); + const findSortDropdown = () => wrapper.findComponent(GlCollapsibleListbox); const findSortDirectionButton = () => wrapper.findComponent(GlButton); - const findDropdownItems = () => findSortDropdown().findAllComponents(GlDropdownItem); + const findDropdownItems = () => findSortDropdown().findAllComponents(GlListboxItem); const findDropdownItemsText = () => findDropdownItems().wrappers.map((w) => w.text()); describe('template', () => { @@ -89,7 +92,7 @@ describe('GlobalSearchSort', () => { }); it('is set correctly', () => { - expect(findSortDropdown().attributes('text')).toBe(value); + expect(findSortDropdown().props('toggleText')).toBe(value); }); }); }); @@ -116,14 +119,14 @@ describe('GlobalSearchSort', () => { describe('actions', () => { describe.each` - description | index | value - ${'non-sortable'} | ${0} | ${MOCK_SORT_OPTIONS[0].sortParam} - ${'sortable'} | ${1} | ${MOCK_SORT_OPTIONS[1].sortParam.desc} - `('handleSortChange', ({ description, index, value }) => { - describe(`when clicking a ${description} option`, () => { + description | text | value + ${'non-sortable'} | ${MOCK_SORT_OPTIONS[0].title} | ${MOCK_SORT_OPTIONS[0].sortParam} + ${'sortable'} | ${MOCK_SORT_OPTIONS[1].title} | ${MOCK_SORT_OPTIONS[1].sortParam.desc} + `('handleSortChange', ({ description, text, value }) => { + describe(`when selecting a ${description} option`, () => { beforeEach(() => { createComponent(); - findDropdownItems().at(index).vm.$emit('click'); + findSortDropdown().vm.$emit('select', text); }); it('calls setQuery and applyQuery correctly', () => { diff --git a/spec/lib/atlassian/jira_connect/client_spec.rb b/spec/lib/atlassian/jira_connect/client_spec.rb index f1f9dd38947..66ae3658a92 100644 --- a/spec/lib/atlassian/jira_connect/client_spec.rb +++ b/spec/lib/atlassian/jira_connect/client_spec.rb @@ -11,9 +11,10 @@ RSpec.describe Atlassian::JiraConnect::Client, feature_category: :integrations d let_it_be(:mrs_by_title) { create_list(:merge_request, 4, :unique_branches, :jira_title) } let_it_be(:mrs_by_branch) { create_list(:merge_request, 2, :jira_branch) } let_it_be(:red_herrings) { create_list(:merge_request, 1, :unique_branches) } + let_it_be(:mrs_by_description) { create_list(:merge_request, 2, :unique_branches, :jira_description) } let_it_be(:pipelines) do - (red_herrings + mrs_by_branch + mrs_by_title).map do |mr| + (red_herrings + mrs_by_branch + mrs_by_title + mrs_by_description).map do |mr| create(:ci_pipeline, merge_request: mr) end end @@ -253,7 +254,7 @@ RSpec.describe Atlassian::JiraConnect::Client, feature_category: :integrations d it 'only sends information about relevant MRs' do expect(subject).to receive(:post).with( - '/rest/deployments/0.1/bulk', { deployments: have_attributes(size: 6) } + '/rest/deployments/0.1/bulk', { deployments: have_attributes(size: 8) } ).and_call_original subject.send(:store_deploy_info, project: project, deployments: deployments) @@ -378,7 +379,7 @@ RSpec.describe Atlassian::JiraConnect::Client, feature_category: :integrations d it 'only sends information about relevant MRs' do expect(subject).to receive(:post) - .with('/rest/builds/0.1/bulk', { builds: have_attributes(size: 6) }) + .with('/rest/builds/0.1/bulk', { builds: have_attributes(size: 8) }) .and_call_original subject.send(:store_build_info, project: project, pipelines: pipelines) diff --git a/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb b/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb index f6fca39fa68..523b7ddaa09 100644 --- a/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb +++ b/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb @@ -69,7 +69,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::DeploymentEntity, feature_ca subject.deployable.update!(pipeline: pipeline) end - %i[jira_branch jira_title].each do |trait| + %i[jira_branch jira_title jira_description].each do |trait| context "because it belongs to an MR with a #{trait}" do let(:merge_request) { create(:merge_request, trait) } diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb index 34be6ec7fa9..a86283ea4ba 100644 --- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb +++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb @@ -300,7 +300,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting, feature_category: :er it { expect(result[:issue].gitlab_commit_path).to eq(nil) } end - context 'when repo commit matches first relase version' do + context 'when repo commit matches first release version' do let(:commit) { instance_double(Commit, id: commit_id) } let(:repository) { instance_double(Repository, commit: commit) } diff --git a/spec/requests/api/admin/dictionary_spec.rb b/spec/requests/api/admin/dictionary_spec.rb new file mode 100644 index 00000000000..effd3572423 --- /dev/null +++ b/spec/requests/api/admin/dictionary_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::Admin::Dictionary, feature_category: :database do + let(:admin) { create(:admin) } + let(:path) { "/admin/databases/main/dictionary/tables/achievements" } + + describe 'GET admin/databases/:database_name/dictionary/tables/:table_name' do + it_behaves_like "GET request permissions for admin mode" + + subject(:show_table_dictionary) do + get api(path, admin, admin_mode: true) + end + + context 'when the database does not exist' do + it 'returns bad request' do + get api("/admin/databases/#{non_existing_record_id}/dictionary/tables/achievements", admin, admin_mode: true) + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + + context 'when the table does not exist' do + it 'returns not found' do + get api("/admin/databases/main/dictionary/tables/#{non_existing_record_id}", admin, admin_mode: true) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'with a malicious table_name' do + it 'returns an error' do + get api("/admin/databases/main/dictionary/tables/%2E%2E%2Fpasswords.yml", admin, admin_mode: true) + + expect(response).to have_gitlab_http_status(:error) + end + end + + context 'when the params are correct' do + let(:dictionary_dir) { Rails.root.join('spec/fixtures') } + let(:path_file) { Rails.root.join(dictionary_dir, 'achievements.yml') } + + it 'fetches the table dictionary' do + allow(Gitlab::Database::GitlabSchema).to receive(:dictionary_paths).and_return([dictionary_dir]) + + expect(Gitlab::PathTraversal).to receive(:check_allowed_absolute_path_and_path_traversal!).twice.with( + path_file.to_s, [dictionary_dir.to_s]).and_call_original + + show_table_dictionary + + aggregate_failures "testing response" do + expect(json_response['table_name']).to eq('achievements') + expect(json_response['feature_categories']).to eq(['feature_category_example']) + end + end + end + end +end diff --git a/spec/requests/api/integrations_spec.rb b/spec/requests/api/integrations_spec.rb index 8334d6b6832..6fd2aafd546 100644 --- a/spec/requests/api/integrations_spec.rb +++ b/spec/requests/api/integrations_spec.rb @@ -68,7 +68,6 @@ RSpec.describe API::Integrations, feature_category: :integrations do let(:missing_attributes) do { datadog: %i[archive_trace_events], - discord: %i[branches_to_be_notified notify_only_broken_pipelines], hangouts_chat: %i[notify_only_broken_pipelines], jira: %i[issues_enabled project_key jira_issue_regex jira_issue_prefix vulnerabilities_enabled vulnerabilities_issuetype], mattermost: %i[deployment_channel labels_to_be_notified], diff --git a/spec/scripts/api/create_merge_request_note_spec.rb b/spec/scripts/api/create_merge_request_note_spec.rb new file mode 100644 index 00000000000..74cc68146c5 --- /dev/null +++ b/spec/scripts/api/create_merge_request_note_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative '../../../scripts/api/create_merge_request_note' + +RSpec.describe CreateMergeRequestNote, feature_category: :tooling do + describe '#execute' do + let(:project_id) { 12345 } + let(:iid) { 1 } + let(:content) { 'test123' } + + let(:options) do + { + api_token: 'token', + endpoint: 'https://example.gitlab.com', + project: project_id, + merge_request: Struct.new(:iid).new(iid) + } + end + + subject { described_class.new(options) } + + it 'requests create_merge_request_comment from the gitlab client' do + client = double('Gitlab::Client') # rubocop:disable RSpec/VerifiedDoubles + + expect(Gitlab).to receive(:client) + .with(endpoint: options[:endpoint], private_token: options[:api_token]) + .and_return(client) + + expect(client).to receive(:create_merge_request_comment).with( + project_id, iid, content + ).and_return(true) + + subject.execute(content) + end + end +end diff --git a/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb new file mode 100644 index 00000000000..aee16334003 --- /dev/null +++ b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb @@ -0,0 +1,279 @@ +# frozen_string_literal: true + +# rubocop:disable RSpec/VerifiedDoubles + +require 'fast_spec_helper' +require_relative '../../scripts/generate-message-to-run-e2e-pipeline' +require_relative '../support/helpers/stub_env' + +RSpec.describe GenerateMessageToRunE2ePipeline, feature_category: :tooling do + include StubENV + + let(:options) do + { + project: '13083', + pipeline_id: '13083', + api_token: 'asdf1234', + endpoint: 'https://gitlab.com/api/v4' + } + end + + let(:client) { double('Gitlab::Client') } + + let(:note_content) do + <<~MARKDOWN + <!-- Run e2e warning begin --> + Some note + <!-- Run e2e warning end --> + MARKDOWN + end + + before do + allow(Gitlab).to receive(:client) + .with(endpoint: options[:endpoint], private_token: options[:api_token]) + .and_return(client) + end + + subject { described_class.new(options) } + + describe '#execute' do + let(:commit_merge_request) do + Struct.new(:author, :iid).new( + Struct.new(:id, :username).new( + '2', + 'test_user' + ), + '123' + ) + end + + let(:merge_request) { instance_double(CommitMergeRequests, execute: [commit_merge_request]) } + let(:merge_request_note_client) { instance_double(CreateMergeRequestNote, execute: true) } + + before do + stub_env( + 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257' + ) + + allow(CommitMergeRequests).to receive(:new) + .with(options.merge(sha: ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA'])) + .and_return(merge_request) + end + + context 'when there are qa_test_folders' do + before do + allow(subject).to receive(:qa_tests_folders?).and_return(true) + end + + context 'when there is no existing note' do + before do + allow(subject).to receive(:existing_note).and_return(nil) + allow(subject).to receive(:content).and_return(note_content) + + allow(client).to receive(:create_merge_request_comment) + .with(options[:project], '123', note_content) + end + + it 'adds a new note' do + expect(CreateMergeRequestNote).to receive(:new) + .with(options.merge(merge_request: commit_merge_request)) + .and_return(merge_request_note_client) + + expect(merge_request_note_client).to receive(:execute).with(note_content) + + subject.execute + end + end + + context 'when there is existing note' do + before do + allow(subject).to receive(:existing_note).and_return(true) + end + + it 'does not add a new note' do + expect(CreateMergeRequestNote).not_to receive(:new) + + subject.execute + end + end + end + + context 'when there are no qa_test_folders' do + before do + allow(subject).to receive(:qa_tests_folders?).and_return(false) + end + + it 'does not add a new note' do + expect(CreateMergeRequestNote).not_to receive(:new) + + subject.execute + end + end + end + + describe '#qa_tests_folders?' do + before do + allow(File).to receive(:exist?).with(any_args).and_return(true) + allow(File).to receive(:open).with(any_args).and_return(file_contents) + end + + context 'when QA_TESTS is empty' do + let(:file_contents) do + %w[ + QA_SUITES='QA::Scenario::Test::Instance::All' + QA_TESTS='' + QA_FEATURE_FLAGS='' + ] + end + + it 'returns false' do + expect(subject.send(:qa_tests_folders?)).to be_falsy + end + end + + context 'when QA_TESTS has a spec file' do + let(:file_contents) do + %w[ + QA_SUITES='QA::Scenario::Test::Instance::All' + QA_TESTS='qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb' + QA_FEATURE_FLAGS='' + ] + end + + it 'returns false' do + expect(subject.send(:qa_tests_folders?)).to be_falsy + end + end + + context 'when QA_TESTS has folders' do + let(:file_contents) do + [ + "QA_SUITES='QA::Scenario::Test::Instance::All'", + "QA_TESTS='qa/specs/features/browser_ui/1_manage/ qa/specs/features/browser_ui/2_plan'", + "QA_FEATURE_FLAGS=''" + ] + end + + it 'returns true' do + expect(subject.send(:qa_tests_folders?)).to be_truthy + end + end + end + + describe '#match?' do + it 'returns true for a note that matches NOTE_PATTERN' do + expect(subject.send(:match?, note_content)).to be_truthy + end + + it 'returns false for a note that does not match NOTE_PATTERN' do + expect(subject.send(:match?, 'Some random text')).to be_falsy + end + end + + describe '#existing_note' do + let(:mr_comments_response) do + [ + double(:mr_comment, id: 1, body: 'foo'), + double(:mr_comment, id: 2, body: 'bar'), + existing_note + ] + end + + before do + allow(client) + .to receive(:merge_request_comments) + .with(any_args) + .and_return(double(auto_paginate: mr_comments_response)) + allow(subject).to receive(:merge_request).and_return(double(:merge_request, id: 2, iid: 123)) + end + + context 'when note exists' do + let(:existing_note) do + double( + :mr_comment, + id: 3, + body: note_content + ) + end + + it 'returns the existing note' do + expect(subject.send(:existing_note)).to eq existing_note + end + end + + context 'when note doesnt exists' do + let(:existing_note) do + double( + :mr_comment, + id: 3, + body: 'random content' + ) + end + + it 'returns nil' do + expect(subject.send(:existing_note)).to eq nil + end + end + end + + describe '#content' do + let(:author_username) { 'sam_smith' } + + let(:expected_content) do + <<~MARKDOWN + <!-- Run e2e warning begin --> + :warning: @#{author_username} Some end-to-end (E2E) tests have been selected based on the stage label on this MR. + If not run already, please run the `e2e:package-and-test-ee` job in the `qa` stage + and review the results **before merging this MR**. (E2E tests are not run automatically on some MRs due to [runner resource constraints](https://gitlab.com/gitlab-org/gitlab-qa/-/issues/261).) + + If you would like to run all e2e tests, please apply the ~"pipeline:run-all-e2e" label and restart the pipeline. + + Once done, please apply the ✅ emoji on this comment. + + For any questions or help in reviewing the E2E test results, please reach out on the internal #quality Slack channel. + <!-- Run e2e warning end --> + MARKDOWN + end + + before do + allow(subject).to receive(:merge_request).and_return(double(:merge_request, + author: double(username: author_username))) + end + + it 'returns content text with author username' do + expect(subject.send(:content)).to eq expected_content + end + end + + describe '#author_username' do + let(:author_username) { 'sam_smith' } + + before do + allow(subject).to receive(:merge_request).and_return(double(:merge_request, + author: double(username: author_username))) + end + + it 'returns nil' do + expect(subject.send(:author_username)).to eq author_username + end + end + + describe '#env' do + before do + stub_env( + 'VAR_WITH_VALUE' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257', + 'EMPTY_VAR' => ' ' + ) + end + + it 'returns env var when not empty' do + expect(subject.send(:env, 'VAR_WITH_VALUE')).to eq 'bfcd2b9b5cad0b889494ce830697392c8ca11257' + end + + it 'returns nil when env var is empty' do + expect(subject.send(:env, 'EMPTY_VAR')).to be_nil + end + end +end + +# rubocop:enable RSpec/VerifiedDoubles |