diff options
Diffstat (limited to 'spec')
14 files changed, 291 insertions, 31 deletions
diff --git a/spec/features/projects/infrastructure_registry_spec.rb b/spec/features/projects/infrastructure_registry_spec.rb index a648a4fc1ce..10ac61973fb 100644 --- a/spec/features/projects/infrastructure_registry_spec.rb +++ b/spec/features/projects/infrastructure_registry_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Infrastructure Registry', feature_category: :groups_and_projects do +RSpec.describe 'Infrastructure Registry', feature_category: :package_registry do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/features/projects/packages_spec.rb b/spec/features/projects/packages_spec.rb index 5073c147b6c..4e222a67b87 100644 --- a/spec/features/projects/packages_spec.rb +++ b/spec/features/projects/packages_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Packages', feature_category: :groups_and_projects do +RSpec.describe 'Packages', feature_category: :package_registry do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/features/projects/terraform_spec.rb b/spec/features/projects/terraform_spec.rb index 518fa79f003..aefc7be7ced 100644 --- a/spec/features/projects/terraform_spec.rb +++ b/spec/features/projects/terraform_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Terraform', :js, feature_category: :groups_and_projects do +RSpec.describe 'Terraform', :js, feature_category: :package_registry do let_it_be(:project) { create(:project) } let_it_be(:terraform_state) { create(:terraform_state, :locked, :with_version, project: project) } diff --git a/spec/frontend/invite_members/components/members_token_select_spec.js b/spec/frontend/invite_members/components/members_token_select_spec.js index a4b8a8b0197..1cda9853ccd 100644 --- a/spec/frontend/invite_members/components/members_token_select_spec.js +++ b/spec/frontend/invite_members/components/members_token_select_spec.js @@ -12,6 +12,7 @@ const placeholder = 'Search for a member'; const user1 = { id: 1, name: 'John Smith', username: 'one_1', avatar_url: '' }; const user2 = { id: 2, name: 'Jane Doe', username: 'two_2', avatar_url: '' }; const allUsers = [user1, user2]; +const handleEnterSpy = jest.fn(); const createComponent = (props) => { return shallowMount(MembersTokenSelect, { @@ -22,7 +23,11 @@ const createComponent = (props) => { ...props, }, stubs: { - GlTokenSelector: stubComponent(GlTokenSelector), + GlTokenSelector: stubComponent(GlTokenSelector, { + methods: { + handleEnter: handleEnterSpy, + }, + }), }, }); }; @@ -173,6 +178,14 @@ describe('MembersTokenSelect', () => { }); }); }); + + it('allows tab to function as enter', () => { + tokenSelector.vm.$emit('text-input', 'username'); + + tokenSelector.vm.$emit('keydown', new KeyboardEvent('keydown', { key: 'Tab' })); + + expect(handleEnterSpy).toHaveBeenCalled(); + }); }); describe('when user is selected', () => { diff --git a/spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb b/spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb new file mode 100644 index 00000000000..c16356bfda7 --- /dev/null +++ b/spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Diffblue-Cover.gitlab-ci.yml', feature_category: :continuous_integration do + subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Diffblue-Cover') } + + describe 'the created pipeline' do + let(:pipeline_branch) { 'patch-1' } + let_it_be(:project) { create(:project, :repository, create_branch: 'patch-1') } + let(:user) { project.first_owner } + + let(:mr_service) { MergeRequests::CreatePipelineService.new(project: project, current_user: user) } + let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: pipeline_branch) } + let(:mr_pipeline) { mr_service.execute(merge_request).payload } + let(:mr_build_names) { mr_pipeline.builds.pluck(:name) } + + before do + stub_ci_pipeline_yaml_file(template.content) + end + + it 'creates diffblue-cover jobs' do + expect(mr_build_names).to include('diffblue-cover') + end + end +end diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb index 36c6e805bdf..98f0d32960b 100644 --- a/spec/lib/gitlab/ci/templates/templates_spec.rb +++ b/spec/lib/gitlab/ci/templates/templates_spec.rb @@ -20,6 +20,7 @@ RSpec.describe 'CI YML Templates' do context 'that support autodevops' do exceptions = [ + 'Diffblue-Cover.gitlab-ci.yml', # no auto-devops 'Security/DAST.gitlab-ci.yml', # DAST stage is defined inside AutoDevops yml 'Security/DAST-API.gitlab-ci.yml', # no auto-devops 'Security/API-Fuzzing.gitlab-ci.yml', # no auto-devops diff --git a/spec/lib/gitlab/database/migration_spec.rb b/spec/lib/gitlab/database/migration_spec.rb index 18bbc6c1dd3..8390a5ff19e 100644 --- a/spec/lib/gitlab/database/migration_spec.rb +++ b/spec/lib/gitlab/database/migration_spec.rb @@ -34,6 +34,12 @@ RSpec.describe Gitlab::Database::Migration do # untouched. expect(described_class[described_class.current_version]).to be < ActiveRecord::Migration::Current end + + it 'matches the version used by Rubocop' do + require 'rubocop' + load 'rubocop/cop/migration/versioned_migration_class.rb' + expect(described_class.current_version).to eq(RuboCop::Cop::Migration::VersionedMigrationClass::CURRENT_MIGRATION_VERSION) + end end describe Gitlab::Database::Migration::LockRetriesConcern do diff --git a/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb b/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb index 4bd4455d1bd..f4f38a861ee 100644 --- a/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb +++ b/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb @@ -7,10 +7,11 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category: let_it_be_with_reload(:group) { create(:group) } let_it_be(:seed_count) { 2 } let_it_be(:last_resource_id) { seed_count - 1 } + let(:publish) { true } let(:group_path) { group.path } - subject(:seeder) { described_class.new(group_path: group_path, seed_count: seed_count) } + subject(:seeder) { described_class.new(group_path: group_path, seed_count: seed_count, publish: publish) } before_all do group.add_owner(admin) @@ -28,12 +29,26 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category: end context 'when project name already exists' do - before do - create(:project, namespace: group, name: "ci_seed_resource_0") + context 'in the same group' do + before do + create(:project, namespace: group, name: 'ci_seed_resource_0') + end + + it 'skips that project creation and keeps seeding' do + expect { seed }.to change { Project.count }.by(seed_count - 1) + end end - it 'skips that project creation and keeps seeding' do - expect { seed }.to change { Project.count }.by(seed_count - 1) + context 'in a different group' do + let(:new_group) { create(:group) } + + before do + create(:project, namespace: new_group, name: 'ci_seed_resource_0') + end + + it 'executes the project creation' do + expect { seed }.to change { Project.count }.by(seed_count) + end end end @@ -65,6 +80,26 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category: end end + describe 'publish argument' do + context 'when false' do + let(:publish) { false } + + it 'creates catalog resources in draft state' do + group.projects.each do |project| + expect(project.catalog_resource.state).to be('draft') + end + end + end + + context 'when true' do + it 'creates catalog resources in published state' do + group.projects.each do |project| + expect(project.catalog_resource&.state).to be('published') + end + end + end + end + it 'skips seeding a project if the project name already exists' do # We call the same command twice, as it means it would try to recreate # projects that were already created! @@ -87,12 +122,11 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category: project = group.projects.last default_branch = project.default_branch_or_main - expect(project.repository.blob_at(default_branch, "README.md")).not_to be_nil - expect(project.repository.blob_at(default_branch, "template.yml")).not_to be_nil + expect(project.repository.blob_at(default_branch, 'README.md')).not_to be_nil + expect(project.repository.blob_at(default_branch, 'templates/component.yml')).not_to be_nil end - # This should be run again when fixing: https://gitlab.com/gitlab-org/gitlab/-/issues/429649 - xit 'creates projects with CI catalog resources' do + it 'creates projects with CI catalog resources' do expect { seed }.to change { Project.count }.by(seed_count) expect(group.projects.all?(&:catalog_resource)).to eq true diff --git a/spec/models/ci/catalog/listing_spec.rb b/spec/models/ci/catalog/listing_spec.rb index 2d20acd4091..9d20d944e5a 100644 --- a/spec/models/ci/catalog/listing_spec.rb +++ b/spec/models/ci/catalog/listing_spec.rb @@ -185,11 +185,11 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do end describe '#find_resource' do + let_it_be(:accessible_resource) { create(:ci_catalog_resource, :published, project: public_project) } + subject { list.find_resource(id: id) } context 'when the resource is published and visible to the user' do - let_it_be(:accessible_resource) { create(:ci_catalog_resource, :published, project: public_project) } - let(:id) { accessible_resource.id } it 'fetches the resource' do @@ -200,9 +200,7 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do context 'when the resource is not found' do let(:id) { 'not-an-id' } - it 'returns nil' do - is_expected.to be_nil - end + it { is_expected.to be_nil } end context 'when the resource is not published' do @@ -210,9 +208,7 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do let(:id) { draft_resource.id } - it 'returns nil' do - is_expected.to be_nil - end + it { is_expected.to be_nil } end context "when the current user cannot read code on the resource's project" do @@ -220,8 +216,25 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do let(:id) { inaccessible_resource.id } - it 'returns nil' do - is_expected.to be_nil + it { is_expected.to be_nil } + end + + context 'when the current user is anonymous' do + let(:user) { nil } + + context 'when the resource is public' do + let(:id) { accessible_resource.id } + + it 'fetches the public resource' do + is_expected.to eq(accessible_resource) + end + end + + context 'when the resource is internal' do + let(:internal_resource) { create(:ci_catalog_resource, :published, project: internal_project) } + let(:id) { internal_resource.id } + + it { is_expected.to be_nil } end end end diff --git a/spec/policies/organizations/organization_policy_spec.rb b/spec/policies/organizations/organization_policy_spec.rb index 3fcfa63b1b2..7eed497d644 100644 --- a/spec/policies/organizations/organization_policy_spec.rb +++ b/spec/policies/organizations/organization_policy_spec.rb @@ -12,6 +12,7 @@ RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do let_it_be(:current_user) { nil } it { is_expected.to be_allowed(:read_organization) } + it { is_expected.to be_disallowed(:admin_organization) } end context 'when the user is an admin' do @@ -34,11 +35,13 @@ RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do create :organization_user, organization: organization, user: current_user end - it { is_expected.to be_allowed(:read_organization_user) } + it { is_expected.to be_allowed(:admin_organization) } it { is_expected.to be_allowed(:read_organization) } + it { is_expected.to be_allowed(:read_organization_user) } end context 'when the user is not part of the organization' do + it { is_expected.to be_disallowed(:admin_organization) } it { is_expected.to be_disallowed(:read_organization_user) } # All organizations are currently public, and hence they are allowed to be read # even if the user is not a part of the organization. diff --git a/spec/requests/api/graphql/mutations/organizations/update_spec.rb b/spec/requests/api/graphql/mutations/organizations/update_spec.rb new file mode 100644 index 00000000000..573a7227e3c --- /dev/null +++ b/spec/requests/api/graphql/mutations/organizations/update_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Organizations::Update, feature_category: :cell do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + let_it_be_with_reload(:organization) do + create(:organization) { |org| create(:organization_user, organization: org, user: user) } + end + + let(:mutation) { graphql_mutation(:organization_update, params) } + let(:name) { 'Name' } + let(:path) { 'path' } + let(:description) { 'org-description' } + let(:params) do + { + id: organization.to_global_id.to_s, + name: name, + path: path, + description: description + } + end + + subject(:update_organization) { post_graphql_mutation(mutation, current_user: current_user) } + + it { expect(described_class).to require_graphql_authorizations(:admin_organization) } + + def mutation_response + graphql_mutation_response(:organization_update) + end + + context 'when the user does not have permission' do + let(:current_user) { nil } + + it_behaves_like 'a mutation that returns a top-level access error' + + it 'does not update the organization' do + initial_name = organization.name + initial_path = organization.path + + update_organization + organization.reset + + expect(organization.name).to eq(initial_name) + expect(organization.path).to eq(initial_path) + end + end + + context 'when the user has permission' do + let(:current_user) { user } + + context 'when the params are invalid' do + let(:name) { '' } + + it 'returns the validation error' do + update_organization + + expect(mutation_response).to include('errors' => ["Name can't be blank"]) + end + end + + context 'when single attribute is update' do + using RSpec::Parameterized::TableSyntax + + where(attribute: %w[name path description]) + + with_them do + let(:value) { "new-#{attribute}" } + let(:attribute_hash) { { attribute => value } } + let(:params) { { id: organization.to_global_id.to_s }.merge(attribute_hash) } + + it 'updates the given field' do + update_organization + + expect(graphql_data_at(:organization_update, :organization)).to match a_hash_including(attribute_hash) + expect(mutation_response['errors']).to be_empty + end + end + end + + it 'returns the updated organization' do + update_organization + + expect(graphql_data_at(:organization_update, :organization)).to match a_hash_including( + 'name' => name, + 'path' => path, + 'description' => description + ) + expect(mutation_response['errors']).to be_empty + end + end +end diff --git a/spec/requests/organizations/settings_controller_spec.rb b/spec/requests/organizations/settings_controller_spec.rb index 77048b04b0c..1d98e598159 100644 --- a/spec/requests/organizations/settings_controller_spec.rb +++ b/spec/requests/organizations/settings_controller_spec.rb @@ -46,7 +46,7 @@ RSpec.describe Organizations::SettingsController, feature_category: :cell do create :organization_user, organization: organization, user: user end - it_behaves_like 'organization - not found response' + it_behaves_like 'organization - successful response' it_behaves_like 'organization - action disabled by `ui_for_organizations` feature flag' end end diff --git a/spec/rubocop/cop/migration/versioned_migration_class_spec.rb b/spec/rubocop/cop/migration/versioned_migration_class_spec.rb index b92d9d21498..89657fbfa91 100644 --- a/spec/rubocop/cop/migration/versioned_migration_class_spec.rb +++ b/spec/rubocop/cop/migration/versioned_migration_class_spec.rb @@ -49,7 +49,7 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor it 'adds an offence if inheriting from ActiveRecord::Migration' do expect_offense(<<~RUBY) class MyMigration < ActiveRecord::Migration[6.1] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning. end RUBY end @@ -57,23 +57,23 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor it 'adds an offence if inheriting from old version of Gitlab::Database::Migration' do expect_offense(<<~RUBY) class MyMigration < Gitlab::Database::Migration[2.0] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning. end RUBY end it 'adds an offence if including Gitlab::Database::MigrationHelpers directly' do expect_offense(<<~RUBY) - class MyMigration < Gitlab::Database::Migration[2.1] + class MyMigration < Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] include Gitlab::Database::MigrationHelpers - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning. end RUBY end it 'excludes ActiveRecord classes defined inside the migration' do expect_no_offenses(<<~RUBY) - class TestMigration < Gitlab::Database::Migration[2.1] + class TestMigration < Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] class TestModel < ApplicationRecord end @@ -85,7 +85,7 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor it 'excludes parentless classes defined inside the migration' do expect_no_offenses(<<~RUBY) - class TestMigration < Gitlab::Database::Migration[2.1] + class TestMigration < Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] class TestClass end end diff --git a/spec/services/organizations/update_service_spec.rb b/spec/services/organizations/update_service_spec.rb new file mode 100644 index 00000000000..976df1129d5 --- /dev/null +++ b/spec/services/organizations/update_service_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Organizations::UpdateService, feature_category: :cell do + describe '#execute' do + let_it_be(:user) { create(:user) } + let_it_be_with_reload(:organization) { create(:organization) } + + let(:current_user) { user } + let(:name) { 'Name' } + let(:path) { 'path' } + let(:description) { nil } + let(:params) { { name: name, path: path } } + + subject(:response) do + described_class.new(organization, current_user: current_user, params: params).execute + end + + context 'when user does not have permission' do + let(:current_user) { nil } + + it 'returns an error' do + expect(response).to be_error + + expect(response.message).to match_array(['You have insufficient permissions to update the organization']) + end + end + + context 'when user has permission' do + before do + create(:organization_user, organization: organization, user: current_user) + end + + shared_examples 'updating an organization' do + it 'updates the organization' do + response + organization.reset + + expect(response).to be_success + expect(organization.name).to eq(name) + expect(organization.path).to eq(path) + expect(organization.description).to eq(description) + end + end + + context 'with description' do + let(:description) { 'Organization description' } + let(:params) do + { + name: name, + path: path, + description: description + } + end + + it_behaves_like 'updating an organization' + end + + include_examples 'updating an organization' + + it 'returns an error when the organization is not updated' do + params[:name] = nil + + expect(response).to be_error + expect(response.message).to match_array(["Name can't be blank"]) + end + end + end +end |