summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorYorick Peterse <yorick@yorickpeterse.com>2019-10-30 15:22:45 +0100
committerYorick Peterse <yorick@yorickpeterse.com>2019-10-30 15:22:45 +0100
commitad8eea383406037a207c80421e6e4bfa357f8044 (patch)
tree396b89ad72b9d7e35fab26c6ee22c978a12defbb /spec
parent228d752ff09362002cc904d28edee7d63cc3cef2 (diff)
parentb0f939a79fe16ff760d6e589c8f9cd71c0fa1da7 (diff)
downloadgitlab-ce-ad8eea383406037a207c80421e6e4bfa357f8044.tar.gz
Merge dev.gitlab.org@master into GitLab.com@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/application_controller_spec.rb2
-rw-r--r--spec/controllers/concerns/internal_redirect_spec.rb3
-rw-r--r--spec/controllers/concerns/lfs_request_spec.rb43
-rw-r--r--spec/controllers/projects/autocomplete_sources_controller_spec.rb35
-rw-r--r--spec/controllers/projects/commits_controller_spec.rb4
-rw-r--r--spec/controllers/projects/error_tracking_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb4
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb2
-rw-r--r--spec/controllers/projects_controller_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb5
-rw-r--r--spec/features/projects/tags/user_views_tags_spec.rb2
-rw-r--r--spec/finders/labels_finder_spec.rb83
-rw-r--r--spec/fixtures/api/graphql/recursive-introspection.graphql57
-rw-r--r--spec/fixtures/api/graphql/recursive-query.graphql47
-rw-r--r--spec/fixtures/api/graphql/small-recursive-introspection.graphql15
-rw-r--r--spec/frontend/project_find_file_spec.js37
-rw-r--r--spec/helpers/markup_helper_spec.rb78
-rw-r--r--spec/models/milestone_spec.rb8
-rw-r--r--spec/models/note_spec.rb77
-rw-r--r--spec/models/project_spec.rb12
-rw-r--r--spec/models/wiki_page_spec.rb17
-rw-r--r--spec/policies/commit_policy_spec.rb48
-rw-r--r--spec/policies/group_policy_spec.rb82
-rw-r--r--spec/policies/namespace_policy_spec.rb3
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb48
-rw-r--r--spec/requests/api/merge_requests_spec.rb32
-rw-r--r--spec/requests/api/projects_spec.rb16
-rw-r--r--spec/services/auto_merge/base_service_spec.rb3
-rw-r--r--spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb7
-rw-r--r--spec/services/concerns/merge_requests/assigns_merge_params_spec.rb70
-rw-r--r--spec/services/error_tracking/list_projects_service_spec.rb13
-rw-r--r--spec/services/merge_requests/build_service_spec.rb3
-rw-r--r--spec/services/merge_requests/update_service_spec.rb24
-rw-r--r--spec/services/projects/operations/update_service_spec.rb21
-rw-r--r--spec/services/projects/participants_service_spec.rb104
-rw-r--r--spec/services/projects/transfer_service_spec.rb18
-rw-r--r--spec/support/controllers/sessionless_auth_controller_shared_examples.rb22
-rw-r--r--spec/support/helpers/graphql_helpers.rb22
-rw-r--r--spec/support/shared_examples/controllers/todos_shared_examples.rb2
39 files changed, 959 insertions, 114 deletions
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 94afe741057..bb7f5ec2b28 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -186,7 +186,7 @@ describe ApplicationController do
expect(response).to have_gitlab_http_status(404)
end
- it 'redirects to login page via authenticate_user! if not authenticated' do
+ it 'redirects to login page if not authenticated' do
get :index
expect(response).to redirect_to new_user_session_path
diff --git a/spec/controllers/concerns/internal_redirect_spec.rb b/spec/controllers/concerns/internal_redirect_spec.rb
index da68c8c8697..e5e50cfd55e 100644
--- a/spec/controllers/concerns/internal_redirect_spec.rb
+++ b/spec/controllers/concerns/internal_redirect_spec.rb
@@ -19,7 +19,8 @@ describe InternalRedirect do
[
'Hello world',
'//example.com/hello/world',
- 'https://example.com/hello/world'
+ 'https://example.com/hello/world',
+ "not-starting-with-a-slash\n/starting/with/slash"
]
end
diff --git a/spec/controllers/concerns/lfs_request_spec.rb b/spec/controllers/concerns/lfs_request_spec.rb
index cb8c0b8f71c..823b9a50434 100644
--- a/spec/controllers/concerns/lfs_request_spec.rb
+++ b/spec/controllers/concerns/lfs_request_spec.rb
@@ -16,13 +16,17 @@ describe LfsRequest do
end
def project
- @project ||= Project.find(params[:id])
+ @project ||= Project.find_by(id: params[:id])
end
def download_request?
true
end
+ def upload_request?
+ false
+ end
+
def ci?
false
end
@@ -49,4 +53,41 @@ describe LfsRequest do
expect(assigns(:storage_project)).to eq(project)
end
end
+
+ context 'user is authenticated without access to lfs' do
+ before do
+ allow(controller).to receive(:authenticate_user)
+ allow(controller).to receive(:authentication_result) do
+ Gitlab::Auth::Result.new
+ end
+ end
+
+ context 'with access to the project' do
+ it 'returns 403' do
+ get :show, params: { id: project.id }
+
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'without access to the project' do
+ context 'project does not exist' do
+ it 'returns 404' do
+ get :show, params: { id: 'does not exist' }
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'project is private' do
+ let(:project) { create(:project, :private) }
+
+ it 'returns 404' do
+ get :show, params: { id: project.id }
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+ end
end
diff --git a/spec/controllers/projects/autocomplete_sources_controller_spec.rb b/spec/controllers/projects/autocomplete_sources_controller_spec.rb
index 34765ae3951..fc8fe1ac4f6 100644
--- a/spec/controllers/projects/autocomplete_sources_controller_spec.rb
+++ b/spec/controllers/projects/autocomplete_sources_controller_spec.rb
@@ -8,6 +8,10 @@ describe Projects::AutocompleteSourcesController do
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
+ def members_by_username(username)
+ json_response.find { |member| member['username'] == username }
+ end
+
describe 'GET members' do
before do
group.add_owner(user)
@@ -17,22 +21,21 @@ describe Projects::AutocompleteSourcesController do
it 'returns an array of member object' do
get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id }
- all = json_response.find {|member| member["username"] == 'all'}
- the_group = json_response.find {|member| member["username"] == group.full_path}
- the_user = json_response.find {|member| member["username"] == user.username}
-
- expect(all.symbolize_keys).to include(username: 'all',
- name: 'All Project and Group Members',
- count: 1)
-
- expect(the_group.symbolize_keys).to include(type: group.class.name,
- name: group.full_name,
- avatar_url: group.avatar_url,
- count: 1)
-
- expect(the_user.symbolize_keys).to include(type: user.class.name,
- name: user.name,
- avatar_url: user.avatar_url)
+ expect(members_by_username('all').symbolize_keys).to include(
+ username: 'all',
+ name: 'All Project and Group Members',
+ count: 1)
+
+ expect(members_by_username(group.full_path).symbolize_keys).to include(
+ type: group.class.name,
+ name: group.full_name,
+ avatar_url: group.avatar_url,
+ count: 1)
+
+ expect(members_by_username(user.username).symbolize_keys).to include(
+ type: user.class.name,
+ name: user.name,
+ avatar_url: user.avatar_url)
end
end
diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb
index 9c4d6fdcb2a..1977e92e42b 100644
--- a/spec/controllers/projects/commits_controller_spec.rb
+++ b/spec/controllers/projects/commits_controller_spec.rb
@@ -142,7 +142,7 @@ describe Projects::CommitsController do
context 'token authentication' do
context 'public project' do
- it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do
+ it_behaves_like 'authenticates sessionless user', :show, :atom, { public: true, ignore_incrementing: true } do
before do
public_project = create(:project, :repository, :public)
@@ -152,7 +152,7 @@ describe Projects::CommitsController do
end
context 'private project' do
- it_behaves_like 'authenticates sessionless user', :show, :atom, public: false do
+ it_behaves_like 'authenticates sessionless user', :show, :atom, { public: false, ignore_incrementing: true } do
before do
private_project = create(:project, :repository, :private)
private_project.add_maintainer(user)
diff --git a/spec/controllers/projects/error_tracking_controller_spec.rb b/spec/controllers/projects/error_tracking_controller_spec.rb
index 4c224e960a6..31868f5f717 100644
--- a/spec/controllers/projects/error_tracking_controller_spec.rb
+++ b/spec/controllers/projects/error_tracking_controller_spec.rb
@@ -146,7 +146,7 @@ describe Projects::ErrorTrackingController do
it 'redirects to sign-in page' do
post :list_projects, params: list_projects_params
- expect(response).to have_gitlab_http_status(:unauthorized)
+ expect(response).to have_gitlab_http_status(:redirect)
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 4c2b58551bf..8770a5ee303 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1441,7 +1441,7 @@ describe Projects::IssuesController do
context 'private project with token authentication' do
let(:private_project) { create(:project, :private) }
- it_behaves_like 'authenticates sessionless user', :index, :atom do
+ it_behaves_like 'authenticates sessionless user', :index, :atom, ignore_incrementing: true do
before do
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
@@ -1449,7 +1449,7 @@ describe Projects::IssuesController do
end
end
- it_behaves_like 'authenticates sessionless user', :calendar, :ics do
+ it_behaves_like 'authenticates sessionless user', :calendar, :ics, ignore_incrementing: true do
before do
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index b99b5d611fc..f077b4c99fc 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -41,7 +41,7 @@ describe Projects::TagsController do
context 'private project with token authentication' do
let(:private_project) { create(:project, :repository, :private) }
- it_behaves_like 'authenticates sessionless user', :index, :atom do
+ it_behaves_like 'authenticates sessionless user', :index, :atom, ignore_incrementing: true do
before do
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 321f5ecdbc9..22538565698 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -1149,7 +1149,7 @@ describe ProjectsController do
context 'private project with token authentication' do
let(:private_project) { create(:project, :private) }
- it_behaves_like 'authenticates sessionless user', :show, :atom do
+ it_behaves_like 'authenticates sessionless user', :show, :atom, ignore_incrementing: true do
before do
default_params.merge!(id: private_project, namespace_id: private_project.namespace)
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index a9a127da56f..f6eeb8d7065 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -819,7 +819,10 @@ describe 'Pipelines', :js do
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
- it { expect(page).to have_content 'You need to sign in' }
+ it 'redirects the user to sign_in and displays the flash alert' do
+ expect(page).to have_content 'You need to sign in'
+ expect(page.current_path).to eq("/users/sign_in")
+ end
end
end
diff --git a/spec/features/projects/tags/user_views_tags_spec.rb b/spec/features/projects/tags/user_views_tags_spec.rb
index f344b682715..bc570f502bf 100644
--- a/spec/features/projects/tags/user_views_tags_spec.rb
+++ b/spec/features/projects/tags/user_views_tags_spec.rb
@@ -15,7 +15,7 @@ describe 'User views tags', :feature do
it do
visit project_tags_path(project, format: :atom)
- expect(page).to have_gitlab_http_status(401)
+ expect(page.current_path).to eq("/users/sign_in")
end
end
diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb
index 2681f098fec..7590c399cf9 100644
--- a/spec/finders/labels_finder_spec.rb
+++ b/spec/finders/labels_finder_spec.rb
@@ -128,6 +128,89 @@ describe LabelsFinder do
expect(finder.execute).to eq [private_subgroup_label_1]
end
end
+
+ context 'when including labels from group projects with limited visibility' do
+ let(:finder) { described_class.new(user, group_id: group_4.id) }
+ let(:group_4) { create(:group) }
+ let(:limited_visibility_project) { create(:project, :public, group: group_4) }
+ let(:visible_project) { create(:project, :public, group: group_4) }
+ let!(:group_label_1) { create(:group_label, group: group_4) }
+ let!(:limited_visibility_label) { create(:label, project: limited_visibility_project) }
+ let!(:visible_label) { create(:label, project: visible_project) }
+
+ shared_examples 'with full visibility' do
+ it 'returns all projects labels' do
+ expect(finder.execute).to eq [group_label_1, limited_visibility_label, visible_label]
+ end
+ end
+
+ shared_examples 'with limited visibility' do
+ it 'returns only authorized projects labels' do
+ expect(finder.execute).to eq [group_label_1, visible_label]
+ end
+ end
+
+ context 'when merge requests and issues are not visible for non members' do
+ before do
+ limited_visibility_project.project_feature.update!(
+ merge_requests_access_level: ProjectFeature::PRIVATE,
+ issues_access_level: ProjectFeature::PRIVATE
+ )
+ end
+
+ context 'when user is not a group member' do
+ it_behaves_like 'with limited visibility'
+ end
+
+ context 'when user is a group member' do
+ before do
+ group_4.add_developer(user)
+ end
+
+ it_behaves_like 'with full visibility'
+ end
+ end
+
+ context 'when merge requests are not visible for non members' do
+ before do
+ limited_visibility_project.project_feature.update!(
+ merge_requests_access_level: ProjectFeature::PRIVATE
+ )
+ end
+
+ context 'when user is not a group member' do
+ it_behaves_like 'with full visibility'
+ end
+
+ context 'when user is a group member' do
+ before do
+ group_4.add_developer(user)
+ end
+
+ it_behaves_like 'with full visibility'
+ end
+ end
+
+ context 'when issues are not visible for non members' do
+ before do
+ limited_visibility_project.project_feature.update!(
+ issues_access_level: ProjectFeature::PRIVATE
+ )
+ end
+
+ context 'when user is not a group member' do
+ it_behaves_like 'with full visibility'
+ end
+
+ context 'when user is a group member' do
+ before do
+ group_4.add_developer(user)
+ end
+
+ it_behaves_like 'with full visibility'
+ end
+ end
+ end
end
context 'filtering by project_id' do
diff --git a/spec/fixtures/api/graphql/recursive-introspection.graphql b/spec/fixtures/api/graphql/recursive-introspection.graphql
new file mode 100644
index 00000000000..db970bb14b6
--- /dev/null
+++ b/spec/fixtures/api/graphql/recursive-introspection.graphql
@@ -0,0 +1,57 @@
+query allSchemaTypes {
+ __schema {
+ types {
+ fields {
+ type{
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ type {
+ fields {
+ name
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/spec/fixtures/api/graphql/recursive-query.graphql b/spec/fixtures/api/graphql/recursive-query.graphql
new file mode 100644
index 00000000000..d1616c4de6e
--- /dev/null
+++ b/spec/fixtures/api/graphql/recursive-query.graphql
@@ -0,0 +1,47 @@
+{
+ project(fullPath: "gitlab-org/gitlab-ce") {
+ group {
+ projects {
+ edges {
+ node {
+ group {
+ projects {
+ edges {
+ node {
+ group {
+ projects {
+ edges {
+ node {
+ group {
+ projects {
+ edges {
+ node {
+ group {
+ projects {
+ edges {
+ node {
+ group {
+ description
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/spec/fixtures/api/graphql/small-recursive-introspection.graphql b/spec/fixtures/api/graphql/small-recursive-introspection.graphql
new file mode 100644
index 00000000000..1025043b474
--- /dev/null
+++ b/spec/fixtures/api/graphql/small-recursive-introspection.graphql
@@ -0,0 +1,15 @@
+query allSchemaTypes {
+ __schema {
+ types {
+ fields {
+ type {
+ fields {
+ type {
+ name
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/spec/frontend/project_find_file_spec.js b/spec/frontend/project_find_file_spec.js
index 8102033139f..e60f9f62747 100644
--- a/spec/frontend/project_find_file_spec.js
+++ b/spec/frontend/project_find_file_spec.js
@@ -3,6 +3,9 @@ import $ from 'jquery';
import ProjectFindFile from '~/project_find_file';
import axios from '~/lib/utils/axios_utils';
import { TEST_HOST } from 'helpers/test_constants';
+import sanitize from 'sanitize-html';
+
+jest.mock('sanitize-html', () => jest.fn(val => val));
const BLOB_URL_TEMPLATE = `${TEST_HOST}/namespace/project/blob/master`;
const FILE_FIND_URL = `${TEST_HOST}/namespace/project/files/master?format=json`;
@@ -38,31 +41,31 @@ describe('ProjectFindFile', () => {
href: el.querySelector('a').href,
}));
+ const files = [
+ 'fileA.txt',
+ 'fileB.txt',
+ 'fi#leC.txt',
+ 'folderA/fileD.txt',
+ 'folder#B/fileE.txt',
+ 'folde?rC/fil#F.txt',
+ ];
+
beforeEach(() => {
// Create a mock adapter for stubbing axios API requests
mock = new MockAdapter(axios);
element = $(TEMPLATE);
+ mock.onGet(FILE_FIND_URL).replyOnce(200, files);
+ getProjectFindFileInstance(); // This triggers a load / axios call + subsequent render in the constructor
});
afterEach(() => {
// Reset the mock adapter
mock.restore();
+ sanitize.mockClear();
});
it('loads and renders elements from remote server', done => {
- const files = [
- 'fileA.txt',
- 'fileB.txt',
- 'fi#leC.txt',
- 'folderA/fileD.txt',
- 'folder#B/fileE.txt',
- 'folde?rC/fil#F.txt',
- ];
- mock.onGet(FILE_FIND_URL).replyOnce(200, files);
-
- getProjectFindFileInstance(); // This triggers a load / axios call + subsequent render in the constructor
-
setImmediate(() => {
expect(findFiles()).toEqual(
files.map(text => ({
@@ -74,4 +77,14 @@ describe('ProjectFindFile', () => {
done();
});
});
+
+ it('sanitizes search text', done => {
+ const searchText = element.find('.file-finder-input').val();
+
+ setImmediate(() => {
+ expect(sanitize).toHaveBeenCalledTimes(1);
+ expect(sanitize).toHaveBeenCalledWith(searchText);
+ done();
+ });
+ });
});
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 364f215420a..32851249b2e 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -3,18 +3,18 @@
require 'spec_helper'
describe MarkupHelper do
- let!(:project) { create(:project, :repository) }
-
- let(:user) { create(:user, username: 'gfm') }
- let(:commit) { project.commit }
- let(:issue) { create(:issue, project: project) }
- let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
- let(:snippet) { create(:project_snippet, project: project) }
-
- before do
- # Ensure the generated reference links aren't redacted
+ set(:project) { create(:project, :repository) }
+ set(:user) do
+ user = create(:user, username: 'gfm')
project.add_maintainer(user)
+ user
+ end
+ set(:issue) { create(:issue, project: project) }
+ set(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+ set(:snippet) { create(:project_snippet, project: project) }
+ let(:commit) { project.commit }
+ before do
# Helper expects a @project instance variable
helper.instance_variable_set(:@project, project)
@@ -44,8 +44,8 @@ describe MarkupHelper do
describe "override default project" do
let(:actual) { issue.to_reference }
- let(:second_project) { create(:project, :public) }
- let(:second_issue) { create(:issue, project: second_project) }
+ set(:second_project) { create(:project, :public) }
+ set(:second_issue) { create(:issue, project: second_project) }
it 'links to the issue' do
expected = urls.project_issue_path(second_project, second_issue)
@@ -55,7 +55,7 @@ describe MarkupHelper do
describe 'uploads' do
let(:text) { "![ImageTest](/uploads/test.png)" }
- let(:group) { create(:group) }
+ set(:group) { create(:group) }
subject { helper.markdown(text) }
@@ -77,7 +77,7 @@ describe MarkupHelper do
end
describe "with a group in the context" do
- let(:project_in_group) { create(:project, group: group) }
+ set(:project_in_group) { create(:project, group: group) }
before do
helper.instance_variable_set(:@group, group)
@@ -235,38 +235,48 @@ describe MarkupHelper do
end
describe '#render_wiki_content' do
+ let(:wiki) { double('WikiPage', path: "file.#{extension}") }
+ let(:context) do
+ {
+ pipeline: :wiki, project: project, project_wiki: wiki,
+ page_slug: 'nested/page', issuable_state_filter_enabled: true
+ }
+ end
+
before do
- @wiki = double('WikiPage')
- allow(@wiki).to receive(:content).and_return('wiki content')
- allow(@wiki).to receive(:slug).and_return('nested/page')
- helper.instance_variable_set(:@project_wiki, @wiki)
+ expect(wiki).to receive(:content).and_return('wiki content')
+ expect(wiki).to receive(:slug).and_return('nested/page')
+ helper.instance_variable_set(:@project_wiki, wiki)
end
- it "uses Wiki pipeline for markdown files" do
- allow(@wiki).to receive(:format).and_return(:markdown)
+ context 'when file is Markdown' do
+ let(:extension) { 'md' }
- expect(helper).to receive(:markdown_unsafe).with('wiki content',
- pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page",
- issuable_state_filter_enabled: true)
+ it 'renders using #markdown_unsafe helper method' do
+ expect(helper).to receive(:markdown_unsafe).with('wiki content', context)
- helper.render_wiki_content(@wiki)
+ helper.render_wiki_content(wiki)
+ end
end
- it "uses Asciidoctor for asciidoc files" do
- allow(@wiki).to receive(:format).and_return(:asciidoc)
+ context 'when file is Asciidoc' do
+ let(:extension) { 'adoc' }
- expect(helper).to receive(:asciidoc_unsafe).with('wiki content')
+ it 'renders using Gitlab::Asciidoc' do
+ expect(Gitlab::Asciidoc).to receive(:render)
- helper.render_wiki_content(@wiki)
+ helper.render_wiki_content(wiki)
+ end
end
- it "uses the Gollum renderer for all other file types" do
- allow(@wiki).to receive(:format).and_return(:rdoc)
- formatted_content_stub = double('formatted_content')
- expect(formatted_content_stub).to receive(:html_safe)
- allow(@wiki).to receive(:formatted_content).and_return(formatted_content_stub)
+ context 'any other format' do
+ let(:extension) { 'foo' }
- helper.render_wiki_content(@wiki)
+ it 'renders all other formats using Gitlab::OtherMarkup' do
+ expect(Gitlab::OtherMarkup).to receive(:render)
+
+ helper.render_wiki_content(wiki)
+ end
end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 2ecbe548520..120ba67f328 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -227,6 +227,14 @@ describe Milestone do
end
end
+ describe '#to_ability_name' do
+ it 'returns milestone' do
+ milestone = build(:milestone)
+
+ expect(milestone.to_ability_name).to eq('milestone')
+ end
+ end
+
describe '.search' do
let(:milestone) { create(:milestone, title: 'foo', description: 'bar') }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 4c320b4b145..3ab88b52568 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -379,6 +379,63 @@ describe Note do
expect(label_note.cross_reference?).to be_falsy
end
end
+
+ context 'when system note metadata is not present' do
+ let(:note) { build(:note, :system) }
+
+ before do
+ allow(note).to receive(:system_note_metadata).and_return(nil)
+ end
+
+ it 'delegates to the system note service' do
+ expect(SystemNotes::IssuablesService).to receive(:cross_reference?).with(note.note)
+
+ note.cross_reference?
+ end
+ end
+
+ context 'with a system note' do
+ let(:issue) { create(:issue, project: create(:project, :repository)) }
+ let(:note) { create(:system_note, note: "test", noteable: issue, project: issue.project) }
+
+ shared_examples 'system_note_metadata includes note action' do
+ it 'delegates to the cross-reference regex' do
+ expect(note).to receive(:matches_cross_reference_regex?)
+
+ note.cross_reference?
+ end
+ end
+
+ context 'with :label action' do
+ let!(:metadata) {create(:system_note_metadata, note: note, action: :label)}
+
+ it_behaves_like 'system_note_metadata includes note action'
+
+ it { expect(note.cross_reference?).to be_falsy }
+
+ context 'with cross reference label note' do
+ let(:label) { create(:label, project: issue.project)}
+ let(:note) { create(:system_note, note: "added #{label.to_reference} label", noteable: issue, project: issue.project) }
+
+ it { expect(note.cross_reference?).to be_truthy }
+ end
+ end
+
+ context 'with :milestone action' do
+ let!(:metadata) {create(:system_note_metadata, note: note, action: :milestone)}
+
+ it_behaves_like 'system_note_metadata includes note action'
+
+ it { expect(note.cross_reference?).to be_falsy }
+
+ context 'with cross reference milestone note' do
+ let(:milestone) { create(:milestone, project: issue.project)}
+ let(:note) { create(:system_note, note: "added #{milestone.to_reference} milestone", noteable: issue, project: issue.project) }
+
+ it { expect(note.cross_reference?).to be_truthy }
+ end
+ end
+ end
end
describe 'clear_blank_line_code!' do
@@ -578,24 +635,30 @@ describe Note do
end
describe '#to_ability_name' do
- it 'returns snippet for a project snippet note' do
- expect(build(:note_on_project_snippet).to_ability_name).to eq('project_snippet')
+ it 'returns note' do
+ expect(build(:note).to_ability_name).to eq('note')
+ end
+ end
+
+ describe '#noteable_ability_name' do
+ it 'returns project_snippet for a project snippet note' do
+ expect(build(:note_on_project_snippet).noteable_ability_name).to eq('project_snippet')
end
it 'returns personal_snippet for a personal snippet note' do
- expect(build(:note_on_personal_snippet).to_ability_name).to eq('personal_snippet')
+ expect(build(:note_on_personal_snippet).noteable_ability_name).to eq('personal_snippet')
end
it 'returns merge_request for an MR note' do
- expect(build(:note_on_merge_request).to_ability_name).to eq('merge_request')
+ expect(build(:note_on_merge_request).noteable_ability_name).to eq('merge_request')
end
it 'returns issue for an issue note' do
- expect(build(:note_on_issue).to_ability_name).to eq('issue')
+ expect(build(:note_on_issue).noteable_ability_name).to eq('issue')
end
- it 'returns issue for a commit note' do
- expect(build(:note_on_commit).to_ability_name).to eq('commit')
+ it 'returns commit for a commit note' do
+ expect(build(:note_on_commit).noteable_ability_name).to eq('commit')
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 5922a6f36f5..71b999048b4 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3416,7 +3416,7 @@ describe Project do
end
end
- describe '.ids_with_milestone_available_for' do
+ describe '.ids_with_issuables_available_for' do
let!(:user) { create(:user) }
it 'returns project ids with milestones available for user' do
@@ -3426,7 +3426,7 @@ describe Project do
project_4 = create(:project, :public)
project_4.project_feature.update(issues_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE )
- project_ids = described_class.ids_with_milestone_available_for(user).pluck(:id)
+ project_ids = described_class.ids_with_issuables_available_for(user).pluck(:id)
expect(project_ids).to include(project_2.id, project_3.id)
expect(project_ids).not_to include(project_1.id, project_4.id)
@@ -4444,6 +4444,14 @@ describe Project do
end
end
+ describe '#to_ability_name' do
+ it 'returns project' do
+ project = build(:project_empty_repo)
+
+ expect(project.to_ability_name).to eq('project')
+ end
+ end
+
describe '#execute_hooks' do
let(:data) { { ref: 'refs/heads/master', data: 'data' } }
it 'executes active projects hooks with the specified scope' do
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 8f3730f97ac..38415613b9e 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -358,6 +358,23 @@ describe WikiPage do
end
end
+ describe '#path' do
+ let(:path) { 'mypath.md' }
+ let(:wiki_page) { instance_double('Gitlab::Git::WikiPage', path: path).as_null_object }
+
+ it 'returns the path when persisted' do
+ page = described_class.new(wiki, wiki_page, true)
+
+ expect(page.path).to eq(path)
+ end
+
+ it 'returns nil when not persisted' do
+ page = described_class.new(wiki, wiki_page, false)
+
+ expect(page.path).to be_nil
+ end
+ end
+
describe '#directory' do
context 'when the page is at the root directory' do
it 'returns an empty string' do
diff --git a/spec/policies/commit_policy_spec.rb b/spec/policies/commit_policy_spec.rb
index 41f6fb08426..40183f51e9e 100644
--- a/spec/policies/commit_policy_spec.rb
+++ b/spec/policies/commit_policy_spec.rb
@@ -8,28 +8,42 @@ describe CommitPolicy do
let(:commit) { project.repository.head_commit }
let(:policy) { described_class.new(user, commit) }
+ shared_examples 'can read commit and create a note' do
+ it 'can read commit' do
+ expect(policy).to be_allowed(:read_commit)
+ end
+
+ it 'can create a note' do
+ expect(policy).to be_allowed(:create_note)
+ end
+ end
+
+ shared_examples 'cannot read commit nor create a note' do
+ it 'can not read commit' do
+ expect(policy).to be_disallowed(:read_commit)
+ end
+
+ it 'can not create a note' do
+ expect(policy).to be_disallowed(:create_note)
+ end
+ end
+
context 'when project is public' do
let(:project) { create(:project, :public, :repository) }
- it 'can read commit and create a note' do
- expect(policy).to be_allowed(:read_commit)
- end
+ it_behaves_like 'can read commit and create a note'
context 'when repository access level is private' do
let(:project) { create(:project, :public, :repository, :repository_private) }
- it 'can not read commit and create a note' do
- expect(policy).to be_disallowed(:read_commit)
- end
+ it_behaves_like 'cannot read commit nor create a note'
context 'when the user is a project member' do
before do
project.add_developer(user)
end
- it 'can read commit and create a note' do
- expect(policy).to be_allowed(:read_commit)
- end
+ it_behaves_like 'can read commit and create a note'
end
end
end
@@ -37,9 +51,7 @@ describe CommitPolicy do
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
- it 'can not read commit and create a note' do
- expect(policy).to be_disallowed(:read_commit)
- end
+ it_behaves_like 'cannot read commit nor create a note'
context 'when the user is a project member' do
before do
@@ -50,6 +62,18 @@ describe CommitPolicy do
expect(policy).to be_allowed(:read_commit)
end
end
+
+ context 'when the user is a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it_behaves_like 'cannot read commit nor create a note'
+
+ it 'cannot download code' do
+ expect(policy).to be_disallowed(:download_code)
+ end
+ end
end
end
end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 9634a591592..ae9d125f970 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -356,6 +356,88 @@ describe GroupPolicy do
end
end
+ context 'transfer_projects' do
+ shared_examples_for 'allowed to transfer projects' do
+ before do
+ group.update(project_creation_level: project_creation_level)
+ end
+
+ it { is_expected.to be_allowed(:transfer_projects) }
+ end
+
+ shared_examples_for 'not allowed to transfer projects' do
+ before do
+ group.update(project_creation_level: project_creation_level)
+ end
+
+ it { is_expected.to be_disallowed(:transfer_projects) }
+ end
+
+ context 'reporter' do
+ let(:current_user) { reporter }
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::NO_ONE_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS }
+ end
+ end
+
+ context 'developer' do
+ let(:current_user) { developer }
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::NO_ONE_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS }
+ end
+ end
+
+ context 'maintainer' do
+ let(:current_user) { maintainer }
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::NO_ONE_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS }
+ end
+ end
+
+ context 'owner' do
+ let(:current_user) { owner }
+
+ it_behaves_like 'not allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::NO_ONE_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS }
+ end
+
+ it_behaves_like 'allowed to transfer projects' do
+ let(:project_creation_level) { ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS }
+ end
+ end
+ end
+
context "create_projects" do
context 'when group has no project creation level set' do
before_all do
diff --git a/spec/policies/namespace_policy_spec.rb b/spec/policies/namespace_policy_spec.rb
index ece0519112a..c0a5119c550 100644
--- a/spec/policies/namespace_policy_spec.rb
+++ b/spec/policies/namespace_policy_spec.rb
@@ -8,7 +8,7 @@ describe NamespacePolicy do
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, owner: owner) }
- let(:owner_permissions) { [:create_projects, :admin_namespace, :read_namespace, :read_statistics] }
+ let(:owner_permissions) { [:create_projects, :admin_namespace, :read_namespace, :read_statistics, :transfer_projects] }
subject { described_class.new(current_user, namespace) }
@@ -33,6 +33,7 @@ describe NamespacePolicy do
let(:owner) { create(:user, projects_limit: 0) }
it { is_expected.to be_disallowed(:create_projects) }
+ it { is_expected.to be_disallowed(:transfer_projects) }
end
end
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index d02eccedf32..2aeb75a10b4 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -15,7 +15,7 @@ describe 'GitlabSchema configurations' do
subject
- expect(graphql_errors.flatten.first['message']).to include('which exceeds max complexity of 1')
+ expect_graphql_errors_to_include /which exceeds max complexity of 1/
end
end
end
@@ -23,12 +23,11 @@ describe 'GitlabSchema configurations' do
describe '#max_depth' do
context 'when query depth is too high' do
it 'shows error' do
- errors = { "message" => "Query has depth of 2, which exceeds max depth of 1" }
allow(GitlabSchema).to receive(:max_query_depth).and_return 1
subject
- expect(graphql_errors.flatten).to include(errors)
+ expect_graphql_errors_to_include /exceeds max depth/
end
end
@@ -38,7 +37,42 @@ describe 'GitlabSchema configurations' do
subject
- expect(Array.wrap(graphql_errors).compact).to be_empty
+ expect_graphql_errors_to_be_empty
+ end
+ end
+ end
+ end
+
+ context 'depth, complexity and recursion checking' do
+ context 'unauthenticated recursive queries' do
+ context 'a not-quite-recursive-enough introspective query' do
+ it 'succeeds' do
+ query = File.read(Rails.root.join('spec/fixtures/api/graphql/small-recursive-introspection.graphql'))
+
+ post_graphql(query, current_user: nil)
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'a deep but simple recursive introspective query' do
+ it 'fails due to recursion' do
+ query = File.read(Rails.root.join('spec/fixtures/api/graphql/recursive-introspection.graphql'))
+
+ post_graphql(query, current_user: nil)
+
+ expect_graphql_errors_to_include [/Recursive query/]
+ end
+ end
+
+ context 'a deep recursive non-introspective query' do
+ it 'fails due to recursion, complexity and depth' do
+ allow(GitlabSchema).to receive(:max_query_complexity).and_return 1
+ query = File.read(Rails.root.join('spec/fixtures/api/graphql/recursive-query.graphql'))
+
+ post_graphql(query, current_user: nil)
+
+ expect_graphql_errors_to_include [/Recursive query/, /exceeds max complexity/, /exceeds max depth/]
end
end
end
@@ -88,7 +122,7 @@ describe 'GitlabSchema configurations' do
# Expect errors for each query
expect(graphql_errors.size).to eq(3)
graphql_errors.each do |single_query_errors|
- expect(single_query_errors.first['message']).to include('which exceeds max complexity of 4')
+ expect_graphql_errors_to_include(/which exceeds max complexity of 4/)
end
end
end
@@ -105,12 +139,12 @@ describe 'GitlabSchema configurations' do
end
context 'when IntrospectionQuery' do
- it 'is not too complex' do
+ it 'is not too complex nor recursive' do
query = File.read(Rails.root.join('spec/fixtures/api/graphql/introspection.graphql'))
post_graphql(query, current_user: nil)
- expect(graphql_errors).to be_nil
+ expect_graphql_errors_to_be_empty
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 8063004549e..c622add7f8f 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1741,6 +1741,38 @@ describe API::MergeRequests do
expect(json_response['state']).to eq('closed')
expect(json_response['force_remove_source_branch']).to be_truthy
end
+
+ context 'with a merge request across forks' do
+ let(:fork_owner) { create(:user) }
+ let(:source_project) { fork_project(project, fork_owner) }
+ let(:target_project) { project }
+
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ target_project: target_project,
+ source_branch: 'fixes',
+ merge_params: { 'force_remove_source_branch' => false })
+ end
+
+ it 'is true for an authorized user' do
+ put api("/projects/#{target_project.id}/merge_requests/#{merge_request.iid}", fork_owner), params: { state_event: 'close', remove_source_branch: true }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['state']).to eq('closed')
+ expect(json_response['force_remove_source_branch']).to be true
+ end
+
+ it 'is false for an unauthorized user' do
+ expect do
+ put api("/projects/#{target_project.id}/merge_requests/#{merge_request.iid}", target_project.owner), params: { state_event: 'close', remove_source_branch: true }
+ end.not_to change { merge_request.reload.merge_params }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['state']).to eq('closed')
+ expect(json_response['force_remove_source_branch']).to be false
+ end
+ end
end
context "to close a MR" do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 585bf57fa4c..ffac7872464 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -2684,6 +2684,22 @@ describe API::Projects do
expect(response).to have_gitlab_http_status(400)
end
end
+
+ context 'when authenticated as developer' do
+ before do
+ group.add_developer(user)
+ end
+
+ context 'target namespace allows developers to create projects' do
+ let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
+
+ it 'fails transferring the project to the target namespace' do
+ put api("/projects/#{project.id}/transfer", user), params: { namespace: group.id }
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+ end
end
it_behaves_like 'custom attributes endpoints', 'projects' do
diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb
index a409f21a7e4..0a6bcb1badc 100644
--- a/spec/services/auto_merge/base_service_spec.rb
+++ b/spec/services/auto_merge/base_service_spec.rb
@@ -51,7 +51,7 @@ describe AutoMerge::BaseService do
expect(merge_request.merge_params['commit_message']).to eq("Merge branch 'patch-12' into 'master'")
expect(merge_request.merge_params['sha']).to eq('200fcc9c260f7219eaf0daba87d818f0922c5b18')
expect(merge_request.merge_params['should_remove_source_branch']).to eq(false)
- expect(merge_request.merge_params['squash']).to eq(false)
+ expect(merge_request.squash).to eq(false)
expect(merge_request.merge_params['squash_commit_message']).to eq('Update README.md')
end
end
@@ -108,7 +108,6 @@ describe AutoMerge::BaseService do
'commit_message' => "Merge branch 'patch-12' into 'master'",
'sha' => "200fcc9c260f7219eaf0daba87d818f0922c5b18",
'should_remove_source_branch' => false,
- 'squash' => false,
'squash_commit_message' => "Update README.md"
}
end
diff --git a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
index c396539cf56..1bebeacb4d4 100644
--- a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
+++ b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
@@ -59,8 +59,9 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do
it 'sets the params, merge_user, and flag' do
expect(merge_request).to be_valid
expect(merge_request.merge_when_pipeline_succeeds).to be_truthy
- expect(merge_request.merge_params).to include commit_message: 'Awesome message'
+ expect(merge_request.merge_params).to include 'commit_message' => 'Awesome message'
expect(merge_request.merge_user).to be user
+ expect(merge_request.auto_merge_strategy).to eq AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS
end
it 'creates a system note' do
@@ -73,7 +74,7 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do
end
context 'already approved' do
- let(:service) { described_class.new(project, user, new_key: true) }
+ let(:service) { described_class.new(project, user, should_remove_source_branch: true) }
let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) }
before do
@@ -90,7 +91,7 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do
expect(SystemNoteService).not_to receive(:merge_when_pipeline_succeeds)
service.execute(mr_merge_if_green_enabled)
- expect(mr_merge_if_green_enabled.merge_params).to have_key(:new_key)
+ expect(mr_merge_if_green_enabled.merge_params).to have_key('should_remove_source_branch')
end
end
end
diff --git a/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb b/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb
new file mode 100644
index 00000000000..5b653aa331c
--- /dev/null
+++ b/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb
@@ -0,0 +1,70 @@
+require 'spec_helper'
+
+describe MergeRequests::AssignsMergeParams do
+ it 'raises an error when used from an instance that does not respond to #current_user' do
+ define_class = -> { Class.new { include MergeRequests::AssignsMergeParams }.new }
+
+ expect { define_class.call }.to raise_error %r{can not be included in (.*) without implementing #current_user}
+ end
+
+ describe '#assign_allowed_merge_params' do
+ let(:merge_request) { build(:merge_request) }
+
+ let(:params) do
+ { commit_message: 'Commit Message',
+ 'should_remove_source_branch' => true,
+ unknown_symbol: 'Unknown symbol',
+ 'unknown_string' => 'Unknown String' }
+ end
+
+ subject(:merge_request_service) do
+ Class.new do
+ attr_accessor :current_user
+
+ include MergeRequests::AssignsMergeParams
+
+ def initialize(user)
+ @current_user = user
+ end
+ end
+ end
+
+ it 'only assigns known parameters to the merge request' do
+ service = merge_request_service.new(merge_request.author)
+
+ service.assign_allowed_merge_params(merge_request, params)
+
+ expect(merge_request.merge_params).to eq('commit_message' => 'Commit Message', 'should_remove_source_branch' => true)
+ end
+
+ it 'returns a hash without the known merge params' do
+ service = merge_request_service.new(merge_request.author)
+
+ result = service.assign_allowed_merge_params(merge_request, params)
+
+ expect(result).to eq({ 'unknown_symbol' => 'Unknown symbol', 'unknown_string' => 'Unknown String' })
+ end
+
+ context 'the force_remove_source_branch param' do
+ let(:params) { { force_remove_source_branch: true } }
+
+ it 'assigns the param if the user is allowed to do that' do
+ service = merge_request_service.new(merge_request.author)
+
+ result = service.assign_allowed_merge_params(merge_request, params)
+
+ expect(merge_request.force_remove_source_branch?).to be true
+ expect(result).to be_empty
+ end
+
+ it 'only removes the param if the user is not allowed to do that' do
+ service = merge_request_service.new(build(:user))
+
+ result = service.assign_allowed_merge_params(merge_request, params)
+
+ expect(merge_request.force_remove_source_branch?).to be_falsy
+ expect(result).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/services/error_tracking/list_projects_service_spec.rb b/spec/services/error_tracking/list_projects_service_spec.rb
index 730fccc599e..a272a604184 100644
--- a/spec/services/error_tracking/list_projects_service_spec.rb
+++ b/spec/services/error_tracking/list_projects_service_spec.rb
@@ -50,6 +50,19 @@ describe ErrorTracking::ListProjectsService do
end
end
+ context 'masked param token' do
+ let(:params) { ActionController::Parameters.new(token: "*********", api_host: new_api_host) }
+
+ before do
+ expect(error_tracking_setting).to receive(:list_sentry_projects)
+ .and_return({ projects: [] })
+ end
+
+ it 'uses database token' do
+ expect { subject.execute }.not_to change { error_tracking_setting.token }
+ end
+ end
+
context 'sentry client raises exception' do
context 'Sentry::Client::Error' do
before do
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 46e86d5b4cb..9b358839c06 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -83,8 +83,9 @@ describe MergeRequests::BuildService do
expect(merge_request.force_remove_source_branch?).to be_truthy
end
- context 'with force_remove_source_branch parameter' do
+ context 'with force_remove_source_branch parameter when the user is authorized' do
let(:mr_params) { params.merge(force_remove_source_branch: '1') }
+ let(:source_project) { fork_project(project, user) }
let(:merge_request) { described_class.new(project, user, mr_params).execute }
it 'assigns force_remove_source_branch' do
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 8c796475de0..741420d76a7 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -646,5 +646,29 @@ describe MergeRequests::UpdateService, :mailer do
expect(merge_request.allow_collaboration).to be_truthy
end
end
+
+ context 'updating `force_remove_source_branch`' do
+ let(:target_project) { create(:project, :repository, :public) }
+ let(:source_project) { fork_project(target_project, nil, repository: true) }
+ let(:user) { target_project.owner }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ source_branch: 'fixes',
+ target_project: target_project)
+ end
+
+ it "cannot be done by members of the target project when they don't have access" do
+ expect { update_merge_request(force_remove_source_branch: true) }
+ .not_to change { merge_request.reload.force_remove_source_branch? }.from(nil)
+ end
+
+ it 'can be done by members of the target project if they can push to the source project' do
+ source_project.add_developer(user)
+
+ expect { update_merge_request(force_remove_source_branch: true) }
+ .to change { merge_request.reload.force_remove_source_branch? }.from(nil).to(true)
+ end
+ end
end
end
diff --git a/spec/services/projects/operations/update_service_spec.rb b/spec/services/projects/operations/update_service_spec.rb
index b2f9fd6df79..81d59a98b9b 100644
--- a/spec/services/projects/operations/update_service_spec.rb
+++ b/spec/services/projects/operations/update_service_spec.rb
@@ -145,6 +145,27 @@ describe Projects::Operations::UpdateService do
end
end
+ context 'with masked param token' do
+ let(:params) do
+ {
+ error_tracking_setting_attributes: {
+ enabled: false,
+ token: '*' * 8
+ }
+ }
+ end
+
+ before do
+ create(:project_error_tracking_setting, project: project, token: 'token')
+ end
+
+ it 'does not update token' do
+ expect(result[:status]).to eq(:success)
+
+ expect(project.error_tracking_setting.token).to eq('token')
+ end
+ end
+
context 'with invalid parameters' do
let(:params) { {} }
diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb
index 4def83513a4..239d28557ee 100644
--- a/spec/services/projects/participants_service_spec.rb
+++ b/spec/services/projects/participants_service_spec.rb
@@ -57,4 +57,108 @@ describe Projects::ParticipantsService do
end
end
end
+
+ describe '#project_members' do
+ subject(:usernames) { service.project_members.map { |member| member[:username] } }
+
+ context 'when there is a project in group namespace' do
+ set(:public_group) { create(:group, :public) }
+ set(:public_project) { create(:project, :public, namespace: public_group)}
+
+ set(:public_group_owner) { create(:user) }
+
+ let(:service) { described_class.new(public_project, create(:user)) }
+
+ before do
+ public_group.add_owner(public_group_owner)
+ end
+
+ it 'returns members of a group' do
+ expect(usernames).to include(public_group_owner.username)
+ end
+ end
+
+ context 'when there is a private group and a public project' do
+ set(:public_group) { create(:group, :public) }
+ set(:private_group) { create(:group, :private, :nested) }
+ set(:public_project) { create(:project, :public, namespace: public_group)}
+
+ set(:project_issue) { create(:issue, project: public_project)}
+
+ set(:public_group_owner) { create(:user) }
+ set(:private_group_member) { create(:user) }
+ set(:public_project_maintainer) { create(:user) }
+ set(:private_group_owner) { create(:user) }
+
+ set(:group_ancestor_owner) { create(:user) }
+
+ before(:context) do
+ public_group.add_owner public_group_owner
+ private_group.add_developer private_group_member
+ public_project.add_maintainer public_project_maintainer
+
+ private_group.add_owner private_group_owner
+ private_group.parent.add_owner group_ancestor_owner
+ end
+
+ context 'when the private group is invited to the public project' do
+ before(:context) do
+ create(:project_group_link, group: private_group, project: public_project)
+ end
+
+ context 'when a user who is outside the public project and the private group is signed in' do
+ let(:service) { described_class.new(public_project, create(:user)) }
+
+ it 'does not return the private group' do
+ expect(usernames).not_to include(private_group.name)
+ end
+
+ it 'does not return private group members' do
+ expect(usernames).not_to include(private_group_member.username)
+ end
+
+ it 'returns the project maintainer' do
+ expect(usernames).to include(public_project_maintainer.username)
+ end
+
+ it 'returns project members from an invited public group' do
+ invited_public_group = create(:group, :public)
+ invited_public_group.add_owner create(:user)
+
+ create(:project_group_link, group: invited_public_group, project: public_project)
+
+ expect(usernames).to include(invited_public_group.users.first.username)
+ end
+
+ it 'does not return ancestors of the private group' do
+ expect(usernames).not_to include(group_ancestor_owner.username)
+ end
+ end
+
+ context 'when private group owner is signed in' do
+ let(:service) { described_class.new(public_project, private_group_owner) }
+
+ it 'returns private group members' do
+ expect(usernames).to include(private_group_member.username)
+ end
+
+ it 'returns ancestors of the the private group' do
+ expect(usernames).to include(group_ancestor_owner.username)
+ end
+ end
+
+ context 'when the namespace owner of the public project is signed in' do
+ let(:service) { described_class.new(public_project, public_group_owner) }
+
+ it 'returns private group members' do
+ expect(usernames).to include(private_group_member.username)
+ end
+
+ it 'does not return members of the ancestral groups of the private group' do
+ expect(usernames).to include(group_ancestor_owner.username)
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 26d8ac9b479..298867f483b 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -222,6 +222,24 @@ describe Projects::TransferService do
it { expect(project.errors[:new_namespace]).to include('Project with same name or path in target namespace already exists') }
end
+ context 'target namespace allows developers to create projects' do
+ let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
+
+ context 'the user is a member of the target namespace with developer permissions' do
+ subject(:transfer_project_result) { transfer_project(project, user, group) }
+
+ before do
+ group.add_developer(user)
+ end
+
+ it 'does not allow project transfer to the target namespace' do
+ expect(transfer_project_result).to eq false
+ expect(project.namespace).to eq(user.namespace)
+ expect(project.errors[:new_namespace]).to include('Transfer failed, please contact an admin.')
+ end
+ end
+ end
+
def transfer_project(project, user, new_namespace)
service = Projects::TransferService.new(project, user)
diff --git a/spec/support/controllers/sessionless_auth_controller_shared_examples.rb b/spec/support/controllers/sessionless_auth_controller_shared_examples.rb
index b5149a0fcb1..bc95fcd6b88 100644
--- a/spec/support/controllers/sessionless_auth_controller_shared_examples.rb
+++ b/spec/support/controllers/sessionless_auth_controller_shared_examples.rb
@@ -34,8 +34,15 @@ shared_examples 'authenticates sessionless user' do |path, format, params|
context 'when the personal access token has no api scope', unless: params[:public] do
it 'does not log the user in' do
- expect(authentication_metrics)
- .to increment(:user_unauthenticated_counter)
+ # Several instances of where these specs are shared route the request
+ # through ApplicationController#route_not_found which does not involve
+ # the usual auth code from Devise, so does not increment the
+ # :user_unauthenticated_counter
+ #
+ unless params[:ignore_incrementing]
+ expect(authentication_metrics)
+ .to increment(:user_unauthenticated_counter)
+ end
personal_access_token.update(scopes: [:read_user])
@@ -84,8 +91,15 @@ shared_examples 'authenticates sessionless user' do |path, format, params|
end
it "doesn't log the user in otherwise", unless: params[:public] do
- expect(authentication_metrics)
- .to increment(:user_unauthenticated_counter)
+ # Several instances of where these specs are shared route the request
+ # through ApplicationController#route_not_found which does not involve
+ # the usual auth code from Devise, so does not increment the
+ # :user_unauthenticated_counter
+ #
+ unless params[:ignore_incrementing]
+ expect(authentication_metrics)
+ .to increment(:user_unauthenticated_counter)
+ end
get path, params: default_params.merge(private_token: 'token')
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 4d2ad165fd6..6fb1d279456 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -129,6 +129,7 @@ module GraphqlHelpers
allow_unlimited_graphql_complexity
allow_unlimited_graphql_depth
+ allow_high_graphql_recursion
type = GitlabSchema.types[class_name.to_s]
return "" unless type
@@ -213,6 +214,23 @@ module GraphqlHelpers
end
end
+ def expect_graphql_errors_to_include(regexes_to_match)
+ raise "No errors. Was expecting to match #{regexes_to_match}" if graphql_errors.nil? || graphql_errors.empty?
+
+ error_messages = flattened_errors.collect { |error_hash| error_hash["message"] }
+ Array.wrap(regexes_to_match).flatten.each do |regex|
+ expect(error_messages).to include a_string_matching regex
+ end
+ end
+
+ def expect_graphql_errors_to_be_empty
+ expect(flattened_errors).to be_empty
+ end
+
+ def flattened_errors
+ Array.wrap(graphql_errors).flatten.compact
+ end
+
# Raises an error if no response is found
def graphql_mutation_response(mutation_name)
graphql_data.fetch(GraphqlHelpers.fieldnamerize(mutation_name))
@@ -260,6 +278,10 @@ module GraphqlHelpers
allow_any_instance_of(GitlabSchema).to receive(:max_depth).and_return nil
allow(GitlabSchema).to receive(:max_query_depth).with(any_args).and_return nil
end
+
+ def allow_high_graphql_recursion
+ allow_any_instance_of(Gitlab::Graphql::QueryAnalyzers::RecursionAnalyzer).to receive(:recursion_threshold).and_return 1000
+ end
end
# This warms our schema, doing this as part of loading the helpers to avoid
diff --git a/spec/support/shared_examples/controllers/todos_shared_examples.rb b/spec/support/shared_examples/controllers/todos_shared_examples.rb
index f3f9abb7da2..914bf506320 100644
--- a/spec/support/shared_examples/controllers/todos_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/todos_shared_examples.rb
@@ -39,7 +39,7 @@ shared_examples 'todos actions' do
post_create
end.to change { user.todos.count }.by(0)
- expect(response).to have_gitlab_http_status(parent.is_a?(Group) ? 401 : 302)
+ expect(response).to have_gitlab_http_status(302)
end
end
end