diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-09 18:07:50 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-09 18:07:50 +0300 |
commit | e38a99eb0725697297386dd0bb1045b1fd55493a (patch) | |
tree | e6298122cbb5418f59c140f4f9e303abdc0739b5 /spec | |
parent | 7c41737ae53e3a237f356480ae04ec3ba182447b (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
32 files changed, 910 insertions, 76 deletions
diff --git a/spec/frontend/boards/components/board_filtered_search_spec.js b/spec/frontend/boards/components/board_filtered_search_spec.js index 1a07b9f0b78..f1113ee3073 100644 --- a/spec/frontend/boards/components/board_filtered_search_spec.js +++ b/spec/frontend/boards/components/board_filtered_search_spec.js @@ -3,7 +3,10 @@ import Vue from 'vue'; import Vuex from 'vuex'; import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue'; import * as urlUtility from '~/lib/utils/url_utility'; -import { __ } from '~/locale'; +import { + TOKEN_TITLE_AUTHOR, + TOKEN_TITLE_LABEL, +} from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; @@ -17,7 +20,7 @@ describe('BoardFilteredSearch', () => { const tokens = [ { icon: 'labels', - title: __('Label'), + title: TOKEN_TITLE_LABEL, type: 'label', operators: [ { value: '=', description: 'is' }, @@ -30,7 +33,7 @@ describe('BoardFilteredSearch', () => { }, { icon: 'pencil', - title: __('Author'), + title: TOKEN_TITLE_AUTHOR, type: 'author', operators: [ { value: '=', description: 'is' }, diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js index 17dcf5868a2..c99ae118db7 100644 --- a/spec/frontend/boards/mock_data.js +++ b/spec/frontend/boards/mock_data.js @@ -1,7 +1,14 @@ import { GlFilteredSearchToken } from '@gitlab/ui'; import { keyBy } from 'lodash'; import { ListType } from '~/boards/constants'; -import { __ } from '~/locale'; +import { + TOKEN_TITLE_ASSIGNEE, + TOKEN_TITLE_AUTHOR, + TOKEN_TITLE_LABEL, + TOKEN_TITLE_MILESTONE, + TOKEN_TITLE_RELEASE, + TOKEN_TITLE_TYPE, +} from '~/vue_shared/components/filtered_search_bar/constants'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'; import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; @@ -742,7 +749,7 @@ export const mockConfidentialToken = { export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedIn) => [ { icon: 'user', - title: __('Assignee'), + title: TOKEN_TITLE_ASSIGNEE, type: 'assignee', operators: [ { value: '=', description: 'is' }, @@ -755,7 +762,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI }, { icon: 'pencil', - title: __('Author'), + title: TOKEN_TITLE_AUTHOR, type: 'author', operators: [ { value: '=', description: 'is' }, @@ -769,7 +776,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI }, { icon: 'labels', - title: __('Label'), + title: TOKEN_TITLE_LABEL, type: 'label', operators: [ { value: '=', description: 'is' }, @@ -783,7 +790,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI ...(isSignedIn ? [mockEmojiToken, mockConfidentialToken] : []), { icon: 'clock', - title: __('Milestone'), + title: TOKEN_TITLE_MILESTONE, symbol: '%', type: 'milestone', shouldSkipSort: true, @@ -793,7 +800,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI }, { icon: 'issues', - title: __('Type'), + title: TOKEN_TITLE_TYPE, type: 'type', token: GlFilteredSearchToken, unique: true, @@ -804,7 +811,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI }, { type: 'release', - title: __('Release'), + title: TOKEN_TITLE_RELEASE, icon: 'rocket', token: ReleaseToken, fetchReleases: expect.any(Function), diff --git a/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js index d85574262fe..8eeba4d6274 100644 --- a/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js @@ -1,5 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import MergeChecksFailed from '~/vue_merge_request_widget/components/states/merge_checks_failed.vue'; +import { DETAILED_MERGE_STATUS } from '~/vue_merge_request_widget/constants'; let wrapper; @@ -15,9 +16,10 @@ describe('Merge request widget merge checks failed state component', () => { }); it.each` - mrState | displayText - ${{ approvals: true, isApproved: false }} | ${'approvalNeeded'} - ${{ detailedMergeStatus: 'BLOCKED_STATUS' }} | ${'blockingMergeRequests'} + mrState | displayText + ${{ approvals: true, isApproved: false }} | ${'approvalNeeded'} + ${{ detailedMergeStatus: DETAILED_MERGE_STATUS.BLOCKED_STATUS }} | ${'blockingMergeRequests'} + ${{ detailedMergeStatus: DETAILED_MERGE_STATUS.EXTERNAL_STATUS_CHECKS }} | ${'externalStatusChecksFailed'} `('display $displayText text for $mrState', ({ mrState, displayText }) => { factory({ mr: mrState }); diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index 6971ec83ce2..c2c78be6a0f 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -391,7 +391,7 @@ RSpec.describe UsersHelper do expect_next_instance_of(Admin::UserSerializer) do |instance| expect(instance).to receive(:represent).with([user], { current_user: user }).and_return(entity) end - expect(entity).to receive(:as_json).and_return({ "username" => "admin" }) + expect(entity).to receive(:to_json).and_return("{\"username\":\"admin\"}") expect(data[:users]).to eq "{\"username\":\"admin\"}" end diff --git a/spec/lib/feature/gitaly_spec.rb b/spec/lib/feature/gitaly_spec.rb index ed80e31e3cd..33696290483 100644 --- a/spec/lib/feature/gitaly_spec.rb +++ b/spec/lib/feature/gitaly_spec.rb @@ -6,73 +6,207 @@ RSpec.describe Feature::Gitaly do let_it_be(:project) { create(:project) } let_it_be(:project_2) { create(:project) } + let_it_be(:repository) { project.repository.raw } + let_it_be(:repository_2) { project_2.repository.raw } + before do skip_feature_flags_yaml_validation + allow(Feature::Definition).to receive(:get).with(any_args).and_return( + Feature::Definition.new('flag.yml', name: :flag, type: :development) + ) end - describe ".enabled?" do + describe ".enabled_for_any?" do context 'when the flag is set globally' do - let(:feature_flag) { 'global_flag' } - context 'when the gate is closed' do before do stub_feature_flags(gitaly_global_flag: false) end it 'returns false' do - expect(described_class.enabled?(feature_flag)).to be(false) + expect(described_class.enabled_for_any?(:gitaly_global_flag)).to be(false) end end context 'when the flag defaults to on' do it 'returns true' do - expect(described_class.enabled?(feature_flag)).to be(true) + expect(described_class.enabled_for_any?(:gitaly_global_flag)).to be(true) end end end context 'when the flag is enabled for a particular project' do - let(:feature_flag) { 'project_flag' } - before do stub_feature_flags(gitaly_project_flag: project) end it 'returns true for that project' do - expect(described_class.enabled?(feature_flag, project)).to be(true) + expect(described_class.enabled_for_any?(:gitaly_project_flag, project)).to be(true) end it 'returns false for any other project' do - expect(described_class.enabled?(feature_flag, project_2)).to be(false) + expect(described_class.enabled_for_any?(:gitaly_project_flag, project_2)).to be(false) end it 'returns false when no project is passed' do - expect(described_class.enabled?(feature_flag)).to be(false) + expect(described_class.enabled_for_any?(:gitaly_project_flag)).to be(false) + end + end + + context 'when the flag is enabled for a particular repository' do + before do + stub_feature_flags(gitaly_repository_flag: repository) + end + + it 'returns true for that repository' do + expect(described_class.enabled_for_any?(:gitaly_repository_flag, repository)).to be(true) + end + + it 'returns false for any other repository' do + expect(described_class.enabled_for_any?(:gitaly_repository_flag, repository_2)).to be(false) + end + + it 'returns false when no repository is passed' do + expect(described_class.enabled_for_any?(:gitaly_repository_flag)).to be(false) + end + end + + context 'when the flag is checked with multiple input actors' do + before do + stub_feature_flags(gitaly_flag: repository) + end + + it 'returns true if any of the flag is enabled for any of the input actors' do + expect(described_class.enabled_for_any?(:gitaly_flag, project, repository)).to be(true) + end + + it 'returns false if any of the flag is not enabled for any of the input actors' do + expect( + described_class.enabled_for_any?(:gitaly_flag, project, project_2, repository_2) + ).to be(false) end end end describe ".server_feature_flags" do + let(:group) { create(:group) } + let(:user) { create(:user) } + before do - stub_feature_flags(gitaly_global_flag: true, gitaly_project_flag: project, non_gitaly_flag: false) + stub_feature_flags( + gitaly_global_flag: true, + gitaly_project_flag: project, + gitaly_repository_flag: repository, + gitaly_user_flag: user, + gitaly_group_flag: group, + non_gitaly_flag: false + ) end subject { described_class.server_feature_flags } it 'returns a hash of flags starting with the prefix, with dashes instead of underscores' do expect(subject).to eq('gitaly-feature-global-flag' => 'true', - 'gitaly-feature-project-flag' => 'false') + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') end context 'when a project is passed' do it 'returns the value for the flag on the given project' do - expect(described_class.server_feature_flags(project)) + expect(described_class.server_feature_flags(project: project)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'true', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + + expect(described_class.server_feature_flags(project: project_2)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + end + end + + context 'when a repository is passed' do + it 'returns the value for the flag on the given repository' do + expect(described_class.server_feature_flags(repository: repository)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'true', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + + expect(described_class.server_feature_flags(repository: repository_2)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + end + end + + context 'when a user is passed' do + it 'returns the value for the flag on the given user' do + expect(described_class.server_feature_flags(user: user)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'true', + 'gitaly-feature-group-flag' => 'false') + + expect(described_class.server_feature_flags(user: create(:user))) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + end + end + + context 'when a group is passed' do + it 'returns the value for the flag on the given group' do + expect(described_class.server_feature_flags(group: group)) .to eq('gitaly-feature-global-flag' => 'true', - 'gitaly-feature-project-flag' => 'true') + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'true') - expect(described_class.server_feature_flags(project_2)) + expect(described_class.server_feature_flags(group: create(:group))) .to eq('gitaly-feature-global-flag' => 'true', - 'gitaly-feature-project-flag' => 'false') + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + end + end + + context 'when multiple actors are passed' do + it 'returns the corresponding enablement status for actors' do + expect(described_class.server_feature_flags(project: project_2, repository: repository)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'false', + 'gitaly-feature-repository-flag' => 'true', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + + expect(described_class.server_feature_flags(project: project, repository: repository_2)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'true', + 'gitaly-feature-repository-flag' => 'false', + 'gitaly-feature-user-flag' => 'false', + 'gitaly-feature-group-flag' => 'false') + + expect(described_class.server_feature_flags(user: user, project: project, repository: repository, group: group)) + .to eq('gitaly-feature-global-flag' => 'true', + 'gitaly-feature-project-flag' => 'true', + 'gitaly-feature-repository-flag' => 'true', + 'gitaly-feature-user-flag' => 'true', + 'gitaly-feature-group-flag' => 'true') end end @@ -88,4 +222,67 @@ RSpec.describe Feature::Gitaly do end end end + + describe ".user_actor" do + let(:user) { create(:user) } + + context 'when user is passed in' do + it 'returns a actor wrapper from user' do + expect(described_class.user_actor(user).flipper_id).to eql(user.flipper_id) + end + end + + context 'when called without user and user_id is available in application context' do + it 'returns a actor wrapper from user_id' do + ::Gitlab::ApplicationContext.with_context(user: user) do + expect(described_class.user_actor.flipper_id).to eql(user.flipper_id) + end + end + end + + context 'when called without user and user_id is absent from application context' do + it 'returns nil' do + expect(described_class.user_actor).to be(nil) + end + end + + context 'when something else is passed' do + it 'returns nil' do + expect(described_class.user_actor(1234)).to be(nil) + end + end + end + + describe ".project_actor" do + let_it_be(:project) { create(:project) } + + context 'when project is passed in' do + it 'returns a actor wrapper from project' do + expect(described_class.project_actor(project).flipper_id).to eql(project.flipper_id) + end + end + + context 'when something else is passed in' do + it 'returns nil' do + expect(described_class.project_actor(1234)).to be(nil) + end + end + end + + describe ".group_actor" do + let_it_be(:group) { create(:group ) } + let_it_be(:project) { create(:project, group: group) } + + context 'when project is passed in' do + it "returns a actor wrapper from project's group" do + expect(described_class.group_actor(project).flipper_id).to eql(group.flipper_id) + end + end + + context 'when something else is passed in' do + it 'returns nil' do + expect(described_class.group_actor(1234)).to be(nil) + end + end + end end diff --git a/spec/lib/gitlab/application_context_spec.rb b/spec/lib/gitlab/application_context_spec.rb index 8b2a228b935..58d462aa27f 100644 --- a/spec/lib/gitlab/application_context_spec.rb +++ b/spec/lib/gitlab/application_context_spec.rb @@ -44,7 +44,7 @@ RSpec.describe Gitlab::ApplicationContext do describe '.push' do it 'passes the expected context on to labkit' do fake_proc = duck_type(:call) - expected_context = { user: fake_proc, client_id: fake_proc } + expected_context = { user: fake_proc, user_id: fake_proc, client_id: fake_proc } expect(Labkit::Context).to receive(:push).with(expected_context) @@ -108,14 +108,16 @@ RSpec.describe Gitlab::ApplicationContext do context = described_class.new(user: -> { user }, project: -> { project }, namespace: -> { subgroup }) expect(result(context)) - .to include(user: user.username, project: project.full_path, root_namespace: namespace.full_path) + .to include(user: user.username, user_id: user.id, project: project.full_path, + root_namespace: namespace.full_path) end it 'correctly loads the expected values when passed directly' do context = described_class.new(user: user, project: project, namespace: subgroup) expect(result(context)) - .to include(user: user.username, project: project.full_path, root_namespace: namespace.full_path) + .to include(user: user.username, user_id: user.id, project: project.full_path, + root_namespace: namespace.full_path) end it 'falls back to a projects namespace when a project is passed but no namespace' do diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb index 1306d61d99c..8475c3a8b19 100644 --- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb @@ -14,6 +14,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do super end + + def validate_context! + # no-op + end end end @@ -95,6 +99,24 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do expect(file.error_message).to eq('Included file `some/file/xxxxxxxxxxxxxxxx.yml` does not have valid YAML syntax!') end end + + context 'when the class has no validate_context!' do + let(:test_class) do + Class.new(described_class) do + def initialize(params, context) + @location = params + + super + end + end + end + + let(:location) { 'some/file/config.yaml' } + + it 'raises an error' do + expect { valid? }.to raise_error(NotImplementedError) + end + end end describe '#to_hash' do diff --git a/spec/lib/gitlab/git/object_pool_spec.rb b/spec/lib/gitlab/git/object_pool_spec.rb index 3b1eb0319f8..b158c7227d4 100644 --- a/spec/lib/gitlab/git/object_pool_spec.rb +++ b/spec/lib/gitlab/git/object_pool_spec.rb @@ -78,44 +78,40 @@ RSpec.describe Gitlab::Git::ObjectPool do end describe '#fetch' do - let(:commit_count) { source_repository.commit_count } + context 'when the object pool repository exists' do + let!(:pool_repository) { create(:pool_repository, :ready) } - context "when the object's pool repository exists" do - it 'does not raise an error' do - expect { subject.fetch }.not_to raise_error + context 'without changes' do + it 'does not raise an error' do + expect { subject.fetch }.not_to raise_error + end end - end - - context "when the object's pool repository does not exist" do - before do - subject.delete - end - - it "re-creates the object pool's repository" do - subject.fetch - - expect(subject.repository.exists?).to be true - end - - it 'does not raise an error' do - expect { subject.fetch }.not_to raise_error - end - - it 'fetches objects from the source repository' do - new_commit_id = source_repository.create_file( - pool_repository.source_project.owner, - 'a.file', - 'This is a file', - branch_name: source_repository.root_ref, - message: 'Add a file' - ) - - expect(subject.repository.exists?).to be false - - subject.fetch - expect(subject.repository.commit_count('refs/remotes/origin/heads/master')).to eq(commit_count) - expect(subject.repository.commit(new_commit_id).id).to eq(new_commit_id) + context 'with new commit in source repository' do + let(:branch_name) { Gitlab::Git::Ref.extract_branch_name(source_repository.root_ref) } + let(:source_ref_name) { "refs/heads/#{branch_name}" } + let(:pool_ref_name) { "refs/remotes/origin/heads/#{branch_name}" } + + let(:new_commit_id) do + source_repository.create_file( + pool_repository.source_project.owner, + 'a.file', + 'This is a file', + branch_name: branch_name, + message: 'Add a file' + ) + end + + it 'fetches objects from the source repository' do + # Sanity-check that the commit does not yet exist in the pool repository. + expect(subject.repository.commit(new_commit_id)).to be_nil + + subject.fetch + + expect(subject.repository.commit(pool_ref_name).id).to eq(new_commit_id) + expect(subject.repository.commit_count(pool_ref_name)) + .to eq(source_repository.raw_repository.commit_count(source_ref_name)) + end end end end diff --git a/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb b/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb new file mode 100644 index 00000000000..dd54ac0c6ac --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb @@ -0,0 +1,210 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do + let(:user) { create(:user) } + let(:service) do + Class.new do + include Gitlab::GitalyClient::WithFeatureFlagActors + end.new + end + + describe '#user_actor' do + context 'when user is not available in ApplicationContext' do + it 'returns nil' do + expect(service.user_actor).to be(nil) + end + end + + context 'when user is available in ApplicationContext' do + around do |example| + ::Gitlab::ApplicationContext.with_context(user: user) { example.run } + end + + it 'returns corresponding user record' do + expect(service.user_actor.flipper_id).to eql(user.flipper_id) + end + end + + context 'when user does not exist' do + around do |example| + ::Gitlab::ApplicationContext.with_context(user: SecureRandom.uuid) { example.run } + end + + it 'returns corresponding user record' do + expect(service.user_actor).to be(nil) + end + end + end + + describe '#repository, #project_actor, #group_actor' do + context 'when normal project repository' do + let_it_be(:project) { create(:project, group: create(:group)) } + let(:expected_project) { project } + let(:expected_group) { Feature::Gitaly::ActorWrapper.new(::Group, project.group.id) } + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { project.repository } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { project.repository.raw } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { raw_repo_without_container(project.repository) } + end + end + + context 'when project wiki repository' do + let_it_be(:project) { create(:project, :wiki_repo, group: create(:group)) } + let(:expected_project) { nil } + let(:expected_group) { nil } + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { project.wiki.repository } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { project.wiki.repository.raw } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { raw_repo_without_container(project.wiki.repository) } + end + end + + context 'when repository of project in user namespace' do + let_it_be(:project) { create(:project, namespace: create(:user).namespace) } + let(:expected_project) { project } + let(:expected_group) { Feature::Gitaly::ActorWrapper.new(::Group, project.namespace_id) } + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { project.repository } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { project.repository.raw } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { raw_repo_without_container(project.repository) } + end + end + + context 'when personal snippet' do + let(:snippet) { create(:personal_snippet) } + let(:expected_project) { nil } + let(:expected_group) { nil } + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { snippet.repository } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { snippet.repository.raw } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { raw_repo_without_container(snippet.repository) } + end + end + + context 'when project snippet' do + let_it_be(:project) { create(:project, group: create(:group)) } + let(:snippet) { create(:project_snippet, project: project) } + let(:expected_project) { nil } + let(:expected_group) { nil } + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { snippet.repository } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { snippet.repository.raw } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { raw_repo_without_container(snippet.repository) } + end + end + + context 'when project design' do + let_it_be(:project) { create(:project, group: create(:group)) } + let(:issue) { create(:issue, project: project) } + let(:design) { create(:design, issue: issue) } + + let(:expected_project) { project } + let(:expected_group) { project.group } + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { design.repository } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { design.repository.raw } + end + + it_behaves_like 'Gitaly feature flag actors are inferred from repository' do + let(:repository) { raw_repo_without_container(design.repository) } + end + end + end + + describe '#gitaly_client_call' do + let(:call_arg_1) { double } + let(:call_arg_2) { double } + let(:call_arg_3) { double } + let(:call_result) { double } + + before do + allow(Gitlab::GitalyClient).to receive(:call).and_return(call_result) + end + + context 'when actors_aware_gitaly_calls flag is enabled' do + let(:repository_actor) { instance_double(::Repository) } + let(:user_actor) { instance_double(::User) } + let(:project_actor) { instance_double(Project) } + let(:group_actor) { instance_double(Group) } + + before do + stub_feature_flags(actors_aware_gitaly_calls: true) + + allow(service).to receive(:user_actor).and_return(user_actor) + allow(service).to receive(:repository_actor).and_return(repository_actor) + allow(service).to receive(:project_actor).and_return(project_actor) + allow(service).to receive(:group_actor).and_return(group_actor) + allow(Gitlab::GitalyClient).to receive(:with_feature_flag_actors).and_call_original + end + + it 'triggers client call with feature flag actors' do + result = service.gitaly_client_call(call_arg_1, call_arg_2, karg: call_arg_3) + + expect(Gitlab::GitalyClient).to have_received(:call).with(call_arg_1, call_arg_2, karg: call_arg_3) + expect(Gitlab::GitalyClient).to have_received(:with_feature_flag_actors).with( + repository: repository_actor, + user: user_actor, + project: project_actor, + group: group_actor + ) + expect(result).to be(call_result) + end + end + + context 'when actors_aware_gitaly_calls not enabled' do + before do + stub_feature_flags(actors_aware_gitaly_calls: false) + end + + it 'triggers client call without feature flag actors' do + expect(Gitlab::GitalyClient).not_to receive(:with_feature_flag_actors) + + result = service.gitaly_client_call(call_arg_1, call_arg_2, karg: call_arg_3) + + expect(Gitlab::GitalyClient).to have_received(:call).with(call_arg_1, call_arg_2, karg: call_arg_3) + expect(result).to be(call_result) + end + end + end +end diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index a3840ca843f..a3b2fb2d9d0 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -259,6 +259,58 @@ RSpec.describe Gitlab::GitalyClient do end end + shared_examples 'gitaly feature flags in metadata' do + before do + allow(Feature::Gitaly).to receive(:server_feature_flags).and_return( + 'gitaly-feature-a' => 'true', + 'gitaly-feature-b' => 'false' + ) + end + + it 'evaluates Gitaly server feature flags' do + metadata = described_class.request_kwargs('default', timeout: 1)[:metadata] + + expect(Feature::Gitaly).to have_received(:server_feature_flags).with(no_args) + expect(metadata['gitaly-feature-a']).to be('true') + expect(metadata['gitaly-feature-b']).to be('false') + end + + context 'when there are actors' do + let(:repository_actor) { double(:actor) } + let(:project_actor) { double(:actor) } + let(:user_actor) { double(:actor) } + let(:group_actor) { double(:actor) } + + it 'evaluates Gitaly server feature flags with actors' do + metadata = described_class.with_feature_flag_actors( + repository: repository_actor, + project: project_actor, + user: user_actor, + group: group_actor + ) do + described_class.request_kwargs('default', timeout: 1)[:metadata] + end + + expect(Feature::Gitaly).to have_received(:server_feature_flags).with( + repository: repository_actor, + project: project_actor, + user: user_actor, + group: group_actor + ) + expect(metadata['gitaly-feature-a']).to be('true') + expect(metadata['gitaly-feature-b']).to be('false') + end + end + end + + context 'server_feature_flags when RequestStore is activated', :request_store do + it_behaves_like 'gitaly feature flags in metadata' + end + + context 'server_feature_flags when RequestStore is not activated' do + it_behaves_like 'gitaly feature flags in metadata' + end + context 'gitlab_git_env' do let(:policy) { 'gitaly-route-repository-accessor-policy' } @@ -585,4 +637,42 @@ RSpec.describe Gitlab::GitalyClient do end end end + + describe '.with_feature_flag_actor', :request_store do + shared_examples 'with_feature_flag_actor' do + let(:repository_actor) { double(:actor) } + let(:project_actor) { double(:actor) } + let(:user_actor) { double(:actor) } + let(:group_actor) { double(:actor) } + + it 'allows access to feature flag actors inside the block' do + expect(described_class.feature_flag_actors).to eql({}) + + described_class.with_feature_flag_actors( + repository: repository_actor, + project: project_actor, + user: user_actor, + group: group_actor + ) do + expect( + described_class.feature_flag_actors + ).to eql( + repository: repository_actor, + project: project_actor, + user: user_actor, + group: group_actor) + end + + expect(described_class.feature_flag_actors).to eql({}) + end + end + + context 'when RequestStore is activated', :request_store do + it_behaves_like 'with_feature_flag_actor' + end + + context 'when RequestStore is not activated' do + it_behaves_like 'with_feature_flag_actor' + end + end end diff --git a/spec/lib/gitlab/slash_commands/application_help_spec.rb b/spec/lib/gitlab/slash_commands/application_help_spec.rb index b82121bf3a8..b182c0e5cc6 100644 --- a/spec/lib/gitlab/slash_commands/application_help_spec.rb +++ b/spec/lib/gitlab/slash_commands/application_help_spec.rb @@ -4,11 +4,13 @@ require 'spec_helper' RSpec.describe Gitlab::SlashCommands::ApplicationHelp do let(:params) { { command: '/gitlab', text: 'help' } } + let_it_be(:user) { create(:user) } + let_it_be(:chat_user) { create(:chat_name, user: user) } let(:project) { build(:project) } describe '#execute' do subject do - described_class.new(project, params).execute + described_class.new(project, chat_user, params).execute end it 'displays the help section' do @@ -16,5 +18,23 @@ RSpec.describe Gitlab::SlashCommands::ApplicationHelp do expect(subject[:text]).to include('Available commands') expect(subject[:text]).to include('/gitlab [project name or alias] issue show') end + + context 'with incident declare command' do + context 'when feature flag is enabled' do + it 'displays the declare command' do + expect(subject[:text]).to include('/gitlab incident declare') + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(incident_declare_slash_command: false) + end + + it 'does not displays the declare command' do + expect(subject[:text]).not_to include('/gitlab incident declare') + end + end + end end end diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index 069577b3846..f4664bcfef9 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -122,5 +122,25 @@ RSpec.describe Gitlab::SlashCommands::Command do it { is_expected.to eq(Gitlab::SlashCommands::IssueComment) } end + + context 'when incident declare is triggered' do + context 'IncidentNew is triggered' do + let(:params) { { text: 'incident declare' } } + + it { is_expected.to eq(Gitlab::SlashCommands::IncidentManagement::IncidentNew) } + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(incident_declare_slash_command: false) + end + + context 'IncidentNew is triggered' do + let(:params) { { text: 'incident declare' } } + + it { is_expected.not_to eq(Gitlab::SlashCommands::IncidentManagement::IncidentNew) } + end + end + end end end diff --git a/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb b/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb new file mode 100644 index 00000000000..ee54f29aec7 --- /dev/null +++ b/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SlashCommands::IncidentManagement::IncidentNew do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + let_it_be(:chat_name) { create(:chat_name, user: user) } + let_it_be(:regex_match) { described_class.match('declare') } + + subject do + described_class.new(project, chat_name) + end + + describe '#execute' do + context 'when invoked' do + it 'sends ephemeral response' do + response = subject.execute(regex_match) + + expect(response[:response_type]).to be(:ephemeral) + expect(response[:text]).to eq('It works!') + end + end + end + + describe '#allowed?' do + context 'when user has permissions' do + before do + project.add_developer(user) + end + + it 'returns true' do + expect(described_class).to be_allowed(project, user) + end + end + + context 'when feature flag is disabled' do + before do + project.add_developer(user) + stub_feature_flags(incident_declare_slash_command: false) + end + + it 'returns false in allowed?' do + expect(described_class).not_to be_allowed(project, user) + end + end + end + + describe '#collection' do + context 'when collection method id called' do + it 'calls IssuesFinder' do + expect_next_instance_of(IssuesFinder) do |finder| + expect(finder).to receive(:execute) + end + + subject.collection + end + end + end +end diff --git a/spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb b/spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb new file mode 100644 index 00000000000..cbc584b931f --- /dev/null +++ b/spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SlashCommands::Presenters::IncidentManagement::IncidentNew do + subject { described_class.new } + + it 'returns the ephemeral message' do + message = subject.present('It works!') + + expect(message).to be_a(Hash) + expect(message[:text]).to eq('It works!') + expect(message[:response_type]).to be(:ephemeral) + end +end diff --git a/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb b/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb new file mode 100644 index 00000000000..9a17f375f82 --- /dev/null +++ b/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe SyncNewAmountUsedForCiNamespaceMonthlyUsages, migration: :gitlab_ci do + let(:namespace_usages) { table(:ci_namespace_monthly_usages) } + + before do + # Disabling the trigger temporarily to allow records being created with out-of-sync + # `new_amount_used` and `amount_used`. This will simulate existing records before + # we add the trigger. + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_namespace_monthly_usages DISABLE TRIGGER sync_namespaces_amount_used_columns") + + this_month = Time.now.utc.beginning_of_month + last_month = 1.month.ago.utc.beginning_of_month + last_year = 1.year.ago.utc.beginning_of_month + + namespace_usages.create!(namespace_id: 1, date: last_year) + namespace_usages.create!(namespace_id: 1, date: this_month, amount_used: 10, new_amount_used: 0) + namespace_usages.create!(namespace_id: 1, date: last_month, amount_used: 20, new_amount_used: 0) + + namespace_usages.create!(namespace_id: 2, date: last_year) + namespace_usages.create!(namespace_id: 2, date: this_month, amount_used: 30, new_amount_used: 0) + namespace_usages.create!(namespace_id: 2, date: last_month, amount_used: 40, new_amount_used: 0) + + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_namespace_monthly_usages ENABLE TRIGGER sync_namespaces_amount_used_columns") + end + + it 'updates `new_amount_used` with values from `amount_used`' do + expect(namespace_usages.where(new_amount_used: 0).count).to eq(6) + + migrate! + + expect(namespace_usages.where(new_amount_used: 0).count).to eq(2) + expect(namespace_usages.order(:id).pluck(:new_amount_used)) + .to contain_exactly(0, 0, 10, 20, 30, 40) + end +end diff --git a/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb b/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb new file mode 100644 index 00000000000..8d45f1107ea --- /dev/null +++ b/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe SyncNewAmountUsedForCiProjectMonthlyUsages, migration: :gitlab_ci do + let(:project_usages) { table(:ci_project_monthly_usages) } + + before do + # Disabling the trigger temporarily to allow records being created with out-of-sync + # `new_amount_used` and `amount_used`. This will simulate existing records before + # we add the trigger. + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_project_monthly_usages DISABLE TRIGGER sync_projects_amount_used_columns") + + this_month = Time.now.utc.beginning_of_month + last_month = 1.month.ago.utc.beginning_of_month + last_year = 1.year.ago.utc.beginning_of_month + + project_usages.create!(project_id: 1, date: last_year) + project_usages.create!(project_id: 1, date: this_month, amount_used: 10, new_amount_used: 0) + project_usages.create!(project_id: 1, date: last_month, amount_used: 20, new_amount_used: 0) + + project_usages.create!(project_id: 2, date: last_year) + project_usages.create!(project_id: 2, date: this_month, amount_used: 30, new_amount_used: 0) + project_usages.create!(project_id: 2, date: last_month, amount_used: 40, new_amount_used: 0) + + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_project_monthly_usages ENABLE TRIGGER sync_projects_amount_used_columns") + end + + it 'updates `new_amount_used` with values from `amount_used`' do + expect(project_usages.where(new_amount_used: 0).count).to eq(6) + + migrate! + + expect(project_usages.where(new_amount_used: 0).count).to eq(2) + expect(project_usages.order(:id).pluck(:new_amount_used)) + .to contain_exactly(0, 0, 10, 20, 30, 40) + end +end diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb index 05ab8c4108e..427a99efadd 100644 --- a/spec/models/clusters/applications/cert_manager_spec.rb +++ b/spec/models/clusters/applications/cert_manager_spec.rb @@ -10,6 +10,11 @@ RSpec.describe Clusters::Applications::CertManager do include_examples 'cluster application version specs', :clusters_applications_cert_manager include_examples 'cluster application initial status specs' + describe 'default values' do + it { expect(cert_manager.version).to eq(described_class::VERSION) } + it { expect(cert_manager.email).to eq("admin@example.com") } + end + describe '#can_uninstall?' do subject { cert_manager.can_uninstall? } diff --git a/spec/models/clusters/applications/crossplane_spec.rb b/spec/models/clusters/applications/crossplane_spec.rb index 7082576028b..d1abaa52c7f 100644 --- a/spec/models/clusters/applications/crossplane_spec.rb +++ b/spec/models/clusters/applications/crossplane_spec.rb @@ -14,6 +14,11 @@ RSpec.describe Clusters::Applications::Crossplane do it { is_expected.to validate_presence_of(:stack) } end + describe 'default values' do + it { expect(subject.version).to eq(described_class::VERSION) } + it { expect(subject.stack).to be_empty } + end + describe '#can_uninstall?' do subject { crossplane.can_uninstall? } diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb index 5212e321a55..1b8be92475a 100644 --- a/spec/models/clusters/applications/helm_spec.rb +++ b/spec/models/clusters/applications/helm_spec.rb @@ -5,6 +5,10 @@ require 'spec_helper' RSpec.describe Clusters::Applications::Helm do include_examples 'cluster application core specs', :clusters_applications_helm + describe 'default values' do + it { expect(subject.version).to eq(Gitlab::Kubernetes::Helm::V2::BaseCommand::HELM_VERSION) } + end + describe '.available' do subject { described_class.available } diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index e16d97c42d9..e5caa11452e 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -18,6 +18,11 @@ RSpec.describe Clusters::Applications::Ingress do allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) end + describe 'default values' do + it { expect(subject.ingress_type).to eq("nginx") } + it { expect(subject.version).to eq(described_class::VERSION) } + end + describe '#can_uninstall?' do subject { ingress.can_uninstall? } diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb index e7de2d24334..9336d2352f8 100644 --- a/spec/models/clusters/applications/jupyter_spec.rb +++ b/spec/models/clusters/applications/jupyter_spec.rb @@ -10,6 +10,10 @@ RSpec.describe Clusters::Applications::Jupyter do it { is_expected.to belong_to(:oauth_application) } + describe 'default values' do + it { expect(subject.version).to eq(described_class::VERSION) } + end + describe '#can_uninstall?' do let(:ingress) { create(:clusters_applications_ingress, :installed, external_hostname: 'localhost.localdomain') } let(:jupyter) { create(:clusters_applications_jupyter, cluster: ingress.cluster) } diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb index d0e470bfa42..3914450339a 100644 --- a/spec/models/clusters/applications/knative_spec.rb +++ b/spec/models/clusters/applications/knative_spec.rb @@ -21,6 +21,10 @@ RSpec.describe Clusters::Applications::Knative do it { is_expected.to have_one(:serverless_domain_cluster).class_name('::Serverless::DomainCluster').with_foreign_key('clusters_applications_knative_id').inverse_of(:knative) } end + describe 'default values' do + it { expect(subject.version).to eq(described_class::VERSION) } + end + describe 'when cloud run is enabled' do let(:cluster) { create(:cluster, :provided_by_gcp, :cloud_run_enabled) } let(:knative_cloud_run) { create(:clusters_applications_knative, cluster: cluster) } diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index b60c5ec114d..15c3162270e 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -12,6 +12,13 @@ RSpec.describe Clusters::Applications::Prometheus do include_examples 'cluster application helm specs', :clusters_applications_prometheus include_examples 'cluster application initial status specs' + describe 'default values' do + subject(:prometheus) { build(:clusters_applications_prometheus) } + + it { expect(prometheus.alert_manager_token).to be_an_instance_of(String) } + it { expect(prometheus.version).to eq(described_class::VERSION) } + end + describe 'after_destroy' do let(:cluster) { create(:cluster, :with_installed_helm) } let(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index 8f02161843b..04b5ae9641d 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -13,6 +13,10 @@ RSpec.describe Clusters::Applications::Runner do it { is_expected.to belong_to(:runner) } + describe 'default values' do + it { expect(subject.version).to eq(described_class::VERSION) } + end + describe '#can_uninstall?' do let(:gitlab_runner) { create(:clusters_applications_runner, runner: ci_runner) } diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 73cd7bb9075..be64d72e031 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -49,6 +49,10 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do it { is_expected.to respond_to :project } it { is_expected.to be_namespace_per_environment } + describe 'default values' do + it { expect(subject.helm_major_version).to eq(3) } + end + it_behaves_like 'it has loose foreign keys' do let(:factory_name) { :cluster } end diff --git a/spec/models/clusters/integrations/prometheus_spec.rb b/spec/models/clusters/integrations/prometheus_spec.rb index 90e99aefdce..d6d1105cdb1 100644 --- a/spec/models/clusters/integrations/prometheus_spec.rb +++ b/spec/models/clusters/integrations/prometheus_spec.rb @@ -15,6 +15,16 @@ RSpec.describe Clusters::Integrations::Prometheus do it { is_expected.not_to allow_value(nil).for(:enabled) } end + describe 'default values' do + subject(:integration) { build(:clusters_integrations_prometheus) } + + before do + allow(SecureRandom).to receive(:hex).and_return('randomtoken') + end + + it { expect(integration.alert_manager_token).to eq('randomtoken') } + end + describe 'after_destroy' do subject(:integration) { create(:clusters_integrations_prometheus, cluster: cluster, enabled: true) } diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index 35ed6f4e2c6..99dbb654b7f 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -21,6 +21,12 @@ RSpec.describe Clusters::Platforms::Kubernetes do it_behaves_like 'having unique enum values' + describe 'default values' do + let(:kubernetes) { create(:cluster_platform_kubernetes) } + + it { expect(kubernetes.authorization_type).to eq("rbac") } + end + describe 'before_validation' do let(:kubernetes) { create(:cluster_platform_kubernetes, :configured, namespace: namespace) } diff --git a/spec/models/clusters/providers/aws_spec.rb b/spec/models/clusters/providers/aws_spec.rb index 3b4a48cc5be..2afed663edf 100644 --- a/spec/models/clusters/providers/aws_spec.rb +++ b/spec/models/clusters/providers/aws_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Clusters::Providers::Aws do include_examples 'provider status', :cluster_provider_aws - describe 'default_value_for' do + describe 'default values' do let(:provider) { build(:cluster_provider_aws) } it "sets default values" do diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb index ad9ada04875..a1f00069937 100644 --- a/spec/models/clusters/providers/gcp_spec.rb +++ b/spec/models/clusters/providers/gcp_spec.rb @@ -8,13 +8,14 @@ RSpec.describe Clusters::Providers::Gcp do include_examples 'provider status', :cluster_provider_gcp - describe 'default_value_for' do + describe 'default values' do let(:gcp) { build(:cluster_provider_gcp) } it "has default value" do expect(gcp.zone).to eq('us-central1-a') expect(gcp.num_nodes).to eq(3) expect(gcp.machine_type).to eq('n1-standard-2') + expect(gcp.cloud_run).to eq(false) end end diff --git a/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb b/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb index 2e00abe2f8e..6cdd7954b5f 100644 --- a/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb +++ b/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb @@ -129,6 +129,7 @@ RSpec.shared_examples_for 'collection cache helper' do before do allow(::Gitlab::Metrics::WebTransaction).to receive(:current).and_return(transaction) allow(transaction).to receive(:increment) + allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(any_args).and_call_original allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return(caller_id) end diff --git a/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb new file mode 100644 index 00000000000..f26b9a4a7bd --- /dev/null +++ b/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +def raw_repo_without_container(repository) + Gitlab::Git::Repository.new(repository.shard, + "#{repository.disk_path}.git", + repository.repo_type.identifier_for_container(repository.container), + repository.container.full_path) +end + +RSpec.shared_examples 'Gitaly feature flag actors are inferred from repository' do + it 'captures correct actors' do + service.repository_actor = repository + + expect(service.repository_actor.flipper_id).to eql(repository.flipper_id) + + if expected_project.nil? + expect(service.project_actor).to be(nil) + else + expect(service.project_actor.flipper_id).to eql(expected_project.flipper_id) + end + + if expected_group.nil? + expect(service.group_actor).to be(nil) + else + expect(service.group_actor.flipper_id).to eql(expected_group.flipper_id) + end + end + + it 'does not issues SQL queries after the first invocation' do + service.repository_actor = repository + + service.repository_actor + service.project_actor + service.group_actor + + recorder = ActiveRecord::QueryRecorder.new do + 3.times do + service.repository_actor + service.project_actor + service.group_actor + end + end + + expect(recorder.count).to be(0) + end +end diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb index a0cf3b1e978..b8db262598b 100644 --- a/spec/workers/repository_check/single_repository_worker_spec.rb +++ b/spec/workers/repository_check/single_repository_worker_spec.rb @@ -16,7 +16,7 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do repository = instance_double(::Gitlab::Git::Repository) allow(::Gitlab::Git::Repository).to receive(:new) - .with(project.repository_storage, "#{project.disk_path}.git", anything, anything) + .with(project.repository_storage, "#{project.disk_path}.git", anything, anything, container: project) .and_return(repository) worker.perform(project.id) @@ -31,7 +31,7 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do repository = project.repository.raw expect(repository).to receive(:fsck).and_raise(::Gitlab::Git::Repository::GitError) expect(::Gitlab::Git::Repository).to receive(:new) - .with(project.repository_storage, "#{project.disk_path}.git", anything, anything) + .with(project.repository_storage, "#{project.disk_path}.git", anything, anything, container: project) .and_return(repository) worker.perform(project.id) @@ -46,7 +46,7 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do repository = project.repository.raw expect(repository).to receive(:fsck).and_call_original expect(::Gitlab::Git::Repository).to receive(:new) - .with(project.repository_storage, "#{project.disk_path}.git", anything, anything) + .with(project.repository_storage, "#{project.disk_path}.git", anything, anything, container: project) .and_return(repository) expect do @@ -68,7 +68,7 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do repository = project.wiki.repository.raw expect(repository).to receive(:fsck).and_raise(::Gitlab::Git::Repository::GitError) expect(::Gitlab::Git::Repository).to receive(:new) - .with(project.repository_storage, "#{project.disk_path}.wiki.git", anything, anything) + .with(project.repository_storage, "#{project.disk_path}.wiki.git", anything, anything, container: project.wiki) .and_return(repository) worker.perform(project.id) @@ -81,7 +81,7 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do # Make sure the test would fail if the wiki repo was checked repository = instance_double(::Gitlab::Git::Repository) allow(::Gitlab::Git::Repository).to receive(:new) - .with(project.repository_storage, "#{project.disk_path}.wiki.git", anything, anything) + .with(project.repository_storage, "#{project.disk_path}.wiki.git", anything, anything, container: project) .and_return(repository) subject.perform(project.id) |