Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGrzegorz Bizon <grzesiek.bizon@gmail.com>2016-03-19 20:50:15 +0300
committerGrzegorz Bizon <grzesiek.bizon@gmail.com>2016-03-19 20:50:15 +0300
commit0115ad66d264f4670f241251acd3e36991134576 (patch)
treee60e7773e909de64ccdeebd1cc97928d24073cd2 /spec
parent9b13ce0b7a50e65dfba31d4865a728c725daa3fe (diff)
parent4f0302f00ef0c51b67b73429ace0a632971b7f1b (diff)
Merge branch 'master' into feature/issue-move
* master: (121 commits) Dedupe labels in labels selector in Dashboard pages Refactor colors and lists Add a safeguard in MergeRequest#compute_diverged_commits_count Fix an issue when the target branch of a MR had been deleted Add avatar to issue and MR pages header Cleanup somce css colors Re-group scss variables Refactor `Todo#target` Fixes issue with filter label missing on labels & milestones Rename `Todo#to_reference` to `Todo#target_reference` Fixed failing tests Updated controller with before_action Fixed other issues based on feedback Fixes issue on dashboard issues Full labels data in JSON Fixed issue with labels dropdown getting wrong labels Update CHANGELOG Use `Note#for_project_snippet?` to skip notes on project snippet Use `Commit#short_id` instead of `Commit.truncate_sha` Reuse `for_commit?` on conditional validations Update schema info comment on todo related files ... Conflicts: app/models/issue.rb db/schema.rb spec/models/issue_spec.rb
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb96
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb162
-rw-r--r--spec/factories/issues.rb4
-rw-r--r--spec/factories/merge_requests.rb5
-rw-r--r--spec/factories/todos.rb10
-rw-r--r--spec/features/issues/new_branch_button_spec.rb49
-rw-r--r--spec/features/merge_requests/filter_by_milestone_spec.rb2
-rw-r--r--spec/features/security/project/internal_access_spec.rb57
-rw-r--r--spec/features/security/project/private_access_spec.rb52
-rw-r--r--spec/features/security/project/public_access_spec.rb41
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb72
-rw-r--r--spec/lib/ci/status_spec.rb23
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb1
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb14
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb69
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb2
-rw-r--r--spec/lib/gitlab/search_results_spec.rb91
-rw-r--r--spec/models/commit_spec.rb13
-rw-r--r--spec/models/concerns/mentionable_spec.rb5
-rw-r--r--spec/models/concerns/milestoneish_spec.rb104
-rw-r--r--spec/models/event_spec.rb36
-rw-r--r--spec/models/issue_spec.rb17
-rw-r--r--spec/models/merge_request_spec.rb48
-rw-r--r--spec/models/milestone_spec.rb20
-rw-r--r--spec/models/repository_spec.rb111
-rw-r--r--spec/models/todo_spec.rb85
-rw-r--r--spec/models/user_spec.rb15
-rw-r--r--spec/requests/api/issues_spec.rb112
-rw-r--r--spec/requests/api/users_spec.rb27
-rw-r--r--spec/services/git_push_service_spec.rb13
-rw-r--r--spec/services/projects/autocomplete_service_spec.rb79
-rw-r--r--spec/services/projects/housekeeping_service_spec.rb4
-rw-r--r--spec/services/system_note_service_spec.rb12
-rw-r--r--spec/services/todo_service_spec.rb9
-rw-r--r--spec/support/matchers/access_matchers.rb2
-rw-r--r--spec/support/mentionable_shared_examples.rb2
36 files changed, 1352 insertions, 112 deletions
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index 8e06d4bdc77..98ae424ed7c 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -17,49 +17,79 @@ describe Projects::BranchesController do
describe "POST create" do
render_views
- before do
- post :create,
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- branch_name: branch,
- ref: ref
- end
+ context "on creation of a new branch" do
+ before do
+ post :create,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: branch,
+ ref: ref
+ end
- context "valid branch name, valid source" do
- let(:branch) { "merge_branch" }
- let(:ref) { "master" }
- it 'redirects' do
- expect(subject).
- to redirect_to("/#{project.path_with_namespace}/tree/merge_branch")
+ context "valid branch name, valid source" do
+ let(:branch) { "merge_branch" }
+ let(:ref) { "master" }
+ it 'redirects' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/tree/merge_branch")
+ end
+ end
+
+ context "invalid branch name, valid ref" do
+ let(:branch) { "<script>alert('merge');</script>" }
+ let(:ref) { "master" }
+ it 'redirects' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');")
+ end
+ end
+
+ context "valid branch name, invalid ref" do
+ let(:branch) { "merge_branch" }
+ let(:ref) { "<script>alert('ref');</script>" }
+ it { is_expected.to render_template('new') }
+ end
+
+ context "invalid branch name, invalid ref" do
+ let(:branch) { "<script>alert('merge');</script>" }
+ let(:ref) { "<script>alert('ref');</script>" }
+ it { is_expected.to render_template('new') }
+ end
+
+ context "valid branch name with encoded slashes" do
+ let(:branch) { "feature%2Ftest" }
+ let(:ref) { "<script>alert('ref');</script>" }
+ it { is_expected.to render_template('new') }
+ it { project.repository.branch_names.include?('feature/test') }
end
end
- context "invalid branch name, valid ref" do
- let(:branch) { "<script>alert('merge');</script>" }
- let(:ref) { "master" }
+ describe "created from the new branch button on issues" do
+ let(:branch) { "1-feature-branch" }
+ let!(:issue) { create(:issue, project: project) }
+
+
it 'redirects' do
+ post :create,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: branch,
+ issue_iid: issue.iid
+
expect(subject).
- to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');")
+ to redirect_to("/#{project.path_with_namespace}/tree/1-feature-branch")
end
- end
- context "valid branch name, invalid ref" do
- let(:branch) { "merge_branch" }
- let(:ref) { "<script>alert('ref');</script>" }
- it { is_expected.to render_template('new') }
- end
+ it 'posts a system note' do
+ expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch")
- context "invalid branch name, invalid ref" do
- let(:branch) { "<script>alert('merge');</script>" }
- let(:ref) { "<script>alert('ref');</script>" }
- it { is_expected.to render_template('new') }
- end
+ post :create,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: branch,
+ issue_iid: issue.iid
+ end
- context "valid branch name with encoded slashes" do
- let(:branch) { "feature%2Ftest" }
- let(:ref) { "<script>alert('ref');</script>" }
- it { is_expected.to render_template('new') }
- it { project.repository.branch_names.include?('feature/test')}
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 76d56bc989d..2cd81231144 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1,16 +1,16 @@
require('spec_helper')
describe Projects::IssuesController do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
- let(:issue) { create(:issue, project: project) }
+ describe "GET #index" do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:issue) { create(:issue, project: project) }
- before do
- sign_in(user)
- project.team << [user, :developer]
- end
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
- describe "GET #index" do
it "returns index" do
get :index, namespace_id: project.namespace.path, project_id: project.path
@@ -38,6 +38,152 @@ describe Projects::IssuesController do
get :index, namespace_id: project.namespace.path, project_id: project.path
expect(response.status).to eq(404)
end
+ end
+
+ describe 'Confidential Issues' do
+ let(:project) { create(:empty_project, :public) }
+ let(:assignee) { create(:assignee) }
+ let(:author) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:member) { create(:user) }
+ let(:admin) { create(:admin) }
+ let!(:issue) { create(:issue, project: project) }
+ let!(:unescaped_parameter_value) { create(:issue, :confidential, project: project, author: author) }
+ let!(:request_forgery_timing_attack) { create(:issue, :confidential, project: project, assignee: assignee) }
+
+ describe 'GET #index' do
+ it 'should not list confidential issues for guests' do
+ sign_out(:user)
+ get_issues
+
+ expect(assigns(:issues)).to eq [issue]
+ end
+
+ it 'should not list confidential issues for non project members' do
+ sign_in(non_member)
+ get_issues
+
+ expect(assigns(:issues)).to eq [issue]
+ end
+
+ it 'should list confidential issues for author' do
+ sign_in(author)
+ get_issues
+
+ expect(assigns(:issues)).to include unescaped_parameter_value
+ expect(assigns(:issues)).not_to include request_forgery_timing_attack
+ end
+
+ it 'should list confidential issues for assignee' do
+ sign_in(assignee)
+ get_issues
+
+ expect(assigns(:issues)).not_to include unescaped_parameter_value
+ expect(assigns(:issues)).to include request_forgery_timing_attack
+ end
+
+ it 'should list confidential issues for project members' do
+ sign_in(member)
+ project.team << [member, :developer]
+
+ get_issues
+
+ expect(assigns(:issues)).to include unescaped_parameter_value
+ expect(assigns(:issues)).to include request_forgery_timing_attack
+ end
+
+ it 'should list confidential issues for admin' do
+ sign_in(admin)
+ get_issues
+
+ expect(assigns(:issues)).to include unescaped_parameter_value
+ expect(assigns(:issues)).to include request_forgery_timing_attack
+ end
+
+ def get_issues
+ get :index,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param
+ end
+ end
+ shared_examples_for 'restricted action' do |http_status|
+ it 'returns 404 for guests' do
+ sign_out :user
+ go(id: unescaped_parameter_value.to_param)
+
+ expect(response).to have_http_status :not_found
+ end
+
+ it 'returns 404 for non project members' do
+ sign_in(non_member)
+ go(id: unescaped_parameter_value.to_param)
+
+ expect(response).to have_http_status :not_found
+ end
+
+ it "returns #{http_status[:success]} for author" do
+ sign_in(author)
+ go(id: unescaped_parameter_value.to_param)
+
+ expect(response).to have_http_status http_status[:success]
+ end
+
+ it "returns #{http_status[:success]} for assignee" do
+ sign_in(assignee)
+ go(id: request_forgery_timing_attack.to_param)
+
+ expect(response).to have_http_status http_status[:success]
+ end
+
+ it "returns #{http_status[:success]} for project members" do
+ sign_in(member)
+ project.team << [member, :developer]
+ go(id: unescaped_parameter_value.to_param)
+
+ expect(response).to have_http_status http_status[:success]
+ end
+
+ it "returns #{http_status[:success]} for admin" do
+ sign_in(admin)
+ go(id: unescaped_parameter_value.to_param)
+
+ expect(response).to have_http_status http_status[:success]
+ end
+ end
+
+ describe 'GET #show' do
+ it_behaves_like 'restricted action', success: 200
+
+ def go(id:)
+ get :show,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: id
+ end
+ end
+
+ describe 'GET #edit' do
+ it_behaves_like 'restricted action', success: 200
+
+ def go(id:)
+ get :edit,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: id
+ end
+ end
+
+ describe 'PUT #update' do
+ it_behaves_like 'restricted action', success: 302
+
+ def go(id:)
+ put :update,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: id,
+ issue: { title: 'New title' }
+ end
+ end
end
end
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 722095de590..e72aa9479b7 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -4,6 +4,10 @@ FactoryGirl.define do
author
project
+ trait :confidential do
+ confidential true
+ end
+
trait :closed do
state :closed
end
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index a9df5fa1d3a..e281e2f227b 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -51,6 +51,11 @@ FactoryGirl.define do
trait :with_diffs do
end
+ trait :without_diffs do
+ source_branch "improve/awesome"
+ target_branch "master"
+ end
+
trait :conflict do
source_branch "feature_conflict"
target_branch "feature"
diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb
index bd85b1d798a..7ae06c27840 100644
--- a/spec/factories/todos.rb
+++ b/spec/factories/todos.rb
@@ -5,14 +5,15 @@
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
-# target_id :integer not null
+# target_id :integer
# target_type :string not null
# author_id :integer
-# note_id :integer
# action :integer not null
# state :string not null
# created_at :datetime
# updated_at :datetime
+# note_id :integer
+# commit_id :string
#
FactoryGirl.define do
@@ -30,5 +31,10 @@ FactoryGirl.define do
trait :mentioned do
action { Todo::MENTIONED }
end
+
+ trait :on_commit do
+ commit_id RepoHelpers.sample_commit.id
+ target_type "Commit"
+ end
end
end
diff --git a/spec/features/issues/new_branch_button_spec.rb b/spec/features/issues/new_branch_button_spec.rb
new file mode 100644
index 00000000000..9219b767547
--- /dev/null
+++ b/spec/features/issues/new_branch_button_spec.rb
@@ -0,0 +1,49 @@
+require 'rails_helper'
+
+feature 'Start new branch from an issue', feature: true do
+ let!(:project) { create(:project) }
+ let!(:issue) { create(:issue, project: project) }
+ let!(:user) { create(:user)}
+
+ context "for team members" do
+ before do
+ project.team << [user, :master]
+ login_as(user)
+ end
+
+ it 'shown the new branch button', js: false do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+
+ expect(page).to have_link "New Branch"
+ end
+
+ context "when there is a referenced merge request" do
+ let(:note) do
+ create(:note, :on_issue, :system, project: project,
+ note: "mentioned in !#{referenced_mr.iid}")
+ end
+ let(:referenced_mr) do
+ create(:merge_request, :simple, source_project: project, target_project: project,
+ description: "Fixes ##{issue.iid}", author: user)
+ end
+
+ before do
+ issue.notes << note
+
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it "hides the new branch button", js: true do
+ expect(page).not_to have_link "New Branch"
+ expect(page).to have_content /1 Related Merge Request/
+ end
+ end
+ end
+
+ context "for visiters" do
+ it 'no button is shown', js: false do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ expect(page).not_to have_link "New Branch"
+ end
+ end
+end
diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb
index 1b2fd1bab10..b76e4c74c79 100644
--- a/spec/features/merge_requests/filter_by_milestone_spec.rb
+++ b/spec/features/merge_requests/filter_by_milestone_spec.rb
@@ -30,8 +30,6 @@ feature 'Merge Request filtering by Milestone', feature: true do
def filter_by_milestone(title)
find(".js-milestone-select").click
- sleep 0.5
find(".milestone-filter a", text: title).click
- sleep 1
end
end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 57563add74c..f88c591d897 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -8,10 +8,12 @@ describe "Internal Project Access", feature: true do
let(:master) { create(:user) }
let(:guest) { create(:user) }
let(:reporter) { create(:user) }
+ let(:external_team_member) { create(:user, external: true) }
before do
# full access
project.team << [master, :master]
+ project.team << [external_team_member, :master]
# readonly
project.team << [reporter, :reporter]
@@ -34,6 +36,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -45,6 +49,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -56,6 +62,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -67,6 +75,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -78,6 +88,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -89,22 +101,23 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/blob" do
- before do
- commit = project.repository.commit
- path = '.gitignore'
- @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
- end
+ let(:commit) { project.repository.commit }
+ subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore')) }
- it { expect(@blob_path).to be_allowed_for master }
- it { expect(@blob_path).to be_allowed_for reporter }
- it { expect(@blob_path).to be_allowed_for :admin }
- it { expect(@blob_path).to be_allowed_for guest }
- it { expect(@blob_path).to be_allowed_for :user }
- it { expect(@blob_path).to be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/edit" do
@@ -115,6 +128,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -126,6 +141,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -137,6 +154,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -149,6 +168,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -160,6 +181,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -171,6 +194,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -182,6 +207,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -193,6 +220,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -209,6 +238,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -225,6 +256,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -236,6 +269,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index a1e111c6cab..19f287ce7a4 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -8,10 +8,12 @@ describe "Private Project Access", feature: true do
let(:master) { create(:user) }
let(:guest) { create(:user) }
let(:reporter) { create(:user) }
+ let(:external_team_member) { create(:user, external: true) }
before do
# full access
project.team << [master, :master]
+ project.team << [external_team_member, :master]
# readonly
project.team << [reporter, :reporter]
@@ -34,6 +36,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -45,6 +49,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -56,6 +62,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -67,6 +75,7 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -78,6 +87,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -89,22 +100,23 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/blob" do
- before do
- commit = project.repository.commit
- path = '.gitignore'
- @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
- end
+ let(:commit) { project.repository.commit }
+ subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore'))}
- it { expect(@blob_path).to be_allowed_for master }
- it { expect(@blob_path).to be_allowed_for reporter }
- it { expect(@blob_path).to be_allowed_for :admin }
- it { expect(@blob_path).to be_denied_for guest }
- it { expect(@blob_path).to be_denied_for :user }
- it { expect(@blob_path).to be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/edit" do
@@ -115,6 +127,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -126,6 +140,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -137,6 +153,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -149,6 +167,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -160,6 +180,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -171,6 +193,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -187,6 +211,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -203,6 +229,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
@@ -214,6 +242,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
+ it { is_expected.to be_allowed_for external_team_member }
it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index b98476f854e..4e135076367 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -38,6 +38,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -49,6 +50,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -60,6 +62,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -71,6 +74,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -82,6 +86,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -93,6 +98,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
@@ -107,6 +113,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -118,6 +125,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
end
@@ -135,6 +143,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -146,23 +155,22 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
end
describe "GET /:project_path/blob" do
- before do
- commit = project.repository.commit
- path = '.gitignore'
- @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
- end
+ let(:commit) { project.repository.commit }
+
+ subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore')) }
- it { expect(@blob_path).to be_allowed_for master }
- it { expect(@blob_path).to be_allowed_for reporter }
- it { expect(@blob_path).to be_allowed_for :admin }
- it { expect(@blob_path).to be_allowed_for guest }
- it { expect(@blob_path).to be_allowed_for :user }
- it { expect(@blob_path).to be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/edit" do
@@ -173,6 +181,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
@@ -184,6 +193,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
@@ -195,6 +205,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -207,6 +218,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
@@ -218,6 +230,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -229,6 +242,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
@@ -240,6 +254,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -251,6 +266,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
@@ -267,6 +283,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -283,6 +300,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
@@ -294,6 +312,7 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index e9bb388e361..9acf6304bcb 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -44,8 +44,78 @@ describe Banzai::Filter::RedactorFilter, lib: true do
end
end
- context "for user references" do
+ context 'with data-issue' do
+ context 'for confidential issues' do
+ it 'removes references for non project members' do
+ non_member = create(:user)
+ project = create(:empty_project, :public)
+ issue = create(:issue, :confidential, project: project)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ doc = filter(link, current_user: non_member)
+
+ expect(doc.css('a').length).to eq 0
+ end
+
+ it 'allows references for author' do
+ author = create(:user)
+ project = create(:empty_project, :public)
+ issue = create(:issue, :confidential, project: project, author: author)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ doc = filter(link, current_user: author)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'allows references for assignee' do
+ assignee = create(:user)
+ project = create(:empty_project, :public)
+ issue = create(:issue, :confidential, project: project, assignee: assignee)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ doc = filter(link, current_user: assignee)
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'allows references for project members' do
+ member = create(:user)
+ project = create(:empty_project, :public)
+ project.team << [member, :developer]
+ issue = create(:issue, :confidential, project: project)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ doc = filter(link, current_user: member)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'allows references for admin' do
+ admin = create(:admin)
+ project = create(:empty_project, :public)
+ issue = create(:issue, :confidential, project: project)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ doc = filter(link, current_user: admin)
+
+ expect(doc.css('a').length).to eq 1
+ end
+ end
+
+ it 'allows references for non confidential issues' do
+ user = create(:user)
+ project = create(:empty_project, :public)
+ issue = create(:issue, project: project)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 1
+ end
+ end
+
+ context "for user references" do
context 'with data-group' do
it 'removes unpermitted Group references' do
user = create(:user)
diff --git a/spec/lib/ci/status_spec.rb b/spec/lib/ci/status_spec.rb
index 1539720bb8d..47f3df6e3ce 100644
--- a/spec/lib/ci/status_spec.rb
+++ b/spec/lib/ci/status_spec.rb
@@ -48,6 +48,29 @@ describe Ci::Status do
it { is_expected.to eq 'success' }
end
+ context 'success and canceled' do
+ let(:statuses) do
+ [create(type, status: :success), create(type, status: :canceled)]
+ end
+ it { is_expected.to eq 'failed' }
+ end
+
+ context 'all canceled' do
+ let(:statuses) do
+ [create(type, status: :canceled), create(type, status: :canceled)]
+ end
+ it { is_expected.to eq 'canceled' }
+ end
+
+ context 'success and canceled but allowed to fail' do
+ let(:statuses) do
+ [create(type, status: :success),
+ create(type, status: :canceled, allow_failure: true)]
+ end
+
+ it { is_expected.to eq 'success' }
+ end
+
context 'one finished and second running but allowed to fail' do
let(:statuses) do
[create(type, status: :success),
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 04cf11fc6f1..844fd79c991 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -11,6 +11,7 @@ describe Gitlab::ClosingIssueExtractor, lib: true do
subject { described_class.new(project, project.creator) }
before do
+ project.team << [project.creator, :developer]
project2.team << [project.creator, :master]
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 0d9694f2c13..a0cbef6e6a4 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -18,4 +18,18 @@ describe Gitlab::Diff::File, lib: true do
describe :mode_changed? do
it { expect(diff_file.mode_changed?).to be_falsey }
end
+
+ describe '#too_large?' do
+ it 'returns true for a file that is too large' do
+ expect(diff).to receive(:too_large?).and_return(true)
+
+ expect(diff_file.too_large?).to eq(true)
+ end
+
+ it 'returns false for a file that is small enough' do
+ expect(diff).to receive(:too_large?).and_return(false)
+
+ expect(diff_file.too_large?).to eq(false)
+ end
+ end
end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 09adbc07dcb..db0ff95b4f5 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -1,11 +1,12 @@
require 'spec_helper'
describe Gitlab::ProjectSearchResults, lib: true do
+ let(:user) { create(:user) }
let(:project) { create(:project) }
let(:query) { 'hello world' }
describe 'initialize with empty ref' do
- let(:results) { Gitlab::ProjectSearchResults.new(project, query, '') }
+ let(:results) { Gitlab::ProjectSearchResults.new(user, project, query, '') }
it { expect(results.project).to eq(project) }
it { expect(results.repository_ref).to be_nil }
@@ -14,10 +15,74 @@ describe Gitlab::ProjectSearchResults, lib: true do
describe 'initialize with ref' do
let(:ref) { 'refs/heads/test' }
- let(:results) { Gitlab::ProjectSearchResults.new(project, query, ref) }
+ let(:results) { Gitlab::ProjectSearchResults.new(user, project, query, ref) }
it { expect(results.project).to eq(project) }
it { expect(results.repository_ref).to eq(ref) }
it { expect(results.query).to eq('hello world') }
end
+
+ describe 'confidential issues' do
+ let(:query) { 'issue' }
+ let(:author) { create(:user) }
+ let(:assignee) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:member) { create(:user) }
+ let(:admin) { create(:admin) }
+ let!(:issue) { create(:issue, project: project, title: 'Issue 1') }
+ let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
+ let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignee: assignee) }
+
+ it 'should not list project confidential issues for non project members' do
+ results = described_class.new(non_member, project, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).not_to include security_issue_1
+ expect(issues).not_to include security_issue_2
+ expect(results.issues_count).to eq 1
+ end
+
+ it 'should list project confidential issues for author' do
+ results = described_class.new(author, project, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).to include security_issue_1
+ expect(issues).not_to include security_issue_2
+ expect(results.issues_count).to eq 2
+ end
+
+ it 'should list project confidential issues for assignee' do
+ results = described_class.new(assignee, project.id, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).not_to include security_issue_1
+ expect(issues).to include security_issue_2
+ expect(results.issues_count).to eq 2
+ end
+
+ it 'should list project confidential issues for project members' do
+ project.team << [member, :developer]
+
+ results = described_class.new(member, project, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).to include security_issue_1
+ expect(issues).to include security_issue_2
+ expect(results.issues_count).to eq 3
+ end
+
+ it 'should list all project issues for admin' do
+ results = described_class.new(admin, project, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).to include security_issue_1
+ expect(issues).to include security_issue_2
+ expect(results.issues_count).to eq 3
+ end
+ end
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index ba47a3540ff..f2922160331 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
describe Gitlab::ReferenceExtractor, lib: true do
let(:project) { create(:project) }
+
subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
it 'accesses valid user objects' do
@@ -41,6 +42,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
end
it 'accesses valid issue objects' do
+ project.team << [project.creator, :developer]
@i0 = create(:issue, project: project)
@i1 = create(:issue, project: project)
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index bb18f417858..f4afe597e8d 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe Gitlab::SearchResults do
+ let(:user) { create(:user) }
let!(:project) { create(:project, name: 'foo') }
let!(:issue) { create(:issue, project: project, title: 'foo') }
@@ -9,7 +10,7 @@ describe Gitlab::SearchResults do
end
let!(:milestone) { create(:milestone, project: project, title: 'foo') }
- let(:results) { described_class.new(Project.all, 'foo') }
+ let(:results) { described_class.new(user, Project.all, 'foo') }
describe '#total_count' do
it 'returns the total amount of search hits' do
@@ -52,4 +53,92 @@ describe Gitlab::SearchResults do
expect(results.empty?).to eq(false)
end
end
+
+ describe 'confidential issues' do
+ let(:project_1) { create(:empty_project) }
+ let(:project_2) { create(:empty_project) }
+ let(:project_3) { create(:empty_project) }
+ let(:project_4) { create(:empty_project) }
+ let(:query) { 'issue' }
+ let(:limit_projects) { Project.where(id: [project_1.id, project_2.id, project_3.id]) }
+ let(:author) { create(:user) }
+ let(:assignee) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:member) { create(:user) }
+ let(:admin) { create(:admin) }
+ let!(:issue) { create(:issue, project: project_1, title: 'Issue 1') }
+ let!(:security_issue_1) { create(:issue, :confidential, project: project_1, title: 'Security issue 1', author: author) }
+ let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project_1, assignee: assignee) }
+ let!(:security_issue_3) { create(:issue, :confidential, project: project_2, title: 'Security issue 3', author: author) }
+ let!(:security_issue_4) { create(:issue, :confidential, project: project_3, title: 'Security issue 4', assignee: assignee) }
+ let!(:security_issue_5) { create(:issue, :confidential, project: project_4, title: 'Security issue 5') }
+
+ it 'should not list confidential issues for non project members' do
+ results = described_class.new(non_member, limit_projects, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).not_to include security_issue_1
+ expect(issues).not_to include security_issue_2
+ expect(issues).not_to include security_issue_3
+ expect(issues).not_to include security_issue_4
+ expect(issues).not_to include security_issue_5
+ expect(results.issues_count).to eq 1
+ end
+
+ it 'should list confidential issues for author' do
+ results = described_class.new(author, limit_projects, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).to include security_issue_1
+ expect(issues).not_to include security_issue_2
+ expect(issues).to include security_issue_3
+ expect(issues).not_to include security_issue_4
+ expect(issues).not_to include security_issue_5
+ expect(results.issues_count).to eq 3
+ end
+
+ it 'should list confidential issues for assignee' do
+ results = described_class.new(assignee, limit_projects, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).not_to include security_issue_1
+ expect(issues).to include security_issue_2
+ expect(issues).not_to include security_issue_3
+ expect(issues).to include security_issue_4
+ expect(issues).not_to include security_issue_5
+ expect(results.issues_count).to eq 3
+ end
+
+ it 'should list confidential issues for project members' do
+ project_1.team << [member, :developer]
+ project_2.team << [member, :developer]
+
+ results = described_class.new(member, limit_projects, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).to include security_issue_1
+ expect(issues).to include security_issue_2
+ expect(issues).to include security_issue_3
+ expect(issues).not_to include security_issue_4
+ expect(issues).not_to include security_issue_5
+ expect(results.issues_count).to eq 4
+ end
+
+ it 'should list all issues for admin' do
+ results = described_class.new(admin, limit_projects, query)
+ issues = results.objects('issues')
+
+ expect(issues).to include issue
+ expect(issues).to include security_issue_1
+ expect(issues).to include security_issue_2
+ expect(issues).to include security_issue_3
+ expect(issues).to include security_issue_4
+ expect(issues).not_to include security_issue_5
+ expect(results.issues_count).to eq 5
+ end
+ end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 253902512c3..0e9111c8029 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -86,10 +86,21 @@ eos
let(:issue) { create :issue, project: project }
let(:other_project) { create :project, :public }
let(:other_issue) { create :issue, project: other_project }
+ let(:commiter) { create :user }
+
+ before do
+ project.team << [commiter, :developer]
+ other_project.team << [commiter, :developer]
+ end
it 'detects issues that this commit is marked as closing' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
- allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid} and #{ext_ref}")
+
+ allow(commit).to receive_messages(
+ safe_message: "Fixes ##{issue.iid} and #{ext_ref}",
+ committer_email: commiter.email
+ )
+
expect(commit.closes_issues).to include(issue)
expect(commit.closes_issues).to include(other_issue)
end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 20f0c561e44..cb33edde820 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -48,7 +48,8 @@ describe Issue, "Mentionable" do
describe '#create_new_cross_references!' do
let(:project) { create(:project) }
- let(:issues) { create_list(:issue, 2, project: project) }
+ let(:author) { create(:author) }
+ let(:issues) { create_list(:issue, 2, project: project, author: author) }
context 'before changes are persisted' do
it 'ignores pre-existing references' do
@@ -91,7 +92,7 @@ describe Issue, "Mentionable" do
end
def create_issue(description:)
- create(:issue, project: project, description: description)
+ create(:issue, project: project, description: description, author: author)
end
end
end
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
new file mode 100644
index 00000000000..47c3be673c5
--- /dev/null
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -0,0 +1,104 @@
+require 'spec_helper'
+
+describe Milestone, 'Milestoneish' do
+ let(:author) { create(:user) }
+ let(:assignee) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:member) { create(:user) }
+ let(:admin) { create(:admin) }
+ let(:project) { create(:project, :public) }
+ let(:milestone) { create(:milestone, project: project) }
+ let!(:issue) { create(:issue, project: project, milestone: milestone) }
+ let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) }
+ let!(:security_issue_2) { create(:issue, :confidential, project: project, assignee: assignee, milestone: milestone) }
+ let!(:closed_issue_1) { create(:issue, :closed, project: project, milestone: milestone) }
+ let!(:closed_issue_2) { create(:issue, :closed, project: project, milestone: milestone) }
+ let!(:closed_security_issue_1) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
+ let!(:closed_security_issue_2) { create(:issue, :confidential, :closed, project: project, assignee: assignee, milestone: milestone) }
+ let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
+ let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignee: assignee, milestone: milestone) }
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
+
+ before do
+ project.team << [member, :developer]
+ end
+
+ describe '#closed_items_count' do
+ it 'should not count confidential issues for non project members' do
+ expect(milestone.closed_items_count(non_member)).to eq 2
+ end
+
+ it 'should count confidential issues for author' do
+ expect(milestone.closed_items_count(author)).to eq 4
+ end
+
+ it 'should count confidential issues for assignee' do
+ expect(milestone.closed_items_count(assignee)).to eq 4
+ end
+
+ it 'should count confidential issues for project members' do
+ expect(milestone.closed_items_count(member)).to eq 6
+ end
+
+ it 'should count all issues for admin' do
+ expect(milestone.closed_items_count(admin)).to eq 6
+ end
+ end
+
+ describe '#total_items_count' do
+ it 'should not count confidential issues for non project members' do
+ expect(milestone.total_items_count(non_member)).to eq 4
+ end
+
+ it 'should count confidential issues for author' do
+ expect(milestone.total_items_count(author)).to eq 7
+ end
+
+ it 'should count confidential issues for assignee' do
+ expect(milestone.total_items_count(assignee)).to eq 7
+ end
+
+ it 'should count confidential issues for project members' do
+ expect(milestone.total_items_count(member)).to eq 10
+ end
+
+ it 'should count all issues for admin' do
+ expect(milestone.total_items_count(admin)).to eq 10
+ end
+ end
+
+ describe '#complete?' do
+ it 'returns false when has items opened' do
+ expect(milestone.complete?(non_member)).to eq false
+ end
+
+ it 'returns true when all items are closed' do
+ issue.close
+ merge_request.close
+
+ expect(milestone.complete?(non_member)).to eq true
+ end
+ end
+
+ describe '#percent_complete' do
+ it 'should not count confidential issues for non project members' do
+ expect(milestone.percent_complete(non_member)).to eq 50
+ end
+
+ it 'should count confidential issues for author' do
+ expect(milestone.percent_complete(author)).to eq 57
+ end
+
+ it 'should count confidential issues for assignee' do
+ expect(milestone.percent_complete(assignee)).to eq 57
+ end
+
+ it 'should count confidential issues for project members' do
+ expect(milestone.percent_complete(member)).to eq 60
+ end
+
+ it 'should count confidential issues for admin' do
+ expect(milestone.percent_complete(admin)).to eq 60
+ end
+ end
+end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index ec2a923f91b..5fe44246738 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -65,6 +65,42 @@ describe Event, models: true do
it { expect(@event.author).to eq(@user) }
end
+ describe '#proper?' do
+ context 'issue event' do
+ let(:project) { create(:empty_project, :public) }
+ let(:non_member) { create(:user) }
+ let(:member) { create(:user) }
+ let(:author) { create(:author) }
+ let(:assignee) { create(:user) }
+ let(:admin) { create(:admin) }
+ let(:event) { Event.new(project: project, action: Event::CREATED, target: issue, author_id: author.id) }
+
+ before do
+ project.team << [member, :developer]
+ end
+
+ context 'for non confidential issues' do
+ let(:issue) { create(:issue, project: project, author: author, assignee: assignee) }
+
+ it { expect(event.proper?(non_member)).to eq true }
+ it { expect(event.proper?(author)).to eq true }
+ it { expect(event.proper?(assignee)).to eq true }
+ it { expect(event.proper?(member)).to eq true }
+ it { expect(event.proper?(admin)).to eq true }
+ end
+
+ context 'for confidential issues' do
+ let(:issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) }
+
+ it { expect(event.proper?(non_member)).to eq false }
+ it { expect(event.proper?(author)).to eq true }
+ it { expect(event.proper?(assignee)).to eq true }
+ it { expect(event.proper?(member)).to eq true }
+ it { expect(event.proper?(admin)).to eq true }
+ end
+ end
+ end
+
describe '.limit_recent' do
let!(:event1) { create(:closed_issue_event) }
let!(:event2) { create(:closed_issue_event) }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 0d6e9cb3a4c..1b54d498169 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -180,6 +180,15 @@ describe Issue, models: true do
end
end
+ describe '#related_branches' do
+ it "should " do
+ allow(subject.project.repository).to receive(:branch_names).
+ and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name])
+
+ expect(subject.related_branches).to eq [subject.to_branch_name]
+ end
+ end
+
it_behaves_like 'an editable mentionable' do
subject { create(:issue) }
@@ -190,4 +199,12 @@ describe Issue, models: true do
it_behaves_like 'a Taskable' do
let(:subject) { create :issue }
end
+
+ describe "#to_branch_name" do
+ let(:issue) { build(:issue, title: 'a' * 30) }
+
+ it "starts with the issue iid" do
+ expect(issue.to_branch_name).to match /\A#{issue.iid}-a+\z/
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 8bf68013fd2..2165cfb7a32 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -86,6 +86,41 @@ describe MergeRequest, models: true do
end
end
+ describe '#target_sha' do
+ context 'when the target branch does not exist anymore' do
+ subject { create(:merge_request).tap { |mr| mr.update_attribute(:target_branch, 'deleted') } }
+
+ it 'returns nil' do
+ expect(subject.target_sha).to be_nil
+ end
+ end
+ end
+
+ describe '#source_sha' do
+ let(:last_branch_commit) { subject.source_project.repository.commit(subject.source_branch) }
+
+ context 'with diffs' do
+ subject { create(:merge_request, :with_diffs) }
+ it 'returns the sha of the source branch last commit' do
+ expect(subject.source_sha).to eq(last_branch_commit.sha)
+ end
+ end
+
+ context 'without diffs' do
+ subject { create(:merge_request, :without_diffs) }
+ it 'returns the sha of the source branch last commit' do
+ expect(subject.source_sha).to eq(last_branch_commit.sha)
+ end
+ end
+
+ context 'when the merge request is being created' do
+ subject { build(:merge_request, source_branch: nil, compare_commits: []) }
+ it 'returns nil' do
+ expect(subject.source_sha).to be_nil
+ end
+ end
+ end
+
describe '#to_reference' do
it 'returns a String reference to the object' do
expect(subject.to_reference).to eq "!#{subject.iid}"
@@ -150,6 +185,7 @@ describe MergeRequest, models: true do
let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") }
before do
+ subject.project.team << [subject.author, :developer]
allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
end
@@ -284,6 +320,18 @@ describe MergeRequest, models: true do
let(:project) { create(:project) }
let(:fork_project) { create(:project, forked_from_project: project) }
+ context 'when the target branch does not exist anymore' do
+ subject { create(:merge_request).tap { |mr| mr.update_attribute(:target_branch, 'deleted') } }
+
+ it 'does not crash' do
+ expect{ subject.diverged_commits_count }.not_to raise_error
+ end
+
+ it 'returns 0' do
+ expect(subject.diverged_commits_count).to eq(0)
+ end
+ end
+
context 'diverged on same repository' do
subject(:merge_request_with_divergence) { create(:merge_request, :diverged, source_project: project, target_project: project) }
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index de1757bf67a..72a4ea70228 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -32,6 +32,7 @@ describe Milestone, models: true do
let(:milestone) { create(:milestone) }
let(:issue) { create(:issue) }
+ let(:user) { create(:user) }
describe "unique milestone title per project" do
it "shouldn't accept the same title in a project twice" do
@@ -50,18 +51,17 @@ describe Milestone, models: true do
describe "#percent_complete" do
it "should not count open issues" do
milestone.issues << issue
- expect(milestone.percent_complete).to eq(0)
+ expect(milestone.percent_complete(user)).to eq(0)
end
it "should count closed issues" do
issue.close
milestone.issues << issue
- expect(milestone.percent_complete).to eq(100)
+ expect(milestone.percent_complete(user)).to eq(100)
end
it "should recover from dividing by zero" do
- expect(milestone.issues).to receive(:size).and_return(0)
- expect(milestone.percent_complete).to eq(0)
+ expect(milestone.percent_complete(user)).to eq(0)
end
end
@@ -103,7 +103,7 @@ describe Milestone, models: true do
)
end
- it { expect(milestone.percent_complete).to eq(75) }
+ it { expect(milestone.percent_complete(user)).to eq(75) }
end
describe :items_count do
@@ -113,23 +113,23 @@ describe Milestone, models: true do
milestone.merge_requests << create(:merge_request)
end
- it { expect(milestone.closed_items_count).to eq(1) }
- it { expect(milestone.total_items_count).to eq(3) }
- it { expect(milestone.is_empty?).to be_falsey }
+ it { expect(milestone.closed_items_count(user)).to eq(1) }
+ it { expect(milestone.total_items_count(user)).to eq(3) }
+ it { expect(milestone.is_empty?(user)).to be_falsey }
end
describe :can_be_closed? do
it { expect(milestone.can_be_closed?).to be_truthy }
end
- describe :is_empty? do
+ describe :total_items_count do
before do
create :closed_issue, milestone: milestone
create :merge_request, milestone: milestone
end
it 'Should return total count of issues and merge requests assigned to milestone' do
- expect(milestone.total_items_count).to eq 2
+ expect(milestone.total_items_count(user)).to eq 2
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index fc2ab2d9931..a57229a4fdf 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -597,9 +597,9 @@ describe Repository, models: true do
describe '#after_push_commit' do
it 'flushes the cache' do
- expect(repository).to receive(:expire_cache).with('master')
+ expect(repository).to receive(:expire_cache).with('master', '123')
- repository.after_push_commit('master')
+ repository.after_push_commit('master', '123')
end
end
@@ -703,4 +703,111 @@ describe Repository, models: true do
repository.rm_tag('8.5')
end
end
+
+ describe '#avatar' do
+ it 'returns the first avatar file found in the repository' do
+ expect(repository).to receive(:blob_at_branch).
+ with('master', 'logo.png').
+ and_return(true)
+
+ expect(repository.avatar).to eq('logo.png')
+ end
+
+ it 'caches the output' do
+ allow(repository).to receive(:blob_at_branch).
+ with('master', 'logo.png').
+ and_return(true)
+
+ expect(repository.avatar).to eq('logo.png')
+
+ expect(repository).to_not receive(:blob_at_branch)
+ expect(repository.avatar).to eq('logo.png')
+ end
+ end
+
+ describe '#expire_avatar_cache' do
+ let(:cache) { repository.send(:cache) }
+
+ before do
+ allow(repository).to receive(:cache).and_return(cache)
+ end
+
+ context 'without a branch or revision' do
+ it 'flushes the cache' do
+ expect(cache).to receive(:expire).with(:avatar)
+
+ repository.expire_avatar_cache
+ end
+ end
+
+ context 'with a branch' do
+ it 'does not flush the cache if the branch is not the default branch' do
+ expect(cache).not_to receive(:expire)
+
+ repository.expire_avatar_cache('cats')
+ end
+
+ it 'flushes the cache if the branch equals the default branch' do
+ expect(cache).to receive(:expire).with(:avatar)
+
+ repository.expire_avatar_cache(repository.root_ref)
+ end
+ end
+
+ context 'with a branch and revision' do
+ let(:commit) { double(:commit) }
+
+ before do
+ allow(repository).to receive(:commit).and_return(commit)
+ end
+
+ it 'does not flush the cache if the commit does not change any logos' do
+ diff = double(:diff, new_path: 'test.txt')
+
+ expect(commit).to receive(:diffs).and_return([diff])
+ expect(cache).not_to receive(:expire)
+
+ repository.expire_avatar_cache(repository.root_ref, '123')
+ end
+
+ it 'flushes the cache if the commit changes any of the logos' do
+ diff = double(:diff, new_path: Repository::AVATAR_FILES[0])
+
+ expect(commit).to receive(:diffs).and_return([diff])
+ expect(cache).to receive(:expire).with(:avatar)
+
+ repository.expire_avatar_cache(repository.root_ref, '123')
+ end
+ end
+ end
+
+ describe '#build_cache' do
+ let(:cache) { repository.send(:cache) }
+
+ it 'builds the caches if they do not already exist' do
+ expect(cache).to receive(:exist?).
+ exactly(repository.cache_keys.length).
+ times.
+ and_return(false)
+
+ repository.cache_keys.each do |key|
+ expect(repository).to receive(key)
+ end
+
+ repository.build_cache
+ end
+
+ it 'does not build any caches that already exist' do
+ expect(cache).to receive(:exist?).
+ exactly(repository.cache_keys.length).
+ times.
+ and_return(true)
+
+ repository.cache_keys.each do |key|
+ expect(repository).to_not receive(key)
+ end
+
+ repository.build_cache
+ end
+ end
end
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index fe9ea7e7d1e..d9b86b9368f 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -5,19 +5,24 @@
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
-# target_id :integer not null
+# target_id :integer
# target_type :string not null
# author_id :integer
-# note_id :integer
# action :integer not null
# state :string not null
# created_at :datetime
# updated_at :datetime
+# note_id :integer
+# commit_id :string
#
require 'spec_helper'
describe Todo, models: true do
+ let(:project) { create(:project) }
+ let(:commit) { project.commit }
+ let(:issue) { create(:issue) }
+
describe 'relationships' do
it { is_expected.to belong_to(:author).class_name("User") }
it { is_expected.to belong_to(:note) }
@@ -33,8 +38,22 @@ describe Todo, models: true do
describe 'validations' do
it { is_expected.to validate_presence_of(:action) }
- it { is_expected.to validate_presence_of(:target) }
+ it { is_expected.to validate_presence_of(:target_type) }
it { is_expected.to validate_presence_of(:user) }
+
+ context 'for commits' do
+ subject { described_class.new(target_type: 'Commit') }
+
+ it { is_expected.to validate_presence_of(:commit_id) }
+ it { is_expected.not_to validate_presence_of(:target_id) }
+ end
+
+ context 'for issuables' do
+ subject { described_class.new(target: issue) }
+
+ it { is_expected.to validate_presence_of(:target_id) }
+ it { is_expected.not_to validate_presence_of(:commit_id) }
+ end
end
describe '#body' do
@@ -55,15 +74,69 @@ describe Todo, models: true do
end
end
- describe '#done!' do
+ describe '#done' do
it 'changes state to done' do
todo = create(:todo, state: :pending)
- expect { todo.done! }.to change(todo, :state).from('pending').to('done')
+ expect { todo.done }.to change(todo, :state).from('pending').to('done')
end
it 'does not raise error when is already done' do
todo = create(:todo, state: :done)
- expect { todo.done! }.not_to raise_error
+ expect { todo.done }.not_to raise_error
+ end
+ end
+
+ describe '#for_commit?' do
+ it 'returns true when target is a commit' do
+ subject.target_type = 'Commit'
+ expect(subject.for_commit?).to eq true
+ end
+
+ it 'returns false when target is an issuable' do
+ subject.target_type = 'Issue'
+ expect(subject.for_commit?).to eq false
+ end
+ end
+
+ describe '#target' do
+ context 'for commits' do
+ it 'returns an instance of Commit when exists' do
+ subject.project = project
+ subject.target_type = 'Commit'
+ subject.commit_id = commit.id
+
+ expect(subject.target).to be_a(Commit)
+ expect(subject.target).to eq commit
+ end
+
+ it 'returns nil when does not exists' do
+ subject.project = project
+ subject.target_type = 'Commit'
+ subject.commit_id = 'xxxx'
+
+ expect(subject.target).to be_nil
+ end
+ end
+
+ it 'returns the issuable for issuables' do
+ subject.target_id = issue.id
+ subject.target_type = issue.class.name
+ expect(subject.target).to eq issue
+ end
+ end
+
+ describe '#target_reference' do
+ it 'returns the short commit id for commits' do
+ subject.project = project
+ subject.target_type = 'Commit'
+ subject.commit_id = commit.id
+
+ expect(subject.target_reference).to eq commit.short_id
+ end
+
+ it 'returns reference for issuables' do
+ subject.target = issue
+ expect(subject.target_reference).to eq issue.to_reference
end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 6290ab3ebec..0ab7fd88ce6 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -180,6 +180,20 @@ describe User, models: true do
it { is_expected.to respond_to(:is_admin?) }
it { is_expected.to respond_to(:name) }
it { is_expected.to respond_to(:private_token) }
+ it { is_expected.to respond_to(:external?) }
+ end
+
+ describe 'before save hook' do
+ context 'when saving an external user' do
+ let(:user) { create(:user) }
+ let(:external_user) { create(:user, external: true) }
+
+ it "sets other properties aswell" do
+ expect(external_user.can_create_team).to be_falsey
+ expect(external_user.can_create_group).to be_falsey
+ expect(external_user.projects_limit).to be 0
+ end
+ end
end
describe '#confirm' do
@@ -404,6 +418,7 @@ describe User, models: true do
expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit)
expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group)
expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme)
+ expect(user.external).to be_falsey
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 571ea2dae4c..bb2ab058003 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -3,7 +3,11 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace ) }
+ let(:non_member) { create(:user) }
+ let(:author) { create(:author) }
+ let(:assignee) { create(:assignee) }
+ let(:admin) { create(:admin) }
+ let!(:project) { create(:project, :public, namespace: user.namespace ) }
let!(:closed_issue) do
create :closed_issue,
author: user,
@@ -12,6 +16,13 @@ describe API::API, api: true do
state: :closed,
milestone: milestone
end
+ let!(:confidential_issue) do
+ create :issue,
+ :confidential,
+ project: project,
+ author: author,
+ assignee: assignee
+ end
let!(:issue) do
create :issue,
author: user,
@@ -123,10 +134,43 @@ describe API::API, api: true do
let(:base_url) { "/projects/#{project.id}" }
let(:title) { milestone.title }
- it "should return project issues" do
+ it 'should return project issues without confidential issues for non project members' do
+ get api("#{base_url}/issues", non_member)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.first['title']).to eq(issue.title)
+ end
+
+ it 'should return project confidential issues for author' do
+ get api("#{base_url}/issues", author)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.first['title']).to eq(issue.title)
+ end
+
+ it 'should return project confidential issues for assignee' do
+ get api("#{base_url}/issues", assignee)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.first['title']).to eq(issue.title)
+ end
+
+ it 'should return project issues with confidential issues for project members' do
get api("#{base_url}/issues", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.first['title']).to eq(issue.title)
+ end
+
+ it 'should return project confidential issues for admin' do
+ get api("#{base_url}/issues", admin)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
expect(json_response.first['title']).to eq(issue.title)
end
@@ -206,6 +250,41 @@ describe API::API, api: true do
get api("/projects/#{project.id}/issues/54321", user)
expect(response.status).to eq(404)
end
+
+ context 'confidential issues' do
+ it "should return 404 for non project members" do
+ get api("/projects/#{project.id}/issues/#{confidential_issue.id}", non_member)
+ expect(response.status).to eq(404)
+ end
+
+ it "should return confidential issue for project members" do
+ get api("/projects/#{project.id}/issues/#{confidential_issue.id}", user)
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(confidential_issue.title)
+ expect(json_response['iid']).to eq(confidential_issue.iid)
+ end
+
+ it "should return confidential issue for author" do
+ get api("/projects/#{project.id}/issues/#{confidential_issue.id}", author)
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(confidential_issue.title)
+ expect(json_response['iid']).to eq(confidential_issue.iid)
+ end
+
+ it "should return confidential issue for assignee" do
+ get api("/projects/#{project.id}/issues/#{confidential_issue.id}", assignee)
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(confidential_issue.title)
+ expect(json_response['iid']).to eq(confidential_issue.iid)
+ end
+
+ it "should return confidential issue for admin" do
+ get api("/projects/#{project.id}/issues/#{confidential_issue.id}", admin)
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(confidential_issue.title)
+ expect(json_response['iid']).to eq(confidential_issue.iid)
+ end
+ end
end
describe "POST /projects/:id/issues" do
@@ -294,6 +373,35 @@ describe API::API, api: true do
expect(response.status).to eq(400)
expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
end
+
+ context 'confidential issues' do
+ it "should return 403 for non project members" do
+ put api("/projects/#{project.id}/issues/#{confidential_issue.id}", non_member),
+ title: 'updated title'
+ expect(response.status).to eq(403)
+ end
+
+ it "should update a confidential issue for project members" do
+ put api("/projects/#{project.id}/issues/#{confidential_issue.id}", user),
+ title: 'updated title'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('updated title')
+ end
+
+ it "should update a confidential issue for author" do
+ put api("/projects/#{project.id}/issues/#{confidential_issue.id}", author),
+ title: 'updated title'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('updated title')
+ end
+
+ it "should update a confidential issue for admin" do
+ put api("/projects/#{project.id}/issues/#{confidential_issue.id}", admin),
+ title: 'updated title'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('updated title')
+ end
+ end
end
describe 'PUT /projects/:id/issues/:issue_id to update labels' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 96e8c8c51f8..679227bf881 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -120,6 +120,26 @@ describe API::API, api: true do
expect(response.status).to eq(201)
end
+ it 'creates non-external users by default' do
+ post api("/users", admin), attributes_for(:user)
+ expect(response.status).to eq(201)
+
+ user_id = json_response['id']
+ new_user = User.find(user_id)
+ expect(new_user).not_to eq nil
+ expect(new_user.external).to be_falsy
+ end
+
+ it 'should allow an external user to be created' do
+ post api("/users", admin), attributes_for(:user, external: true)
+ expect(response.status).to eq(201)
+
+ user_id = json_response['id']
+ new_user = User.find(user_id)
+ expect(new_user).not_to eq nil
+ expect(new_user.external).to be_truthy
+ end
+
it "should not create user with invalid email" do
post api('/users', admin),
email: 'invalid email',
@@ -262,6 +282,13 @@ describe API::API, api: true do
expect(user.reload.admin).to eq(true)
end
+ it "should update external status" do
+ put api("/users/#{user.id}", admin), { external: true }
+ expect(response.status).to eq 200
+ expect(json_response['external']).to eq(true)
+ expect(user.reload.external?).to be_truthy
+ end
+
it "should not update admin status" do
put api("/users/#{admin_user.id}", admin), { can_create_group: false }
expect(response.status).to eq(200)
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 145bc937560..8490a729e51 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -29,7 +29,8 @@ describe GitPushService, services: true do
it { is_expected.to be_truthy }
it 'flushes general cached data' do
- expect(project.repository).to receive(:expire_cache).with('master')
+ expect(project.repository).to receive(:expire_cache).
+ with('master', newrev)
subject
end
@@ -46,7 +47,8 @@ describe GitPushService, services: true do
it { is_expected.to be_truthy }
it 'flushes general cached data' do
- expect(project.repository).to receive(:expire_cache).with('master')
+ expect(project.repository).to receive(:expire_cache).
+ with('master', newrev)
subject
end
@@ -65,7 +67,8 @@ describe GitPushService, services: true do
end
it 'flushes general cached data' do
- expect(project.repository).to receive(:expire_cache).with('master')
+ expect(project.repository).to receive(:expire_cache).
+ with('master', newrev)
subject
end
@@ -212,12 +215,16 @@ describe GitPushService, services: true do
let(:commit) { project.commit }
before do
+ project.team << [commit_author, :developer]
+ project.team << [user, :developer]
+
allow(commit).to receive_messages(
safe_message: "this commit \n mentions #{issue.to_reference}",
references: [issue],
author_name: commit_author.name,
author_email: commit_author.email
)
+
allow(project.repository).to receive(:commits_between).and_return([commit])
end
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
new file mode 100644
index 00000000000..6108c26a78b
--- /dev/null
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -0,0 +1,79 @@
+require 'spec_helper'
+
+describe Projects::AutocompleteService, services: true do
+ describe '#issues' do
+ describe 'confidential issues' do
+ let(:author) { create(:user) }
+ let(:assignee) { create(:user) }
+ let(:non_member) { create(:user) }
+ let(:member) { create(:user) }
+ let(:admin) { create(:admin) }
+ let(:project) { create(:empty_project, :public) }
+ let!(:issue) { create(:issue, project: project, title: 'Issue 1') }
+ let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
+ let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignee: assignee) }
+
+ it 'should not list project confidential issues for guests' do
+ autocomplete = described_class.new(project, nil)
+ issues = autocomplete.issues.map(&:iid)
+
+ expect(issues).to include issue.iid
+ expect(issues).not_to include security_issue_1.iid
+ expect(issues).not_to include security_issue_2.iid
+ expect(issues.count).to eq 1
+ end
+
+ it 'should not list project confidential issues for non project members' do
+ autocomplete = described_class.new(project, non_member)
+ issues = autocomplete.issues.map(&:iid)
+
+ expect(issues).to include issue.iid
+ expect(issues).not_to include security_issue_1.iid
+ expect(issues).not_to include security_issue_2.iid
+ expect(issues.count).to eq 1
+ end
+
+ it 'should list project confidential issues for author' do
+ autocomplete = described_class.new(project, author)
+ issues = autocomplete.issues.map(&:iid)
+
+ expect(issues).to include issue.iid
+ expect(issues).to include security_issue_1.iid
+ expect(issues).not_to include security_issue_2.iid
+ expect(issues.count).to eq 2
+ end
+
+ it 'should list project confidential issues for assignee' do
+ autocomplete = described_class.new(project, assignee)
+ issues = autocomplete.issues.map(&:iid)
+
+ expect(issues).to include issue.iid
+ expect(issues).not_to include security_issue_1.iid
+ expect(issues).to include security_issue_2.iid
+ expect(issues.count).to eq 2
+ end
+
+ it 'should list project confidential issues for project members' do
+ project.team << [member, :developer]
+
+ autocomplete = described_class.new(project, member)
+ issues = autocomplete.issues.map(&:iid)
+
+ expect(issues).to include issue.iid
+ expect(issues).to include security_issue_1.iid
+ expect(issues).to include security_issue_2.iid
+ expect(issues.count).to eq 3
+ end
+
+ it 'should list all project issues for admin' do
+ autocomplete = described_class.new(project, admin)
+ issues = autocomplete.issues.map(&:iid)
+
+ expect(issues).to include issue.iid
+ expect(issues).to include security_issue_1.iid
+ expect(issues).to include security_issue_2.iid
+ expect(issues.count).to eq 3
+ end
+ end
+ end
+end
diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb
index 93bf1b81fbe..4c5ced7e746 100644
--- a/spec/services/projects/housekeeping_service_spec.rb
+++ b/spec/services/projects/housekeeping_service_spec.rb
@@ -12,7 +12,7 @@ describe Projects::HousekeepingService do
it 'enqueues a sidekiq job' do
expect(subject).to receive(:try_obtain_lease).and_return(true)
- expect(GitlabShellWorker).to receive(:perform_async).with(:gc, project.path_with_namespace)
+ expect(GitlabShellOneShotWorker).to receive(:perform_async).with(:gc, project.path_with_namespace)
subject.execute
expect(project.pushes_since_gc).to eq(0)
@@ -20,7 +20,7 @@ describe Projects::HousekeepingService do
it 'does not enqueue a job when no lease can be obtained' do
expect(subject).to receive(:try_obtain_lease).and_return(false)
- expect(GitlabShellWorker).not_to receive(:perform_async)
+ expect(GitlabShellOneShotWorker).not_to receive(:perform_async)
expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken)
expect(project.pushes_since_gc).to eq(0)
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 7c93ce304f9..240eae10052 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -280,6 +280,18 @@ describe SystemNoteService, services: true do
end
end
+ describe '.new_issue_branch' do
+ subject { described_class.new_issue_branch(noteable, project, author, "1-mepmep") }
+
+ it_behaves_like 'a system note'
+
+ context 'when a branch is created from the new branch button' do
+ it 'sets the note text' do
+ expect(subject.note).to match /\AStarted branch [`1-mepmep`]/
+ end
+ end
+ end
+
describe '.cross_reference' do
subject { described_class.cross_reference(noteable, mentioner, author) }
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 96420acb31d..b4728807b8b 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -148,8 +148,13 @@ describe TodoService, services: true do
should_not_create_todo(user: stranger, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
end
- it 'does not create todo when leaving a note on commit' do
- should_not_create_any_todo { service.new_note(note_on_commit, john_doe) }
+ it 'creates a todo for each valid mentioned user when leaving a note on commit' do
+ service.new_note(note_on_commit, john_doe)
+
+ should_create_todo(user: michael, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
+ should_create_todo(user: author, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
+ should_not_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
+ should_not_create_todo(user: stranger, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
end
it 'does not create todo when leaving a note on snippet' do
diff --git a/spec/support/matchers/access_matchers.rb b/spec/support/matchers/access_matchers.rb
index 558e8b1612f..4e007c777e3 100644
--- a/spec/support/matchers/access_matchers.rb
+++ b/spec/support/matchers/access_matchers.rb
@@ -15,6 +15,8 @@ module AccessMatchers
logout
when :admin
login_as(create(:admin))
+ when :external
+ login_as(create(:user, external: true))
when User
login_as(user)
else
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index fce91015fd4..e876d44c166 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -52,6 +52,8 @@ shared_context 'mentionable context' do
end
set_mentionable_text.call(ref_string)
+
+ project.team << [author, :developer]
end
end