summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-03 21:09:39 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-03 21:09:39 +0000
commit4bf395cded929b1f2d2419079d8107604c9f930f (patch)
treed6edb3ab04e1a8241f9ac44ebb789cfc6ebaeff9 /spec
parent49058851264455c22a5ba00c8671b7d4cdfd8ee9 (diff)
downloadgitlab-ce-4bf395cded929b1f2d2419079d8107604c9f930f.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/invites_controller_spec.rb84
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb49
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb12
-rw-r--r--spec/features/dashboard/todos/target_state_spec.rb20
-rw-r--r--spec/features/dashboard/todos/todos_filtering_spec.rb2
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb38
-rw-r--r--spec/features/invites_spec.rb39
-rw-r--r--spec/features/markdown/mermaid_spec.rb23
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb5
-rw-r--r--spec/frontend/members/store/mutations_spec.js6
-rw-r--r--spec/graphql/features/authorization_spec.rb6
-rw-r--r--spec/graphql/mutations/base_mutation_spec.rb4
-rw-r--r--spec/graphql/mutations/todos/mark_done_spec.rb10
-rw-r--r--spec/graphql/mutations/todos/restore_spec.rb10
-rw-r--r--spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb24
-rw-r--r--spec/graphql/resolvers/todo_resolver_spec.rb39
-rw-r--r--spec/graphql/subscriptions/issuable_updated_spec.rb2
-rw-r--r--spec/lib/gitlab/auth_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/build_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb24
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb19
-rw-r--r--spec/lib/gitlab/graphql/calls_gitaly/field_extension_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/copy_field_description_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/mount_mutation_spec.rb4
-rw-r--r--spec/lib/gitlab/graphql/negatable_arguments_spec.rb6
-rw-r--r--spec/lib/gitlab/graphql/pagination/connections_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/present/field_extension_spec.rb16
-rw-r--r--spec/lib/gitlab/graphql/queries_spec.rb24
-rw-r--r--spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb12
-rw-r--r--spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb12
-rw-r--r--spec/lib/sidebars/projects/menus/analytics_menu_spec.rb16
-rw-r--r--spec/models/diff_note_spec.rb6
-rw-r--r--spec/models/discussion_note_spec.rb11
-rw-r--r--spec/models/legacy_diff_note_spec.rb11
-rw-r--r--spec/models/project_spec.rb19
-rw-r--r--spec/models/synthetic_note_spec.rb11
-rw-r--r--spec/policies/issue_policy_spec.rb85
-rw-r--r--spec/policies/personal_access_token_policy_spec.rb7
-rw-r--r--spec/policies/project_policy_spec.rb57
-rw-r--r--spec/policies/todo_policy_spec.rb24
-rw-r--r--spec/requests/admin/impersonation_tokens_controller_spec.rb38
-rw-r--r--spec/requests/api/graphql/current_user/todos_query_spec.rb45
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_done_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_many_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_spec.rb10
-rw-r--r--spec/requests/api/personal_access_tokens_spec.rb12
-rw-r--r--spec/requests/api/projects_spec.rb33
-rw-r--r--spec/requests/api/todos_spec.rb71
-rw-r--r--spec/requests/git_http_spec.rb26
-rw-r--r--spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb2
-rw-r--r--spec/rubocop/cop/graphql/descriptions_spec.rb20
-rw-r--r--spec/rubocop/cop/graphql/id_type_spec.rb2
-rw-r--r--spec/rubocop/cop/graphql/json_type_spec.rb4
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb67
-rw-r--r--spec/services/git/process_ref_changes_service_spec.rb10
-rw-r--r--spec/services/issues/create_service_spec.rb21
-rw-r--r--spec/services/issues/update_service_spec.rb25
-rw-r--r--spec/services/todos/allowed_target_filter_service_spec.rb59
-rw-r--r--spec/support/helpers/graphql_helpers.rb2
-rw-r--r--spec/tooling/graphql/docs/renderer_spec.rb44
61 files changed, 995 insertions, 292 deletions
diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb
index 345e8e47d1d..c5e693e3489 100644
--- a/spec/controllers/invites_controller_spec.rb
+++ b/spec/controllers/invites_controller_spec.rb
@@ -25,9 +25,64 @@ RSpec.describe InvitesController do
end
end
+ shared_examples 'invite email match enforcement' do |error_status:, flash_alert: nil|
+ it 'accepts user if invite email matches signed in user' do
+ expect do
+ request
+ end.to change { project_members.include?(user) }.from(false).to(true)
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:notice]).to include 'You have been granted'
+ end
+
+ it 'accepts invite if invite email matches confirmed secondary email' do
+ secondary_email = create(:email, :confirmed, user: user)
+ member.update!(invite_email: secondary_email.email)
+
+ expect do
+ request
+ end.to change { project_members.include?(user) }.from(false).to(true)
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:notice]).to include 'You have been granted'
+ end
+
+ it 'does not accept if invite email matches unconfirmed secondary email' do
+ secondary_email = create(:email, user: user)
+ member.update!(invite_email: secondary_email.email)
+
+ expect do
+ request
+ end.not_to change { project_members.include?(user) }
+
+ expect(response).to have_gitlab_http_status(error_status)
+ expect(flash[:alert]).to eq(flash_alert)
+ end
+
+ it 'does not accept if invite email does not match signed in user' do
+ member.update!(invite_email: 'bogus@email.com')
+
+ expect do
+ request
+ end.not_to change { project_members.include?(user) }
+
+ expect(response).to have_gitlab_http_status(error_status)
+ expect(flash[:alert]).to eq(flash_alert)
+ end
+ end
+
describe 'GET #show', :snowplow do
subject(:request) { get :show, params: params }
+ context 'when logged in' do
+ before do
+ sign_in(user)
+ end
+
+ it_behaves_like 'invite email match enforcement', error_status: :ok
+ it_behaves_like 'invalid token'
+ end
+
context 'when it is an initial invite email' do
let(:extra_params) { { invite_type: 'initial_email' } }
@@ -69,34 +124,6 @@ RSpec.describe InvitesController do
end
end
- context 'when logged in' do
- before do
- sign_in(user)
- end
-
- it 'accepts user if invite email matches signed in user' do
- expect do
- request
- end.to change { project_members.include?(user) }.from(false).to(true)
-
- expect(response).to have_gitlab_http_status(:found)
- expect(flash[:notice]).to include 'You have been granted'
- end
-
- it 'forces re-confirmation if email does not match signed in user' do
- member.update!(invite_email: 'bogus@email.com')
-
- expect do
- request
- end.not_to change { project_members.include?(user) }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(flash[:notice]).to be_nil
- end
-
- it_behaves_like 'invalid token'
- end
-
context 'when not logged in' do
context 'when invite token belongs to a valid member' do
context 'when instance allows sign up' do
@@ -223,6 +250,7 @@ RSpec.describe InvitesController do
subject(:request) { post :accept, params: params }
+ it_behaves_like 'invite email match enforcement', error_status: :redirect, flash_alert: 'The invitation could not be accepted.'
it_behaves_like 'invalid token'
end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 2379ff9fd98..65a563fac7c 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -302,35 +302,46 @@ RSpec.describe Projects::PipelinesController do
end
describe 'GET #show' do
- render_views
-
- let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
-
- subject { get_pipeline_html }
-
def get_pipeline_html
get :show, params: { namespace_id: project.namespace, project_id: project, id: pipeline }, format: :html
end
- def create_build_with_artifacts(stage, stage_idx, name)
- create(:ci_build, :artifacts, :tags, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name)
- end
+ context 'when the project is public' do
+ render_views
- before do
- create_build_with_artifacts('build', 0, 'job1')
- create_build_with_artifacts('build', 0, 'job2')
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ def create_build_with_artifacts(stage, stage_idx, name)
+ create(:ci_build, :artifacts, :tags, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name)
+ end
+
+ before do
+ create_build_with_artifacts('build', 0, 'job1')
+ create_build_with_artifacts('build', 0, 'job2')
+ end
+
+ it 'avoids N+1 database queries', :request_store do
+ control_count = ActiveRecord::QueryRecorder.new { get_pipeline_html }.count
+ expect(response).to have_gitlab_http_status(:ok)
+
+ create_build_with_artifacts('build', 0, 'job3')
+
+ expect { get_pipeline_html }.not_to exceed_query_limit(control_count)
+ expect(response).to have_gitlab_http_status(:ok)
+ end
end
- it 'avoids N+1 database queries', :request_store do
- get_pipeline_html
+ context 'when the project is private' do
+ let(:project) { create(:project, :private, :repository) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
- control_count = ActiveRecord::QueryRecorder.new { get_pipeline_html }.count
- expect(response).to have_gitlab_http_status(:ok)
+ it 'returns `not_found` when the user does not have access' do
+ sign_in(create(:user))
- create_build_with_artifacts('build', 0, 'job3')
+ get_pipeline_html
- expect { get_pipeline_html }.not_to exceed_query_limit(control_count)
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index ee64e71f176..7466150addf 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -83,4 +83,16 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
expect(no_personal_access_tokens_message).to have_text("This user has no active impersonation tokens.")
end
end
+
+ describe "impersonation disabled state" do
+ before do
+ stub_config_setting(impersonation_enabled: false)
+ end
+
+ it "does not show impersonation tokens tab" do
+ visit admin_user_path(user)
+
+ expect(page).not_to have_content("Impersonation Tokens")
+ end
+ end
end
diff --git a/spec/features/dashboard/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb
index 4c43948201c..b0aafdda59a 100644
--- a/spec/features/dashboard/todos/target_state_spec.rb
+++ b/spec/features/dashboard/todos/target_state_spec.rb
@@ -3,16 +3,20 @@
require 'spec_helper'
RSpec.describe 'Dashboard > Todo target states' do
- let(:user) { create(:user) }
- let(:author) { create(:user) }
- let(:project) { create(:project, :public) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:author) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+
+ before_all do
+ project.add_developer(user)
+ end
before do
sign_in(user)
end
it 'on a closed issue todo has closed label' do
- issue_closed = create(:issue, state: 'closed')
+ issue_closed = create(:issue, state: 'closed', project: project)
create_todo issue_closed
visit dashboard_todos_path
@@ -22,7 +26,7 @@ RSpec.describe 'Dashboard > Todo target states' do
end
it 'on an open issue todo does not have an open label' do
- issue_open = create(:issue)
+ issue_open = create(:issue, project: project)
create_todo issue_open
visit dashboard_todos_path
@@ -32,7 +36,7 @@ RSpec.describe 'Dashboard > Todo target states' do
end
it 'on a merged merge request todo has merged label' do
- mr_merged = create(:merge_request, :simple, :merged, author: user)
+ mr_merged = create(:merge_request, :simple, :merged, author: user, source_project: project)
create_todo mr_merged
visit dashboard_todos_path
@@ -42,7 +46,7 @@ RSpec.describe 'Dashboard > Todo target states' do
end
it 'on a closed merge request todo has closed label' do
- mr_closed = create(:merge_request, :simple, :closed, author: user)
+ mr_closed = create(:merge_request, :simple, :closed, author: user, source_project: project)
create_todo mr_closed
visit dashboard_todos_path
@@ -52,7 +56,7 @@ RSpec.describe 'Dashboard > Todo target states' do
end
it 'on an open merge request todo does not have an open label' do
- mr_open = create(:merge_request, :simple, author: user)
+ mr_open = create(:merge_request, :simple, author: user, source_project: project)
create_todo mr_open
visit dashboard_todos_path
diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb
index b1464af4194..53209db3107 100644
--- a/spec/features/dashboard/todos/todos_filtering_spec.rb
+++ b/spec/features/dashboard/todos/todos_filtering_spec.rb
@@ -128,7 +128,7 @@ RSpec.describe 'Dashboard > User filters todos', :js do
describe 'filter by action' do
before do
- create(:todo, :build_failed, user: user_1, author: user_2, project: project_1)
+ create(:todo, :build_failed, user: user_1, author: user_2, project: project_1, target: merge_request)
create(:todo, :marked, user: user_1, author: user_2, project: project_1, target: issue1)
create(:todo, :review_requested, user: user_1, author: user_2, project: project_1, target: issue1)
end
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index 0bc6cc9c017..7345bfa19e2 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -3,10 +3,16 @@
require 'spec_helper'
RSpec.describe 'Dashboard Todos' do
+ include DesignManagementTestHelpers
+
let_it_be(:user) { create(:user, username: 'john') }
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :public) }
- let_it_be(:issue) { create(:issue, due_date: Date.today, title: "Fix bug") }
+ let_it_be(:issue) { create(:issue, project: project, due_date: Date.today, title: "Fix bug") }
+
+ before_all do
+ project.add_developer(user)
+ end
context 'User does not have todos' do
before do
@@ -21,8 +27,8 @@ RSpec.describe 'Dashboard Todos' do
context 'when the todo references a merge request' do
let(:referenced_mr) { create(:merge_request, source_project: project) }
- let(:note) { create(:note, project: project, note: "Check out #{referenced_mr.to_reference}") }
- let!(:todo) { create(:todo, :mentioned, user: user, project: project, author: author, note: note) }
+ let(:note) { create(:note, project: project, note: "Check out #{referenced_mr.to_reference}", noteable: create(:issue, project: project)) }
+ let!(:todo) { create(:todo, :mentioned, user: user, project: project, author: author, note: note, target: note.noteable) }
before do
sign_in(user)
@@ -39,9 +45,26 @@ RSpec.describe 'Dashboard Todos' do
end
end
- context 'User has a todo', :js do
+ context 'user has an unauthorized todo' do
before do
+ sign_in(user)
+ end
+
+ it 'does not render the todo' do
+ unauthorized_issue = create(:issue)
+ create(:todo, :mentioned, user: user, project: unauthorized_issue.project, target: unauthorized_issue, author: author)
create(:todo, :mentioned, user: user, project: project, target: issue, author: author)
+
+ visit dashboard_todos_path
+
+ expect(page).to have_selector('.todos-list .todo', count: 1)
+ end
+ end
+
+ context 'User has a todo', :js do
+ let_it_be(:user_todo) { create(:todo, :mentioned, user: user, project: project, target: issue, author: author) }
+
+ before do
sign_in(user)
visit dashboard_todos_path
@@ -183,7 +206,7 @@ RSpec.describe 'Dashboard Todos' do
end
context 'approval todo' do
- let(:merge_request) { create(:merge_request, title: "Fixes issue") }
+ let(:merge_request) { create(:merge_request, title: "Fixes issue", source_project: project) }
before do
create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user)
@@ -199,7 +222,7 @@ RSpec.describe 'Dashboard Todos' do
end
context 'review request todo' do
- let(:merge_request) { create(:merge_request, title: "Fixes issue") }
+ let(:merge_request) { create(:merge_request, title: "Fixes issue", source_project: project) }
before do
create(:todo, :review_requested, user: user, project: project, target: merge_request, author: user)
@@ -355,7 +378,7 @@ RSpec.describe 'Dashboard Todos' do
end
context 'User has a Build Failed todo' do
- let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) }
+ let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author, target: create(:merge_request, source_project: project)) }
before do
sign_in(user)
@@ -386,6 +409,7 @@ RSpec.describe 'Dashboard Todos' do
end
before do
+ enable_design_management
project.add_developer(user)
sign_in(user)
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index cf234032d33..fdd822ef25b 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -90,48 +90,17 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
end
context 'when signed in and an invite link is clicked' do
- context 'when an invite email is a secondary email for the user' do
- let(:invite_email) { 'user_secondary@example.com' }
-
- before do
- sign_in(user)
- visit invite_path(group_invite.raw_invite_token)
- end
-
- it 'sends user to the invite url and allows them to decline' do
- expect(current_path).to eq(invite_path(group_invite.raw_invite_token))
- expect(page).to have_content("Note that this invitation was sent to #{invite_email}")
- expect(page).to have_content("but you are signed in as #{user.to_reference} with email #{user.email}")
-
- click_link('Decline')
-
- expect(page).to have_content('You have declined the invitation')
- expect(current_path).to eq(dashboard_projects_path)
- expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound
- end
-
- it 'sends uer to the invite url and allows them to accept' do
- expect(current_path).to eq(invite_path(group_invite.raw_invite_token))
- expect(page).to have_content("Note that this invitation was sent to #{invite_email}")
- expect(page).to have_content("but you are signed in as #{user.to_reference} with email #{user.email}")
-
- click_link('Accept invitation')
-
- expect(page).to have_content('You have been granted')
- expect(current_path).to eq(activity_group_path(group))
- end
- end
-
context 'when user is an existing member' do
before do
- sign_in(owner)
+ group.add_developer(user)
+ sign_in(user)
visit invite_path(group_invite.raw_invite_token)
end
it 'shows message user already a member' do
expect(current_path).to eq(invite_path(group_invite.raw_invite_token))
- expect(page).to have_link(owner.name, href: user_url(owner))
- expect(page).to have_content('However, you are already a member of this group.')
+ expect(page).to have_link(user.name, href: user_path(user))
+ expect(page).to have_content('You are already a member of this group.')
end
end
end
diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb
index c4994838d26..e080c7ffb3f 100644
--- a/spec/features/markdown/mermaid_spec.rb
+++ b/spec/features/markdown/mermaid_spec.rb
@@ -260,8 +260,6 @@ RSpec.describe 'Mermaid rendering', :js do
description *= 51
- project = create(:project, :public)
-
wiki_page = build(:wiki_page, { container: project, content: description })
wiki_page.create message: 'mermaid test commit' # rubocop:disable Rails/SaveBang
wiki_page = project.wiki.find_page(wiki_page.slug)
@@ -277,6 +275,27 @@ RSpec.describe 'Mermaid rendering', :js do
expect(page).not_to have_selector('.js-lazy-render-mermaid-container')
end
end
+
+ it 'does not allow HTML injection' do
+ description = <<~MERMAID
+ ```mermaid
+ %%{init: {"flowchart": {"htmlLabels": "false"}} }%%
+ flowchart
+ A["<iframe></iframe>"]
+ ```
+ MERMAID
+
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ wait_for_requests
+ wait_for_mermaid
+
+ page.within('.description') do
+ expect(page).not_to have_xpath("//iframe")
+ end
+ end
end
def wait_for_mermaid
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 0958e1d1891..ce2083b397a 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -365,9 +365,8 @@ RSpec.describe 'Pipeline', :js do
let(:project) { create(:project, :public, :repository, public_builds: false) }
let(:role) { :guest }
- it 'does not show failed jobs tab pane' do
- expect(page).to have_link('Pipeline')
- expect(page).not_to have_content('Failed Jobs')
+ it 'does not show the pipeline details page' do
+ expect(page).to have_content('Not Found')
end
end
end
diff --git a/spec/frontend/members/store/mutations_spec.js b/spec/frontend/members/store/mutations_spec.js
index 72423c6b4d4..8160cc373d8 100644
--- a/spec/frontend/members/store/mutations_spec.js
+++ b/spec/frontend/members/store/mutations_spec.js
@@ -44,8 +44,7 @@ describe('Vuex members mutations', () => {
describe('when error has a message', () => {
it('shows error message', () => {
const error = new Error('Request failed with status code 422');
- const message =
- 'User email "john.smith@gmail.com" does not match the allowed domain of example.com';
+ const message = 'User email does not match the allowed domain of example.com';
error.response = {
data: { message },
@@ -88,8 +87,7 @@ describe('Vuex members mutations', () => {
describe('when error has a message', () => {
it('shows error message', () => {
const error = new Error('Request failed with status code 422');
- const message =
- 'User email "john.smith@gmail.com" does not match the allowed domain of example.com';
+ const message = 'User email does not match the allowed domain of example.com';
error.response = {
data: { message },
diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb
index 0dc3a9c85e7..faf19104731 100644
--- a/spec/graphql/features/authorization_spec.rb
+++ b/spec/graphql/features/authorization_spec.rb
@@ -105,7 +105,7 @@ RSpec.describe 'DeclarativePolicy authorization in GraphQL ' do
describe 'with a single permission' do
let(:type) do
type_factory do |type|
- type.field :name, GraphQL::STRING_TYPE, null: true, authorize: permission_single
+ type.field :name, GraphQL::Types::String, null: true, authorize: permission_single
end
end
@@ -124,7 +124,7 @@ RSpec.describe 'DeclarativePolicy authorization in GraphQL ' do
let(:type) do
permissions = permission_collection
type_factory do |type|
- type.field :name, GraphQL::STRING_TYPE,
+ type.field :name, GraphQL::Types::String,
null: true,
authorize: permissions
end
@@ -332,7 +332,7 @@ RSpec.describe 'DeclarativePolicy authorization in GraphQL ' do
type_factory do |type|
type.graphql_name 'FakeIssueType'
type.authorize :read_issue
- type.field :id, GraphQL::ID_TYPE, null: false
+ type.field :id, GraphQL::Types::ID, null: false
end
end
diff --git a/spec/graphql/mutations/base_mutation_spec.rb b/spec/graphql/mutations/base_mutation_spec.rb
index 5c51b74713b..7939fadb37b 100644
--- a/spec/graphql/mutations/base_mutation_spec.rb
+++ b/spec/graphql/mutations/base_mutation_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe ::Mutations::BaseMutation do
context 'when argument is nullable and required' do
let(:mutation_class) do
Class.new(described_class) do
- argument :foo, GraphQL::STRING_TYPE, required: :nullable
+ argument :foo, GraphQL::Types::String, required: :nullable
end
end
@@ -35,7 +35,7 @@ RSpec.describe ::Mutations::BaseMutation do
context 'when argument is required and NOT nullable' do
let(:mutation_class) do
Class.new(described_class) do
- argument :foo, GraphQL::STRING_TYPE, required: true
+ argument :foo, GraphQL::Types::String, required: true
end
end
diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb
index b5f2ff5d044..9723ac8af42 100644
--- a/spec/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/graphql/mutations/todos/mark_done_spec.rb
@@ -5,17 +5,23 @@ require 'spec_helper'
RSpec.describe Mutations::Todos::MarkDone do
include GraphqlHelpers
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done) }
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending, target: issue) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :pending) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+ before_all do
+ project.add_developer(current_user)
+ end
+
specify { expect(described_class).to require_graphql_authorizations(:update_todo) }
describe '#resolve' do
diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb
index 22fb1bba7a8..954bb3db668 100644
--- a/spec/graphql/mutations/todos/restore_spec.rb
+++ b/spec/graphql/mutations/todos/restore_spec.rb
@@ -5,17 +5,23 @@ require 'spec_helper'
RSpec.describe Mutations::Todos::Restore do
include GraphqlHelpers
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :pending) }
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :pending, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :done) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
+ before_all do
+ project.add_developer(current_user)
+ end
+
specify { expect(described_class).to require_graphql_authorizations(:update_todo) }
describe '#resolve' do
diff --git a/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
index c0367f7d42e..ccc861baae5 100644
--- a/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
@@ -5,14 +5,24 @@ require 'spec_helper'
RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do
include GraphqlHelpers
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+
+ let(:current_user) { reporter }
+
+ before_all do
+ project.add_guest(guest)
+ project.add_reporter(reporter)
+ end
specify do
expect(described_class).to have_nullable_graphql_type(::Types::Ci::AnalyticsType)
end
def resolve_statistics(project, args)
- resolve(described_class, obj: project, args: args)
+ ctx = { current_user: current_user }
+ resolve(described_class, obj: project, args: args, ctx: ctx)
end
describe '#resolve' do
@@ -32,5 +42,15 @@ RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do
:pipeline_times_values
)
end
+
+ context 'when the user does not have access to the CI/CD analytics data' do
+ let(:current_user) { guest }
+
+ it 'returns nil' do
+ result = resolve_statistics(project, {})
+
+ expect(result).to be_nil
+ end
+ end
end
end
diff --git a/spec/graphql/resolvers/todo_resolver_spec.rb b/spec/graphql/resolvers/todo_resolver_spec.rb
index ac14852b365..0760935a2fe 100644
--- a/spec/graphql/resolvers/todo_resolver_spec.rb
+++ b/spec/graphql/resolvers/todo_resolver_spec.rb
@@ -4,19 +4,28 @@ require 'spec_helper'
RSpec.describe Resolvers::TodoResolver do
include GraphqlHelpers
+ include DesignManagementTestHelpers
specify do
expect(described_class).to have_nullable_graphql_type(Types::TodoType.connection_type)
end
describe '#resolve' do
+ let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:author1) { create(:user) }
let_it_be(:author2) { create(:user) }
- let_it_be(:merge_request_todo_pending) { create(:todo, user: current_user, target_type: 'MergeRequest', state: :pending, action: Todo::MENTIONED, author: author1) }
- let_it_be(:issue_todo_done) { create(:todo, user: current_user, state: :done, action: Todo::ASSIGNED, author: author2) }
- let_it_be(:issue_todo_pending) { create(:todo, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) }
+ let_it_be(:issue_todo_done) { create(:todo, user: current_user, state: :done, action: Todo::ASSIGNED, author: author2, target: issue) }
+ let_it_be(:issue_todo_pending) { create(:todo, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: issue) }
+
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let!(:merge_request_todo_pending) { create(:todo, user: current_user, target: merge_request, state: :pending, action: Todo::MENTIONED, author: author1) }
+
+ before_all do
+ project.add_developer(current_user)
+ end
it 'calls TodosFinder' do
expect_next_instance_of(TodosFinder) do |finder|
@@ -40,7 +49,9 @@ RSpec.describe Resolvers::TodoResolver do
end
it 'returns the todos for multiple filters' do
- design_todo_pending = create(:todo, target_type: 'DesignManagement::Design', user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
+ enable_design_management
+ design = create(:design, issue: issue)
+ design_todo_pending = create(:todo, target: design, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
todos = resolve_todos(type: ['MergeRequest', 'DesignManagement::Design'])
@@ -59,11 +70,15 @@ RSpec.describe Resolvers::TodoResolver do
group3 = create(:group)
group1.add_developer(current_user)
+ issue1 = create(:issue, project: create(:project, group: group1))
group2.add_developer(current_user)
+ issue2 = create(:issue, project: create(:project, group: group2))
+ group3.add_developer(current_user)
+ issue3 = create(:issue, project: create(:project, group: group3))
- todo4 = create(:todo, group: group1, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
- todo5 = create(:todo, group: group2, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
- create(:todo, group: group3, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
+ todo4 = create(:todo, group: group1, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: issue1)
+ todo5 = create(:todo, group: group2, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: issue2)
+ create(:todo, group: group3, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: issue3)
todos = resolve_todos(group_id: [group2.id, group1.id])
@@ -93,9 +108,13 @@ RSpec.describe Resolvers::TodoResolver do
project2 = create(:project)
project3 = create(:project)
- todo4 = create(:todo, project: project1, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
- todo5 = create(:todo, project: project2, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
- create(:todo, project: project3, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1)
+ project1.add_developer(current_user)
+ project2.add_developer(current_user)
+ project3.add_developer(current_user)
+
+ todo4 = create(:todo, project: project1, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: create(:issue, project: project1))
+ todo5 = create(:todo, project: project2, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: create(:issue, project: project2))
+ create(:todo, project: project3, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1, target: create(:issue, project: project3))
todos = resolve_todos(project_id: [project2.id, project1.id])
diff --git a/spec/graphql/subscriptions/issuable_updated_spec.rb b/spec/graphql/subscriptions/issuable_updated_spec.rb
index cc88b37627d..c15b4f532ef 100644
--- a/spec/graphql/subscriptions/issuable_updated_spec.rb
+++ b/spec/graphql/subscriptions/issuable_updated_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe Subscriptions::IssuableUpdated do
end
end
- context 'when a GraphQL::ID_TYPE is provided' do
+ context 'when a GraphQL::Types::ID is provided' do
let(:issuable_id) { issue.to_gid.to_s }
it 'raises an exception' do
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 2e3dce3f418..ffd8b09558c 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -336,6 +336,15 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
expect_results_with_abilities(impersonation_token, described_class.full_authentication_abilities)
end
+ it 'fails if it is an impersonation token but impersonation is blocked' do
+ stub_config_setting(impersonation_enabled: false)
+
+ impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api'])
+
+ expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip'))
+ .to eq(Gitlab::Auth::Result.new(nil, nil, nil, nil))
+ end
+
it 'limits abilities based on scope' do
personal_access_token = create(:personal_access_token, scopes: %w[read_user sudo])
diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
index 6019318a401..7771289abe6 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
@@ -136,7 +136,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
source: :push,
- origin_ref: 'mytag',
+ origin_ref: origin_ref,
checkout_sha: project.commit.id,
after_sha: nil,
before_sha: nil,
@@ -147,6 +147,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do
current_user: user)
end
+ let(:origin_ref) { 'mytag' }
+
before do
allow_any_instance_of(Repository).to receive(:tag_exists?).with('mytag').and_return(true)
@@ -156,6 +158,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do
it 'correctly indicated that this is a tagged pipeline' do
expect(pipeline).to be_tag
end
+
+ context 'when origin_ref is branch but tag ref with the same name exists' do
+ let(:origin_ref) { 'refs/heads/mytag' }
+
+ it 'correctly indicated that a pipeline is not tagged' do
+ expect(pipeline).not_to be_tag
+ end
+ end
end
context 'when pipeline is running for a merge request' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index 8568b763b7a..c22a0e23794 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -27,6 +27,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do
it { is_expected.to eq(true) }
end
+ context 'for fully described tag ref' do
+ let(:origin_ref) { 'refs/tags/master' }
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'for fully described branch ref' do
+ let(:origin_ref) { 'refs/heads/master' }
+
+ it { is_expected.to eq(true) }
+ end
+
context 'for invalid branch' do
let(:origin_ref) { 'something' }
@@ -43,6 +55,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do
it { is_expected.to eq(true) }
end
+ context 'for fully described tag ref' do
+ let(:origin_ref) { 'refs/tags/v1.0.0' }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'for fully described branch ref' do
+ let(:origin_ref) { 'refs/heads/v1.0.0' }
+
+ it { is_expected.to eq(false) }
+ end
+
context 'for invalid ref' do
let(:origin_ref) { 'something' }
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index e8470657181..2ef3b324db8 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -138,6 +138,25 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
expect(issue.assignees).to be_empty
expect(issue.milestone).to be_nil
end
+
+ context 'when issues are set to private' do
+ before do
+ project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
+ end
+
+ it 'applies quick action commands present on templates' do
+ file_content = %(Text from service_desk2 template \n/label ~#{label.title} \n/milestone %"#{milestone.name}")
+ set_template_file('service_desk2', file_content)
+
+ receiver.execute
+
+ issue = Issue.last
+ expect(issue.description).to include('Text from service_desk2 template')
+ expect(issue.label_ids).to include(label.id)
+ expect(issue.author_id).to eq(User.support_bot.id)
+ expect(issue.milestone).to eq(milestone)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/graphql/calls_gitaly/field_extension_spec.rb b/spec/lib/gitlab/graphql/calls_gitaly/field_extension_spec.rb
index 1d8849f7e38..33f49dbc8d4 100644
--- a/spec/lib/gitlab/graphql/calls_gitaly/field_extension_spec.rb
+++ b/spec/lib/gitlab/graphql/calls_gitaly/field_extension_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Gitlab::Graphql::CallsGitaly::FieldExtension, :request_store do
let(:field_args) { {} }
let(:owner) { fresh_object_type }
let(:field) do
- ::Types::BaseField.new(name: 'value', type: GraphQL::STRING_TYPE, null: true, owner: owner, **field_args)
+ ::Types::BaseField.new(name: 'value', type: GraphQL::Types::String, null: true, owner: owner, **field_args)
end
def resolve_value
diff --git a/spec/lib/gitlab/graphql/copy_field_description_spec.rb b/spec/lib/gitlab/graphql/copy_field_description_spec.rb
index 310b4046b56..84aa548f2cf 100644
--- a/spec/lib/gitlab/graphql/copy_field_description_spec.rb
+++ b/spec/lib/gitlab/graphql/copy_field_description_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::Graphql::CopyFieldDescription do
Class.new(Types::BaseObject) do
graphql_name "TestType"
- field :field_name, GraphQL::STRING_TYPE, null: true, description: 'Foo'
+ field :field_name, GraphQL::Types::String, null: true, description: 'Foo'
end
end
diff --git a/spec/lib/gitlab/graphql/mount_mutation_spec.rb b/spec/lib/gitlab/graphql/mount_mutation_spec.rb
index d6b932e08d2..fe25e923506 100644
--- a/spec/lib/gitlab/graphql/mount_mutation_spec.rb
+++ b/spec/lib/gitlab/graphql/mount_mutation_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe Gitlab::Graphql::MountMutation do
Class.new(Mutations::BaseMutation) do
graphql_name 'TestMutation'
- argument :foo, GraphQL::STRING_TYPE, required: false
- field :bar, GraphQL::STRING_TYPE, null: true
+ argument :foo, GraphQL::Types::String, required: false
+ field :bar, GraphQL::Types::String, null: true
end
end
diff --git a/spec/lib/gitlab/graphql/negatable_arguments_spec.rb b/spec/lib/gitlab/graphql/negatable_arguments_spec.rb
index bc6e25eb018..71ef75836c0 100644
--- a/spec/lib/gitlab/graphql/negatable_arguments_spec.rb
+++ b/spec/lib/gitlab/graphql/negatable_arguments_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Gitlab::Graphql::NegatableArguments do
it 'defines any arguments passed as block' do
test_resolver.negated do
- argument :foo, GraphQL::STRING_TYPE, required: false
+ argument :foo, GraphQL::Types::String, required: false
end
expect(test_resolver.arguments['not'].type.arguments.keys).to match_array(['foo'])
@@ -27,10 +27,10 @@ RSpec.describe Gitlab::Graphql::NegatableArguments do
it 'defines all arguments passed as block even if called multiple times' do
test_resolver.negated do
- argument :foo, GraphQL::STRING_TYPE, required: false
+ argument :foo, GraphQL::Types::String, required: false
end
test_resolver.negated do
- argument :bar, GraphQL::STRING_TYPE, required: false
+ argument :bar, GraphQL::Types::String, required: false
end
expect(test_resolver.arguments['not'].type.arguments.keys).to match_array(%w[foo bar])
diff --git a/spec/lib/gitlab/graphql/pagination/connections_spec.rb b/spec/lib/gitlab/graphql/pagination/connections_spec.rb
index e89e5c17644..f3f59113c81 100644
--- a/spec/lib/gitlab/graphql/pagination/connections_spec.rb
+++ b/spec/lib/gitlab/graphql/pagination/connections_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe ::Gitlab::Graphql::Pagination::Connections do
let(:node_type) do
Class.new(::GraphQL::Schema::Object) do
graphql_name 'Node'
- field :value, GraphQL::INT_TYPE, null: false
+ field :value, GraphQL::Types::Int, null: false
end
end
diff --git a/spec/lib/gitlab/graphql/present/field_extension_spec.rb b/spec/lib/gitlab/graphql/present/field_extension_spec.rb
index 6ea313d30b3..5f0f444e0bb 100644
--- a/spec/lib/gitlab/graphql/present/field_extension_spec.rb
+++ b/spec/lib/gitlab/graphql/present/field_extension_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
let(:owner) { fresh_object_type }
let(:field_name) { 'value' }
let(:field) do
- ::Types::BaseField.new(name: field_name, type: GraphQL::STRING_TYPE, null: true, owner: owner)
+ ::Types::BaseField.new(name: field_name, type: GraphQL::Types::String, null: true, owner: owner)
end
let(:base_presenter) do
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
Module.new do
include ::Types::BaseInterface
- field :interface_field, GraphQL::STRING_TYPE, null: true
+ field :interface_field, GraphQL::Types::String, null: true
end
end
@@ -58,7 +58,7 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
end
it 'resolves the interface field using the implementation from the presenter' do
- field = ::Types::BaseField.new(name: :interface_field, type: GraphQL::STRING_TYPE, null: true, owner: interface)
+ field = ::Types::BaseField.new(name: :interface_field, type: GraphQL::Types::String, null: true, owner: interface)
value = resolve_field(field, object, object_type: implementation)
expect(value).to eq 'made of concrete'
@@ -67,7 +67,7 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
context 'when the implementation is inherited' do
it 'resolves the interface field using the implementation from the presenter' do
subclass = Class.new(implementation) { graphql_name 'Subclass' }
- field = ::Types::BaseField.new(name: :interface_field, type: GraphQL::STRING_TYPE, null: true, owner: interface)
+ field = ::Types::BaseField.new(name: :interface_field, type: GraphQL::Types::String, null: true, owner: interface)
value = resolve_field(field, object, object_type: subclass)
expect(value).to eq 'made of concrete'
@@ -79,8 +79,8 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
def parent
type = fresh_object_type('Parent')
type.present_using(provide_foo)
- type.field :foo, ::GraphQL::INT_TYPE, null: true
- type.field :value, ::GraphQL::STRING_TYPE, null: true
+ type.field :foo, ::GraphQL::Types::Int, null: true
+ type.field :value, ::GraphQL::Types::String, null: true
type
end
@@ -88,7 +88,7 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
type = Class.new(parent)
type.graphql_name 'Child'
type.present_using(provide_bar)
- type.field :bar, ::GraphQL::INT_TYPE, null: true
+ type.field :bar, ::GraphQL::Types::Int, null: true
type
end
@@ -150,7 +150,7 @@ RSpec.describe Gitlab::Graphql::Present::FieldExtension do
let(:field) do
::Types::BaseField.new(
name: field_name,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: true,
owner: owner,
resolve: ->(obj, args, ctx) { 'Hello from a proc' }
diff --git a/spec/lib/gitlab/graphql/queries_spec.rb b/spec/lib/gitlab/graphql/queries_spec.rb
index a1cd2cdb2de..8b7f4ca7933 100644
--- a/spec/lib/gitlab/graphql/queries_spec.rb
+++ b/spec/lib/gitlab/graphql/queries_spec.rb
@@ -21,30 +21,30 @@ RSpec.describe Gitlab::Graphql::Queries do
let_it_be(:schema) do
author = Class.new(GraphQL::Schema::Object) do
graphql_name 'Author'
- field :name, GraphQL::STRING_TYPE, null: true
- field :handle, GraphQL::STRING_TYPE, null: false
- field :verified, GraphQL::BOOLEAN_TYPE, null: false
+ field :name, GraphQL::Types::String, null: true
+ field :handle, GraphQL::Types::String, null: false
+ field :verified, GraphQL::Types::Boolean, null: false
end
post = Class.new(GraphQL::Schema::Object) do
graphql_name 'Post'
- field :name, GraphQL::STRING_TYPE, null: false
- field :title, GraphQL::STRING_TYPE, null: false
- field :content, GraphQL::STRING_TYPE, null: true
+ field :name, GraphQL::Types::String, null: false
+ field :title, GraphQL::Types::String, null: false
+ field :content, GraphQL::Types::String, null: true
field :author, author, null: false
end
author.field :posts, [post], null: false do
- argument :blog_title, GraphQL::STRING_TYPE, required: false
+ argument :blog_title, GraphQL::Types::String, required: false
end
blog = Class.new(GraphQL::Schema::Object) do
graphql_name 'Blog'
- field :title, GraphQL::STRING_TYPE, null: false
- field :description, GraphQL::STRING_TYPE, null: false
+ field :title, GraphQL::Types::String, null: false
+ field :description, GraphQL::Types::String, null: false
field :main_author, author, null: false
field :posts, [post], null: false
field :post, post, null: true do
- argument :slug, GraphQL::STRING_TYPE, required: true
+ argument :slug, GraphQL::Types::String, required: true
end
end
@@ -52,10 +52,10 @@ RSpec.describe Gitlab::Graphql::Queries do
query(Class.new(GraphQL::Schema::Object) do
graphql_name 'Query'
field :blog, blog, null: true do
- argument :title, GraphQL::STRING_TYPE, required: true
+ argument :title, GraphQL::Types::String, required: true
end
field :post, post, null: true do
- argument :slug, GraphQL::STRING_TYPE, required: true
+ argument :slug, GraphQL::Types::String, required: true
end
end)
end
diff --git a/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb b/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb
index 6494cdfe522..98385cd80cc 100644
--- a/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb
+++ b/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb
@@ -228,4 +228,16 @@ RSpec.describe Gitlab::MarkdownCache::ActiveRecord::Extension do
thing.refresh_markdown_cache!
end
end
+
+ context 'when persisted cache is nil' do
+ before do
+ thing.update_column(:cached_markdown_version, nil)
+ end
+
+ it 'does not save the generated HTML' do
+ expect(thing).to receive(:update_columns)
+
+ thing.refresh_markdown_cache!
+ end
+ end
end
diff --git a/spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb b/spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb
deleted file mode 100644
index f65b247d5d7..00000000000
--- a/spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::OmniauthLogging::JSONFormatter do
- it "generates log in json format" do
- Timecop.freeze(Time.utc(2019, 12, 04, 9, 10, 11, 123456)) do
- expect(subject.call(:info, Time.now, 'omniauth', 'log message'))
- .to eq %Q({"severity":"info","timestamp":"2019-12-04T09:10:11.123Z","pid":#{Process.pid},"progname":"omniauth","message":"log message"}\n)
- end
- end
-end
diff --git a/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb b/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb
index ed94b81520e..9d5f029fff5 100644
--- a/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb
@@ -4,15 +4,19 @@ require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu do
let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:guest) do
+ create(:user).tap { |u| project.add_guest(u) }
+ end
- let(:user) { project.owner }
- let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, current_ref: project.repository.root_ref) }
+ let(:owner) { project.owner }
+ let(:current_user) { owner }
+ let(:context) { Sidebars::Projects::Context.new(current_user: current_user, container: project, current_ref: project.repository.root_ref) }
subject { described_class.new(context) }
describe '#render?' do
context 'whe user cannot read analytics' do
- let(:user) { nil }
+ let(:current_user) { nil }
it 'returns false' do
expect(subject.render?).to be false
@@ -79,7 +83,7 @@ RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu do
end
describe 'when the user does not have access' do
- let(:user) { nil }
+ let(:current_user) { guest }
specify { is_expected.to be_nil }
end
@@ -99,7 +103,7 @@ RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu do
end
describe 'when the user does not have access' do
- let(:user) { nil }
+ let(:current_user) { nil }
specify { is_expected.to be_nil }
end
@@ -111,7 +115,7 @@ RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu do
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
- let(:user) { nil }
+ let(:current_user) { nil }
specify { is_expected.to be_nil }
end
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 2731eadecc0..11652d9841b 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -552,4 +552,10 @@ RSpec.describe DiffNote do
expect(subject.on_image?).to be_truthy
end
end
+
+ describe '#to_ability_name' do
+ subject { described_class.new.to_ability_name }
+
+ it { is_expected.to eq('note') }
+ end
end
diff --git a/spec/models/discussion_note_spec.rb b/spec/models/discussion_note_spec.rb
new file mode 100644
index 00000000000..6e1b39cc438
--- /dev/null
+++ b/spec/models/discussion_note_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DiscussionNote do
+ describe '#to_ability_name' do
+ subject { described_class.new.to_ability_name }
+
+ it { is_expected.to eq('note') }
+ end
+end
diff --git a/spec/models/legacy_diff_note_spec.rb b/spec/models/legacy_diff_note_spec.rb
new file mode 100644
index 00000000000..ee3bbf186b9
--- /dev/null
+++ b/spec/models/legacy_diff_note_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe LegacyDiffNote do
+ describe '#to_ability_name' do
+ subject { described_class.new.to_ability_name }
+
+ it { is_expected.to eq('note') }
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 3d0afaee645..66d650b4f84 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2421,39 +2421,20 @@ RSpec.describe Project, factory_default: :keep do
let_it_be_with_reload(:project) { create(:project) }
it 'updates project_feature', :aggregate_failures do
- # Simulate an existing project that has container_registry enabled
- project.update_column(:container_registry_enabled, true)
- project.project_feature.update_column(:container_registry_access_level, ProjectFeature::ENABLED)
-
project.update!(container_registry_enabled: false)
- expect(project.read_attribute(:container_registry_enabled)).to eq(false)
expect(project.project_feature.container_registry_access_level).to eq(ProjectFeature::DISABLED)
project.update!(container_registry_enabled: true)
- expect(project.read_attribute(:container_registry_enabled)).to eq(true)
expect(project.project_feature.container_registry_access_level).to eq(ProjectFeature::ENABLED)
end
-
- it 'rollsback both projects and project_features row in case of error', :aggregate_failures do
- project.update_column(:container_registry_enabled, true)
- project.project_feature.update_column(:container_registry_access_level, ProjectFeature::ENABLED)
-
- allow(project).to receive(:valid?).and_return(false)
-
- expect { project.update!(container_registry_enabled: false) }.to raise_error(ActiveRecord::RecordInvalid)
-
- expect(project.reload.read_attribute(:container_registry_enabled)).to eq(true)
- expect(project.project_feature.reload.container_registry_access_level).to eq(ProjectFeature::ENABLED)
- end
end
describe '#container_registry_enabled' do
let_it_be_with_reload(:project) { create(:project) }
it 'delegates to project_feature', :aggregate_failures do
- project.update_column(:container_registry_enabled, true)
project.project_feature.update_column(:container_registry_access_level, ProjectFeature::DISABLED)
expect(project.container_registry_enabled).to eq(false)
diff --git a/spec/models/synthetic_note_spec.rb b/spec/models/synthetic_note_spec.rb
new file mode 100644
index 00000000000..55fa4f7c33d
--- /dev/null
+++ b/spec/models/synthetic_note_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe SyntheticNote do
+ describe '#to_ability_name' do
+ subject { described_class.new.to_ability_name }
+
+ it { is_expected.to eq('note') }
+ end
+end
diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb
index bc09191f6ec..8ff936d5a35 100644
--- a/spec/policies/issue_policy_spec.rb
+++ b/spec/policies/issue_policy_spec.rb
@@ -11,13 +11,37 @@ RSpec.describe IssuePolicy do
let(:reporter) { create(:user) }
let(:group) { create(:group, :public) }
let(:reporter_from_group_link) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:support_bot) { User.support_bot }
def permissions(user, issue)
described_class.new(user, issue)
end
+ shared_examples 'support bot with service desk enabled' do
+ before do
+ allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
+ allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
+
+ project.update!(service_desk_enabled: true)
+ end
+
+ it 'allows support_bot to read issues, create and set metadata on new issues' do
+ expect(permissions(support_bot, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(support_bot, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(support_bot, new_issue)).to be_allowed(:create_issue, :set_issue_metadata)
+ end
+ end
+
+ shared_examples 'support bot with service desk disabled' do
+ it 'allows support_bot to read issues, create and set metadata on new issues' do
+ expect(permissions(support_bot, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(support_bot, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(support_bot, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata)
+ end
+ end
+
context 'a private project' do
- let(:non_member) { create(:user) }
let(:project) { create(:project, :private) }
let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) }
let(:issue_no_assignee) { create(:issue, project: project) }
@@ -34,12 +58,6 @@ RSpec.describe IssuePolicy do
create(:project_group_link, group: group, project: project)
end
- it 'does not allow non-members to read issues' do
- expect(permissions(non_member, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
- expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
- expect(permissions(non_member, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata)
- end
-
it 'allows guests to read issues' do
expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid)
expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata)
@@ -82,6 +100,15 @@ RSpec.describe IssuePolicy do
expect(permissions(assignee, new_issue)).to be_allowed(:create_issue, :set_issue_metadata)
end
+ it 'does not allow non-members to read, update or create issues' do
+ expect(permissions(non_member, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(non_member, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata)
+ end
+
+ it_behaves_like 'support bot with service desk disabled'
+ it_behaves_like 'support bot with service desk enabled'
+
context 'with confidential issues' do
let(:confidential_issue) { create(:issue, :confidential, project: project, assignees: [assignee], author: author) }
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
@@ -196,7 +223,8 @@ RSpec.describe IssuePolicy do
expect(permissions(author, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
expect(permissions(author, issue_locked)).to be_disallowed(:admin_issue, :reopen_issue, :set_issue_metadata)
- expect(permissions(author, new_issue)).to be_allowed(:create_issue, :set_issue_metadata)
+ expect(permissions(author, new_issue)).to be_allowed(:create_issue)
+ expect(permissions(author, new_issue)).to be_disallowed(:set_issue_metadata)
end
it 'allows issue assignees to read, reopen and update their issues' do
@@ -208,14 +236,44 @@ RSpec.describe IssuePolicy do
expect(permissions(assignee, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
expect(permissions(assignee, issue_locked)).to be_disallowed(:admin_issue, :reopen_issue, :set_issue_metadata)
+ end
- expect(permissions(author, new_issue)).to be_allowed(:create_issue, :set_issue_metadata)
+ it 'allows non-members to read and create issues' do
+ expect(permissions(non_member, issue)).to be_allowed(:read_issue, :read_issue_iid)
+ expect(permissions(non_member, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
+ expect(permissions(non_member, new_issue)).to be_allowed(:create_issue)
+ end
+
+ it 'allows non-members to read issues' do
+ expect(permissions(non_member, issue)).to be_allowed(:read_issue, :read_issue_iid)
+ expect(permissions(non_member, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
+ end
+
+ it 'does not allow non-members to update, admin or set metadata' do
+ expect(permissions(non_member, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(non_member, new_issue)).to be_disallowed(:set_issue_metadata)
end
+ it 'allows support_bot to read issues' do
+ # support_bot is still allowed read access in public projects through :public_access permission,
+ # see project_policy public_access rules policy (rule { can?(:public_access) }.policy {...})
+ expect(permissions(support_bot, issue)).to be_allowed(:read_issue, :read_issue_iid)
+ expect(permissions(support_bot, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata)
+
+ expect(permissions(support_bot, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
+ expect(permissions(support_bot, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata)
+
+ expect(permissions(support_bot, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata)
+ end
+
+ it_behaves_like 'support bot with service desk enabled'
+
context 'when issues are private' do
before do
project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
end
+
let(:issue) { create(:issue, project: project, author: author) }
let(:visitor) { create(:user) }
let(:admin) { create(:user, :admin) }
@@ -258,6 +316,15 @@ RSpec.describe IssuePolicy do
expect(permissions(admin, issue)).to be_disallowed(:create_note)
end
end
+
+ it 'does not allow non-members to update or create issues' do
+ expect(permissions(non_member, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata)
+ expect(permissions(non_member, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata)
+ end
+
+ it_behaves_like 'support bot with service desk disabled'
+ it_behaves_like 'support bot with service desk enabled'
end
context 'with confidential issues' do
diff --git a/spec/policies/personal_access_token_policy_spec.rb b/spec/policies/personal_access_token_policy_spec.rb
index b5e8d40b133..e146133429b 100644
--- a/spec/policies/personal_access_token_policy_spec.rb
+++ b/spec/policies/personal_access_token_policy_spec.rb
@@ -41,6 +41,13 @@ RSpec.describe PersonalAccessTokenPolicy do
it { is_expected.to be_allowed(:read_token) }
it { is_expected.to be_allowed(:revoke_token) }
end
+
+ context 'subject of the impersonated token' do
+ let_it_be(:token) { build_stubbed(:personal_access_token, user: current_user, impersonation: true) }
+
+ it { is_expected.to be_disallowed(:read_token) }
+ it { is_expected.to be_disallowed(:revoke_token) }
+ end
end
context 'current_user is a blocked administrator', :enable_admin_mode do
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 70869a9f36b..a6beb12886b 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -480,8 +480,8 @@ RSpec.describe ProjectPolicy do
let(:current_user) { User.support_bot }
context 'with service desk disabled' do
- it { expect_allowed(:guest_access) }
- it { expect_disallowed(:create_note, :read_project) }
+ it { expect_allowed(:public_access) }
+ it { expect_disallowed(:guest_access, :create_note, :read_project) }
end
context 'with service desk enabled' do
@@ -1131,12 +1131,20 @@ RSpec.describe ProjectPolicy do
let_it_be(:project_with_analytics_enabled) { create(:project, :analytics_enabled) }
before do
+ project_with_analytics_disabled.add_guest(guest)
+ project_with_analytics_private.add_guest(guest)
+ project_with_analytics_enabled.add_guest(guest)
+
+ project_with_analytics_disabled.add_reporter(reporter)
+ project_with_analytics_private.add_reporter(reporter)
+ project_with_analytics_enabled.add_reporter(reporter)
+
project_with_analytics_disabled.add_developer(developer)
project_with_analytics_private.add_developer(developer)
project_with_analytics_enabled.add_developer(developer)
end
- context 'when analytics is enabled for the project' do
+ context 'when analytics is disabled for the project' do
let(:project) { project_with_analytics_disabled }
context 'for guest user' do
@@ -1145,6 +1153,16 @@ RSpec.describe ProjectPolicy do
it { is_expected.to be_disallowed(:read_cycle_analytics) }
it { is_expected.to be_disallowed(:read_insights) }
it { is_expected.to be_disallowed(:read_repository_graphs) }
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+
+ context 'for reporter user' do
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_disallowed(:read_cycle_analytics) }
+ it { is_expected.to be_disallowed(:read_insights) }
+ it { is_expected.to be_disallowed(:read_repository_graphs) }
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
end
context 'for developer' do
@@ -1153,6 +1171,7 @@ RSpec.describe ProjectPolicy do
it { is_expected.to be_disallowed(:read_cycle_analytics) }
it { is_expected.to be_disallowed(:read_insights) }
it { is_expected.to be_disallowed(:read_repository_graphs) }
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
end
end
@@ -1162,9 +1181,19 @@ RSpec.describe ProjectPolicy do
context 'for guest user' do
let(:current_user) { guest }
- it { is_expected.to be_disallowed(:read_cycle_analytics) }
- it { is_expected.to be_disallowed(:read_insights) }
+ it { is_expected.to be_allowed(:read_cycle_analytics) }
+ it { is_expected.to be_allowed(:read_insights) }
it { is_expected.to be_disallowed(:read_repository_graphs) }
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+
+ context 'for reporter user' do
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_allowed(:read_cycle_analytics) }
+ it { is_expected.to be_allowed(:read_insights) }
+ it { is_expected.to be_allowed(:read_repository_graphs) }
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
end
context 'for developer' do
@@ -1173,18 +1202,29 @@ RSpec.describe ProjectPolicy do
it { is_expected.to be_allowed(:read_cycle_analytics) }
it { is_expected.to be_allowed(:read_insights) }
it { is_expected.to be_allowed(:read_repository_graphs) }
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
end
end
context 'when analytics is enabled for the project' do
- let(:project) { project_with_analytics_private }
+ let(:project) { project_with_analytics_enabled }
context 'for guest user' do
let(:current_user) { guest }
- it { is_expected.to be_disallowed(:read_cycle_analytics) }
- it { is_expected.to be_disallowed(:read_insights) }
+ it { is_expected.to be_allowed(:read_cycle_analytics) }
+ it { is_expected.to be_allowed(:read_insights) }
it { is_expected.to be_disallowed(:read_repository_graphs) }
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+
+ context 'for reporter user' do
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_allowed(:read_cycle_analytics) }
+ it { is_expected.to be_allowed(:read_insights) }
+ it { is_expected.to be_allowed(:read_repository_graphs) }
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
end
context 'for developer' do
@@ -1193,6 +1233,7 @@ RSpec.describe ProjectPolicy do
it { is_expected.to be_allowed(:read_cycle_analytics) }
it { is_expected.to be_allowed(:read_insights) }
it { is_expected.to be_allowed(:read_repository_graphs) }
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
end
end
end
diff --git a/spec/policies/todo_policy_spec.rb b/spec/policies/todo_policy_spec.rb
index b4876baa504..16435b21666 100644
--- a/spec/policies/todo_policy_spec.rb
+++ b/spec/policies/todo_policy_spec.rb
@@ -9,22 +9,28 @@ RSpec.describe TodoPolicy do
let_it_be(:user2) { create(:user) }
let_it_be(:user3) { create(:user) }
- let_it_be(:todo1) { create(:todo, author: author, user: user1) }
- let_it_be(:todo2) { create(:todo, author: author, user: user2) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ let_it_be(:todo1) { create(:todo, author: author, user: user1, issue: issue) }
+ let_it_be(:todo2) { create(:todo, author: author, user: user2, issue: issue) }
let_it_be(:todo3) { create(:todo, author: author, user: user2) }
- let_it_be(:todo4) { create(:todo, author: author, user: user3) }
+ let_it_be(:todo4) { create(:todo, author: author, user: user3, issue: issue) }
def permissions(user, todo)
described_class.new(user, todo)
end
+ before_all do
+ project.add_developer(user1)
+ project.add_developer(user2)
+ end
+
describe 'own_todo' do
- it 'allows owners to access their own todos' do
+ it 'allows owners to access their own todos if they can read todo target' do
[
[user1, todo1],
- [user2, todo2],
- [user2, todo3],
- [user3, todo4]
+ [user2, todo2]
].each do |user, todo|
expect(permissions(user, todo)).to be_allowed(:read_todo)
end
@@ -38,7 +44,9 @@ RSpec.describe TodoPolicy do
[user2, todo4],
[user3, todo1],
[user3, todo2],
- [user3, todo3]
+ [user3, todo3],
+ [user2, todo3],
+ [user3, todo4]
].each do |user, todo|
expect(permissions(user, todo)).to be_disallowed(:read_todo)
end
diff --git a/spec/requests/admin/impersonation_tokens_controller_spec.rb b/spec/requests/admin/impersonation_tokens_controller_spec.rb
new file mode 100644
index 00000000000..018f497e7e5
--- /dev/null
+++ b/spec/requests/admin/impersonation_tokens_controller_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::ImpersonationTokensController, :enable_admin_mode do
+ let(:admin) { create(:admin) }
+ let!(:user) { create(:user) }
+
+ before do
+ sign_in(admin)
+ end
+
+ context "when impersonation is disabled" do
+ before do
+ stub_config_setting(impersonation_enabled: false)
+ end
+
+ it "shows error page for index page" do
+ get admin_user_impersonation_tokens_path(user_id: user.username)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it "responds with 404 for create action" do
+ post admin_user_impersonation_tokens_path(user_id: user.username)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it "responds with 404 for revoke action" do
+ token = create(:personal_access_token, :impersonation, user: user)
+
+ put revoke_admin_user_impersonation_token_path(user_id: user.username, id: token.id)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/current_user/todos_query_spec.rb b/spec/requests/api/graphql/current_user/todos_query_spec.rb
index e298de0df01..981b10a7467 100644
--- a/spec/requests/api/graphql/current_user/todos_query_spec.rb
+++ b/spec/requests/api/graphql/current_user/todos_query_spec.rb
@@ -4,12 +4,17 @@ require 'spec_helper'
RSpec.describe 'Query current user todos' do
include GraphqlHelpers
+ include DesignManagementTestHelpers
let_it_be(:current_user) { create(:user) }
- let_it_be(:commit_todo) { create(:on_commit_todo, user: current_user, project: create(:project, :repository)) }
- let_it_be(:issue_todo) { create(:todo, user: current_user, target: create(:issue)) }
- let_it_be(:merge_request_todo) { create(:todo, user: current_user, target: create(:merge_request)) }
- let_it_be(:design_todo) { create(:todo, user: current_user, target: create(:design)) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:unauthorize_project) { create(:project) }
+ let_it_be(:commit_todo) { create(:on_commit_todo, user: current_user, project: project) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:issue_todo) { create(:todo, project: project, user: current_user, target: issue) }
+ let_it_be(:merge_request_todo) { create(:todo, project: project, user: current_user, target: create(:merge_request, source_project: project)) }
+ let_it_be(:design_todo) { create(:todo, project: project, user: current_user, target: create(:design, issue: issue)) }
+ let_it_be(:unauthorized_todo) { create(:todo, user: current_user, project: unauthorize_project, target: create(:issue, project: unauthorize_project)) }
let(:fields) do
<<~QUERY
@@ -23,16 +28,22 @@ RSpec.describe 'Query current user todos' do
graphql_query_for('currentUser', {}, query_graphql_field('todos', {}, fields))
end
+ before_all do
+ project.add_developer(current_user)
+ end
+
subject { graphql_data.dig('currentUser', 'todos', 'nodes') }
before do
+ enable_design_management
+
post_graphql(query, current_user: current_user)
end
it_behaves_like 'a working graphql query'
it 'contains the expected ids' do
- is_expected.to include(
+ is_expected.to contain_exactly(
a_hash_including('id' => commit_todo.to_global_id.to_s),
a_hash_including('id' => issue_todo.to_global_id.to_s),
a_hash_including('id' => merge_request_todo.to_global_id.to_s),
@@ -41,11 +52,33 @@ RSpec.describe 'Query current user todos' do
end
it 'returns Todos for all target types' do
- is_expected.to include(
+ is_expected.to contain_exactly(
a_hash_including('targetType' => 'COMMIT'),
a_hash_including('targetType' => 'ISSUE'),
a_hash_including('targetType' => 'MERGEREQUEST'),
a_hash_including('targetType' => 'DESIGN')
)
end
+
+ context 'when requesting a single field' do
+ let(:fields) do
+ <<~QUERY
+ nodes {
+ id
+ }
+ QUERY
+ end
+
+ it 'avoids N+1 queries', :request_store do
+ control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
+
+ project2 = create(:project)
+ project2.add_developer(current_user)
+ issue2 = create(:issue, project: project2)
+ create(:todo, user: current_user, target: issue2, project: project2)
+
+ # An additional query is made for each different group that owns a todo through a project
+ expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control).with_threshold(2)
+ end
+ end
end
diff --git a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
index 8f92105dc9c..9ac98db91e2 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
@@ -5,14 +5,16 @@ require 'spec_helper'
RSpec.describe 'Marking all todos done' do
include GraphqlHelpers
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
let_it_be(:other_user2) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done) }
- let_it_be(:todo3) { create(:todo, user: current_user, author: author, state: :pending) }
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending, target: issue) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
+ let_it_be(:todo3) { create(:todo, user: current_user, author: author, state: :pending, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :pending) }
@@ -28,6 +30,10 @@ RSpec.describe 'Marking all todos done' do
)
end
+ before_all do
+ project.add_developer(current_user)
+ end
+
def mutation_response
graphql_mutation_response(:todos_mark_all_done)
end
diff --git a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
index 8a9a0b9e845..7f5ea71c760 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
@@ -5,12 +5,14 @@ require 'spec_helper'
RSpec.describe 'Marking todos done' do
include GraphqlHelpers
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done) }
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending, target: issue) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :pending) }
@@ -29,6 +31,10 @@ RSpec.describe 'Marking todos done' do
)
end
+ before_all do
+ project.add_developer(current_user)
+ end
+
def mutation_response
graphql_mutation_response(:todo_mark_done)
end
diff --git a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
index e71a232ff7c..70e3cc7f5cd 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
@@ -5,12 +5,14 @@ require 'spec_helper'
RSpec.describe 'Restoring many Todos' do
include GraphqlHelpers
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done) }
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :done) }
@@ -30,6 +32,10 @@ RSpec.describe 'Restoring many Todos' do
)
end
+ before_all do
+ project.add_developer(current_user)
+ end
+
def mutation_response
graphql_mutation_response(:todo_restore_many)
end
diff --git a/spec/requests/api/graphql/mutations/todos/restore_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
index a58c7fc69fc..d995191c97e 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
@@ -5,12 +5,14 @@ require 'spec_helper'
RSpec.describe 'Restoring Todos' do
include GraphqlHelpers
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
- let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done) }
- let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :pending) }
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done, target: issue) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :pending, target: issue) }
let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :done) }
@@ -29,6 +31,10 @@ RSpec.describe 'Restoring Todos' do
)
end
+ before_all do
+ project.add_developer(current_user)
+ end
+
def mutation_response
graphql_mutation_response(:todo_restore)
end
diff --git a/spec/requests/api/personal_access_tokens_spec.rb b/spec/requests/api/personal_access_tokens_spec.rb
index ccc5f322ff9..0ff2c46e693 100644
--- a/spec/requests/api/personal_access_tokens_spec.rb
+++ b/spec/requests/api/personal_access_tokens_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe API::PersonalAccessTokens do
let_it_be(:path) { '/personal_access_tokens' }
let_it_be(:token1) { create(:personal_access_token) }
let_it_be(:token2) { create(:personal_access_token) }
+ let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: token1.user) }
let_it_be(:current_user) { create(:user) }
describe 'GET /personal_access_tokens' do
@@ -24,8 +25,9 @@ RSpec.describe API::PersonalAccessTokens do
get api(path, current_user), params: { user_id: token1.user.id }
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.count).to eq(1)
+ expect(json_response.count).to eq(2)
expect(json_response.first['user_id']).to eq(token1.user.id)
+ expect(json_response.last['id']).to eq(token_impersonated.id)
end
end
@@ -34,6 +36,7 @@ RSpec.describe API::PersonalAccessTokens do
let_it_be(:user) { create(:user) }
let_it_be(:token) { create(:personal_access_token, user: current_user)}
let_it_be(:other_token) { create(:personal_access_token, user: user) }
+ let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: current_user) }
it 'returns all PATs belonging to the signed-in user' do
get api(path, current_user, personal_access_token: token)
@@ -95,6 +98,7 @@ RSpec.describe API::PersonalAccessTokens do
context 'when current_user is not an administrator' do
let_it_be(:user_token) { create(:personal_access_token, user: current_user) }
let_it_be(:user_token_path) { "/personal_access_tokens/#{user_token.id}" }
+ let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: current_user) }
it 'fails revokes a different users token' do
delete api(path, current_user)
@@ -107,6 +111,12 @@ RSpec.describe API::PersonalAccessTokens do
expect(response).to have_gitlab_http_status(:no_content)
end
+
+ it 'cannot revoke impersonation token' do
+ delete api("/personal_access_tokens/#{token_impersonated.id}", current_user)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 06d27dcb87f..288f8480a5b 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -231,7 +231,6 @@ RSpec.describe API::Projects do
end
it 'includes correct value of container_registry_enabled', :aggregate_failures do
- project.update_column(:container_registry_enabled, true)
project.project_feature.update!(container_registry_access_level: ProjectFeature::DISABLED)
get api('/projects', user)
@@ -1113,6 +1112,16 @@ RSpec.describe API::Projects do
expect(Project.find_by(path: project[:path]).container_registry_access_level).to eq(ProjectFeature::ENABLED)
end
+ it 'assigns container_registry_enabled to project' do
+ project = attributes_for(:project, { container_registry_enabled: true })
+
+ post api('/projects', user), params: project
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['container_registry_enabled']).to eq(true)
+ expect(Project.find_by(path: project[:path]).container_registry_access_level).to eq(ProjectFeature::ENABLED)
+ end
+
it 'creates a project using a template' do
expect { post api('/projects', user), params: { template_name: 'rails', name: 'rails-test' } }
.to change { Project.count }.by(1)
@@ -1560,6 +1569,18 @@ RSpec.describe API::Projects do
expect(json_response['error']).to eq('name is missing')
end
+ it 'sets container_registry_enabled' do
+ project = attributes_for(:project).tap do |attrs|
+ attrs[:container_registry_enabled] = true
+ end
+
+ post api("/projects/user/#{user.id}", admin), params: project
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['container_registry_enabled']).to eq(true)
+ expect(Project.find_by(path: project[:path]).container_registry_access_level).to eq(ProjectFeature::ENABLED)
+ end
+
it 'assigns attributes to project' do
project = attributes_for(:project, {
issues_enabled: false,
@@ -3050,6 +3071,16 @@ RSpec.describe API::Projects do
expect(Project.find_by(path: project[:path]).container_registry_access_level).to eq(ProjectFeature::PRIVATE)
end
+ it 'sets container_registry_enabled' do
+ project.project_feature.update!(container_registry_access_level: ProjectFeature::DISABLED)
+
+ put(api("/projects/#{project.id}", user), params: { container_registry_enabled: true })
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['container_registry_enabled']).to eq(true)
+ expect(project.reload.container_registry_access_level).to eq(ProjectFeature::ENABLED)
+ end
+
it 'returns 400 when nothing sent' do
project_param = {}
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 00de1ef5964..d31f571e636 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -3,18 +3,22 @@
require 'spec_helper'
RSpec.describe API::Todos do
+ include DesignManagementTestHelpers
+
let_it_be(:group) { create(:group) }
let_it_be(:project_1) { create(:project, :repository, group: group) }
let_it_be(:project_2) { create(:project) }
let_it_be(:author_1) { create(:user) }
let_it_be(:author_2) { create(:user) }
let_it_be(:john_doe) { create(:user, username: 'john_doe') }
+ let_it_be(:issue) { create(:issue, project: project_1) }
let_it_be(:merge_request) { create(:merge_request, source_project: project_1) }
let_it_be(:merge_request_todo) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) }
- let_it_be(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) }
- let_it_be(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) }
+ let_it_be(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe, target: issue) }
+ let_it_be(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe, target: issue) }
let_it_be(:pending_3) { create(:on_commit_todo, project: project_1, author: author_2, user: john_doe) }
- let_it_be(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) }
+ let_it_be(:pending_4) { create(:on_commit_todo, project: project_1, author: author_2, user: john_doe, commit_id: 'invalid_id') }
+ let_it_be(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe, target: issue) }
let_it_be(:award_emoji_1) { create(:award_emoji, awardable: merge_request, user: author_1, name: 'thumbsup') }
let_it_be(:award_emoji_2) { create(:award_emoji, awardable: pending_1.target, user: author_1, name: 'thumbsup') }
let_it_be(:award_emoji_3) { create(:award_emoji, awardable: pending_2.target, user: author_2, name: 'thumbsdown') }
@@ -77,13 +81,13 @@ RSpec.describe API::Todos do
expect(json_response[0]['target_type']).to eq('Commit')
expect(json_response[1]['target_type']).to eq('Issue')
- expect(json_response[1]['target']['upvotes']).to eq(0)
+ expect(json_response[1]['target']['upvotes']).to eq(1)
expect(json_response[1]['target']['downvotes']).to eq(1)
expect(json_response[1]['target']['merge_requests_count']).to eq(0)
expect(json_response[2]['target_type']).to eq('Issue')
expect(json_response[2]['target']['upvotes']).to eq(1)
- expect(json_response[2]['target']['downvotes']).to eq(0)
+ expect(json_response[2]['target']['downvotes']).to eq(1)
expect(json_response[2]['target']['merge_requests_count']).to eq(0)
expect(json_response[3]['target_type']).to eq('MergeRequest')
@@ -93,6 +97,19 @@ RSpec.describe API::Todos do
expect(json_response[3]['target']['downvotes']).to eq(0)
end
+ context "when current user does not have access to one of the TODO's target" do
+ it 'filters out unauthorized todos' do
+ no_access_project = create(:project, :repository, group: group)
+ no_access_merge_request = create(:merge_request, source_project: no_access_project)
+ no_access_todo = create(:todo, project: no_access_project, author: author_2, user: john_doe, target: no_access_merge_request)
+
+ get api('/todos', john_doe)
+
+ expect(json_response.count).to eq(4)
+ expect(json_response.map { |t| t['id'] }).not_to include(no_access_todo.id, pending_4.id)
+ end
+ end
+
context 'and using the author filter' do
it 'filters based on author_id param' do
get api('/todos', john_doe), params: { author_id: author_2.id }
@@ -163,23 +180,31 @@ RSpec.describe API::Todos do
end
it 'avoids N+1 queries', :request_store do
+ create_issue_todo_for(john_doe)
create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request)
get api('/todos', john_doe)
- control = ActiveRecord::QueryRecorder.new { get api('/todos', john_doe) }
+ control1 = ActiveRecord::QueryRecorder.new { get api('/todos', john_doe) }
+
+ create_issue_todo_for(john_doe)
+ create_mr_todo_for(john_doe, project_2)
+ create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe, target: merge_request)
+ new_todo = create_mr_todo_for(john_doe)
+ merge_request_3 = create(:merge_request, :jira_branch, source_project: new_todo.project)
+ create(:on_commit_todo, project: new_todo.project, author: author_1, user: john_doe, target: merge_request_3)
+ create(:todo, project: new_todo.project, author: author_2, user: john_doe, target: merge_request_3)
- merge_request_2 = create(:merge_request, source_project: project_2)
- create(:todo, project: project_2, author: author_2, user: john_doe, target: merge_request_2)
+ expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control1).with_threshold(4)
+ control2 = ActiveRecord::QueryRecorder.new { get api('/todos', john_doe) }
- project_3 = create(:project, :repository)
- project_3.add_developer(john_doe)
- merge_request_3 = create(:merge_request, source_project: project_3)
- create(:todo, project: project_3, author: author_2, user: john_doe, target: merge_request_3)
- create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe)
- create(:on_commit_todo, project: project_3, author: author_1, user: john_doe)
+ create_issue_todo_for(john_doe)
+ create_issue_todo_for(john_doe, project_1)
+ create_issue_todo_for(john_doe, project_1)
+
+ # Additional query only when target belongs to project from different group
+ expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control2).with_threshold(1)
- expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control)
expect(response).to have_gitlab_http_status(:ok)
end
@@ -201,6 +226,8 @@ RSpec.describe API::Todos do
end
before do
+ enable_design_management
+
api_request
end
@@ -222,6 +249,20 @@ RSpec.describe API::Todos do
)
end
end
+
+ def create_mr_todo_for(user, project = nil)
+ new_project = project || create(:project, group: create(:group))
+ new_project.add_developer(user) if project.blank?
+ new_merge_request = create(:merge_request, source_project: new_project)
+ create(:todo, project: new_project, author: user, user: user, target: new_merge_request)
+ end
+
+ def create_issue_todo_for(user, project = nil)
+ new_project = project || create(:project, group: create(:group))
+ new_project.group.add_developer(user) if project.blank?
+ issue = create(:issue, project: new_project)
+ create(:todo, project: new_project, target: issue, author: user, user: user)
+ end
end
describe 'POST /todos/:id/mark_as_done' do
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 2a91dae32b8..e4a0c034b20 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -706,6 +706,32 @@ RSpec.describe 'Git HTTP requests' do
end
end
end
+
+ context 'when token is impersonated' do
+ context 'when impersonation is off' do
+ before do
+ stub_config_setting(impersonation_enabled: false)
+ end
+
+ it 'responds to uploads with status 401 unauthorized' do
+ write_access_token = create(:personal_access_token, :impersonation, user: user, scopes: [:write_repository])
+
+ upload(path, user: user.username, password: write_access_token.token) do |response|
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+ end
+
+ context 'when impersonation is on' do
+ it 'responds to uploads with status 200' do
+ write_access_token = create(:personal_access_token, :impersonation, user: user, scopes: [:write_repository])
+
+ upload(path, user: user.username, password: write_access_token.token) do |response|
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
index 30028a1f1aa..35b21477d80 100644
--- a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
+++ b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
@@ -222,7 +222,7 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do
include_examples 'does not set any flags as used', 'field :solution'
include_examples 'does not set any flags as used', 'field :runners, Types::Ci::RunnerType.connection_type'
include_examples 'does not set any flags as used', 'field :runners, Types::Ci::RunnerType.connection_type, null: true, description: "hello world"'
- include_examples 'does not set any flags as used', 'field :solution, type: GraphQL::STRING_TYPE, null: true, description: "URL to the vulnerabilitys details page."'
+ include_examples 'does not set any flags as used', 'field :solution, type: GraphQL::Types::String, null: true, description: "URL to the vulnerabilitys details page."'
end
describe "tracking of usage data metrics known events happens at the beginning of inspection" do
diff --git a/spec/rubocop/cop/graphql/descriptions_spec.rb b/spec/rubocop/cop/graphql/descriptions_spec.rb
index 9709a253bdc..f11b5346843 100644
--- a/spec/rubocop/cop/graphql/descriptions_spec.rb
+++ b/spec/rubocop/cop/graphql/descriptions_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ Please add a `description` property.
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false
end
end
@@ -26,7 +26,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: 'A descriptive description'
end
@@ -39,7 +39,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: 'A descriptive description.'
end
@@ -65,7 +65,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
class FakeType < BaseObject
argument :a_thing,
^^^^^^^^^^^^^^^^^^ Please add a `description` property.
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false
end
end
@@ -78,7 +78,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
class FakeType < BaseObject
argument :a_thing,
^^^^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: 'Behold! A description'
end
@@ -91,7 +91,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
argument :a_thing,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: 'Behold! A description.'
end
@@ -151,7 +151,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: 'Behold! A description'
end
@@ -162,7 +162,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: 'Behold! A description.'
end
@@ -176,7 +176,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
class FakeType < BaseObject
field :a_thing,
^^^^^^^^^^^^^^^ `description` strings must end with a `.`.
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: <<~DESC
Behold! A description
@@ -189,7 +189,7 @@ RSpec.describe RuboCop::Cop::Graphql::Descriptions do
module Types
class FakeType < BaseObject
field :a_thing,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
null: false,
description: <<~DESC
Behold! A description.
diff --git a/spec/rubocop/cop/graphql/id_type_spec.rb b/spec/rubocop/cop/graphql/id_type_spec.rb
index 771e4e32dd2..d71031c6e1a 100644
--- a/spec/rubocop/cop/graphql/id_type_spec.rb
+++ b/spec/rubocop/cop/graphql/id_type_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe RuboCop::Cop::Graphql::IDType do
end
end
- it 'does not add an offense for calls to #argument without GraphQL::ID_TYPE' do
+ it 'does not add an offense for calls to #argument without GraphQL::Types::ID' do
expect_no_offenses(<<~TYPE.strip)
argument :some_arg, ::Types::GlobalIDType[::Awardable], some: other, params: do_not_matter
TYPE
diff --git a/spec/rubocop/cop/graphql/json_type_spec.rb b/spec/rubocop/cop/graphql/json_type_spec.rb
index 50437953c1d..882e2b2ef88 100644
--- a/spec/rubocop/cop/graphql/json_type_spec.rb
+++ b/spec/rubocop/cop/graphql/json_type_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe RuboCop::Cop::Graphql::JSONType do
it 'does not add an offense for other types' do
expect_no_offenses(<<~RUBY.strip)
class MyType
- field :some_field, GraphQL::STRING_TYPE
+ field :some_field, GraphQL::Types::String
end
RUBY
end
@@ -60,7 +60,7 @@ RSpec.describe RuboCop::Cop::Graphql::JSONType do
it 'does not add an offense for other types' do
expect_no_offenses(<<~RUBY.strip)
class MyType
- argument :some_arg, GraphQL::STRING_TYPE
+ argument :some_arg, GraphQL::Types::String
end
RUBY
end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 74e3b7cbca1..3b164f66b59 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1209,6 +1209,73 @@ RSpec.describe Ci::CreatePipelineService do
end
end
+ context 'when pipeline is running for a nonexistant-branch' do
+ let(:gitlab_ci_yaml) { YAML.dump(test: { script: 'test' }) }
+
+ let(:ref_name) { 'refs/heads/nonexistant-branch' }
+
+ let(:pipeline) { execute_service.payload }
+
+ it 'does not create the pipeline' do
+ expect(pipeline).not_to be_created_successfully
+ expect(pipeline.errors[:base]).to eq(['Reference not found'])
+ end
+
+ context 'when there is a tag with that nonexistant-branch' do
+ # v1.0.0 is on the test repo as a tag
+ let(:ref_name) { 'refs/heads/v1.0.0' }
+
+ it 'does not create the pipeline' do
+ expect(pipeline).not_to be_created_successfully
+ expect(pipeline.errors[:base]).to eq(['Reference not found'])
+ end
+ end
+ end
+
+ context 'when pipeline is running for a branch with the name of both a branch and a tag' do
+ let(:gitlab_ci_yaml) { YAML.dump(test: { script: 'test' }) }
+
+ # v1.1.0 is on the test repo as branch and tag
+ let(:ref_name) { 'refs/heads/v1.1.0' }
+
+ let(:pipeline) { execute_service.payload }
+
+ it 'creates the pipeline for the branch' do
+ expect(pipeline).to be_created_successfully
+ expect(pipeline.branch?).to be true
+ expect(pipeline.tag?).to be false
+ end
+ end
+
+ context 'when pipeline is running for a tag with the name of both a branch and a tag' do
+ let(:gitlab_ci_yaml) { YAML.dump(test: { script: 'test' }) }
+
+ # v1.1.0 is on the test repo as branch and tag
+ let(:ref_name) { 'refs/tags/v1.1.0' }
+
+ let(:pipeline) { execute_service.payload }
+
+ it 'creates the pipeline for the tag' do
+ expect(pipeline).to be_created_successfully
+ expect(pipeline.branch?).to be false
+ expect(pipeline.tag?).to be true
+ end
+ end
+
+ context 'when pipeline is running for an ambiguous ref' do
+ let(:gitlab_ci_yaml) { YAML.dump(test: { script: 'test' }) }
+
+ # v1.1.0 is on the test repo as branch and tag
+ let(:ref_name) { 'v1.1.0' }
+
+ let(:pipeline) { execute_service.payload }
+
+ it 'does not create the pipeline' do
+ expect(pipeline).not_to be_created_successfully
+ expect(pipeline.errors[:base]).to eq(['Ref is ambiguous'])
+ end
+ end
+
context 'when pipeline variables are specified' do
let(:variables_attributes) do
[{ key: 'first', secret_value: 'world' },
diff --git a/spec/services/git/process_ref_changes_service_spec.rb b/spec/services/git/process_ref_changes_service_spec.rb
index 087f4ba372b..ac9bac4e6ad 100644
--- a/spec/services/git/process_ref_changes_service_spec.rb
+++ b/spec/services/git/process_ref_changes_service_spec.rb
@@ -109,9 +109,13 @@ RSpec.describe Git::ProcessRefChangesService do
.to receive(:commit)
.and_return(project.commit)
- allow_any_instance_of(Repository)
- .to receive(:branch_exists?)
- .and_return(true)
+ if changes_method == :branch_changes
+ allow_any_instance_of(Repository).to receive(:branch_exists?) { true }
+ end
+
+ if changes_method == :tag_changes
+ allow_any_instance_of(Repository).to receive(:tag_exists?) { true }
+ end
end
context 'when git_push_create_all_pipelines is disabled' do
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index b073ffd291f..0e2b3b957a5 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -226,6 +226,27 @@ RSpec.describe Issues::CreateService do
end
end
+ context 'when sentry identifier is given' do
+ before do
+ sentry_attributes = { sentry_issue_attributes: { sentry_issue_identifier: 42 } }
+ opts.merge!(sentry_attributes)
+ end
+
+ it 'does not assign the sentry error' do
+ expect(issue.sentry_issue).to eq(nil)
+ end
+
+ context 'user is reporter or above' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'assigns the sentry error' do
+ expect(issue.sentry_issue).to be_kind_of(SentryIssue)
+ end
+ end
+ end
+
it 'executes issue hooks when issue is not confidential' do
opts = { title: 'Title', description: 'Description', confidential: false }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 70c3c2a0f5d..1e922401028 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -82,6 +82,31 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.milestone).to eq milestone
end
+ context 'when sentry identifier is given' do
+ before do
+ sentry_attributes = { sentry_issue_attributes: { sentry_issue_identifier: 42 } }
+ opts.merge!(sentry_attributes)
+ end
+
+ it 'assigns the sentry error' do
+ update_issue(opts)
+
+ expect(issue.sentry_issue).to be_kind_of(SentryIssue)
+ end
+
+ context 'user is a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'does not assign the sentry error' do
+ update_issue(opts)
+
+ expect(issue.sentry_issue).to eq(nil)
+ end
+ end
+ end
+
context 'when issue type is not incident' do
before do
update_issue(opts)
diff --git a/spec/services/todos/allowed_target_filter_service_spec.rb b/spec/services/todos/allowed_target_filter_service_spec.rb
new file mode 100644
index 00000000000..707df8e8514
--- /dev/null
+++ b/spec/services/todos/allowed_target_filter_service_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Todos::AllowedTargetFilterService do
+ include DesignManagementTestHelpers
+
+ let_it_be(:authorized_group) { create(:group, :private) }
+ let_it_be(:authorized_project) { create(:project, group: authorized_group) }
+ let_it_be(:unauthorized_group) { create(:group, :private) }
+ let_it_be(:unauthorized_project) { create(:project, group: unauthorized_group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:authorized_issue) { create(:issue, project: authorized_project) }
+ let_it_be(:authorized_issue_todo) { create(:todo, project: authorized_project, target: authorized_issue, user: user) }
+ let_it_be(:unauthorized_issue) { create(:issue, project: unauthorized_project) }
+ let_it_be(:unauthorized_issue_todo) { create(:todo, project: unauthorized_project, target: unauthorized_issue, user: user) }
+ let_it_be(:authorized_design) { create(:design, issue: authorized_issue) }
+ let_it_be(:authorized_design_todo) { create(:todo, project: authorized_project, target: authorized_design, user: user) }
+ let_it_be(:unauthorized_design) { create(:design, issue: unauthorized_issue) }
+ let_it_be(:unauthorized_design_todo) { create(:todo, project: unauthorized_project, target: unauthorized_design, user: user) }
+
+ # Cannot use let_it_be with MRs
+ let(:authorized_mr) { create(:merge_request, source_project: authorized_project) }
+ let(:authorized_mr_todo) { create(:todo, project: authorized_project, user: user, target: authorized_mr) }
+ let(:unauthorized_mr) { create(:merge_request, source_project: unauthorized_project) }
+ let(:unauthorized_mr_todo) { create(:todo, project: unauthorized_project, user: user, target: unauthorized_mr) }
+
+ before_all do
+ authorized_group.add_developer(user)
+ end
+
+ describe '#execute' do
+ subject(:execute_service) { described_class.new(all_todos, user).execute }
+
+ let!(:all_todos) { authorized_todos + unauthorized_todos }
+
+ let(:authorized_todos) do
+ [
+ authorized_mr_todo,
+ authorized_issue_todo,
+ authorized_design_todo
+ ]
+ end
+
+ let(:unauthorized_todos) do
+ [
+ unauthorized_mr_todo,
+ unauthorized_issue_todo,
+ unauthorized_design_todo
+ ]
+ end
+
+ before do
+ enable_design_management
+ end
+
+ it { is_expected.to match_array(authorized_todos) }
+ end
+end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 38cf828ca5e..6f17d3cb496 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -654,7 +654,7 @@ module GraphqlHelpers
Class.new(Types::BaseObject) do
graphql_name 'TestType'
- field :name, GraphQL::STRING_TYPE, null: true
+ field :name, GraphQL::Types::String, null: true
yield(self) if block_given?
end
diff --git a/spec/tooling/graphql/docs/renderer_spec.rb b/spec/tooling/graphql/docs/renderer_spec.rb
index 50ebb754ca4..de5ec928921 100644
--- a/spec/tooling/graphql/docs/renderer_spec.rb
+++ b/spec/tooling/graphql/docs/renderer_spec.rb
@@ -14,13 +14,13 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
let(:template) { Rails.root.join('tooling/graphql/docs/templates/default.md.haml') }
let(:field_description) { 'List of objects.' }
- let(:type) { ::GraphQL::INT_TYPE }
+ let(:type) { ::GraphQL::Types::Int }
let(:query_type) do
Class.new(Types::BaseObject) { graphql_name 'Query' }.tap do |t|
# this keeps type and field_description in scope.
t.field :foo, type, null: true, description: field_description do
- argument :id, GraphQL::ID_TYPE, required: false, description: 'ID of the object.'
+ argument :id, GraphQL::Types::ID, required: false, description: 'ID of the object.'
end
end
end
@@ -73,7 +73,7 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
Class.new(Types::BaseObject) do
graphql_name 'ArrayTest'
- field :foo, [GraphQL::STRING_TYPE], null: false, description: 'A description.'
+ field :foo, [GraphQL::Types::String], null: false, description: 'A description.'
end
end
@@ -129,8 +129,8 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
Class.new(Types::BaseObject) do
graphql_name 'OrderingTest'
- field :foo, GraphQL::STRING_TYPE, null: false, description: 'A description of foo field.'
- field :bar, GraphQL::STRING_TYPE, null: false, description: 'A description of bar field.'
+ field :foo, GraphQL::Types::String, null: false, description: 'A description of foo field.'
+ field :bar, GraphQL::Types::String, null: false, description: 'A description of bar field.'
end
end
@@ -154,7 +154,7 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
let(:type) do
wibble = Class.new(::Types::BaseObject) do
graphql_name 'Wibble'
- field :x, ::GraphQL::INT_TYPE, null: false
+ field :x, ::GraphQL::Types::Int, null: false
end
Class.new(Types::BaseObject) do
@@ -162,16 +162,16 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
description 'Testing doc refs'
field :foo,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: false,
description: 'The foo.',
see: { 'A list of foos' => 'https://example.com/foos' }
field :bar,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: false,
description: 'The bar.',
see: { 'A list of bars' => 'https://example.com/bars' } do
- argument :barity, ::GraphQL::INT_TYPE, required: false, description: '?'
+ argument :barity, ::GraphQL::Types::Int, required: false, description: '?'
end
field :wibbles,
type: wibble.connection_type,
@@ -220,10 +220,10 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
description 'A thing we used to use, but no longer support'
field :foo,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: false,
description: 'A description.' do
- argument :foo_arg, GraphQL::STRING_TYPE,
+ argument :foo_arg, GraphQL::Types::String,
required: false,
description: 'The argument.',
deprecated: { reason: 'Bad argument', milestone: '101.2' }
@@ -257,19 +257,19 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
description 'A thing we used to use, but no longer support'
field :foo,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: false,
deprecated: { reason: 'This is deprecated', milestone: '1.10' },
description: 'A description.'
field :foo_with_args,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: false,
deprecated: { reason: 'Do not use', milestone: '1.10', replacement: 'X.y' },
description: 'A description.' do
- argument :arg, GraphQL::INT_TYPE, required: false, description: 'Argity'
+ argument :arg, GraphQL::Types::Int, required: false, description: 'Argity'
end
field :bar,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: false,
description: 'A description.',
deprecated: {
@@ -328,7 +328,7 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
)
end
- let(:type) { ::GraphQL::INT_TYPE }
+ let(:type) { ::GraphQL::Types::Int }
let(:section) do
<<~DOC
### `Query.bar`
@@ -453,12 +453,12 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
}
mutation.field :everything,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: true,
description: 'What we made prettier.'
mutation.field :omnis,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
null: true,
description: 'What we made prettier.',
deprecated: {
@@ -516,7 +516,7 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
let(:type) do
Class.new(::Types::BaseObject) do
graphql_name 'Foo'
- field :wibble, type: ::GraphQL::INT_TYPE, null: true do
+ field :wibble, type: ::GraphQL::Types::Int, null: true do
argument :date_range,
type: ::Types::TimeframeInputType,
required: true,
@@ -547,10 +547,10 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
let(:type) do
user = Class.new(::Types::BaseObject)
user.graphql_name 'User'
- user.field :user_field, ::GraphQL::STRING_TYPE, null: true
+ user.field :user_field, ::GraphQL::Types::String, null: true
group = Class.new(::Types::BaseObject)
group.graphql_name 'Group'
- group.field :group_field, ::GraphQL::STRING_TYPE, null: true
+ group.field :group_field, ::GraphQL::Types::String, null: true
union = Class.new(::Types::BaseUnion)
union.graphql_name 'UserOrGroup'
@@ -561,7 +561,7 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do
interface.include(::Types::BaseInterface)
interface.graphql_name 'Flying'
interface.description 'Something that can fly.'
- interface.field :flight_speed, GraphQL::INT_TYPE, null: true, description: 'Speed in mph.'
+ interface.field :flight_speed, GraphQL::Types::Int, null: true, description: 'Speed in mph.'
african_swallow = Class.new(::Types::BaseObject)
african_swallow.graphql_name 'AfricanSwallow'